Git init
[framework/multimedia/libmedia-thumbnail.git] / server / thumb-server-internal.c
1 /*
2  * media-thumbnail-server
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Hyunjun Ko <zzoon.ko@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22 #include "thumb-server-internal.h"
23
24 #include <unistd.h>
25 #include <dirent.h>
26 #include <stdio.h>
27 #include <string.h>
28
29
30 #ifdef LOG_TAG
31 #undef LOG_TAG
32 #endif
33
34 #define LOG_TAG "Thumb-Daemon"
35
36 static int sock;
37 GAsyncQueue *g_req_queue = NULL;
38
39 static __thread _server_mode_e g_server_mode = BLOCK_MODE;
40 static __thread int g_media_svr_pid = 0;
41
42 int _thumb_daemon_get_sockfd()
43 {
44         return sock;
45 }
46
47
48 GAsyncQueue *_thumb_daemon_get_queue()
49 {
50         return g_req_queue;
51 }
52
53 void _thumb_daemon_destroy_queue_msg(queueMsg *msg)
54 {
55         if (msg != NULL) {
56                 if (msg->recv_msg != NULL) {
57                         free(msg->recv_msg);
58                         msg->recv_msg = NULL;
59                 }
60
61                 if (msg->res_msg != NULL) {
62                         free(msg->res_msg);
63                         msg->res_msg = NULL;
64                 }
65
66                 msg = NULL;
67         }
68 }
69
70 int _thumb_daemon_compare_pid_with_mediaserver_fast(int pid)
71 {
72     int find_pid = -1;
73
74         char path[128];
75         char buff[128];
76         snprintf(path, sizeof(path), "/proc/%d/status", g_media_svr_pid);
77
78         FILE *fp = NULL;
79         fp = fopen(path, "rt");
80         if (fp) {
81                 fgets(buff, sizeof(buff), fp);
82                 fclose(fp);
83
84                 if (strstr(buff, "media-server")) {
85                         find_pid = g_media_svr_pid;
86                         thumb_dbg(" find_pid : %d", find_pid);
87                 } else {
88                         g_media_svr_pid = 0;
89                         return GETPID_FAIL;
90                 }
91         } else {
92                 thumb_err("Can't read file [%s]", path);
93                 g_media_svr_pid = 0;
94                 return GETPID_FAIL;
95         }
96
97         if (find_pid == pid) {
98                 thumb_dbg("This is a request from media-server");
99                 return MEDIA_SERVER_PID;
100         } else {
101                 thumb_dbg("This is a request from other apps");
102                 return OTHERS_PID;
103         }
104 }
105
106 int _thumb_daemon_compare_pid_with_mediaserver(int pid)
107 {
108     DIR *pdir;
109     struct dirent pinfo;
110     struct dirent *result = NULL;
111
112     pdir = opendir("/proc");
113     if (pdir == NULL) {
114         thumb_err("err: NO_DIR");
115         return GETPID_FAIL;
116     }
117
118     while (!readdir_r(pdir, &pinfo, &result)) {
119         if (result == NULL)
120             break;
121
122         if (pinfo.d_type != 4 || pinfo.d_name[0] == '.'
123             || pinfo.d_name[0] > 57)
124             continue;
125
126         FILE *fp;
127         char buff[128];
128         char path[128];
129
130         snprintf(path, sizeof(path), "/proc/%s/status", pinfo.d_name);
131
132         fp = fopen(path, "rt");
133         if (fp) {
134             fgets(buff, sizeof(buff), fp);
135             fclose(fp);
136
137             if (strstr(buff, "media-server")) {
138                 thumb_dbg("pinfo->d_name : %s", pinfo.d_name);
139                 g_media_svr_pid = atoi(pinfo.d_name);
140                 thumb_dbg("Media Server PID : %d", g_media_svr_pid);
141             }
142         }
143     }
144
145         closedir(pdir);
146
147         if (g_media_svr_pid == pid) {
148                 thumb_dbg("This is a request from media-server");
149                 return MEDIA_SERVER_PID;
150         } else {
151                 thumb_dbg("This is a request from other apps");
152                 return OTHERS_PID;
153         }
154 }
155
156 int _thumb_daemon_recv_by_select(int fd, gboolean is_timeout)
157 {
158         thumb_err("");
159         fd_set fds;
160         int ret = -1;
161
162         FD_ZERO(&fds);
163         FD_SET(fd, &fds);
164
165         if (is_timeout) {
166                 struct timeval timeout;
167                 timeout.tv_sec = 1;
168                 timeout.tv_usec = 0;
169
170                 ret = select(fd + 1, &fds, 0, 0, &timeout);
171         } else {
172                 ret = select(fd + 1, &fds, 0, 0, NULL);
173         }
174
175     return ret;
176 }
177
178 int _thumb_daemon_process_job(thumbMsg *req_msg, thumbMsg *res_msg)
179 {
180         int err = -1;
181
182         err = _media_thumb_process(req_msg, res_msg);
183         if (err < 0) {
184                 if (req_msg->msg_type == THUMB_REQUEST_SAVE) {
185                         thumb_err("_media_thumb_process is failed: %d", err);
186                         res_msg->status = THUMB_FAIL;
187                 } else {
188                         thumb_warn("_media_thumb_process is failed: %d, So use default thumb", err);
189                         res_msg->status = THUMB_SUCCESS;
190                 }
191         } else {
192                 res_msg->status = THUMB_SUCCESS;
193         }
194
195         return err;
196 }
197
198 int _thumb_daemon_process_queue_jobs()
199 {
200         int length = 0;
201
202         while(1) {
203                 length = g_async_queue_length(g_req_queue);
204                 if (length > 0) {
205                         thumb_dbg("There are %d jobs in the queue", length);
206                         queueMsg *data = g_async_queue_pop(g_req_queue);
207
208                         _thumb_daemon_process_job(data->recv_msg, data->res_msg);
209
210                         if (sendto(sock, data->res_msg, sizeof(thumbMsg), 0, (struct sockaddr *)data->client_addr, sizeof(struct sockaddr_in)) != sizeof(thumbMsg)) {
211                                 thumb_err("sendto failed\n");
212                         } else {
213                                 thumb_dbg("Sent %s(%d) \n", data->res_msg->dst_path, strlen(data->res_msg->dst_path));
214                         }
215
216                         _thumb_daemon_destroy_queue_msg(data);
217                 } else {
218                         break;
219                 }
220         }
221
222         g_server_mode = BLOCK_MODE;
223
224         return 0;
225 }
226
227 gboolean _thumb_daemon_udp_thread(void *data)
228 {
229         int err = -1;
230         gboolean is_timeout = FALSE;
231
232         struct sockaddr_in serv_addr;
233         struct sockaddr_in client_addr;
234         unsigned short serv_port;
235         unsigned int client_addr_len;
236
237         queueMsg *queue_msg = NULL;
238         thumbMsg recv_msg;
239         thumbMsg res_msg;
240         int recv_msg_size;
241         char thumb_path[MAX_PATH_SIZE + 1];
242
243         memset((void *)&recv_msg, 0, sizeof(recv_msg));
244         memset((void *)&res_msg, 0, sizeof(res_msg));
245         serv_port = THUMB_DAEMON_PORT;
246
247         if (!g_req_queue) {
248                 g_req_queue = g_async_queue_new();
249         }
250
251         /* Creaete a datagram/UDP socket */
252         if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
253                 thumb_err("socket failed");
254                 return FALSE;
255         }
256
257         memset(thumb_path, 0, sizeof(thumb_path));
258         memset(&serv_addr, 0, sizeof(serv_addr));
259         serv_addr.sin_family = AF_INET;
260         serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
261         serv_addr.sin_port = htons(serv_port);
262
263         /* Bind to the local address */
264         if (bind(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
265                 thumb_err("bind failed");
266                 return FALSE;
267         }
268
269         thumb_dbg("bind success");
270
271         while(1) {
272                 if (g_server_mode == TIMEOUT_MODE) {
273                         thumb_dbg("Wait for other app's request for 1 sec");
274                         is_timeout = TRUE;
275                 } else {
276                         is_timeout = FALSE;
277                 }
278
279                 err = _thumb_daemon_recv_by_select(sock, is_timeout);
280
281                 if (err == 0) {
282                         /* timeout in select() */
283                         err = _thumb_daemon_process_queue_jobs();
284                         continue;
285
286                 } else if (err == -1) {
287                         /* error in select() */
288                         thumb_err("ERROR in select()");
289                         continue;
290
291                 } else {
292                         _pid_e pid_type = 0;
293                         /* Socket is readable */
294                         client_addr_len = sizeof(client_addr);
295                         if ((recv_msg_size = recvfrom(sock, &recv_msg, sizeof(recv_msg), 0, (struct sockaddr *)&client_addr, &client_addr_len)) < 0) {
296                                 thumb_err("recvfrom failed\n");
297                                 continue;
298                         }
299
300                         thumb_dbg("Received [%d] %s(%d) from PID(%d) \n", recv_msg.msg_type, recv_msg.org_path, strlen(recv_msg.org_path), recv_msg.pid);
301
302                         if (g_media_svr_pid > 0) {
303                                 pid_type = _thumb_daemon_compare_pid_with_mediaserver_fast(recv_msg.pid);
304                         }
305
306                         if (g_media_svr_pid <= 0) {
307                                 pid_type = _thumb_daemon_compare_pid_with_mediaserver(recv_msg.pid);
308                         }
309
310                         if (pid_type == GETPID_FAIL) {
311                                 thumb_err("Failed to get media svr pid. So This req is regarded as other app's request.");
312                                 pid_type = OTHERS_PID;
313                         }
314
315                         if (g_server_mode == BLOCK_MODE || pid_type == OTHERS_PID) {
316                                 long start = thumb_get_debug_time();
317
318                                 _thumb_daemon_process_job(&recv_msg, &res_msg);
319
320                                 long end = thumb_get_debug_time();
321                                 thumb_dbg("Time : %f (%s)\n", ((double)(end - start) / (double)CLOCKS_PER_SEC), recv_msg.org_path);
322
323                                 if (sendto(sock, &res_msg, sizeof(res_msg), 0, (struct sockaddr *)&client_addr, sizeof(client_addr)) != sizeof(res_msg)) {
324                                         thumb_err("sendto failed\n");
325                                 } else {
326                                         thumb_dbg("Sent %s(%d) \n", res_msg.dst_path, strlen(res_msg.dst_path));
327                                 }
328
329                                 memset((void *)&recv_msg, 0, sizeof(recv_msg));
330                                 memset((void *)&res_msg, 0, sizeof(res_msg));
331
332                                 if (pid_type == OTHERS_PID) {
333                                         g_server_mode = TIMEOUT_MODE;
334                                 }
335                         } else {
336                                 /* This is a request from media-server on TIMEOUT mode.
337                                    So this req is going to be pushed to the queue */
338
339                                 queue_msg = malloc(sizeof(queueMsg));
340                                 if (queue_msg == NULL) {
341                                         thumb_err("malloc failed");
342                                         continue;
343                                 }
344                                 queue_msg->recv_msg = malloc(sizeof(thumbMsg));
345                                 if (queue_msg->recv_msg == NULL) {
346                                         thumb_err("malloc failed");
347                                         SAFE_FREE(queue_msg);
348                                         continue;
349                                 }
350                                 queue_msg->res_msg = malloc(sizeof(thumbMsg));
351                                 if (queue_msg->res_msg == NULL) {
352                                         thumb_err("malloc failed");
353                                         SAFE_FREE(queue_msg->recv_msg);
354                                         SAFE_FREE(queue_msg);
355                                         continue;
356                                 }
357                                 queue_msg->client_addr = malloc(sizeof(struct sockaddr_in));
358                                 if (queue_msg->client_addr == NULL) {
359                                         thumb_err("malloc failed");
360                                         SAFE_FREE(queue_msg->recv_msg);
361                                         SAFE_FREE(queue_msg->res_msg);
362                                         SAFE_FREE(queue_msg);
363                                         continue;
364                                 }
365
366                                 memcpy(queue_msg->recv_msg, &recv_msg, sizeof(thumbMsg));
367                                 memcpy(queue_msg->res_msg, &res_msg, sizeof(thumbMsg));
368                                 memcpy(queue_msg->client_addr, &client_addr, sizeof(struct sockaddr_in));
369
370                                 g_async_queue_push(g_req_queue, GINT_TO_POINTER(queue_msg));
371                                 g_server_mode = TIMEOUT_MODE;
372                         }
373                 }
374         }
375
376         close(sock);
377
378         return TRUE;
379 }
380