Tizen 2.1 base
[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 /* This function initializes socket for ipc with usb-server */
21 int ipc_request_client_init(int *sock_remote)
22 {
23         __USB_FUNC_ENTER__ ;
24         if (!sock_remote) return -1;
25         int len;
26         struct sockaddr_un remote;
27
28         if (((*sock_remote) = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
29                 perror("socket");
30                 USB_LOG("FAIL: socket(AF_UNIX, SOCK_STREAM, 0)");
31                 return -1;;
32         }
33         remote.sun_family = AF_UNIX;
34         strncpy(remote.sun_path, SOCK_PATH, strlen(SOCK_PATH)+1);
35         len = strlen(remote.sun_path) + sizeof(remote.sun_family);
36
37         if (connect((*sock_remote), (struct sockaddr *)&remote, len) == -1) {
38                 perror("connect");
39                 USB_LOG("FAIL: connect((*sock_remote), (struct sockaddr *)&remote, len)");
40                 return -1;
41         }
42         __USB_FUNC_EXIT__ ;
43         return 0;
44 }
45
46 /* This function closes socket for ipc with usb-server */
47 int ipc_request_client_close(int *sock_remote)
48 {
49         __USB_FUNC_ENTER__ ;
50         if (!sock_remote) return -1;
51         close (*sock_remote);
52         __USB_FUNC_EXIT__ ;
53         return 0;
54 }
55
56 /* This function requests something to usb-server by ipc with socket and gets the results */
57 int request_to_usb_server(int sock_remote, int request, char *answer, char *pkgName)
58 {
59         __USB_FUNC_ENTER__ ;
60         int t;
61         char str[SOCK_STR_LEN];
62
63         USB_LOG("request: %d, pkgName: %s\n", request, pkgName);
64         snprintf(str, SOCK_STR_LEN, "%d|%s", request, pkgName);
65         if (send (sock_remote, str, strlen(str)+1, 0) == -1) {
66                 USB_LOG("FAIL: send (sock_remote, str, strlen(str)+1, 0)\n");
67                 return -1;
68         }
69         if ((t = recv(sock_remote, answer, SOCK_STR_LEN, 0)) > 0) {
70                 if (t < SOCK_STR_LEN) {
71                         answer[t] = '\0';
72                 } else { /* t == SOCK_STR_LEN */
73                         answer[SOCK_STR_LEN-1] = '\0';
74                 }
75                 USB_LOG("[CLIENT] Received value: %s\n", answer);
76         } else {
77                 USB_LOG("FAIL: recv(sock_remote, str, SOCK_STR_LEN, 0)\n");
78                 return -1;
79         }
80         __USB_FUNC_EXIT__ ;
81         return 0;
82 }
83
84 int handle_input_to_server(void *data, char *buf)
85 {
86         __USB_FUNC_ENTER__ ;
87         if (!data) return -1;
88         if (!buf) return -1;
89         struct AccCbData *permCbData = (struct AccCbData *)data;
90         int input = atoi(buf);
91         USB_LOG("Input: %d\n", input);
92
93         switch (input) {
94         case REQ_ACC_PERM_NOTI_YES_BTN:
95                 permCbData->accessory->accPermission = true;
96                 permCbData->request_perm_cb_func((struct usb_accessory_s*)(permCbData->user_data), true);
97                 break;
98         case REQ_ACC_PERM_NOTI_NO_BTN:
99                 permCbData->accessory->accPermission = false;
100                 permCbData->request_perm_cb_func((struct usb_accessory_s*)(permCbData->user_data), false);
101                 break;
102         default:
103                 break;
104         }
105         __USB_FUNC_EXIT__ ;
106         return 0;
107 }
108
109 static int read_message(int fd, char *str, int len)
110 {
111         __USB_FUNC_ENTER__;
112         int ret = -1;
113         while(1) {
114                 ret = read(fd, str, len);
115                 if (ret < 0) {
116                         if (EINTR == errno) {
117                                 USB_LOG("Re-read for error(EINTR)\n");
118                                 continue;
119                         } else {
120                                 USB_LOG("FAIL: read(fd, str, len)\n");
121                                 return -1;
122                         }
123                 } else {
124                         __USB_FUNC_EXIT__;
125                         return 0;
126                 }
127         }
128 }
129
130 int ipc_noti_client_init(void)
131 {
132         __USB_FUNC_ENTER__ ;
133         int sock_local;
134         int ret = -1;
135         int len;
136         struct sockaddr_un serveraddr;
137
138         sock_local = socket(AF_UNIX, SOCK_STREAM, 0);
139         if (sock_local < 0) {
140                 perror("socket");
141                 USB_LOG("FAIL: socket(AF_UNIX, SOCK_STREAM, 0)\n");
142                 return -1;
143         }
144         serveraddr.sun_family = AF_UNIX;
145         strncpy(serveraddr.sun_path, ACC_SOCK_PATH, strlen(ACC_SOCK_PATH)+1);
146         USB_LOG("socket file name: %s\n", serveraddr.sun_path);
147         unlink(serveraddr.sun_path);
148         len = strlen(serveraddr.sun_path) + sizeof(serveraddr.sun_family);
149
150         if (bind (sock_local, (struct sockaddr *)&serveraddr, len) < 0) {
151                 perror("bind");
152                 USB_LOG("FAIL: bind (sock_local, (struct sockaddr_un *)serveraddr)\n");
153                 close(sock_local);
154                 return -1;
155         }
156
157         ret = chown(ACC_SOCK_PATH, 5000, 5000);
158         if (ret < 0) USB_LOG("FAIL: chown(ACC_SOCK_PATH, 5000, 5000)");
159         ret = chmod(ACC_SOCK_PATH, 0777);
160         if (ret < 0) USB_LOG("FAIL: chmod(ACC_SOCK_PATH, 0777);");
161
162         if (listen (sock_local, 5) == -1) {
163                 perror("listen");
164                 USB_LOG("FAIL: listen (sock_local, 5)\n");
165                 close(sock_local);
166                 return -1;
167         }
168
169         __USB_FUNC_EXIT__ ;
170         return sock_local;
171 }
172
173 int ipc_noti_client_close(int *sock_remote)
174 {
175         __USB_FUNC_ENTER__ ;
176         close(*sock_remote);
177         __USB_FUNC_EXIT__ ;
178         return 0;
179 }
180
181 gboolean ipc_noti_client_cb(GIOChannel *g_io_ch, GIOCondition condition, gpointer data)
182 {
183         __USB_FUNC_ENTER__ ;
184         if (!data) return FALSE;
185         if (!g_io_ch) return FALSE;
186         int fd;
187         int ret = -1;
188         struct sockaddr_un client_address;
189         int client_sockfd;
190         int client_len;
191         char input_buf[SOCK_STR_LEN];
192         char output_buf[SOCK_STR_LEN];
193         GError *err;
194         GIOStatus gio_ret;
195
196         fd = g_io_channel_unix_get_fd(g_io_ch);
197         if (fd < 0) {
198                 USB_LOG("FAIL: g_io_channel_unix_get_fd(g_io_ch)\n");
199                 gio_ret = g_io_channel_shutdown(g_io_ch, TRUE, &err);
200                 if (G_IO_STATUS_ERROR == gio_ret) USB_LOG("ERROR: g_io_channel_shutdown(g_io_ch)\n");
201                 g_io_channel_unref(g_io_ch);
202                 return FALSE;
203         }
204
205         client_len = sizeof(client_address);
206         client_sockfd = accept(fd, (struct sockaddr *)&client_address, (socklen_t *)&client_len);
207         if (client_sockfd == -1) {
208                 perror("accept");
209                 USB_LOG("FAIL: accept(fd, (struct sockaddr *)&client_address, (socklen_t *)&client_len)\n");
210                 gio_ret = g_io_channel_shutdown(g_io_ch, TRUE, &err);
211                 if (G_IO_STATUS_ERROR == gio_ret) USB_LOG("ERROR: g_io_channel_shutdown(g_io_ch)\n");
212                 g_io_channel_unref(g_io_ch);
213                 ret = ipc_noti_client_close(&client_sockfd);
214                 if (ret < 0) USB_LOG("FAIL: ipc_noti_client_close(client_sockfd)\n");
215                 return FALSE;
216         }
217
218         if(read_message(client_sockfd, input_buf, sizeof(input_buf)) < 0) {
219                 USB_LOG("FAIL: read_message(client_sockfd, &buf)\n");
220                 snprintf(output_buf, strlen("FAIL"), "%d", IPC_FAIL);
221                 ret = write(client_sockfd, &output_buf, sizeof(output_buf));
222                 if (ret < 0) USB_LOG("FAIL: write(client_sockfd, &output_buf, sizeof(output_buf))\n");
223                 gio_ret = g_io_channel_shutdown(g_io_ch, TRUE, &err);
224                 if (G_IO_STATUS_ERROR == gio_ret) USB_LOG("ERROR: g_io_channel_shutdown(g_io_ch)\n");
225                 g_io_channel_unref(g_io_ch);
226                 ret = ipc_noti_client_close(&client_sockfd);
227                 if (ret < 0) USB_LOG("FAIL: ipc_noti_client_close(client_sockfd)\n");
228                 return FALSE;
229         }
230         USB_LOG("read(): %s\n", input_buf);
231         snprintf(output_buf, SOCK_STR_LEN, "%d", IPC_SUCCESS);
232         ret = write(client_sockfd, &output_buf, sizeof(output_buf));
233         if (ret < 0) USB_LOG("FAIL: write(client_sockfd, &output_buf, sizeof(output_buf))\n");
234         gio_ret = g_io_channel_shutdown(g_io_ch, TRUE, &err);
235         if (G_IO_STATUS_ERROR == gio_ret) USB_LOG("ERROR: g_io_channel_shutdown(g_io_ch)\n");
236         g_io_channel_unref(g_io_ch);
237         ret = ipc_noti_client_close(&client_sockfd);
238         if (ret < 0) USB_LOG("FAIL: ipc_noti_client_close(client_sockfd)\n");
239
240         ret = handle_input_to_server((void *)data, input_buf);
241         if (ret < 0) USB_LOG("FAIL: handle_input_to_server(input_buf, data)\n");
242
243         __USB_FUNC_EXIT__ ;
244         return FALSE;
245 }
246
247 /* This function returns the app id.
248  * After calling this function, the memory space should be freed */
249 char *get_app_id()
250 {
251         __USB_FUNC_ENTER__ ;
252         int pid = getpid();
253         USB_LOG("pid: %d\n", pid);
254         char appId[APP_ID_LEN];
255         int ret = aul_app_get_appid_bypid(getpid(), appId, APP_ID_LEN);
256         um_retvm_if(AUL_R_OK != ret, NULL, "FAIL: aul_app_get_appid_bypid(getpid(), appId)\n");
257         __USB_FUNC_EXIT__ ;
258         return strdup(appId);
259 }
260
261 /* This function find an accessory attached just now
262  * Currently This function supports just one accessory */
263 static int getChangedAcc (struct usb_accessory_s **attAcc)
264 {
265         __USB_FUNC_ENTER__ ;
266         if (attAcc == NULL) return -1;
267         struct usb_accessory_list *accList = NULL;
268         bool ret;
269
270         accList = (struct usb_accessory_list *)malloc(sizeof(struct usb_accessory_list));
271         um_retvm_if(!accList, -1, "accList == NULL");
272
273         ret = getAccList(&accList);
274         if (ret == false) {
275                 USB_LOG("FAIL: getAccList(&accList)");
276                 FREE(accList);
277                 return -1;
278         }
279
280         *attAcc = (struct usb_accessory_s *)malloc(sizeof(struct usb_accessory_s));
281         snprintf((*attAcc)->manufacturer, ACC_ELEMENT_LEN, "%s", accList->accessory->manufacturer);
282         snprintf((*attAcc)->model, ACC_ELEMENT_LEN, "%s", accList->accessory->model);
283         snprintf((*attAcc)->description, ACC_ELEMENT_LEN, "%s", accList->accessory->description);
284         snprintf((*attAcc)->version, ACC_ELEMENT_LEN, "%s", accList->accessory->version);
285         snprintf((*attAcc)->uri, ACC_ELEMENT_LEN, "%s", accList->accessory->uri);
286         snprintf((*attAcc)->serial, ACC_ELEMENT_LEN, "%s", accList->accessory->serial);
287
288         FREE(accList);
289
290         __USB_FUNC_EXIT__ ;
291         return 0;
292 }
293
294 /* This func release memory of an accessory attached just now */
295 static int freeChangedAcc (struct usb_accessory_s **attAcc)
296 {
297         __USB_FUNC_ENTER__ ;
298         if (attAcc == NULL) return -1;
299         FREE(*attAcc);
300         __USB_FUNC_EXIT__ ;
301         return 0;
302 }
303
304 /* Callback function which is called when accessory vconf key is changed */
305 void accessory_status_changed_cb(keynode_t *in_key, void* data)
306 {
307         __USB_FUNC_ENTER__ ;
308         if (!data)  return ;
309         struct AccCbData *conCbData = (struct AccCbData *)data;
310         struct usb_accessory_s *changedAcc = NULL;
311         int ret = -1;
312         int val = -1;
313         ret = vconf_get_int(VCONFKEY_USB_ACCESSORY_STATUS, &val);
314         um_retm_if(ret < 0, "FAIL: vconf_get_int(VCONFKEY_USB_ACCESSORY_STATUS)\n");
315
316         switch (val) {
317         case VCONFKEY_USB_ACCESSORY_STATUS_DISCONNECTED:
318                 conCbData->connection_cb_func(NULL, false, conCbData->user_data);
319                 break;
320         case VCONFKEY_USB_ACCESSORY_STATUS_CONNECTED:
321                 ret = getChangedAcc(&changedAcc);
322                 um_retm_if(ret < 0, "FAIL: getChangedAcc(&changedAcc)\n");
323
324                 conCbData->connection_cb_func(changedAcc, true, conCbData->user_data);
325
326                 ret = freeChangedAcc(&changedAcc);
327                 um_retm_if(ret < 0, "FAIL: freeChangedAcc(&changedAcc)\n");
328                 break;
329         default:
330                 USB_LOG("ERROR: The value of VCONFKEY_USB_ACCESSORY_STATUS is invalid\n");
331                 break;
332         }
333         __USB_FUNC_EXIT__ ;
334 }
335
336 /* Get an element from a string which has all information of an accessory */
337 static bool getAccElement(char *totalInfo[], char accInfo[])
338 {
339         __USB_FUNC_ENTER__ ;
340         if (!totalInfo) return false;
341         if (!accInfo) return false;
342
343         char *finder = *totalInfo;
344
345         if (*totalInfo) {
346                 while (1) {
347                         if (finder == NULL) {
348                                 USB_LOG("ERROR: finder == NULL");
349                                 __USB_FUNC_EXIT__ ;
350                                 return false;
351                         }
352                         if (*finder == '|' || *finder == '\0') {
353                                 *finder = '\0';
354                                 snprintf(accInfo, ACC_ELEMENT_LEN, "%s", *totalInfo);
355                                 USB_LOG("Info: %s", accInfo);
356                                 *totalInfo = ++finder;
357                                 __USB_FUNC_EXIT__ ;
358                                 return true;
359                         }
360                         finder++;
361                 }
362         }
363         __USB_FUNC_EXIT__ ;
364         return false;
365 }
366
367 /* Get all element separated from a string which has all information of an accessory */
368 static int getAccInfo(char *totalInfo[], struct usb_accessory_s **accessory)
369 {
370         __USB_FUNC_ENTER__ ;
371         bool ret = getAccElement(totalInfo, (*accessory)->manufacturer);
372         um_retvm_if(ret == false, -1, "FAIL: getAccElement(totalInfo, manufacturer)\n");
373         ret = getAccElement(totalInfo, (*accessory)->model);
374         um_retvm_if(ret == false, -1, "FAIL: getAccElement(totalInfo, model)\n");
375         ret = getAccElement(totalInfo, (*accessory)->description);
376         um_retvm_if(ret == false, -1, "FAIL: getAccElement(totalInfo, description)\n");
377         ret = getAccElement(totalInfo, (*accessory)->version);
378         um_retvm_if(ret == false, -1, "FAIL: getAccElement(totalInfo, version)\n");
379         ret = getAccElement(totalInfo, (*accessory)->uri);
380         um_retvm_if(ret == false, -1, "FAIL: getAccElement(totalInfo, uri)\n");
381         ret = getAccElement(totalInfo, (*accessory)->serial);
382         um_retvm_if(ret == false, -1, "FAIL: getAccElement(totalInfo, serial)\n");
383
384         __USB_FUNC_EXIT__ ;
385         return 0;
386 }
387
388 /* This function finds a list which contain all accessories attached
389  * Currently, Tizen usb accessory is designed for just one accessory */
390 bool getAccList(struct usb_accessory_list **accList)
391 {
392         __USB_FUNC_ENTER__ ;
393         if (accList == NULL || *accList == NULL) return false;
394         struct usb_accessory_s *accessory = NULL;
395         accessory = (struct usb_accessory_s *)malloc(sizeof(struct usb_accessory_s));
396         (*accList)->next = NULL;
397         (*accList)->accessory = accessory;
398         accessory->accPermission = false;
399
400         int ret = -1;
401         int sock_remote;
402         char buf[SOCK_STR_LEN];
403         ret = ipc_request_client_init(&sock_remote);
404         um_retvm_if(ret < 0, false, "FAIL: ipc_request_client_init(&sock_remote)\n");
405
406         ret = request_to_usb_server(sock_remote, GET_ACC_INFO, buf, NULL);
407         um_retvm_if(ret < 0, false, "FAIL: request_to_usb_server(GET_ACC_INFO)\n");
408         USB_LOG("GET_ACC_INFO: %s\n", buf);
409
410         ret = ipc_request_client_close(&sock_remote);
411         um_retvm_if(ret < 0, false, "FAIL: ipc_request_client_close(&sock_remote)\n");
412
413         char *tempInfo = buf;
414         ret = getAccInfo(&tempInfo, &((*accList)->accessory));
415         um_retvm_if(ret < 0, false, "FAIL: getAccInfo(&tempInfo, accList)\n");
416
417         USB_LOG("Acc manufacturer: %s\n", (*accList)->accessory->manufacturer);
418         USB_LOG("Acc model: %s\n", (*accList)->accessory->model);
419         USB_LOG("Acc description: %s\n", (*accList)->accessory->description);
420         USB_LOG("Acc version: %s\n", (*accList)->accessory->version);
421         USB_LOG("Acc uri: %s\n", (*accList)->accessory->uri);
422         USB_LOG("Acc serial: %s\n", (*accList)->accessory->serial);
423
424         __USB_FUNC_EXIT__ ;
425         return true;
426 }
427
428 /* Release memory of accessory list */
429 bool freeAccList(struct usb_accessory_list *accList)
430 {
431         __USB_FUNC_ENTER__ ;
432         if (accList == NULL) return true;
433         struct usb_accessory_list *tmpList = NULL;
434         while (accList) {
435                 tmpList = accList;
436                 accList = accList->next;
437                 FREE(tmpList->accessory);
438                 FREE(tmpList);
439         }
440         __USB_FUNC_EXIT__ ;
441         return true;
442 }
443
444 bool is_emul_bin()
445 {
446         __USB_FUNC_ENTER__ ;
447         int ret = -1;
448         struct utsname name;
449         ret = uname(&name);
450         if (ret < 0) {
451                 __USB_FUNC_EXIT__ ;
452                 return true;
453         } else {
454                 USB_LOG("Machine name: %s", name.machine);
455                 if (strcasestr(name.machine, "emul")) {
456                         __USB_FUNC_EXIT__ ;
457                         return true;
458                 } else {
459                         __USB_FUNC_EXIT__ ;
460                         return false;
461                 }
462         }
463
464 }