release tizen_2.0 beta
[framework/telephony/tel-plugin-socket_communicator.git] / common / src / sipc_channel.c
1 /*
2  * tel-plugin-socket-communicator
3  *
4  * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Ja-young Gu <jygu@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20
21 #include <stdio.h>
22 #include <string.h>
23
24 #include <errno.h>
25 #include <sys/un.h>
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <sys/stat.h>
29
30 #include "sipc_common.h"
31 #include "sipc.h"
32
33 #ifndef dbg
34 #include "tapi_log.h"
35 #endif
36
37 struct _sipc_channel_key {
38         unsigned int id;
39         int fd;
40 };
41
42 static gboolean _check_key_info(struct _sipc_channel_key *k)
43 {
44         struct stat buf;
45         int ret = 0;
46
47         SIPC_CHECK_DATA_NULL( k, FALSE);
48
49         memset(&buf, '\0', sizeof(struct stat));
50
51         errno = 0;
52         ret = fstat(k->fd, &buf);
53         if (ret < 0) {
54                 // debug msg using strerror( errno );
55                 return FALSE;
56         }
57
58         if ((buf.st_mode & S_IFMT) != S_IFSOCK) {
59                 // debug msg : it's not socket fd
60                 return FALSE;
61         }
62
63         if (k->id == (unsigned int) buf.st_ino)
64                 return TRUE;
65
66         return FALSE;
67 }
68
69 static gboolean _check_channel_type(struct _sipc_channel *ch, sipc_channel_type_e t)
70 {
71         SIPC_CHECK_DATA_NULL( ch, FALSE);
72         SIPC_CHECK_DATA_RANGE( t, SIPC_CHANNEL_TYPE_TX, SIPC_CHANNEL_TYPE_RX, FALSE);
73
74         if (ch->type != t)
75                 return FALSE;
76
77         return TRUE;
78 }
79
80 static gboolean _check_channel_rx_type(struct _sipc_channel *ch)
81 {
82         SIPC_CHECK_DATA_NULL( ch, FALSE);
83
84         if (!_check_channel_type(ch, SIPC_CHANNEL_TYPE_RX))
85                 return FALSE;
86
87         return TRUE;
88 }
89
90 static gboolean _check_channel_info(struct _sipc_channel *ch)
91 {
92         SIPC_CHECK_DATA_NULL( ch, FALSE);
93
94         if (!ch->id || !ch->fd || !ch->type) {
95                 return FALSE;
96         }
97
98         return TRUE;
99 }
100
101 static struct _sipc_header* _create_header(struct _sipc_channel *ch, sipc_command_e c, int data_type, int data_len)
102 {
103         struct _sipc_header *h;
104
105         SIPC_CHECK_DATA_NULL( ch, 0);
106         SIPC_CHECK_DATA_RANGE( c, SIPC_SEND_DATA_SYNC, SIPC_DEREGISTER_CHANNEL, 0);
107
108         h = g_new0( struct _sipc_header, 1 );
109         h->ch_id = ch->id;
110         h->ch_type = ch->type;
111         h->cmd = c;
112         h->en_type = data_type;
113         h->data_len = data_len;
114
115         return h;
116 }
117
118 static int _channel_send(int fd, struct _sipc_header *h, void* in_d, void** out_d)
119 {
120         int p_len;
121         char *p;
122         int ret = -1;
123
124         SIPC_CHECK_DATA_NULL( (fd && h), -1);
125         // 1 will be wrong input
126
127         p_len = sizeof(struct _sipc_header) + h->data_len;
128         p = g_new0( char, p_len );
129
130         memcpy(p, h, sizeof(struct _sipc_header));
131
132         if (in_d && h->data_len)
133                 memcpy(p + sizeof(struct _sipc_header), (char*) in_d, h->data_len);
134
135         ret = send(fd, p, p_len, MSG_NOSIGNAL);
136         dbg("send data (%d) to server", ret);
137         if (ret < 0) {
138                 g_free(p);
139                 g_free(h);
140                 return -1;
141         }
142
143         memset(h, 0, sizeof(struct _sipc_header));
144         ret = recv(fd, h, sizeof(struct _sipc_header), MSG_NOSIGNAL);
145         if (ret < 0) {
146                 dbg("fail to read ack data from server");
147                 g_free(p);
148                 g_free(h);
149                 return -1;
150         }
151
152         if (h->cmd != SIPC_ACK_SUCCESS) {
153                 dbg("fail to request");
154                 g_free(p);
155                 g_free(h);
156                 return -1;
157         }
158
159         if (h->data_len > 0) {
160                 *out_d = g_new0( char, (h->data_len)+1 );
161                 ret = recv(fd, *out_d, h->data_len, MSG_NOSIGNAL);
162                 //dbg("server returns data\n (%s)\n", *out_d);
163         }
164
165         g_free(p);
166         g_free(h);
167         return 1;
168 }
169
170 static int _channel_deliver_data(struct _sipc_header *h, void *data, sipc_callback_t *cb)
171 {
172         int ret = -1;
173         
174         SIPC_CHECK_DATA_NULL( (h && cb), -1);
175
176         ret = cb->func(h->ch_id, data, h->data_len, NULL, cb->data);
177
178         return ret;
179 }
180
181 static gboolean _channel_recv(GIOChannel *ch, GIOCondition con, gpointer data)
182 {
183         int fd = 0;
184         int ret = -1;
185         char *in_d = NULL;
186         struct _sipc_header h_rsp = { 0, };
187         sipc_callback_t* cb;
188         gboolean ack = 0;
189
190         fd = g_io_channel_unix_get_fd(ch);
191         memset(&h_rsp, 0, sizeof(struct _sipc_header));
192
193         ret = recv(fd, &h_rsp, sizeof(struct _sipc_header), MSG_NOSIGNAL);
194         if (ret < 0) {
195                 dbg("recv() fail. ret = %d", ret);
196                 return FALSE;
197         }
198
199         if (h_rsp.data_len > 0) {
200                 in_d = g_new0( char, (h_rsp.data_len)+1 );
201                 ret = recv(fd, in_d, h_rsp.data_len, MSG_NOSIGNAL);
202                 if (ret < 0) {
203                         dbg("error to get header in socket");
204                         g_free(in_d);
205                         return FALSE;
206                 }
207                 dbg("recv data (%d)", ret);
208         }
209
210         cb = (sipc_callback_t*) data;
211         ack = _channel_deliver_data(&h_rsp, (void*) in_d, cb);
212         g_free(in_d);
213
214         if (ack < 0)
215                 return FALSE;
216
217         return TRUE;
218 }
219
220 // API SET
221
222 struct _sipc_channel_key* sipc_channel_key_create()
223 {
224         struct _sipc_channel_key *k;
225         int ret = 0;
226         struct stat buf;
227
228         k = g_new0( struct _sipc_channel_key, 1 );
229
230         k->fd = socket(AF_UNIX, SOCK_STREAM, 0);
231         if (k->fd < 0)
232                 return 0;
233
234         memset(&buf, '\0', sizeof(struct stat));
235
236         errno = 0;
237         ret = fstat(k->fd, &buf);
238         if (ret < 0) {
239                 // debug msg using strerror( errno );
240                 close(k->fd);
241                 return 0;
242         }
243
244         if ((buf.st_mode & S_IFMT) != S_IFSOCK) {
245                 // debug msg : it's not socket fd
246                 close(k->fd);
247                 return 0;
248         }
249
250         k->id = (unsigned int) buf.st_ino;
251
252         return k;
253 }
254
255 struct _sipc_channel* sipc_channel_open(struct _sipc_channel_key *k)
256 {
257         int fd = 0;
258         struct _sipc_channel *ch = 0;
259
260         SIPC_CHECK_DATA_NULL( k, 0);
261
262         if (!_check_key_info(k))
263                 return 0;
264
265         fd = socket(AF_UNIX, SOCK_STREAM, 0);
266         if (fd < 0) {
267                 return 0;
268         }
269
270         ch = g_new0( struct _sipc_channel, 1 );
271         ch->fd = fd;
272         ch->id = k->id;
273
274         return ch;
275 }
276
277 gboolean sipc_channel_set_type(struct _sipc_channel *ch, sipc_channel_type_e t)
278 {
279         SIPC_CHECK_DATA_NULL( ch, FALSE);
280         SIPC_CHECK_DATA_RANGE( t, SIPC_CHANNEL_TYPE_TX, SIPC_CHANNEL_TYPE_RX, FALSE);
281
282         ch->type = t;
283
284         return TRUE;
285 }
286
287 gboolean sipc_channel_connect(struct _sipc_channel *ch, char *path)
288 {
289         struct sockaddr_un server_addr;
290         int ret = -1;
291         struct _sipc_header *h = 0;
292
293         if (!_check_channel_info(ch))
294                 return FALSE;
295
296         memset(&server_addr, 0, sizeof(server_addr));
297
298         server_addr.sun_family = AF_UNIX;
299         strcpy((char*) server_addr.sun_path, path);
300
301         ret = connect(ch->fd, (struct sockaddr*) &server_addr, sizeof(server_addr));
302         if (ret < 0)
303                 return FALSE;
304
305         h = _create_header(ch, SIPC_REGISTER_CHANNEL, 0, 0);
306
307         ret = send(ch->fd, h, sizeof(struct _sipc_header), MSG_NOSIGNAL);
308         dbg("send register data(%d) ch->fd(%d), ch->type(%d)", ret, ch->fd, ch->type);
309         if (ret < 0) {
310                 g_free(h);
311                 return FALSE;
312         }
313
314         memset(h, 0, sizeof(struct _sipc_header));
315         ret = recv(ch->fd, h, sizeof(struct _sipc_header), MSG_NOSIGNAL);
316         dbg("recv register data(%d) ch->fd(%d), h->command(%d)", ret, ch->fd, h->cmd);
317         if (ret < 0) {
318                 g_free(h);
319                 return FALSE;
320         }
321
322         if (h->cmd != SIPC_ACK_SUCCESS) {
323                 g_free(h);
324                 return FALSE;
325         }
326
327         g_free(h);
328         return TRUE;
329 }
330
331 gboolean sipc_channel_register_rx_callback(struct _sipc_channel *ch, sipc_callback_t *cb)
332 {
333         guint tag = 0;
334         GIOChannel *c = 0;
335
336         if (!_check_channel_info(ch))
337                 return FALSE;
338
339         if (!_check_channel_rx_type(ch))
340                 return FALSE;
341
342         SIPC_CHECK_DATA_NULL( cb, FALSE);
343
344         dbg("g_io_channel_unix_new(fd = %d)", ch->fd);
345         c = g_io_channel_unix_new(ch->fd);
346         if (!c) {
347                 // debug msg
348                 dbg("g_io_channel_unix_new failed.");
349                 return FALSE;
350         }
351
352         tag = g_io_add_watch(c, (G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL), (GIOFunc) _channel_recv, cb);
353         if (!tag) {
354                 // debug msg
355                 dbg("g_io_add_watch failed.");
356                 return FALSE;
357         }
358
359         ch->tag = tag;
360
361         return TRUE;
362 }
363
364 int sipc_channel_send(struct _sipc_channel *ch, void *in_d, unsigned int in_data_len, void **out_d, sipc_data_type_e t)
365 {
366         struct _sipc_header *h = 0;
367
368         if (!_check_channel_info(ch))
369                 return -1;
370
371         SIPC_CHECK_DATA_RANGE(t, SIPC_DATA_TYPE_SYNC, SIPC_DATA_TYPE_ASYNC, -1);
372
373         h = _create_header(ch, (sipc_command_e) t, 0, in_data_len);
374
375         return _channel_send(ch->fd, h, in_d, out_d);
376 }
377
378 gboolean sipc_channel_close(struct _sipc_channel *ch, struct _sipc_channel_key *k)
379 {
380         if (!_check_key_info(k))
381                 return FALSE;
382
383         if (!_check_channel_info(ch))
384                 return FALSE;
385
386         sipc_channel_send(ch, 0, 0, NULL, SIPC_DEREGISTER_CHANNEL);
387
388         close(ch->fd);
389
390         return TRUE;
391 }
392
393 gboolean sipc_channel_key_destroy(struct _sipc_channel_key *k)
394 {
395         if (!_check_key_info(k))
396                 return FALSE;
397
398         close(k->fd);
399
400         return TRUE;
401 }
402
403 unsigned int sipc_channel_get_channel_id(struct _sipc_channel *ch)
404 {
405         SIPC_CHECK_DATA_NULL( ch, -1);
406
407         return ch->id;
408 }