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"
42 #define FILE_PUSH_ADDR "remote://:8210"
47 #define PKT_CHUNKSZ 4096
50 struct service_context *svc_ctx;
54 Eina_List *request_list;
55 pthread_mutex_t request_list_lock;
57 int request_pipe[PIPE_MAX];
61 .request_list_lock = PTHREAD_MUTEX_INITIALIZER,
62 .request_pipe = { 0, },
67 REQUEST_TYPE_FILE = 0x00,
68 REQUEST_TYPE_SHM = 0x01,
69 REQUEST_TYPE_PIXMAP = 0x02,
70 REQUEST_TYPE_MAX = 0x02,
80 typedef int (*send_data_func_t)(int fd, const struct request_item *item);
83 * File transfer header.
84 * This must should be shared with client.
97 static inline struct request_item *create_request_item(struct tcb *tcb, int type, void *data)
99 struct request_item *item;
101 item = malloc(sizeof(*item));
103 ErrPrint("Heap: %s\n", strerror(errno));
108 case REQUEST_TYPE_FILE:
109 item->data.filename = strdup(data);
110 if (!item->data.filename) {
111 ErrPrint("Heap: %s\n", strerror(errno));
116 case REQUEST_TYPE_PIXMAP:
117 item->data.pixmap = (unsigned int)data;
119 case REQUEST_TYPE_SHM:
120 item->data.shm = (int)data;
123 ErrPrint("Invalid type of request\n");
133 static inline int destroy_request_item(struct request_item *item)
135 switch (item->type) {
136 case REQUEST_TYPE_FILE:
137 free(item->data.filename);
139 case REQUEST_TYPE_SHM:
140 case REQUEST_TYPE_PIXMAP:
143 return LB_STATUS_ERROR_INVALID;
147 return LB_STATUS_SUCCESS;
150 static int request_file_handler(struct tcb *tcb, struct packet *packet, struct request_item **item)
152 const char *filename;
154 if (packet_get(packet, "s", &filename) != 1) {
155 ErrPrint("Invalid packet\n");
156 return LB_STATUS_ERROR_INVALID;
159 *item = create_request_item(tcb, REQUEST_TYPE_FILE, (void *)filename);
160 return *item ? LB_STATUS_SUCCESS : LB_STATUS_ERROR_MEMORY;
163 static int request_pixmap_handler(struct tcb *tcb, struct packet *packet, struct request_item **item)
167 if (packet_get(packet, "i", &pixmap) != 1) {
168 ErrPrint("Invalid packet\n");
169 return LB_STATUS_ERROR_INVALID;
173 ErrPrint("pixmap is not valid\n");
174 return LB_STATUS_ERROR_INVALID;
179 * Attach to pixmap and copy its data to the client
181 *item = create_request_item(tcb, REQUEST_TYPE_PIXMAP, (void *)pixmap);
182 return *item ? LB_STATUS_SUCCESS : LB_STATUS_ERROR_MEMORY;
185 static int request_shm_handler(struct tcb *tcb, struct packet *packet, struct request_item **item)
189 if (packet_get(packet, "i", &shm) != 1) {
190 ErrPrint("Invalid packet\n");
191 return LB_STATUS_ERROR_INVALID;
195 ErrPrint("shm is not valid: %d\n", shm);
196 return LB_STATUS_ERROR_INVALID;
201 * Attach to SHM and copy its buffer to the client
203 *item = create_request_item(tcb, REQUEST_TYPE_SHM, (void *)shm);
204 return *item ? LB_STATUS_SUCCESS : LB_STATUS_ERROR_MEMORY;
208 static int service_thread_main(struct tcb *tcb, struct packet *packet, void *data)
214 struct request_item *item;
215 struct packet *reply;
218 int (*request_handler)(struct tcb *tcb, struct packet *packet, struct request_item **item);
221 .cmd = "request,file",
222 .request_handler = request_file_handler,
225 .cmd = "request,pixmap",
226 .request_handler = request_pixmap_handler,
229 .cmd = "request,shm",
230 .request_handler = request_shm_handler,
234 .request_handler = NULL,
239 DbgPrint("TCB %p is disconnected\n", tcb);
240 return LB_STATUS_SUCCESS;
243 cmd = packet_command(packet);
245 ErrPrint("Invalid packet. cmd is not valid\n");
246 return LB_STATUS_ERROR_INVALID;
249 switch (packet_type(packet)) {
251 for (i = 0; cmd_table[i].cmd; i++) {
254 * FILE REQUEST COMMAND (Client -> Server)
255 * REPLY FOR REQUEST (Client <- Server)
256 * PUSH FILE (Client <- Server)
258 * Client & Server must has to keep this communication sequence.
260 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");
275 packet_destroy(reply);
279 * After send the reply packet, file push thread can sending a file
281 if (ret != LB_STATUS_SUCCESS || !item)
284 CRITICAL_SECTION_BEGIN(&s_info.request_list_lock);
285 s_info.request_list = eina_list_append(s_info.request_list, item);
286 CRITICAL_SECTION_END(&s_info.request_list_lock);
288 ret = write(s_info.request_pipe[PIPE_WRITE], &ch, sizeof(ch));
290 ErrPrint("write: %s\n", strerror(errno));
292 CRITICAL_SECTION_BEGIN(&s_info.request_list_lock);
293 s_info.request_list = eina_list_remove(s_info.request_list, item);
294 CRITICAL_SECTION_END(&s_info.request_list_lock);
296 destroy_request_item(item);
298 * \note for the client
299 * In this case, the client can waiting files forever.
300 * So the client must has to wait only a few seconds.
301 * If the client could not get the any data in that time,
302 * it should cancel the waiting.
308 case PACKET_REQ_NOACK:
310 /* File service has no this case, it is passive service type */
311 ErrPrint("Invalid packet.\n");
317 return LB_STATUS_SUCCESS;
320 static int send_file(int handle, const struct request_item *item)
322 struct burst_head *head;
323 struct burst_data *body;
330 /* TODO: push a file to the client */
331 fd = open(item->data.filename, O_RDONLY);
333 ErrPrint("open: %s\n", strerror(errno));
337 flen = strlen(item->data.filename);
343 pktsz = sizeof(*head) + flen + 1;
345 head = malloc(pktsz);
347 ErrPrint("heap: %s\n", strerror(errno));
352 fsize = lseek(fd, 0L, SEEK_END);
353 if (fsize == (off_t)-1) {
354 ErrPrint("heap: %s\n", strerror(errno));
362 strcpy(head->fname, item->data.filename);
364 /* Anytime we can fail to send packet */
365 ret = com_core_send(handle, (void *)head, pktsz, 2.0f);
372 if (lseek(fd, 0L, SEEK_SET) == (off_t)-1) {
373 ErrPrint("seek: %s\n", strerror(errno));
375 body = malloc(sizeof(*body));
377 ErrPrint("Heap: %s\n", strerror(errno));
382 ret = com_core_send(handle, (void *)body, sizeof(*body), 2.0f);
393 body = malloc(PKT_CHUNKSZ + sizeof(*body));
395 ErrPrint("heap: %s\n", strerror(errno));
401 if (fsize > PKT_CHUNKSZ) {
402 body->size = PKT_CHUNKSZ;
407 ret = read(fd, body->data, body->size);
409 ErrPrint("read: %s\n", strerror(errno));
416 pktsz = sizeof(*body) + body->size;
419 ret = com_core_send(handle, (void *)body, pktsz, 2.0f);
428 ret = com_core_send(handle, (void *)body, sizeof(*body), 2.0f);
436 ErrPrint("close: %s\n", strerror(errno));
441 static int send_buffer(int handle, const struct request_item *item)
443 struct buffer *buffer;
444 struct burst_head *head;
445 struct burst_data *body;
453 if (item->type == REQUEST_TYPE_SHM)
454 type = BUFFER_TYPE_SHM;
456 type = BUFFER_TYPE_PIXMAP;
458 buffer = buffer_handler_raw_open(type, (void *)item->data.shm);
462 pktsz = sizeof(*head);
464 head = malloc(pktsz);
466 ErrPrint("Heap: %s\n", strerror(errno));
467 (void)buffer_handler_raw_close(buffer);
471 size = head->size = buffer_handler_raw_size(buffer);
474 /* Anytime we can fail to send packet */
475 ret = com_core_send(handle, (void *)head, pktsz, 2.0f);
482 body = malloc(sizeof(*body) + PKT_CHUNKSZ);
488 data = (char *)buffer_handler_raw_data(buffer);
490 while (offset < size) {
491 body->size = size - offset;
493 if (body->size > PKT_CHUNKSZ)
494 body->size = PKT_CHUNKSZ;
496 memcpy(body->data, data, body->size);
497 pktsz = sizeof(*body) + body->size;
499 ret = com_core_send(handle, (void *)body, pktsz, 2.0f);
505 offset += body->size;
511 (void)buffer_handler_raw_close(buffer);
515 static void *push_main(void *data)
520 struct request_item *item;
522 send_data_func_t send_data[] = {
530 FD_SET(s_info.request_pipe[PIPE_READ], &set);
532 ret = select(s_info.request_pipe[PIPE_READ] + 1, &set, NULL, NULL, NULL);
535 if (errno == EINTR) {
536 ErrPrint("INTERRUPTED\n");
540 ErrPrint("Error: %s\n", strerror(errno));
542 } else if (ret == 0) {
543 ErrPrint("Timeout\n");
548 if (!FD_ISSET(s_info.request_pipe[PIPE_READ], &set)) {
549 DbgPrint("Unknown data\n");
554 ret = read(s_info.request_pipe[PIPE_READ], &ch, sizeof(ch));
555 if (ret != sizeof(ch)) {
556 ErrPrint("read: %s\n", strerror(errno));
561 if (ch == PUSH_EXIT) {
562 DbgPrint("Thread is terminating\n");
567 CRITICAL_SECTION_BEGIN(&s_info.request_list_lock);
568 item = eina_list_nth(s_info.request_list, 0);
569 s_info.request_list = eina_list_remove(s_info.request_list, item);
570 CRITICAL_SECTION_END(&s_info.request_list_lock);
573 ErrPrint("Request item is not valid\n");
577 /* Validate the TCB? */
578 conn_fd = tcb_is_valid(s_info.svc_ctx, item->tcb);
580 ErrPrint("TCB is not valid\n");
581 destroy_request_item(item);
587 * From now, we cannot believe the conn_fd.
588 * It can be closed any time.
589 * Even though we using it.
591 if (item->type < REQUEST_TYPE_MAX && item->type >= 0)
592 (void)send_data[item->type](conn_fd, item);
594 ErrPrint("Invalid type\n");
596 destroy_request_item(item);
603 int file_service_init(void)
607 if (s_info.svc_ctx) {
608 ErrPrint("Already initialized\n");
609 return LB_STATUS_ERROR_ALREADY;
612 if (pipe2(s_info.request_pipe, O_NONBLOCK | O_CLOEXEC) < 0) {
613 ErrPrint("pipe: %s\n", strerror(errno));
614 return LB_STATUS_ERROR_FAULT;
617 status = pthread_mutex_init(&s_info.request_list_lock, NULL);
619 ErrPrint("Failed to create lock: %s\n", strerror(status));
620 CLOSE_PIPE(s_info.request_pipe);
621 return LB_STATUS_ERROR_FAULT;
624 s_info.svc_ctx = service_common_create(FILE_SERVICE_ADDR, service_thread_main, NULL);
625 if (!s_info.svc_ctx) {
626 ErrPrint("Unable to activate service thread\n");
628 status = pthread_mutex_destroy(&s_info.request_list_lock);
630 ErrPrint("Destroy lock: %s\n", strerror(status));
632 CLOSE_PIPE(s_info.request_pipe);
633 return LB_STATUS_ERROR_FAULT;
636 status = pthread_create(&s_info.push_thid, NULL, push_main, NULL);
638 ErrPrint("Failed to create a push service: %s\n", strerror(status));
640 service_common_destroy(s_info.svc_ctx);
641 s_info.svc_ctx = NULL;
643 status = pthread_mutex_destroy(&s_info.request_list_lock);
645 ErrPrint("Destroy lock: %s\n", strerror(status));
647 CLOSE_PIPE(s_info.request_pipe);
648 return LB_STATUS_ERROR_FAULT;
653 * Remote service doesn't need to set the additional SMAK label.
656 DbgPrint("Successfully initiated\n");
657 return LB_STATUS_SUCCESS;
661 int file_service_fini(void)
663 struct request_item *item;
669 return LB_STATUS_ERROR_INVALID;
672 status = write(s_info.request_pipe[PIPE_WRITE], &ch, sizeof(ch));
673 if (status != sizeof(ch)) {
674 ErrPrint("write: %s\n", strerror(errno));
675 /* Forcely terminate the thread */
676 status = pthread_cancel(s_info.push_thid);
678 ErrPrint("cancel: %s\n", strerror(status));
681 status = pthread_join(s_info.push_thid, &retval);
683 ErrPrint("join: %s\n", strerror(status));
685 CRITICAL_SECTION_BEGIN(&s_info.request_list_lock);
686 EINA_LIST_FREE(s_info.request_list, item) {
687 destroy_request_item(item);
689 CRITICAL_SECTION_END(&s_info.request_list_lock);
691 service_common_destroy(s_info.svc_ctx);
692 s_info.svc_ctx = NULL;
694 status = pthread_mutex_destroy(&s_info.request_list_lock);
696 ErrPrint("destroy mutex: %s\n", strerror(status));
698 CLOSE_PIPE(s_info.request_pipe);
700 DbgPrint("Successfully Finalized\n");
701 return LB_STATUS_SUCCESS;