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