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;
131 static inline int destroy_request_item(struct request_item *item)
133 switch (item->type) {
134 case REQUEST_TYPE_FILE:
135 free(item->data.filename);
137 case REQUEST_TYPE_SHM:
138 case REQUEST_TYPE_PIXMAP:
141 return LB_STATUS_ERROR_INVALID;
145 return LB_STATUS_SUCCESS;
148 static int request_file_handler(struct tcb *tcb, struct packet *packet, struct request_item **item)
150 const char *filename;
152 if (packet_get(packet, "s", &filename) != 1) {
153 ErrPrint("Invalid packet\n");
154 return LB_STATUS_ERROR_INVALID;
157 *item = create_request_item(tcb, REQUEST_TYPE_FILE, (void *)filename);
158 return *item ? LB_STATUS_SUCCESS : LB_STATUS_ERROR_MEMORY;
161 static int request_pixmap_handler(struct tcb *tcb, struct packet *packet, struct request_item **item)
165 if (packet_get(packet, "i", &pixmap) != 1) {
166 ErrPrint("Invalid packet\n");
167 return LB_STATUS_ERROR_INVALID;
171 ErrPrint("pixmap is not valid\n");
172 return LB_STATUS_ERROR_INVALID;
177 * Attach to pixmap and copy its data to the client
179 *item = create_request_item(tcb, REQUEST_TYPE_PIXMAP, (void *)pixmap);
180 return *item ? LB_STATUS_SUCCESS : LB_STATUS_ERROR_MEMORY;
183 static int request_shm_handler(struct tcb *tcb, struct packet *packet, struct request_item **item)
187 if (packet_get(packet, "i", &shm) != 1) {
188 ErrPrint("Invalid packet\n");
189 return LB_STATUS_ERROR_INVALID;
193 ErrPrint("shm is not valid: %d\n", shm);
194 return LB_STATUS_ERROR_INVALID;
199 * Attach to SHM and copy its buffer to the client
201 *item = create_request_item(tcb, REQUEST_TYPE_SHM, (void *)shm);
202 return *item ? LB_STATUS_SUCCESS : LB_STATUS_ERROR_MEMORY;
206 static int service_thread_main(struct tcb *tcb, struct packet *packet, void *data)
212 struct request_item *item;
213 struct packet *reply;
216 int (*request_handler)(struct tcb *tcb, struct packet *packet, struct request_item **item);
219 .cmd = "request,file",
220 .request_handler = request_file_handler,
223 .cmd = "request,pixmap",
224 .request_handler = request_pixmap_handler,
227 .cmd = "request,shm",
228 .request_handler = request_shm_handler,
232 .request_handler = NULL,
237 DbgPrint("TCB %p is disconnected\n", tcb);
238 return LB_STATUS_SUCCESS;
241 cmd = packet_command(packet);
243 ErrPrint("Invalid packet. cmd is not valid\n");
244 return LB_STATUS_ERROR_INVALID;
247 switch (packet_type(packet)) {
249 for (i = 0; cmd_table[i].cmd; i++) {
252 * FILE REQUEST COMMAND (Client -> Server)
253 * REPLY FOR REQUEST (Client <- Server)
254 * PUSH FILE (Client <- Server)
256 * Client & Server must has to keep this communication sequence.
258 if (strcmp(cmd, cmd_table[i].cmd))
262 ret = cmd_table[i].request_handler(tcb, packet, &item);
264 reply = packet_create_reply(packet, "i", ret);
266 ErrPrint("Failed to create a reply packet\n");
270 if (service_common_unicast_packet(tcb, reply) < 0)
271 ErrPrint("Unable to send reply packet\n");
273 packet_destroy(reply);
277 * After send the reply packet, file push thread can sending a file
279 if (ret != LB_STATUS_SUCCESS || !item)
282 CRITICAL_SECTION_BEGIN(&s_info.request_list_lock);
283 s_info.request_list = eina_list_append(s_info.request_list, item);
284 CRITICAL_SECTION_END(&s_info.request_list_lock);
286 ret = write(s_info.request_pipe[PIPE_WRITE], &ch, sizeof(ch));
288 ErrPrint("write: %s\n", strerror(errno));
290 CRITICAL_SECTION_BEGIN(&s_info.request_list_lock);
291 s_info.request_list = eina_list_remove(s_info.request_list, item);
292 CRITICAL_SECTION_END(&s_info.request_list_lock);
294 destroy_request_item(item);
296 * \note for the client
297 * In this case, the client can waiting files forever.
298 * So the client must has to wait only a few seconds.
299 * If the client could not get the any data in that time,
300 * it should cancel the waiting.
306 case PACKET_REQ_NOACK:
308 /* File service has no this case, it is passive service type */
309 ErrPrint("Invalid packet.\n");
315 return LB_STATUS_SUCCESS;
318 static int send_file(int handle, const struct request_item *item)
320 struct burst_head *head;
321 struct burst_data *body;
328 /* TODO: push a file to the client */
329 fd = open(item->data.filename, O_RDONLY);
331 ErrPrint("open: %s\n", strerror(errno));
335 flen = strlen(item->data.filename);
341 pktsz = sizeof(*head) + flen + 1;
343 head = malloc(pktsz);
345 ErrPrint("heap: %s\n", strerror(errno));
350 fsize = lseek(fd, 0L, SEEK_END);
351 if (fsize == (off_t)-1) {
352 ErrPrint("heap: %s\n", strerror(errno));
360 strcpy(head->fname, item->data.filename);
362 /* Anytime we can fail to send packet */
363 ret = com_core_send(handle, (void *)head, pktsz, 2.0f);
370 if (lseek(fd, 0L, SEEK_SET) == (off_t)-1) {
371 ErrPrint("seek: %s\n", strerror(errno));
373 body = malloc(sizeof(*body));
375 ErrPrint("Heap: %s\n", strerror(errno));
380 ret = com_core_send(handle, (void *)body, sizeof(*body), 2.0f);
391 body = malloc(PKT_CHUNKSZ + sizeof(*body));
393 ErrPrint("heap: %s\n", strerror(errno));
399 if (fsize > PKT_CHUNKSZ) {
400 body->size = PKT_CHUNKSZ;
401 fsize -= PKT_CHUNKSZ;
407 pktsz = sizeof(*body) + body->size;
409 ret = read(fd, body->data, body->size);
411 ErrPrint("read: %s\n", strerror(errno));
417 ret = com_core_send(handle, (void *)body, pktsz, 2.0f);
426 ret = com_core_send(handle, (void *)body, sizeof(*body), 2.0f);
434 ErrPrint("close: %s\n", strerror(errno));
439 static int send_buffer(int handle, const struct request_item *item)
441 struct buffer *buffer;
442 struct burst_head *head;
443 struct burst_data *body;
451 if (item->type == REQUEST_TYPE_SHM)
452 type = BUFFER_TYPE_SHM;
454 type = BUFFER_TYPE_PIXMAP;
456 buffer = buffer_handler_raw_open(type, (void *)item->data.shm);
460 pktsz = sizeof(*head);
462 head = malloc(pktsz);
464 ErrPrint("Heap: %s\n", strerror(errno));
465 (void)buffer_handler_raw_close(buffer);
469 size = head->size = buffer_handler_raw_size(buffer);
472 /* Anytime we can fail to send packet */
473 ret = com_core_send(handle, (void *)head, pktsz, 2.0f);
480 body = malloc(sizeof(*body) + PKT_CHUNKSZ);
486 data = (char *)buffer_handler_raw_data(buffer);
488 while (offset < size) {
489 body->size = size - offset;
491 if (body->size > PKT_CHUNKSZ)
492 body->size = PKT_CHUNKSZ;
494 memcpy(body->data, data, body->size);
495 pktsz = sizeof(*body) + body->size;
497 ret = com_core_send(handle, (void *)body, pktsz, 2.0f);
503 offset += body->size;
509 (void)buffer_handler_raw_close(buffer);
513 static void *push_main(void *data)
518 struct request_item *item;
520 send_data_func_t send_data[] = {
528 FD_SET(s_info.request_pipe[PIPE_READ], &set);
530 ret = select(s_info.request_pipe[PIPE_READ] + 1, &set, NULL, NULL, NULL);
533 if (errno == EINTR) {
534 ErrPrint("INTERRUPTED\n");
538 ErrPrint("Error: %s\n", strerror(errno));
540 } else if (ret == 0) {
541 ErrPrint("Timeout\n");
546 if (!FD_ISSET(s_info.request_pipe[PIPE_READ], &set)) {
547 DbgPrint("Unknown data\n");
552 ret = read(s_info.request_pipe[PIPE_READ], &ch, sizeof(ch));
553 if (ret != sizeof(ch)) {
554 ErrPrint("read: %s\n", strerror(errno));
559 if (ch == PUSH_EXIT) {
560 DbgPrint("Thread is terminating\n");
565 CRITICAL_SECTION_BEGIN(&s_info.request_list_lock);
566 item = eina_list_nth(s_info.request_list, 0);
567 s_info.request_list = eina_list_remove(s_info.request_list, item);
568 CRITICAL_SECTION_END(&s_info.request_list_lock);
571 ErrPrint("Request item is not valid\n");
575 /* Validate the TCB? */
576 conn_fd = tcb_is_valid(s_info.svc_ctx, item->tcb);
578 ErrPrint("TCB is not valid\n");
579 destroy_request_item(item);
585 * From now, we cannot believe the conn_fd.
586 * It can be closed any time.
587 * Even though we using it.
589 if (item->type < REQUEST_TYPE_MAX && item->type >= 0)
590 (void)send_data[item->type](conn_fd, item);
592 ErrPrint("Invalid type\n");
594 destroy_request_item(item);
601 int file_service_init(void)
605 if (s_info.svc_ctx) {
606 ErrPrint("Already initialized\n");
607 return LB_STATUS_ERROR_ALREADY;
610 if (pipe2(s_info.request_pipe, O_NONBLOCK | O_CLOEXEC) < 0) {
611 ErrPrint("pipe: %s\n", strerror(errno));
612 return LB_STATUS_ERROR_FAULT;
615 status = pthread_mutex_init(&s_info.request_list_lock, NULL);
617 ErrPrint("Failed to create lock: %s\n", strerror(status));
618 CLOSE_PIPE(s_info.request_pipe);
619 return LB_STATUS_ERROR_FAULT;
622 s_info.svc_ctx = service_common_create(FILE_SERVICE_ADDR, service_thread_main, NULL);
623 if (!s_info.svc_ctx) {
624 ErrPrint("Unable to activate service thread\n");
626 status = pthread_mutex_destroy(&s_info.request_list_lock);
628 ErrPrint("Destroy lock: %s\n", strerror(status));
630 CLOSE_PIPE(s_info.request_pipe);
631 return LB_STATUS_ERROR_FAULT;
634 status = pthread_create(&s_info.push_thid, NULL, push_main, NULL);
636 ErrPrint("Failed to create a push service: %s\n", strerror(status));
638 service_common_destroy(s_info.svc_ctx);
639 s_info.svc_ctx = NULL;
641 status = pthread_mutex_destroy(&s_info.request_list_lock);
643 ErrPrint("Destroy lock: %s\n", strerror(status));
645 CLOSE_PIPE(s_info.request_pipe);
646 return LB_STATUS_ERROR_FAULT;
651 * Remote service doesn't need to set the additional SMAK label.
654 DbgPrint("Successfully initiated\n");
655 return LB_STATUS_SUCCESS;
659 int file_service_fini(void)
661 struct request_item *item;
667 return LB_STATUS_ERROR_INVALID;
670 status = write(s_info.request_pipe[PIPE_WRITE], &ch, sizeof(ch));
671 if (status != sizeof(ch)) {
672 ErrPrint("write: %s\n", strerror(errno));
673 /* Forcely terminate the thread */
674 status = pthread_cancel(s_info.push_thid);
676 ErrPrint("cancel: %s\n", strerror(status));
679 status = pthread_join(s_info.push_thid, &retval);
681 ErrPrint("join: %s\n", strerror(status));
683 CRITICAL_SECTION_BEGIN(&s_info.request_list_lock);
684 EINA_LIST_FREE(s_info.request_list, item) {
685 destroy_request_item(item);
687 CRITICAL_SECTION_END(&s_info.request_list_lock);
689 service_common_destroy(s_info.svc_ctx);
690 s_info.svc_ctx = NULL;
692 status = pthread_mutex_destroy(&s_info.request_list_lock);
694 ErrPrint("destroy mutex: %s\n", strerror(status));
696 CLOSE_PIPE(s_info.request_pipe);
698 DbgPrint("Successfully Finalized\n");
699 return LB_STATUS_SUCCESS;