2 * Copyright 2012 Samsung Electronics Co., Ltd
4 * Licensed under the Flora License, Version 1.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.tizenopensource.org/license
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
26 #include <secom_socket.h>
29 #include <sys/socket.h>
30 #include <sys/ioctl.h>
34 #define EAPI __attribute__((visibility("default")))
43 request_cb_t request_cb;
50 result_cb_t result_cb;
57 pthread_mutex_t server_mutex;
59 const char *socket_file;
60 struct server_cb server_cb;
63 .server_mutex = PTHREAD_MUTEX_INITIALIZER,
65 .socket_file = "/tmp/.shortcut",
78 PACKET_MAX = 0xFF, /* MAX */
105 struct connection_state {
107 struct packet packet;
123 gboolean check_reply_service(int conn_fd, struct connection_state *state)
125 struct client_cb *client_cb = state->data;
127 if (client_cb->result_cb) {
128 /* If the callback return FAILURE,
129 * remove itself from the callback list */
130 client_cb->result_cb(state->packet.head.data.ack.ret,
131 state->from_pid, client_cb->data);
134 state->state = BEGIN;
138 /* NOTE: If we want close the connection, returns FALSE */
145 gboolean do_reply_service(int conn_fd, struct connection_state *state)
148 struct packet send_packet;
151 if (s_info.server_cb.request_cb) {
157 if (state->packet.head.data.req.field_size.pkgname)
158 pkgname = state->payload;
162 if (state->packet.head.data.req.field_size.name)
163 name = state->payload + state->packet.head.data.req.field_size.pkgname;
167 if (state->packet.head.data.req.field_size.exec) {
168 exec = state->payload + state->packet.head.data.req.field_size.pkgname;
169 exec += state->packet.head.data.req.field_size.name;
174 if (state->packet.head.data.req.field_size.icon) {
175 icon = state->payload + state->packet.head.data.req.field_size.pkgname;
176 icon += state->packet.head.data.req.field_size.name;
177 icon += state->packet.head.data.req.field_size.exec;
182 LOGD("Pkgname: [%s] Type: [%x], Name: [%s], Exec: [%s], Icon: [%s]\n",
184 state->packet.head.data.req.shortcut_type,
189 ret = s_info.server_cb.request_cb(
192 state->packet.head.data.req.shortcut_type,
196 s_info.server_cb.data);
199 send_packet.head.type = PACKET_ACK;
200 send_packet.head.payload_size = 0;
201 send_packet.head.seq = state->packet.head.seq;
202 send_packet.head.data.ack.ret = ret;
204 if (secom_send(conn_fd, (const char*)&send_packet, sizeof(send_packet)) != sizeof(send_packet)) {
205 LOGE("Faield to send ack packet\n");
209 state->state = BEGIN;
218 gboolean filling_payload(int conn_fd, struct connection_state *state)
220 if (state->length < state->packet.head.payload_size) {
224 ret = secom_recv(conn_fd,
225 state->payload + state->length,
226 state->packet.head.payload_size - state->length,
231 if (state->from_pid != check_pid) {
232 LOGD("PID is not matched (%d, expected %d)\n",
233 check_pid, state->from_pid);
237 state->length += ret;
240 if (state->length == state->packet.head.payload_size) {
251 gboolean deal_error_packet(int conn_fd, struct connection_state *state)
253 if (state->length < state->packet.head.payload_size) {
258 buf = alloca(state->packet.head.payload_size - state->length);
260 ret = secom_recv(conn_fd,
262 state->packet.head.payload_size - state->length,
267 if (check_pid != state->from_pid)
268 LOGD("PID is not matched (%d, expected %d)\n",
269 check_pid, state->from_pid);
271 state->length += ret;
274 if (state->length < state->packet.head.payload_size)
277 /* Now, drop this connection */
284 gboolean filling_header(int conn_fd, struct connection_state *state)
286 if (state->length < sizeof(state->packet)) {
290 ret = secom_recv(conn_fd,
291 ((char*)&state->packet) + state->length,
292 sizeof(state->packet) - state->length,
297 if (state->from_pid == 0)
298 state->from_pid = check_pid;
300 if (state->from_pid != check_pid) {
301 LOGD("PID is not matched (%d, expected %d)\n",
302 check_pid, state->from_pid);
306 state->length += ret;
309 if (state->length < sizeof(state->packet))
312 if (state->packet.head.type == PACKET_ACK) {
315 if (state->packet.head.payload_size)
316 state->state = ERROR;
319 } else if (state->packet.head.type == PACKET_REQ) {
320 /* Let's take the next part. */
321 state->state = PAYLOAD;
324 state->payload = calloc(1, state->packet.head.payload_size);
325 if (!state->payload) {
326 LOGE("Heap: %s\n", strerror(errno));
330 LOGE("Invalid packet type\n");
340 gboolean client_connection_cb(GIOChannel *src, GIOCondition cond, gpointer data)
345 struct connection_state *state = data;
346 struct client_cb *client_cb = state->data;
348 if (!(cond & G_IO_IN)) {
349 LOGE("Condition value is unexpected value\n");
354 conn_fd = g_io_channel_unix_get_fd(src);
356 if (ioctl(conn_fd, FIONREAD, &read_size) < 0) {
357 LOGE("Failed to get q size\n");
362 if (read_size == 0) {
363 if (client_cb->result_cb) {
364 /* If the callback return FAILURE,
365 * remove itself from the callback list */
366 client_cb->result_cb(-ECONNABORTED,
367 state->from_pid, client_cb->data);
373 switch (state->state) {
375 state->state = HEADER;
377 ret = filling_header(conn_fd, state);
380 ret = deal_error_packet(conn_fd, state);
387 if (state->state == END)
388 ret = check_reply_service(conn_fd, state);
403 gboolean connection_cb(GIOChannel *src, GIOCondition cond, gpointer data)
406 struct connection_state *state = data;
410 if (!(cond & G_IO_IN)) {
415 conn_fd = g_io_channel_unix_get_fd(src);
417 if (ioctl(conn_fd, FIONREAD, &read_size) < 0) {
418 LOGE("Failed to get q size\n");
423 if (read_size == 0) {
424 LOGE("Disconnected\n");
429 switch (state->state) {
431 state->state = HEADER;
433 ret = filling_header(conn_fd, state);
436 ret = filling_payload(conn_fd, state);
439 LOGE("[%s:%d] Invalid state(%x)\n",
440 __func__, __LINE__, state->state);
445 if (state->state == END) {
446 ret = do_reply_service(conn_fd, state);
447 if (state->payload) {
448 free(state->payload);
449 state->payload = NULL;
452 memset(&state->packet, 0, sizeof(state->packet));
457 secom_put_connection_handle(conn_fd);
460 free(state->payload);
471 gboolean accept_cb(GIOChannel *src, GIOCondition cond, gpointer data)
477 struct connection_state *state;
479 server_fd = g_io_channel_unix_get_fd(src);
480 if (server_fd != s_info.server_fd) {
481 LOGE("Unknown FD is gotten.\n");
483 * In this case, don't try to do anything.
484 * This is not recoverble error */
488 if (!(cond & G_IO_IN)) {
489 close(s_info.server_fd);
490 s_info.server_fd = -1;
494 connection_fd = secom_get_connection_handle(server_fd);
495 if (connection_fd < 0) {
496 /* Error log will be printed from
497 * get_connection_handle function */
501 if (fcntl(connection_fd, F_SETFD, FD_CLOEXEC) < 0)
502 LOGE("Error: %s\n", strerror(errno));
504 if (fcntl(connection_fd, F_SETFL, O_NONBLOCK) < 0)
505 LOGE("Error: %s\n", strerror(errno));
507 gio = g_io_channel_unix_new(connection_fd);
509 LOGE("Failed to create a new connection channel\n");
510 secom_put_connection_handle(connection_fd);
514 state = calloc(1, sizeof(*state));
516 LOGE("Heap: %s\n", strerror(errno));
517 secom_put_connection_handle(connection_fd);
521 state->state = BEGIN;
522 id = g_io_add_watch(gio,
523 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
524 (GIOFunc)connection_cb, state);
527 LOGE("Failed to create g_io watch\n");
529 g_io_channel_unref(gio);
530 g_io_channel_shutdown(gio, TRUE, &err);
531 secom_put_connection_handle(connection_fd);
535 g_io_channel_unref(gio);
541 static inline int init_client(struct client_cb *client_cb,
542 const char *packet, int packet_size)
547 struct connection_state *state;
549 client_fd = secom_create_client(s_info.socket_file);
551 LOGE("Failed to make the client FD\n");
555 if (fcntl(client_fd, F_SETFD, FD_CLOEXEC) < 0)
556 LOGE("Error: %s\n", strerror(errno));
558 if (fcntl(client_fd, F_SETFL, O_NONBLOCK) < 0)
559 LOGE("Error: %s\n", strerror(errno));
561 gio = g_io_channel_unix_new(client_fd);
567 state = calloc(1, sizeof(*state));
569 LOGE("Error: %s\n", strerror(errno));
574 state->data = client_cb;
576 id = g_io_add_watch(gio,
577 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
578 (GIOFunc)client_connection_cb, state);
581 LOGE("Failed to create g_io watch\n");
583 g_io_channel_unref(gio);
584 g_io_channel_shutdown(gio, TRUE, &err);
589 g_io_channel_unref(gio);
591 if (secom_send(client_fd, packet, packet_size) != packet_size) {
593 LOGE("Failed to send all packet "
594 "(g_io_channel is not cleared now\n");
596 g_io_channel_shutdown(gio, TRUE, &err);
607 int init_server(void)
612 if (s_info.server_fd != -1) {
613 LOGE("Already initialized\n");
617 if (pthread_mutex_lock(&s_info.server_mutex) != 0) {
618 LOGE("[%s:%d] Failed to get lock (%s)\n",
619 __func__, __LINE__, strerror(errno));
623 unlink(s_info.socket_file);
624 s_info.server_fd = secom_create_server(s_info.socket_file);
626 if (s_info.server_fd < 0) {
627 LOGE("Failed to open a socket (%s)\n", strerror(errno));
628 if (pthread_mutex_unlock(&s_info.server_mutex) != 0)
629 LOGE("[%s:%d] Failed to do unlock mutex (%s)\n",
630 __func__, __LINE__, strerror(errno));
634 if (fcntl(s_info.server_fd, F_SETFD, FD_CLOEXEC) < 0)
635 LOGE("Error: %s\n", strerror(errno));
637 if (fcntl(s_info.server_fd, F_SETFL, O_NONBLOCK) < 0)
638 LOGE("Error: %s\n", strerror(errno));
640 gio = g_io_channel_unix_new(s_info.server_fd);
642 close(s_info.server_fd);
643 s_info.server_fd = -1;
644 if (pthread_mutex_unlock(&s_info.server_mutex) != 0)
645 LOGE("[%s:%d] Failed to do unlock mutex (%s)\n",
646 __func__, __LINE__, strerror(errno));
650 id = g_io_add_watch(gio,
651 G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
652 (GIOFunc)accept_cb, NULL);
655 LOGE("Failed to create g_io watch\n");
656 g_io_channel_unref(gio);
657 g_io_channel_shutdown(gio, TRUE, &err);
658 close(s_info.server_fd);
659 s_info.server_fd = -1;
660 if (pthread_mutex_unlock(&s_info.server_mutex) != 0)
661 LOGE("[%s:%d] Failed to do unlock mutex (%s)\n",
662 __func__, __LINE__, strerror(errno));
667 g_io_channel_unref(gio);
669 if (pthread_mutex_unlock(&s_info.server_mutex) != 0) {
671 g_io_channel_shutdown(gio, TRUE, &err);
672 LOGE("[%s:%d] Failed to do unlock mutex (%s)\n",
673 __func__, __LINE__, strerror(errno));
675 * We couldn't make a lock for this statements.
676 * We already meet the unrecoverble error
678 close(s_info.server_fd);
679 s_info.server_fd = -1;
688 EAPI int shortcut_set_request_cb(request_cb_t request_cb, void *data)
691 s_info.server_cb.request_cb = request_cb;
692 s_info.server_cb.data = data;
696 LOGE("Failed to initialize the server\n");
704 EAPI int add_to_home_shortcut(const char *pkgname, const char *name, int type, const char *content_info, const char *icon, result_cb_t result_cb, void *data)
706 struct packet *packet;
713 struct client_cb *client_cb;
716 pkgname_len = pkgname ? strlen(pkgname) + 1 : 0;
717 name_len = name ? strlen(name) + 1 : 0;
718 exec_len = content_info ? strlen(content_info) + 1 : 0;
719 icon_len = icon ? strlen(icon) + 1 : 0;
721 packet_size = sizeof(*packet) + name_len + exec_len + icon_len + pkgname_len + 1;
723 packet = alloca(packet_size);
725 LOGE("Heap: %s\n", strerror(errno));
729 packet->head.seq = s_info.seq++;
730 packet->head.type = PACKET_REQ;
731 packet->head.data.req.shortcut_type = type;
732 packet->head.data.req.field_size.pkgname = pkgname_len;
733 packet->head.data.req.field_size.name = name_len;
734 packet->head.data.req.field_size.exec = exec_len;
735 packet->head.data.req.field_size.icon = icon_len;
736 packet->head.payload_size = pkgname_len + name_len + exec_len + icon_len + 1;
738 payload = packet->payload;
740 strncpy(payload, pkgname, pkgname_len);
741 payload += pkgname_len;
742 strncpy(payload, name, name_len);
744 strncpy(payload, content_info, exec_len);
746 strncpy(payload, icon, icon_len);
748 client_cb = malloc(sizeof(*client_cb));
750 LOGE("Heap: %s\n", strerror(errno));
754 client_cb->result_cb = result_cb;
755 client_cb->data = data;
757 if (init_client(client_cb, (const char*)packet, packet_size) < 0) {
758 LOGE("Failed to init client FD\n");
766 EAPI int shortcut_add_to_home(const char *pkgname, const char *name, int type, const char *content_info, const char *icon, result_cb_t result_cb, void *data)
768 return add_to_home_shortcut(pkgname, name, type, content_info, icon, result_cb, data);