289992f5acce5178b51c2099304fe4c6cf32ff15
[platform/core/api/usb-accessory.git] / src / usb_accessory_private.c
1 /*
2  * usb-accessory
3  * Copyright (c) 2012 Samsung Electronics Co., Ltd.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #include "usb_accessory_private.h"
19
20 #define NUM_ACC_INFO_SEPARATOR 5
21
22 static void show_acc_info(struct usb_accessory_s *accessory)
23 {
24         __USB_FUNC_ENTER__ ;
25         if (!accessory)
26                 return;
27
28         USB_LOG("*******************************");
29         USB_LOG("** Acc manufacturer: %s", accessory->manufacturer);
30         USB_LOG("** Acc model       : %s", accessory->model);
31         USB_LOG("** Acc description : %s", accessory->description);
32         USB_LOG("** Acc version     : %s", accessory->version);
33         USB_LOG("** Acc uri         : %s", accessory->uri);
34         USB_LOG("** Acc serial      : %s", accessory->serial);
35         USB_LOG("*******************************");
36         __USB_FUNC_EXIT__ ;
37 }
38
39 void free_accessory(struct usb_accessory_s *accessory)
40 {
41         __USB_FUNC_ENTER__ ;
42
43         if (accessory) {
44                 FREE(accessory->manufacturer);
45                 FREE(accessory->model);
46                 FREE(accessory->description);
47                 FREE(accessory->version);
48                 FREE(accessory->uri);
49                 FREE(accessory->serial);
50                 FREE(accessory);
51         }
52         __USB_FUNC_EXIT__ ;
53 }
54
55 /* Release memory of accessory list */
56 void free_acc_list(struct usb_accessory_list *accList)
57 {
58         __USB_FUNC_ENTER__ ;
59
60         struct usb_accessory_list *tmpList;
61         struct usb_accessory_s *accessory;
62
63         if (!accList)
64                 return;
65
66         while (accList) {
67                 tmpList = accList;
68                 accList = accList->next;
69                 accessory = tmpList->accessory;
70
71                 free_accessory(accessory);
72                 FREE(tmpList);
73         }
74
75         __USB_FUNC_EXIT__ ;
76 }
77
78 /* This function initializes socket for ipc with usb-server */
79 int ipc_request_client_init()
80 {
81         __USB_FUNC_ENTER__ ;
82
83         int sock;
84         struct sockaddr_un remote;
85
86         if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
87                 USB_LOG("FAIL: socket(AF_UNIX, SOCK_STREAM, 0)");
88                 return -1;
89         }
90
91         remote.sun_family = AF_UNIX;
92         strncpy(remote.sun_path, SOCK_PATH, sizeof(remote.sun_path));
93
94         if (connect(sock, (struct sockaddr *)&remote, sizeof(remote)) == -1) {
95                 USB_LOG("FAIL: connect(sock, (struct sockaddr *)&remote, len)");
96                 close(sock);
97                 return -1;
98         }
99
100         __USB_FUNC_EXIT__ ;
101         return sock;
102 }
103
104 /* This function requests something to usb-server by ipc with socket and gets the results */
105 int request_to_usb_server(int sockRemote, int request, void *data, char *answer, int answerLen)
106 {
107         __USB_FUNC_ENTER__ ;
108
109         int t;
110         char str[SOCK_STR_LEN];
111         char *pkgName;
112
113         if (!answer)
114                 return -1;
115
116         switch (request) {
117         case REQ_ACC_PERMISSION:
118         case HAS_ACC_PERMISSION:
119                 pkgName = (char *)data;
120                 USB_LOG("request: %d, pkgName: %s", request, pkgName);
121                 snprintf(str, sizeof(str), "%d|%s", request, pkgName);
122                 break;
123         default:
124                 USB_LOG("request: %d", request);
125                 snprintf(str, sizeof(str), "%d|", request);
126                 break;
127         }
128
129         if (send (sockRemote, str, strlen(str)+1, 0) == -1) {
130                 USB_LOG("FAIL: send (sock_remote, str, strlen(str)+1, 0)");
131                 return -1;
132         }
133
134         if ((t = recv(sockRemote, answer, answerLen, 0)) > 0) {
135                 if (t < answerLen) {
136                         answer[t] = '\0';
137                 } else { /* t == answerLen */
138                         answer[answerLen-1] = '\0';
139                 }
140                 USB_LOG("[CLIENT] Received value: %s", answer);
141
142                 __USB_FUNC_EXIT__ ;
143                 return 0;
144         }
145
146         USB_LOG("FAIL: recv(sock_remote, str, answerLen, 0)");
147
148         __USB_FUNC_EXIT__ ;
149         return -1;
150 }
151
152 static int handle_input_to_server(void *data, char *buf)
153 {
154         __USB_FUNC_ENTER__ ;
155
156         struct AccCbData *permCbData;
157         int input;
158
159         if (!data)
160                 return -1;
161         if (!buf)
162                 return -1;
163
164         permCbData = (struct AccCbData *)data;
165         input = atoi(buf);
166         USB_LOG("Input: %d", input);
167
168         switch (input) {
169         case REQ_ACC_PERM_NOTI_YES_BTN:
170                 permCbData->accessory->accPermission = true;
171                 permCbData->request_perm_cb_func(
172                                 (struct usb_accessory_s*)(permCbData->user_data), true);
173                 break;
174         case REQ_ACC_PERM_NOTI_NO_BTN:
175                 permCbData->accessory->accPermission = false;
176                 permCbData->request_perm_cb_func(
177                                 (struct usb_accessory_s*)(permCbData->user_data), false);
178                 break;
179         default:
180                 USB_LOG("FAIL: buf (%s) is improper", buf);
181                 return -1;
182         }
183         __USB_FUNC_EXIT__ ;
184         return 0;
185 }
186
187 static int read_message(int fd, char *str, int len)
188 {
189         __USB_FUNC_ENTER__;
190         int ret;
191
192         if (!str)
193                 return -1;
194
195         while(1) {
196                 ret = read(fd, str, len);
197                 if (ret >= 0) {
198                         __USB_FUNC_EXIT__;
199                         return 0;
200                 }
201
202                 if (EINTR == errno) {
203                         USB_LOG("Re-read for error(EINTR)");
204                         continue;
205                 }
206
207                 USB_LOG("FAIL: read(fd, str, len)");
208                 return -1;
209         }
210 }
211
212 int ipc_noti_client_init(void)
213 {
214         __USB_FUNC_ENTER__ ;
215         int sock_local;
216         int ret;
217         struct sockaddr_un serveraddr;
218
219         sock_local = socket(AF_UNIX, SOCK_STREAM, 0);
220         if (sock_local < 0) {
221                 USB_LOG("FAIL: socket(AF_UNIX, SOCK_STREAM, 0)");
222                 return -1;
223         }
224
225         serveraddr.sun_family = AF_UNIX;
226         strncpy(serveraddr.sun_path, ACC_SOCK_PATH, strlen(ACC_SOCK_PATH)+1);
227         USB_LOG("socket file name: %s", serveraddr.sun_path);
228
229         unlink(serveraddr.sun_path);
230
231         if (bind (sock_local, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0) {
232                 USB_LOG("FAIL: bind (sock_local, (struct sockaddr_un *)serveraddr)");
233                 close(sock_local);
234                 return -1;
235         }
236
237         ret = chown(ACC_SOCK_PATH, 5000, 5000);
238         if (ret < 0) {
239                 USB_LOG("FAIL: chown(ACC_SOCK_PATH, 5000, 5000)");
240                 close(sock_local);
241                 return -1;
242         }
243
244         ret = chmod(ACC_SOCK_PATH, 0777);
245         if (ret < 0) {
246                 USB_LOG("FAIL: chmod(ACC_SOCK_PATH, 0777);");
247                 close(sock_local);
248                 return -1;
249         }
250
251         if (listen (sock_local, 5) == -1) {
252                 USB_LOG("FAIL: listen (sock_local, 5)");
253                 close(sock_local);
254                 return -1;
255         }
256
257         __USB_FUNC_EXIT__ ;
258         return sock_local;
259 }
260
261 gboolean ipc_noti_client_cb(GIOChannel *gioCh, GIOCondition condition, gpointer data)
262 {
263         __USB_FUNC_ENTER__ ;
264
265         int fd;
266         int ret;
267         int clientlen;
268         struct sockaddr_un clientaddr;
269         int sockfd;
270         char inbuf[SOCK_STR_LEN];
271         char outbuf[SOCK_STR_LEN];
272         GError *err;
273         GIOStatus gret;
274
275         if (!data)
276                 return FALSE;
277         if (!gioCh)
278                 return FALSE;
279
280         fd = g_io_channel_unix_get_fd(gioCh);
281         if (fd < 0) {
282                 USB_LOG("FAIL: g_io_channel_unix_get_fd()");
283                 goto out_gio_unref;
284         }
285
286         clientlen = sizeof(clientaddr);
287         sockfd = accept(fd, (struct sockaddr *)&clientaddr, (socklen_t *)&clientlen);
288         if (sockfd == -1) {
289                 USB_LOG("FAIL: accept()");
290                 goto out_gio_unref;
291         }
292
293         if(read_message(sockfd, inbuf, sizeof(inbuf)) < 0) {
294                 USB_LOG("FAIL: read_message()");
295                 snprintf(outbuf, sizeof(outbuf), "%d", IPC_FAIL);
296                 if (0 > write(sockfd, &outbuf, sizeof(outbuf)))
297                         USB_LOG("FAIL: write()");
298                 goto out_ipc_fd;
299         }
300
301         USB_LOG("read(): %s", inbuf);
302         snprintf(outbuf, sizeof(outbuf), "%d", IPC_SUCCESS);
303         ret = write(sockfd, &outbuf, sizeof(outbuf));
304         if (ret < 0)
305                 USB_LOG("FAIL: write()");
306
307         ret = handle_input_to_server((void *)data, inbuf);
308         if (ret < 0)
309                 USB_LOG("FAIL: handle_input_to_server()");
310
311 out_ipc_fd:
312         close(sockfd);
313 out_gio_unref:
314         gret = g_io_channel_shutdown(gioCh, TRUE, &err);
315         if (G_IO_STATUS_ERROR == gret)
316                 USB_LOG("ERROR: g_io_channel_shutdown(gioCh)");
317         g_io_channel_unref(gioCh);
318
319         __USB_FUNC_EXIT__ ;
320         return FALSE;
321 }
322
323 /* This function returns the app id.
324  * After calling this function, the memory space should be freed */
325 char *get_app_id()
326 {
327         __USB_FUNC_ENTER__ ;
328
329         int ret;
330         char appId[APP_ID_LEN];
331
332         ret = aul_app_get_appid_bypid(getpid(), appId, sizeof(appId));
333         if (ret != AUL_R_OK) {
334                 USB_LOG("FAIL: aul_app_get_appid_bypid()");
335                 return NULL;
336         }
337
338         USB_LOG("appId: %s", appId);
339
340         __USB_FUNC_EXIT__ ;
341         return strdup(appId);
342 }
343
344 /* Get an element from a string which has all information of an accessory */
345 static bool get_acc_element(char **totalInfo, char **info)
346 {
347         __USB_FUNC_ENTER__ ;
348
349         char *finder;
350
351         if (!totalInfo || !(*totalInfo))
352                 return false;
353         if (!info)
354                 return false;
355
356         finder = *totalInfo;
357
358         while (finder) {
359                 if (*finder != '|' && *finder != '\0') {
360                         finder++;
361                         continue;
362                 }
363
364                 *finder = '\0';
365                 *info = strdup(*totalInfo);
366                 USB_LOG("Info: %s", *info);
367                 *totalInfo = ++finder;
368                 __USB_FUNC_EXIT__ ;
369                 return true;
370         }
371
372         __USB_FUNC_EXIT__ ;
373         return false;
374 }
375
376 /* Get all element separated from a string which has all information of an accessory */
377 static int get_acc_info(char *totalInfo, struct usb_accessory_s **accessory)
378 {
379         __USB_FUNC_ENTER__ ;
380
381         bool ret;
382         char *tmpInfo;
383         int numSepBar;
384
385         if (!totalInfo)
386                 goto out_fail;
387         if (!accessory || !(*accessory))
388                 goto out_fail;
389
390         /* Check whether or not the format of the accessory info is correct to parse */
391         tmpInfo = totalInfo;
392         numSepBar = 0;
393         while(*tmpInfo != '\0') {
394                 if (*tmpInfo == '|')
395                         numSepBar++;
396                 tmpInfo++;
397         }
398         if (numSepBar != NUM_ACC_INFO_SEPARATOR) {
399                 USB_LOG("FAIL: Format of string (%s) is improper", totalInfo);
400                 goto out_fail;
401         }
402
403         tmpInfo = totalInfo;
404
405         ret = get_acc_element(&tmpInfo, &((*accessory)->manufacturer));
406         if (!ret)
407                 goto out_fail;
408
409         ret = get_acc_element(&tmpInfo, &((*accessory)->model));
410         if (!ret)
411                 goto out_release_manufacturer;
412
413         ret = get_acc_element(&tmpInfo, &((*accessory)->description));
414         if (!ret)
415                 goto out_release_model;
416
417         ret = get_acc_element(&tmpInfo, &((*accessory)->version));
418         if (!ret)
419                 goto out_release_description;
420
421         ret = get_acc_element(&tmpInfo, &((*accessory)->uri));
422         if (!ret)
423                 goto out_release_version;
424
425         ret = get_acc_element(&tmpInfo, &((*accessory)->serial));
426         if (!ret)
427                 goto out_release_uri;
428
429         (*accessory)->accPermission = false;
430
431         __USB_FUNC_EXIT__ ;
432         return 0;
433
434 out_release_uri:
435         FREE((*accessory)->uri);
436 out_release_version:
437         FREE((*accessory)->version);
438 out_release_description:
439         FREE((*accessory)->description);
440 out_release_model:
441         FREE((*accessory)->model);
442 out_release_manufacturer:
443         FREE((*accessory)->manufacturer);
444 out_fail:
445         __USB_FUNC_EXIT__ ;
446         return -1;
447 }
448
449 /* This function finds a list which contain all accessories attached
450  * Currently, Tizen usb accessory is designed for just one accessory */
451 bool get_acc_list(struct usb_accessory_list **accList)
452 {
453         __USB_FUNC_ENTER__ ;
454
455         struct usb_accessory_s *accessory;
456         int ret;
457         int sock_remote;
458         char buf[SOCK_STR_LEN];
459
460         if (!accList || !(*accList))
461                 return false;
462
463         sock_remote = ipc_request_client_init();
464         if (sock_remote < 0) {
465                 USB_LOG("FAIL: ipc_request_client_init()");
466                 return false;
467         }
468
469         ret = request_to_usb_server(sock_remote, GET_ACC_INFO, NULL, buf, sizeof(buf));
470         if (ret < 0) {
471                 USB_LOG("FAIL: request_to_usb_server(GET_ACC_INFO)");
472                 close(sock_remote);
473                 return false;
474         }
475         USB_LOG("GET_ACC_INFO: %s", buf);
476
477         close(sock_remote);
478
479         accessory = (struct usb_accessory_s *)malloc(sizeof(struct usb_accessory_s));
480         if (!accessory) {
481                 USB_LOG("FAIL: malloc()");
482                 return false;
483         }
484
485         ret = get_acc_info(buf, &accessory);
486         if (0 > ret) {
487                 USB_LOG("FAIL: get_acc_info()");
488                 return false;
489         }
490
491         (*accList)->next = NULL;
492         (*accList)->accessory = accessory;
493
494         show_acc_info((*accList)->accessory);
495
496         __USB_FUNC_EXIT__ ;
497         return true;
498 }
499
500 /* This function find an accessory attached just now
501  * Currently This function supports just one accessory */
502 static int get_changed_acc (struct usb_accessory_s *attAcc)
503 {
504         __USB_FUNC_ENTER__ ;
505
506         struct usb_accessory_list *accList;
507         bool ret;
508
509         if (!attAcc)
510                 return -1;
511
512         accList = (struct usb_accessory_list *)malloc(sizeof(struct usb_accessory_list));
513         if (!accList) {
514                 USB_LOG("FAIL: malloc()");
515                 return -1;
516         }
517
518         ret = get_acc_list(&accList);
519         if (!ret) {
520                 USB_LOG("FAIL: get_acc_list()");
521                 free_acc_list(accList);
522                 return -1;
523         }
524
525         if (!(accList->accessory)) {
526                 USB_LOG("FAIL: accList->accessory == NULL");
527                 free_acc_list(accList);
528                 return -1;
529         }
530
531         attAcc->manufacturer = strdup(accList->accessory->manufacturer);
532         attAcc->model = strdup(accList->accessory->model);
533         attAcc->description = strdup(accList->accessory->description);
534         attAcc->version = strdup(accList->accessory->version);
535         attAcc->uri = strdup(accList->accessory->uri);
536         attAcc->serial = strdup(accList->accessory->serial);
537
538         free_acc_list(accList);
539
540         __USB_FUNC_EXIT__ ;
541         return 0;
542 }
543
544 /* Callback function which is called when accessory vconf key is changed */
545 void accessory_status_changed_cb(keynode_t *key, void* data)
546 {
547         __USB_FUNC_ENTER__ ;
548
549         struct AccCbData *conCbData;
550         struct usb_accessory_s *changedAcc;
551         int ret;
552         int val;
553
554         if (!data)
555                 return;
556
557         conCbData = (struct AccCbData *)data;
558
559         ret = vconf_get_int(VCONFKEY_USB_ACCESSORY_STATUS, &val);
560         if (0 > ret) {
561                 USB_LOG("FAIL: vconf_get_int()");
562                 return ;
563         }
564
565         switch (val) {
566         case VCONFKEY_USB_ACCESSORY_STATUS_DISCONNECTED:
567                 conCbData->connection_cb_func(NULL, false, conCbData->user_data);
568                 break;
569
570         case VCONFKEY_USB_ACCESSORY_STATUS_CONNECTED:
571                 changedAcc = (struct usb_accessory_s *)malloc(sizeof(struct usb_accessory_s));
572                 if (!changedAcc) {
573                         USB_LOG("FAIL: malloc()");
574                         return;
575                 }
576
577                 ret = get_changed_acc(changedAcc);
578                 if (ret < 0) {
579                         USB_LOG("FAIL: get_changed_acc()");
580                         free_accessory(changedAcc);
581                         return;
582                 }
583
584                 conCbData->connection_cb_func(changedAcc, true, conCbData->user_data);
585
586                 free_accessory(changedAcc);
587
588                 break;
589         default:
590                 USB_LOG("ERROR: The value of VCONFKEY_USB_ACCESSORY_STATUS is invalid");
591                 break;
592         }
593         __USB_FUNC_EXIT__ ;
594 }
595
596 bool is_emul_bin()
597 {
598         __USB_FUNC_ENTER__ ;
599         int ret = -1;
600         struct utsname name;
601         ret = uname(&name);
602         if (ret < 0) {
603                 __USB_FUNC_EXIT__ ;
604                 return true;
605         }
606
607         USB_LOG("Machine name: %s", name.machine);
608         if (strcasestr(name.machine, "emul")) {
609                 __USB_FUNC_EXIT__ ;
610                 return true;
611         } else {
612                 __USB_FUNC_EXIT__ ;
613                 return false;
614         }
615 }