From: Manuel Bachmann Date: Mon, 10 Nov 2014 13:33:19 +0000 (+0100) Subject: Implement a notification response wait/send API X-Git-Tag: submit/tizen_common/20141114.091625^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=ca4ab014da6920b269d1792f8fdb84cc57885f2b;p=platform%2Fcore%2Fapi%2Fnotification.git Implement a notification response wait/send API Currently, interactive responses for notifications (done in notification-display-service) are sent using a framework- dependent mechanism. This is prone to become unmaintainable as the scope of GUI notifications broadens. There is a need for a generic way to wait for notifications responses on one side, and to send such a response on another side. We introduce 2 new functions here : - notification_wait_response() : retrieves an integer and a char* from the response, with an optional timeout value. - notification_send_response() : send a response under the form of an integer and an optional char*. Communication is done with sockets using a TID (thread ID) as an identifier. Bug-Tizen: TC-996 Change-Id: I86d9d4bc3399dddff03b7f6c7eacbe2f842c5019 Signed-off-by: Manuel Bachmann --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c230dfd..7fa2c0a7 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,7 +57,7 @@ FOREACH(flag ${pkgs_CFLAGS}) SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") ENDFOREACH(flag) -SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden -g -Wall") +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden -g -Wall -Wno-unused-result") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}") SET(CMAKE_SKIP_BUILD_RPATH TRUE) diff --git a/include/notification.h b/include/notification.h index ddc7e9cc..0243f758 100755 --- a/include/notification.h +++ b/include/notification.h @@ -1884,6 +1884,46 @@ notification_error_e notification_op_get_data(notification_op *noti_op, notification_op_data_type_e type, void *data); +/** + * @brief Wait for a response coming for this notification + * @details The notification should have the EXECUTE_TYPE_RESPONDING flag + * @remarks + * @param[in] noti notification handle + * @param[in] timeout in seconds - 0 for infinite + * @param[out] integer response + * @param[out] text response + * @return NOTIFICATION_ERROR_NONE if success, other value if failure + * @retval NOTIFICATION_ERROR_NONE - success + * @retval NOTIFICATION_ERROR_INVALID_DATA - invalid parameter + * @retval NOTIFICATION_ERROR_NO_MEMORY - not enough memory + * @pre notification handle should be created by notification_new(). + * @post + * @see + */ +notification_error_e notification_wait_response(notification_h noti, + int timeout, + int *respi, + char **respc); + +/** + * @brief Send a response for a waiting notification + * @details + * @remarks + * @param[in] noti notification handle + * @param[in] integer response + * @param[in] text response + * @return NOTIFICATION_ERROR_NONE if success, other value if failure + * @retval NOTIFICATION_ERROR_NONE - success + * @retval NOTIFICATION_ERROR_INVALID_DATA - invalid parameter + * @retval NOTIFICATION_ERROR_NO_MEMORY - not enough memory + * @pre notification handle should be created by notification_new(). + * @post + * @see + */ +notification_error_e notification_send_response(notification_h noti, + int respi, + char *respc); + /** * @} */ diff --git a/src/notification.c b/src/notification.c index f11ac229..17b9985f 100755 --- a/src/notification.c +++ b/src/notification.c @@ -19,11 +19,16 @@ * */ +#define _GNU_SOURCE #include #include #include #include #include +#include +#include +#include +#include #include #include #include @@ -2805,3 +2810,147 @@ EXPORT_API notification_error_e notification_delete_group_by_priv_id(const char } return NOTIFICATION_ERROR_NONE; } + +EXPORT_API notification_error_e notification_wait_response(notification_h noti, + int timeout, + int *respi, + char **respc) +{ + bundle *b, *bc = NULL; + pid_t tid; + const char *tid_c; + int sock_fd, msg_fd; + char *sock_path; + struct sockaddr_un sock_addr; + char msg_buffer[1024]; + ssize_t msg_size; + struct timeval timeout_tv; + char *resp; + + /* a response packet *must* have an execute option TYPE_RESPONDING + with an associated bundle. + If its bundle does not already contain a "tid" hint (which + complex applications such as xwalk may overwrite), we will + try to find the TID and set it in the bundle ourselves. */ + notification_get_execute_option (noti, NOTIFICATION_EXECUTE_TYPE_RESPONDING, + NULL, &b); + + if (b == NULL) + return NOTIFICATION_ERROR_INVALID_DATA; + + tid_c = bundle_get_val(b, "tid"); + if (tid_c == NULL) { + tid = syscall(SYS_gettid); + asprintf((char **)&tid_c, "%d", tid); + bc = bundle_dup(b); + bundle_add(bc, "tid", tid_c); + notification_set_execute_option (noti, NOTIFICATION_EXECUTE_TYPE_RESPONDING, + NULL, NULL, bc); + notification_update(noti); + } + + sock_fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); + if (sock_fd == -1) + return NOTIFICATION_ERROR_NO_MEMORY; + + sock_addr.sun_family = AF_UNIX; + asprintf(&sock_path, "/tmp/.notification-%s", tid_c); + strncpy(sock_addr.sun_path, sock_path, sizeof(sock_addr.sun_path) - 1); + if (bind(sock_fd, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) == -1) { + close(sock_fd); + free(sock_path); + free((char *)tid_c); + return NOTIFICATION_ERROR_NO_MEMORY; + } + + if (timeout > 0) { + timeout_tv.tv_sec = timeout; + timeout_tv.tv_usec = 0; + setsockopt(sock_fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout_tv, sizeof(timeout_tv)); + setsockopt(sock_fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout_tv, sizeof(timeout_tv)); + } + + listen(sock_fd, 1); + msg_fd = accept(sock_fd, NULL, 0); + do { + msg_size = read(msg_fd, msg_buffer, 1024); + } while (msg_size > 0); + + resp = strtok(msg_buffer, "\n"); + if (resp) { + *respi = atoi(resp); + if (respc != NULL) { + resp = strtok(NULL, "\n"); + if (resp) + *respc = resp; + else + *respc = NULL; + } + } else { + *respi = 0; + if (respc != NULL) + *respc = NULL; + } + + close(sock_fd); + unlink(sock_path); + free(sock_path); + free((char *)tid_c); + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API notification_error_e notification_send_response(notification_h noti, + int respi, + char *respc) +{ + bundle *b = NULL; + notification_h notic; + int notic_id; + char *notic_pkgname; + int tid; + const char *tid_c; + int sock_fd; + char *sock_path; + struct sockaddr_un sock_addr; + char *msg_buffer; + + notification_get_id(noti, NULL, ¬ic_id); + notification_get_pkgname(noti, ¬ic_pkgname); + notic = notification_load(notic_pkgname, notic_id); + notification_get_execute_option (notic, NOTIFICATION_EXECUTE_TYPE_RESPONDING, + NULL, &b); + + if (b == NULL) + return NOTIFICATION_ERROR_INVALID_DATA; + + tid_c = bundle_get_val(b, "tid"); + if (tid_c == NULL) + return NOTIFICATION_ERROR_INVALID_DATA; + tid = atoi(tid_c); + + sock_fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); + if (sock_fd == -1) + return NOTIFICATION_ERROR_NO_MEMORY; + + sock_addr.sun_family = AF_UNIX; + asprintf(&sock_path, "/tmp/.notification-%d", tid); + strncpy(sock_addr.sun_path, sock_path, sizeof(sock_addr.sun_path) - 1); + if (connect(sock_fd, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) == -1) { + close(sock_fd); + free(sock_path); + return NOTIFICATION_ERROR_NO_MEMORY; + } + + if (respc) + asprintf(&msg_buffer, "%d\n%s\n", respi, respc); + else + asprintf(&msg_buffer, "%d\n", respi); + write(sock_fd, msg_buffer, strlen(msg_buffer) + 1); + + close(sock_fd); + free(sock_path); + free(msg_buffer); + + return NOTIFICATION_ERROR_NONE; +}