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.
21 #include <sys/types.h>
30 #include <livebox-errno.h>
34 #include "file_service.h"
35 #include "service_common.h"
39 #include "buffer_handler.h"
41 #define FILE_SERVICE_ADDR "remote://:8209"
46 #define PKT_CHUNKSZ 4096
49 struct service_context *svc_ctx;
53 Eina_List *request_list;
54 pthread_mutex_t request_list_lock;
56 int request_pipe[PIPE_MAX];
60 .request_list_lock = PTHREAD_MUTEX_INITIALIZER,
61 .request_pipe = { 0, },
66 REQUEST_TYPE_FILE = 0x00,
67 REQUEST_TYPE_SHM = 0x01,
68 REQUEST_TYPE_PIXMAP = 0x02,
69 REQUEST_TYPE_MAX = 0x02,
79 typedef int (*send_data_func_t)(int fd, const struct request_item *item);
82 * File transfer header.
83 * This must should be shared with client.
96 static inline struct request_item *create_request_item(struct tcb *tcb, int type, void *data)
98 struct request_item *item;
100 item = malloc(sizeof(*item));
102 ErrPrint("Heap: %s\n", strerror(errno));
107 case REQUEST_TYPE_FILE:
108 item->data.filename = strdup(data);
109 if (!item->data.filename) {
110 ErrPrint("Heap: %s\n", strerror(errno));
115 case REQUEST_TYPE_PIXMAP:
116 item->data.pixmap = (unsigned int)data;
118 case REQUEST_TYPE_SHM:
119 item->data.shm = (int)data;
122 ErrPrint("Invalid type of request\n");
132 static inline int destroy_request_item(struct request_item *item)
134 switch (item->type) {
135 case REQUEST_TYPE_FILE:
136 DbgFree(item->data.filename);
138 case REQUEST_TYPE_SHM:
139 case REQUEST_TYPE_PIXMAP:
142 return LB_STATUS_ERROR_INVALID;
146 return LB_STATUS_SUCCESS;
149 static int request_file_handler(struct tcb *tcb, struct packet *packet, struct request_item **item)
151 const char *filename;
153 if (packet_get(packet, "s", &filename) != 1) {
154 ErrPrint("Invalid packet\n");
155 return LB_STATUS_ERROR_INVALID;
158 *item = create_request_item(tcb, REQUEST_TYPE_FILE, (void *)filename);
159 return *item ? LB_STATUS_SUCCESS : LB_STATUS_ERROR_MEMORY;
162 static int request_pixmap_handler(struct tcb *tcb, struct packet *packet, struct request_item **item)
166 if (packet_get(packet, "i", &pixmap) != 1) {
167 ErrPrint("Invalid packet\n");
168 return LB_STATUS_ERROR_INVALID;
172 ErrPrint("pixmap is not valid\n");
173 return LB_STATUS_ERROR_INVALID;
178 * Attach to pixmap and copy its data to the client
180 *item = create_request_item(tcb, REQUEST_TYPE_PIXMAP, (void *)pixmap);
181 return *item ? LB_STATUS_SUCCESS : LB_STATUS_ERROR_MEMORY;
184 static int request_shm_handler(struct tcb *tcb, struct packet *packet, struct request_item **item)
188 if (packet_get(packet, "i", &shm) != 1) {
189 ErrPrint("Invalid packet\n");
190 return LB_STATUS_ERROR_INVALID;
194 ErrPrint("shm is not valid: %d\n", shm);
195 return LB_STATUS_ERROR_INVALID;
200 * Attach to SHM and copy its buffer to the client
202 *item = create_request_item(tcb, REQUEST_TYPE_SHM, (void *)shm);
203 return *item ? LB_STATUS_SUCCESS : LB_STATUS_ERROR_MEMORY;
207 static int service_thread_main(struct tcb *tcb, struct packet *packet, void *data)
213 struct request_item *item;
214 struct packet *reply;
217 int (*request_handler)(struct tcb *tcb, struct packet *packet, struct request_item **item);
220 .cmd = "request,file",
221 .request_handler = request_file_handler,
224 .cmd = "request,pixmap",
225 .request_handler = request_pixmap_handler,
228 .cmd = "request,shm",
229 .request_handler = request_shm_handler,
233 .request_handler = NULL,
238 DbgPrint("TCB %p is disconnected\n", tcb);
239 return LB_STATUS_SUCCESS;
242 cmd = packet_command(packet);
244 ErrPrint("Invalid packet. cmd is not valid\n");
245 return LB_STATUS_ERROR_INVALID;
248 switch (packet_type(packet)) {
250 for (i = 0; cmd_table[i].cmd; i++) {
253 * FILE REQUEST COMMAND (Client -> Server)
254 * REPLY FOR REQUEST (Client <- Server)
255 * PUSH FILE (Client <- Server)
257 * Client & Server must has to keep this communication sequence.
259 if (strcmp(cmd, cmd_table[i].cmd)) {
264 ret = cmd_table[i].request_handler(tcb, packet, &item);
266 reply = packet_create_reply(packet, "i", ret);
268 ErrPrint("Failed to create a reply packet\n");
272 if (service_common_unicast_packet(tcb, reply) < 0) {
273 ErrPrint("Unable to send reply packet\n");
276 packet_destroy(reply);
280 * After send the reply packet, file push thread can sending a file
282 if (ret != LB_STATUS_SUCCESS || !item) {
286 CRITICAL_SECTION_BEGIN(&s_info.request_list_lock);
287 s_info.request_list = eina_list_append(s_info.request_list, item);
288 CRITICAL_SECTION_END(&s_info.request_list_lock);
290 ret = write(s_info.request_pipe[PIPE_WRITE], &ch, sizeof(ch));
292 ErrPrint("write: %s\n", strerror(errno));
294 CRITICAL_SECTION_BEGIN(&s_info.request_list_lock);
295 s_info.request_list = eina_list_remove(s_info.request_list, item);
296 CRITICAL_SECTION_END(&s_info.request_list_lock);
298 destroy_request_item(item);
300 * \note for the client
301 * In this case, the client can waiting files forever.
302 * So the client must has to wait only a few seconds.
303 * If the client could not get the any data in that time,
304 * it should cancel the waiting.
310 case PACKET_REQ_NOACK:
312 /* File service has no this case, it is passive service type */
313 ErrPrint("Invalid packet.\n");
319 return LB_STATUS_SUCCESS;
322 static int send_file(int handle, const struct request_item *item)
324 struct burst_head *head;
325 struct burst_data *body;
332 /* TODO: push a file to the client */
333 fd = open(item->data.filename, O_RDONLY);
335 ErrPrint("open: %s\n", strerror(errno));
339 flen = strlen(item->data.filename);
345 pktsz = sizeof(*head) + flen + 1;
347 head = malloc(pktsz);
349 ErrPrint("heap: %s\n", strerror(errno));
354 fsize = lseek(fd, 0L, SEEK_END);
355 if (fsize == (off_t)-1) {
356 ErrPrint("heap: %s\n", strerror(errno));
364 strcpy(head->fname, item->data.filename);
366 /* Anytime we can fail to send packet */
367 ret = com_core_send(handle, (void *)head, pktsz, 2.0f);
374 if (lseek(fd, 0L, SEEK_SET) == (off_t)-1) {
375 ErrPrint("seek: %s\n", strerror(errno));
377 body = malloc(sizeof(*body));
379 ErrPrint("Heap: %s\n", strerror(errno));
384 ret = com_core_send(handle, (void *)body, sizeof(*body), 2.0f);
396 body = malloc(PKT_CHUNKSZ + sizeof(*body));
398 ErrPrint("heap: %s\n", strerror(errno));
404 if (fsize > PKT_CHUNKSZ) {
405 body->size = PKT_CHUNKSZ;
410 ret = read(fd, body->data, body->size);
412 ErrPrint("read: %s\n", strerror(errno));
419 pktsz = sizeof(*body) + body->size;
422 ret = com_core_send(handle, (void *)body, pktsz, 2.0f);
431 ret = com_core_send(handle, (void *)body, sizeof(*body), 2.0f);
440 ErrPrint("close: %s\n", strerror(errno));
446 static int send_buffer(int handle, const struct request_item *item)
448 struct buffer *buffer;
449 struct burst_head *head;
450 struct burst_data *body;
458 if (item->type == REQUEST_TYPE_SHM) {
459 type = BUFFER_TYPE_SHM;
461 type = BUFFER_TYPE_PIXMAP;
464 buffer = buffer_handler_raw_open(type, (void *)item->data.shm);
469 pktsz = sizeof(*head);
471 head = malloc(pktsz);
473 ErrPrint("Heap: %s\n", strerror(errno));
474 (void)buffer_handler_raw_close(buffer);
478 size = head->size = buffer_handler_raw_size(buffer);
481 /* Anytime we can fail to send packet */
482 ret = com_core_send(handle, (void *)head, pktsz, 2.0f);
489 body = malloc(sizeof(*body) + PKT_CHUNKSZ);
495 data = (char *)buffer_handler_raw_data(buffer);
497 while (offset < size) {
498 body->size = size - offset;
500 if (body->size > PKT_CHUNKSZ) {
501 body->size = PKT_CHUNKSZ;
504 memcpy(body->data, data, body->size);
505 pktsz = sizeof(*body) + body->size;
507 ret = com_core_send(handle, (void *)body, pktsz, 2.0f);
513 offset += body->size;
519 (void)buffer_handler_raw_close(buffer);
523 static void *push_main(void *data)
528 struct request_item *item;
530 send_data_func_t send_data[] = {
538 FD_SET(s_info.request_pipe[PIPE_READ], &set);
540 ret = select(s_info.request_pipe[PIPE_READ] + 1, &set, NULL, NULL, NULL);
543 if (errno == EINTR) {
544 ErrPrint("INTERRUPTED\n");
548 ErrPrint("Error: %s\n", strerror(errno));
550 } else if (ret == 0) {
551 ErrPrint("Timeout\n");
556 if (!FD_ISSET(s_info.request_pipe[PIPE_READ], &set)) {
557 DbgPrint("Unknown data\n");
562 ret = read(s_info.request_pipe[PIPE_READ], &ch, sizeof(ch));
563 if (ret != sizeof(ch)) {
564 ErrPrint("read: %s\n", strerror(errno));
569 if (ch == PUSH_EXIT) {
570 DbgPrint("Thread is terminating\n");
575 CRITICAL_SECTION_BEGIN(&s_info.request_list_lock);
576 item = eina_list_nth(s_info.request_list, 0);
577 s_info.request_list = eina_list_remove(s_info.request_list, item);
578 CRITICAL_SECTION_END(&s_info.request_list_lock);
581 ErrPrint("Request item is not valid\n");
585 /* Validate the TCB? */
586 conn_fd = tcb_is_valid(s_info.svc_ctx, item->tcb);
588 ErrPrint("TCB is not valid\n");
589 destroy_request_item(item);
595 * From now, we cannot believe the conn_fd.
596 * It can be closed any time.
597 * Even though we using it.
599 if (item->type < REQUEST_TYPE_MAX && item->type >= 0) {
600 (void)send_data[item->type](conn_fd, item);
602 ErrPrint("Invalid type\n");
605 destroy_request_item(item);
612 int file_service_init(void)
616 if (s_info.svc_ctx) {
617 ErrPrint("Already initialized\n");
618 return LB_STATUS_ERROR_ALREADY;
621 if (pipe2(s_info.request_pipe, O_CLOEXEC) < 0) {
622 ErrPrint("pipe: %s\n", strerror(errno));
623 return LB_STATUS_ERROR_FAULT;
626 status = pthread_mutex_init(&s_info.request_list_lock, NULL);
628 ErrPrint("Failed to create lock: %s\n", strerror(status));
629 CLOSE_PIPE(s_info.request_pipe);
630 return LB_STATUS_ERROR_FAULT;
633 s_info.svc_ctx = service_common_create(FILE_SERVICE_ADDR, service_thread_main, NULL);
634 if (!s_info.svc_ctx) {
635 ErrPrint("Unable to activate service thread\n");
637 status = pthread_mutex_destroy(&s_info.request_list_lock);
639 ErrPrint("Destroy lock: %s\n", strerror(status));
642 CLOSE_PIPE(s_info.request_pipe);
643 return LB_STATUS_ERROR_FAULT;
646 status = pthread_create(&s_info.push_thid, NULL, push_main, NULL);
648 ErrPrint("Failed to create a push service: %s\n", strerror(status));
650 service_common_destroy(s_info.svc_ctx);
651 s_info.svc_ctx = NULL;
653 status = pthread_mutex_destroy(&s_info.request_list_lock);
655 ErrPrint("Destroy lock: %s\n", strerror(status));
658 CLOSE_PIPE(s_info.request_pipe);
659 return LB_STATUS_ERROR_FAULT;
664 * Remote service doesn't need to set the additional SMAK label.
667 DbgPrint("Successfully initiated\n");
668 return LB_STATUS_SUCCESS;
672 int file_service_fini(void)
674 struct request_item *item;
679 if (!s_info.svc_ctx) {
680 return LB_STATUS_ERROR_INVALID;
684 status = write(s_info.request_pipe[PIPE_WRITE], &ch, sizeof(ch));
685 if (status != sizeof(ch)) {
686 ErrPrint("write: %s\n", strerror(errno));
687 /* Forcely terminate the thread */
688 status = pthread_cancel(s_info.push_thid);
690 ErrPrint("cancel: %s\n", strerror(status));
694 status = pthread_join(s_info.push_thid, &retval);
696 ErrPrint("join: %s\n", strerror(status));
699 CRITICAL_SECTION_BEGIN(&s_info.request_list_lock);
700 EINA_LIST_FREE(s_info.request_list, item) {
701 destroy_request_item(item);
703 CRITICAL_SECTION_END(&s_info.request_list_lock);
705 service_common_destroy(s_info.svc_ctx);
706 s_info.svc_ctx = NULL;
708 status = pthread_mutex_destroy(&s_info.request_list_lock);
710 ErrPrint("destroy mutex: %s\n", strerror(status));
713 CLOSE_PIPE(s_info.request_pipe);
715 DbgPrint("Successfully Finalized\n");
716 return LB_STATUS_SUCCESS;