SRS: srs-client library, proper structures for protocol data
[samsung-ril.git] / srs-client / srs-client.c
1 /**
2  * This file is part of samsung-ril.
3  *
4  * Copyright (C) 2013 Paul Kocialkowski <contact@oaulk.fr>
5  *
6  * samsung-ril is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * samsung-ril is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with samsung-ril.  If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <fcntl.h>
25
26 #include <sys/stat.h>
27 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <sys/un.h>
30 #include <sys/select.h>
31
32 #include <signal.h>
33 #include <arpa/inet.h>
34 #include <netinet/in.h>
35 #include <cutils/sockets.h>
36
37 #include <telephony/ril.h>
38
39 #include <samsung-ril-socket.h>
40 #include <srs-client.h>
41
42 /*
43  * SRS Client fops
44  */
45
46 int srs_client_recv_message(struct srs_client *client, struct srs_message *message)
47 {
48         struct srs_header *header_p;
49         struct srs_header header;
50         void *data = NULL;
51         int length = 0;
52
53         struct timeval timeout;
54         fd_set fds;
55         int rc;
56
57         if (client == NULL || message == NULL || client->fd < 0)
58                 return -EINVAL;
59
60         memset(message, 0, sizeof(struct srs_message));
61         memset(&header, 0, sizeof(header));
62
63         timeout.tv_sec = (SRS_CLIENT_TIMEOUT - SRS_CLIENT_TIMEOUT % 1000000) / 1000000;
64         timeout.tv_usec = SRS_CLIENT_TIMEOUT % 1000000;
65
66         FD_ZERO(&fds);
67         FD_SET(client->fd, &fds);
68
69         rc = select(client->fd + 1, &fds, NULL, NULL, &timeout);
70         if (rc == 0) {
71                 rc = 0;
72                 goto done;
73         } else if (rc < 0 || !FD_ISSET(client->fd, &fds))
74                 goto error;
75
76         SRS_CLIENT_LOCK(client);
77         rc = read(client->fd, &header, sizeof(header));
78         SRS_CLIENT_UNLOCK(client);
79
80         if (rc != sizeof(header))
81                 goto error;
82
83         header_p = &header;
84         message->command = SRS_COMMAND(header_p);
85
86         length = header.length - sizeof(header);
87         if (length > 0) {
88                 data = calloc(1, length);
89                 if (data == NULL)
90                         goto error;
91
92                 FD_ZERO(&fds);
93                 FD_SET(client->fd, &fds);
94
95                 rc = select(client->fd + 1, &fds, NULL, NULL, &timeout);
96                 if (rc <= 0 || !FD_ISSET(client->fd, &fds))
97                         goto error;
98
99                 SRS_CLIENT_LOCK(client);
100                 rc = read(client->fd, data, length);
101                 SRS_CLIENT_UNLOCK(client);
102
103                 if (rc != length)
104                         goto error;
105
106                 message->data = data;
107                 message->length = length;
108         }
109
110         rc = header.length;
111         goto done;
112
113 error:
114         rc = -1;
115
116         if (data != NULL)
117                 free(data);
118
119 done:
120         return rc;
121 }
122
123 int srs_client_send_message(struct srs_client *client, struct srs_message *message)
124 {
125         struct srs_header header;
126         unsigned char *p = NULL;
127         void *data = NULL;
128         int length = 0;
129
130         struct timeval timeout;
131         fd_set fds;
132         int rc;
133
134         if (client == NULL || message == NULL || client->fd < 0)
135                 return -EINVAL;
136
137         memset(&header, 0, sizeof(header));
138         header.length = message->length + sizeof(header);
139         header.group = SRS_GROUP(message->command);
140         header.index = SRS_INDEX(message->command);
141
142         length = header.length;
143         data = calloc(1, length);
144         if (data == NULL)
145                 goto error;
146
147         p = (unsigned char *) data;
148         memcpy(p, &header, sizeof(header));
149         p += sizeof(header);
150         if (message->data != NULL && message->length > 0) {
151                 memcpy(p, message->data, message->length);
152                 p += message->length;
153         }
154
155         timeout.tv_sec = (SRS_CLIENT_TIMEOUT - SRS_CLIENT_TIMEOUT % 1000000) / 1000000;
156         timeout.tv_usec = SRS_CLIENT_TIMEOUT % 1000000;
157
158         FD_ZERO(&fds);
159         FD_SET(client->fd, &fds);
160
161         rc = select(client->fd + 1, NULL, &fds, NULL, &timeout);
162         if (rc <= 0 || !FD_ISSET(client->fd, &fds))
163                 goto error;
164
165         SRS_CLIENT_LOCK(client);
166         rc = write(client->fd, data, length);
167         SRS_CLIENT_UNLOCK(client);
168
169         if (rc != length)
170                 goto error;
171
172         rc = length;
173         goto done;
174
175 error:
176         rc = -1;
177
178 done:
179         if (data != NULL)
180                 free(data);
181
182         return rc;
183 }
184
185 int srs_client_send(struct srs_client *client, unsigned short command, void *data, int length)
186 {
187         struct srs_message message;
188
189         memset(&message, 0, sizeof(message));
190         message.command = command;
191         message.data = data;
192         message.length = length;
193
194         return srs_client_send_message(client, &message);
195 }
196
197 int srs_client_open(struct srs_client *client)
198 {
199         int fd;
200
201         if (client == NULL)
202                 return -EINVAL;
203 #if RIL_VERSION >= 6
204         fd = socket_local_client(SRS_SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
205 #else
206         fd = socket_local_client(SRS_SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
207 #endif
208         if (fd < 0) {
209                 client->fd = -1;
210                 return -1;
211         }
212
213         client->fd = fd;
214         return 0;
215 }
216
217 int srs_client_close(struct srs_client *client)
218 {
219         if (client == NULL || client->fd < 0)
220                 return -EINVAL;
221
222         close(client->fd);
223         client->fd = -1;
224
225         return 0;
226 }
227
228 int srs_client_create(struct srs_client **client_p)
229 {
230         struct srs_client *client;
231
232         if (client_p == NULL)
233                 return -EINVAL;
234
235         client = calloc(1, sizeof(struct srs_client));
236         if (client == NULL) {
237                 *client_p = NULL;
238                 return -1;
239         }
240
241         client->fd = -1;
242         pthread_mutex_init(&(client->mutex), NULL);
243
244         *client_p = client;
245
246         return 0;
247 }
248
249 int srs_client_destroy(struct srs_client *client)
250 {
251         if (client == NULL)
252                 return -EINVAL;
253
254         pthread_mutex_destroy(&(client->mutex));
255
256         free(client);
257
258         return 0;
259 }
260
261 /*
262  * SRS Client thread
263  */
264
265 void *srs_client_thread(void *data)
266 {
267         struct srs_message message;
268         struct srs_client *client;
269         int rc;
270
271         if (data == NULL)
272                 return NULL;
273
274         client = (struct srs_client *) data;
275
276         if (client->thread_cb == NULL)
277                 goto done;
278
279         while (client->thread_run) {
280                 rc = srs_client_recv_message(client, &message);
281                 if (rc < 0)
282                         goto done;
283
284                 client->thread_cb(&message);
285         }
286
287 done:
288         client->thread_run = 0;
289
290         return NULL;
291 }
292
293 int srs_client_thread_start(struct srs_client *client,
294         srs_client_thread_cb cb)
295 {
296         pthread_attr_t attr;
297         int rc;
298
299         if (client == NULL || cb == NULL)
300                 return -EINVAL;
301
302         client->thread_cb = cb;
303         client->thread_run = 1;
304
305         pthread_attr_init(&attr);
306         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
307
308         rc = pthread_create(&(client->thread), &attr, srs_client_thread, (void *) client);
309         if (rc != 0)
310                 return -1;
311
312         return 0;
313 }
314
315 int srs_client_thread_stop(struct srs_client *client)
316 {
317         if (client == NULL)
318                 return -EINVAL;
319
320         client->thread_run = 0;
321
322         return 0;
323 }
324
325 /*
326  * SRS Client inline
327  */
328
329 int srs_client_ping(struct srs_client *client)
330 {
331         struct srs_message message;
332         struct srs_control_ping ping;
333         struct srs_control_ping *ping_p;
334         int rc;
335
336         if (client == NULL)
337                 return -1;
338
339         memset(&message, 0, sizeof(message));
340
341         ping.caffe = SRS_CONTROL_CAFFE;
342         rc = srs_client_send(client, SRS_CONTROL_PING, &ping, sizeof(ping));
343         if (rc < 0)
344                 goto error;
345
346         rc = srs_client_recv_message(client, &message);
347         if (rc < 0 || message.length <= 0 || message.data == NULL)
348                 goto error;
349
350         ping_p = (struct srs_control_ping *) message.data;
351         if (ping_p->caffe != SRS_CONTROL_CAFFE)
352                 goto error;
353
354         rc = 0;
355         goto done;
356
357 error:
358         rc = -1;
359
360 done:
361         if (message.data != NULL)
362                 free(message.data);
363
364         return rc;
365 }