2 * Copyright 2013 Samsung Electronics Co., Ltd
4 * Licensed under the Flora License, Version 1.1 (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://floralicense.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 <sys/types.h>
33 #include <secure_socket.h>
34 #include <widget_errno.h>
40 #define FILE_SERVICE_PORT 8209
42 #define CRITICAL_SECTION_BEGIN(handle) \
45 ret = pthread_mutex_lock(handle); \
47 ErrPrint("Failed to lock: %s\n", strerror(ret)); \
51 #define CRITICAL_SECTION_END(handle) \
54 ret = pthread_mutex_unlock(handle); \
56 ErrPrint("Failed to unlock: %s\n", strerror(ret)); \
60 #define CANCEL_SECTION_BEGIN() do { \
62 ret = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); \
64 ErrPrint("Unable to set cancelate state: %s\n", strerror(ret)); \
68 #define CANCEL_SECTION_END() do { \
70 ret = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); \
72 ErrPrint("Unable to set cancelate state: %s\n", strerror(ret)); \
76 #define CLOSE_PIPE(p) do { \
78 status = close(p[PIPE_READ]); \
80 ErrPrint("close: %d\n", errno); \
82 status = close(p[PIPE_WRITE]); \
84 ErrPrint("close: %d\n", errno); \
92 #define EVT_END_CH 'c'
96 pthread_t file_svc_thid;
97 pthread_mutex_t file_svc_lock;
98 int ctrl_pipe[PIPE_MAX];
99 int evt_pipe[PIPE_MAX];
100 struct dlist *request_list;
103 .ctrl_pipe = { -1, -1 },
104 .evt_pipe = { -1, -1 },
105 .request_list = NULL,
106 .file_service_fd = -1,
109 struct request_item {
112 void (*result_cb)(const char *filename, const char *save_to, int ret, void *data);
118 * File transfer header.
119 * This must should be shared with client.
132 static inline int put_event_ch(int fd, char ch)
136 ret = write(fd, &ch, sizeof(ch));
137 if (ret != sizeof(ch)) {
138 ErrPrint("write: %d\n", errno);
145 static inline int get_event_ch(int fd)
150 ret = read(fd, &ch, sizeof(ch));
151 if (ret != sizeof(ch)) {
152 ErrPrint("read: %d\n", errno);
156 ret = (int)((unsigned int)ch);
160 static inline int file_service_close(int fd)
162 return secure_socket_destroy_handle(fd);
165 static inline int file_service_open(void)
173 addr = malloc(strlen(client_addr()) + 1);
175 ErrPrint("Heap: %d\n", errno);
179 if (sscanf(client_addr(), COM_CORE_REMOTE_SCHEME"%[^:]:%d", addr, &port) != 2) {
180 ErrPrint("Invalid URL\n");
185 len = strlen(COM_CORE_REMOTE_SCHEME);
187 len += 6; /* Port length? */
189 file_addr = malloc(len);
191 ErrPrint("Heap: %d\n", errno);
196 snprintf(file_addr, len, COM_CORE_REMOTE_SCHEME"%s:%d", addr, FILE_SERVICE_PORT);
197 DbgPrint("File service: %s\n", file_addr);
198 fd = secure_socket_create_client(file_addr);
208 static void write_item_to_pipe(struct request_item *item, int ret)
210 item->ret = WIDGET_ERROR_FAULT;
211 if (write(s_info.evt_pipe[PIPE_WRITE], &item, sizeof(item)) != sizeof(item)) {
212 ErrPrint("write: %d\n", errno);
213 free(item->filename);
223 static void *file_service_main(void *data)
235 struct burst_head *head;
236 struct burst_data *body;
238 struct request_item *item;
244 recv_state = RECV_INIT;
245 select_fd = (s_info.file_service_fd > s_info.ctrl_pipe[PIPE_READ] ? s_info.file_service_fd : s_info.ctrl_pipe[PIPE_READ]) + 1;
248 FD_SET(s_info.file_service_fd, &set);
249 FD_SET(s_info.ctrl_pipe[PIPE_READ], &set);
253 ret = select(select_fd , &set, NULL, NULL, &tv);
256 if (errno == EINTR) {
257 ErrPrint("INTERRUPTED\n");
261 ErrPrint("Error: %d\n", errno);
263 } else if (ret == 0) {
264 ErrPrint("Timeout\n");
269 if (item && FD_ISSET(s_info.file_service_fd, &set)) {
270 switch (recv_state) {
273 recvsz = sizeof(*head);
275 head = malloc(recvsz);
277 ErrPrint("Heap: %d\n", errno);
278 ret = WIDGET_ERROR_OUT_OF_MEMORY;
279 write_item_to_pipe(item, ret);
285 recv_state = RECV_HEADER;
288 if (offset < recvsz) {
289 ret = secure_socket_recv(s_info.file_service_fd, (char *)head + offset, recvsz - offset, NULL);
295 recv_state = RECV_INIT;
296 ret = WIDGET_ERROR_FAULT;
297 write_item_to_pipe(item, ret);
303 if (offset == sizeof(*head)) {
306 recvsz += head->flen;
308 tmp = realloc(head, recvsz);
310 ErrPrint("Heap: %d\n", errno);
314 recv_state = RECV_INIT;
316 ret = WIDGET_ERROR_OUT_OF_MEMORY;
317 write_item_to_pipe(item, ret);
323 } else if (offset == recvsz) {
324 DbgPrint("Filesize: %d, name[%s]\n", head->size, head->fname);
325 if (strcmp(item->filename, head->fname)) {
326 ErrPrint("Invalid data sequence (%s <> %s)\n", item->filename, head->fname);
330 recv_state = RECV_INIT;
331 ret = WIDGET_ERROR_FAULT;
332 write_item_to_pipe(item, ret);
337 file_fd = open(item->save_to, O_WRONLY|O_CREAT, 0644);
339 ErrPrint("open: %d\n", errno);
342 recv_state = RECV_INIT;
344 ret = WIDGET_ERROR_IO_ERROR;
345 write_item_to_pipe(item, ret);
350 recv_state = RECV_DATA;
354 ErrPrint("Invalid state\n");
357 recv_state = RECV_INIT;
358 ret = WIDGET_ERROR_INVALID_PARAMETER;
359 write_item_to_pipe(item, ret);
365 body = malloc(sizeof(*body));
369 recv_state = RECV_INIT;
370 ret = WIDGET_ERROR_OUT_OF_MEMORY;
371 write_item_to_pipe(item, ret);
376 recvsz = sizeof(*body);
380 ret = secure_socket_recv(s_info.file_service_fd, (char *)body + offset, recvsz - offset, NULL);
388 recv_state = RECV_INIT;
389 ret = WIDGET_ERROR_FAULT;
390 write_item_to_pipe(item, ret);
395 if (offset == sizeof(*body)) {
398 if (body->size < 0) {
399 ErrPrint("body->size: %d\n", body->size);
404 recv_state = RECV_INIT;
405 ret = WIDGET_ERROR_FAULT;
406 write_item_to_pipe(item, ret);
411 recvsz += body->size;
413 tmp = realloc(body, recvsz);
415 ErrPrint("Heap: %d\n", errno);
421 recv_state = RECV_INIT;
423 ret = WIDGET_ERROR_OUT_OF_MEMORY;
424 write_item_to_pipe(item, ret);
428 } else if (offset == recvsz) {
429 /* Flush this to the file */
430 ret = write(file_fd, body->data, body->size);
432 ErrPrint("write: %d\n", errno);
438 recv_state = RECV_INIT;
440 ret = WIDGET_ERROR_IO_ERROR;
441 write_item_to_pipe(item, ret);
445 if (body->size != ret) {
446 DbgPrint("Body is not flushed correctly: %d, %d\n", ret, body->size);
451 if (file_offset == head->size) {
452 if (close(file_fd) < 0) {
453 ErrPrint("close: %d\n", errno);
455 ret = WIDGET_ERROR_NONE;
456 write_item_to_pipe(item, ret);
467 recv_state = RECV_INIT;
469 ErrPrint("Invalid state\n");
476 recv_state = RECV_INIT;
478 ret = WIDGET_ERROR_FAULT;
479 write_item_to_pipe(item, ret);
484 ErrPrint("Unknown event: %d\n", recv_state);
485 ret = WIDGET_ERROR_FAULT;
486 write_item_to_pipe(item, ret);
490 } else if (item == NULL && recv_state == RECV_INIT && FD_ISSET(s_info.ctrl_pipe[PIPE_READ], &set)) {
494 /* Only if the recv state is not changed, we can get next request item */
495 ch = get_event_ch(s_info.ctrl_pipe[PIPE_READ]);
496 if (ch == EVT_END_CH) {
497 DbgPrint("Service thread is canceled\n");
501 CRITICAL_SECTION_BEGIN(&s_info.file_svc_lock);
502 l = dlist_nth(s_info.request_list, 0);
503 item = dlist_data(l);
504 s_info.request_list = dlist_remove(s_info.request_list, l);
505 CRITICAL_SECTION_END(&s_info.file_svc_lock);
509 return (void *)((long)ret);
513 static gboolean evt_cb(GIOChannel *src, GIOCondition cond, gpointer data)
516 struct request_item *item;
518 fd = g_io_channel_unix_get_fd(src);
520 if (!(cond & G_IO_IN)) {
521 DbgPrint("Client is disconencted\n");
525 if ((cond & G_IO_ERR) || (cond & G_IO_HUP) || (cond & G_IO_NVAL)) {
526 DbgPrint("Client connection is lost\n");
530 if (read(fd, &item, sizeof(item)) != sizeof(item)) {
531 ErrPrint("read: %d\n", errno);
533 if (item->result_cb) {
534 item->result_cb(item->filename, item->save_to, item->ret, item->data);
537 free(item->filename);
545 int file_service_send_request(const char *filename, const char *save_to, void (*result_cb)(const char *filename, const char *save_to, int ret, void *data), void *data)
547 struct request_item *item;
549 item = malloc(sizeof(*item));
551 ErrPrint("Heap: %d\n", errno);
555 item->filename = strdup(filename);
556 if (!item->filename) {
557 ErrPrint("Heap: %d\n", errno);
562 item->save_to = strdup(save_to);
563 if (!item->save_to) {
564 ErrPrint("Heap: %d\n", errno);
565 free(item->filename);
570 item->result_cb = result_cb;
573 CRITICAL_SECTION_BEGIN(&s_info.file_svc_lock);
574 s_info.request_list = dlist_append(s_info.request_list, item);
575 CRITICAL_SECTION_END(&s_info.file_svc_lock);
579 int file_service_init(void)
585 if (strncmp(client_addr(), COM_CORE_REMOTE_SCHEME, strlen(COM_CORE_REMOTE_SCHEME))) {
589 s_info.file_service_fd = file_service_open();
590 if (s_info.file_service_fd < 0) {
594 if (pipe2(s_info.ctrl_pipe, O_NONBLOCK | O_CLOEXEC) < 0) {
595 ErrPrint("file service: %d\n", errno);
596 file_service_close(s_info.file_service_fd);
597 s_info.file_service_fd = -1;
601 if (pipe2(s_info.evt_pipe, O_NONBLOCK | O_CLOEXEC) < 0) {
602 ErrPrint("file service: %d\n", errno);
603 CLOSE_PIPE(s_info.ctrl_pipe);
604 file_service_close(s_info.file_service_fd);
605 s_info.file_service_fd = -1;
609 status = pthread_mutex_init(&s_info.file_svc_lock, NULL);
611 ErrPrint("Mutex: %s\n", strerror(status));
612 CLOSE_PIPE(s_info.ctrl_pipe);
613 CLOSE_PIPE(s_info.evt_pipe);
614 file_service_close(s_info.file_service_fd);
615 s_info.file_service_fd = -1;
619 gio = g_io_channel_unix_new(s_info.evt_pipe[PIPE_READ]);
621 ErrPrint("io channel new\n");
622 status = pthread_mutex_destroy(&s_info.file_svc_lock);
624 ErrPrint("destroy: %s\n", strerror(status));
626 CLOSE_PIPE(s_info.ctrl_pipe);
627 CLOSE_PIPE(s_info.evt_pipe);
628 file_service_close(s_info.file_service_fd);
629 s_info.file_service_fd = -1;
633 g_io_channel_set_close_on_unref(gio, FALSE);
635 id = g_io_add_watch(gio, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, (GIOFunc)evt_cb, NULL);
638 ErrPrint("Failed to add IO watch\n");
639 g_io_channel_shutdown(gio, TRUE, &err);
641 ErrPrint("Shutdown: %s\n", err->message);
644 g_io_channel_unref(gio);
646 status = pthread_mutex_destroy(&s_info.file_svc_lock);
648 ErrPrint("destroy: %s\n", strerror(status));
650 CLOSE_PIPE(s_info.ctrl_pipe);
651 CLOSE_PIPE(s_info.evt_pipe);
652 file_service_close(s_info.file_service_fd);
653 s_info.file_service_fd = -1;
657 status = pthread_create(&s_info.file_svc_thid, NULL, file_service_main, NULL);
660 ErrPrint("Failed to add IO watch\n");
661 g_io_channel_shutdown(gio, TRUE, &err);
663 ErrPrint("Shutdown: %s\n", err->message);
666 g_io_channel_unref(gio);
668 ErrPrint("file service: %s\n", strerror(status));
669 CLOSE_PIPE(s_info.ctrl_pipe);
670 CLOSE_PIPE(s_info.evt_pipe);
671 file_service_close(s_info.file_service_fd);
672 s_info.file_service_fd = -1;
674 status = pthread_mutex_destroy(&s_info.file_svc_lock);
676 ErrPrint("destroy: %s\n", strerror(status));
682 g_io_channel_unref(gio);
686 int file_service_fini(void)
691 if (strncmp(client_addr(), COM_CORE_REMOTE_SCHEME, strlen(COM_CORE_REMOTE_SCHEME))) {
695 (void)put_event_ch(s_info.ctrl_pipe[PIPE_WRITE], EVT_END_CH);
697 ret = pthread_join(s_info.file_svc_thid, &svc_ret);
699 ErrPrint("join: %s\n", strerror(ret));
701 DbgPrint("file svc returns: %p\n", svc_ret);
704 ret = pthread_mutex_destroy(&s_info.file_svc_lock);
706 ErrPrint("destroy: %s\n", strerror(ret));
709 CLOSE_PIPE(s_info.evt_pipe);
710 CLOSE_PIPE(s_info.ctrl_pipe);