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