126c0525b584afcb8ab51f67414c32c7dad0f273
[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 struct _sipc_channel_key {
34         unsigned int id;
35         int fd;
36 };
37
38 static gboolean _check_key_info(struct _sipc_channel_key *k)
39 {
40         struct stat buf;
41         int ret = 0;
42
43         SIPC_CHECK_DATA_NULL( k, FALSE);
44
45         memset(&buf, '\0', sizeof(struct stat));
46
47         errno = 0;
48         ret = fstat(k->fd, &buf);
49         if (ret < 0) {
50                 // debug msg using strerror( errno );
51                 return FALSE;
52         }
53
54         if ((buf.st_mode & S_IFMT) != S_IFSOCK) {
55                 // debug msg : it's not socket fd
56                 return FALSE;
57         }
58
59         if (k->id == (unsigned int) buf.st_ino)
60                 return TRUE;
61
62         return FALSE;
63 }
64
65 static gboolean _check_channel_type(struct _sipc_channel *ch, sipc_channel_type_e t)
66 {
67         SIPC_CHECK_DATA_NULL( ch, FALSE);
68         SIPC_CHECK_DATA_RANGE( t, SIPC_CHANNEL_TYPE_TX, SIPC_CHANNEL_TYPE_RX, FALSE);
69
70         if (ch->type != t)
71                 return FALSE;
72
73         return TRUE;
74 }
75
76 static gboolean _check_channel_rx_type(struct _sipc_channel *ch)
77 {
78         SIPC_CHECK_DATA_NULL( ch, FALSE);
79
80         if (!_check_channel_type(ch, SIPC_CHANNEL_TYPE_RX))
81                 return FALSE;
82
83         return TRUE;
84 }
85
86 static gboolean _check_channel_info(struct _sipc_channel *ch)
87 {
88         SIPC_CHECK_DATA_NULL( ch, FALSE);
89
90         if (!ch->id || !ch->fd || !ch->type) {
91                 return FALSE;
92         }
93
94         return TRUE;
95 }
96
97 static struct _sipc_header* _create_header(struct _sipc_channel *ch, sipc_command_e c, int data_type, int data_len)
98 {
99         struct _sipc_header *h;
100
101         SIPC_CHECK_DATA_NULL( ch, 0);
102         SIPC_CHECK_DATA_RANGE( c, SIPC_SEND_DATA_SYNC, SIPC_DEREGISTER_CHANNEL, 0);
103
104         h = g_new0( struct _sipc_header, 1 );
105         h->ch_id = ch->id;
106         h->ch_type = ch->type;
107         h->cmd = c;
108         h->en_type = data_type;
109         h->data_len = data_len;
110
111         return h;
112 }
113
114 static int _channel_send(int fd, struct _sipc_header *h, void* in_d, void** out_d)
115 {
116         int p_len;
117         char *p;
118         int ret = -1;
119
120         SIPC_CHECK_DATA_NULL( (fd && h), -1);
121         // 1 will be wrong input
122
123         p_len = sizeof(struct _sipc_header) + h->data_len;
124         p = g_new0( char, p_len );
125
126         memcpy(p, h, sizeof(struct _sipc_header));
127
128         if (in_d && h->data_len)
129                 memcpy(p + sizeof(struct _sipc_header), (char*) in_d, h->data_len);
130
131         ret = send(fd, p, p_len, MSG_NOSIGNAL);
132         dbg("send data (%d) to server", ret);
133         if (ret < 0) {
134                 g_free(p);
135                 g_free(h);
136                 return -1;
137         }
138
139         memset(h, 0, sizeof(struct _sipc_header));
140         ret = recv(fd, h, sizeof(struct _sipc_header), MSG_NOSIGNAL);
141         if (ret < 0) {
142                 dbg("fail to read ack data from server");
143                 g_free(p);
144                 g_free(h);
145                 return -1;
146         }
147
148         if (h->cmd != SIPC_ACK_SUCCESS) {
149                 dbg("fail to request");
150                 g_free(p);
151                 g_free(h);
152                 return -1;
153         }
154
155         if (h->data_len > 0) {
156                 *out_d = g_new0( char, (h->data_len)+1 );
157                 ret = recv(fd, *out_d, h->data_len, MSG_NOSIGNAL);
158                 //dbg("server returns data\n (%s)\n", *out_d);
159         }
160
161         g_free(p);
162         g_free(h);
163         return 1;
164 }
165
166 static int _channel_deliver_data(struct _sipc_header *h, void *data, sipc_callback_t *cb)
167 {
168         int ret = -1;
169         
170         SIPC_CHECK_DATA_NULL( (h && cb), -1);
171
172         ret = cb->func(h->ch_id, data, h->data_len, NULL, cb->data);
173
174         return ret;
175 }
176
177 static gboolean _channel_recv(GIOChannel *ch, GIOCondition con, gpointer data)
178 {
179         int fd = 0;
180         int ret = -1;
181         char *in_d = NULL;
182         struct _sipc_header h_rsp = { 0, };
183         sipc_callback_t* cb;
184         gboolean ack = 0;
185
186         fd = g_io_channel_unix_get_fd(ch);
187         memset(&h_rsp, 0, sizeof(struct _sipc_header));
188
189         ret = recv(fd, &h_rsp, sizeof(struct _sipc_header), MSG_NOSIGNAL);
190         if (ret < 0) {
191                 dbg("recv() fail. ret = %d", ret);
192                 return FALSE;
193         }
194
195         if (h_rsp.data_len > 0) {
196                 in_d = g_new0( char, (h_rsp.data_len)+1 );
197                 ret = recv(fd, in_d, h_rsp.data_len, MSG_NOSIGNAL);
198                 if (ret < 0) {
199                         dbg("error to get header in socket");
200                         g_free(in_d);
201                         return FALSE;
202                 }
203                 dbg("recv data (%d)", ret);
204         }
205
206         cb = (sipc_callback_t*) data;
207         ack = _channel_deliver_data(&h_rsp, (void*) in_d, cb);
208         g_free(in_d);
209
210         if (ack < 0)
211                 return FALSE;
212
213         return TRUE;
214 }
215
216 // API SET
217
218 struct _sipc_channel_key* sipc_channel_key_create()
219 {
220         struct _sipc_channel_key *k;
221         int ret = 0;
222         struct stat buf;
223
224         k = g_new0( struct _sipc_channel_key, 1 );
225
226         k->fd = socket(AF_UNIX, SOCK_STREAM, 0);
227         if (k->fd < 0)
228                 return 0;
229
230         memset(&buf, '\0', sizeof(struct stat));
231
232         errno = 0;
233         ret = fstat(k->fd, &buf);
234         if (ret < 0) {
235                 // debug msg using strerror( errno );
236                 close(k->fd);
237                 return 0;
238         }
239
240         if ((buf.st_mode & S_IFMT) != S_IFSOCK) {
241                 // debug msg : it's not socket fd
242                 close(k->fd);
243                 return 0;
244         }
245
246         k->id = (unsigned int) buf.st_ino;
247
248         return k;
249 }
250
251 struct _sipc_channel* sipc_channel_open(struct _sipc_channel_key *k)
252 {
253         int fd = 0;
254         struct _sipc_channel *ch = 0;
255
256         SIPC_CHECK_DATA_NULL( k, 0);
257
258         if (!_check_key_info(k))
259                 return 0;
260
261         fd = socket(AF_UNIX, SOCK_STREAM, 0);
262         if (fd < 0) {
263                 return 0;
264         }
265
266         ch = g_new0( struct _sipc_channel, 1 );
267         ch->fd = fd;
268         ch->id = k->id;
269
270         return ch;
271 }
272
273 gboolean sipc_channel_set_type(struct _sipc_channel *ch, sipc_channel_type_e t)
274 {
275         SIPC_CHECK_DATA_NULL( ch, FALSE);
276         SIPC_CHECK_DATA_RANGE( t, SIPC_CHANNEL_TYPE_TX, SIPC_CHANNEL_TYPE_RX, FALSE);
277
278         ch->type = t;
279
280         return TRUE;
281 }
282
283 gboolean sipc_channel_connect(struct _sipc_channel *ch, char *path)
284 {
285         struct sockaddr_un server_addr;
286         int ret = -1;
287         struct _sipc_header *h = 0;
288
289         if (!_check_channel_info(ch))
290                 return FALSE;
291
292         memset(&server_addr, 0, sizeof(server_addr));
293
294         server_addr.sun_family = AF_UNIX;
295         strcpy((char*) server_addr.sun_path, path);
296
297         ret = connect(ch->fd, (struct sockaddr*) &server_addr, sizeof(server_addr));
298         if (ret < 0)
299                 return FALSE;
300
301         h = _create_header(ch, SIPC_REGISTER_CHANNEL, 0, 0);
302
303         ret = send(ch->fd, h, sizeof(struct _sipc_header), MSG_NOSIGNAL);
304         dbg("send register data(%d) ch->fd(%d), ch->type(%d)", ret, ch->fd, ch->type);
305         if (ret < 0) {
306                 g_free(h);
307                 return FALSE;
308         }
309
310         memset(h, 0, sizeof(struct _sipc_header));
311         ret = recv(ch->fd, h, sizeof(struct _sipc_header), MSG_NOSIGNAL);
312         dbg("recv register data(%d) ch->fd(%d), h->command(%d)", ret, ch->fd, h->cmd);
313         if (ret < 0) {
314                 g_free(h);
315                 return FALSE;
316         }
317
318         if (h->cmd != SIPC_ACK_SUCCESS) {
319                 g_free(h);
320                 return FALSE;
321         }
322
323         g_free(h);
324         return TRUE;
325 }
326
327 gboolean sipc_channel_register_rx_callback(struct _sipc_channel *ch, sipc_callback_t *cb)
328 {
329         guint tag = 0;
330         GIOChannel *c = 0;
331
332         if (!_check_channel_info(ch))
333                 return FALSE;
334
335         if (!_check_channel_rx_type(ch))
336                 return FALSE;
337
338         SIPC_CHECK_DATA_NULL( cb, FALSE);
339
340         dbg("g_io_channel_unix_new(fd = %d)", ch->fd);
341         c = g_io_channel_unix_new(ch->fd);
342         if (!c) {
343                 // debug msg
344                 dbg("g_io_channel_unix_new failed.");
345                 return FALSE;
346         }
347
348         tag = g_io_add_watch(c, (G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL), (GIOFunc) _channel_recv, cb);
349         if (!tag) {
350                 // debug msg
351                 dbg("g_io_add_watch failed.");
352                 return FALSE;
353         }
354
355         ch->tag = tag;
356
357         return TRUE;
358 }
359
360 int sipc_channel_send(struct _sipc_channel *ch, void *in_d, unsigned int in_data_len, void **out_d, sipc_data_type_e t)
361 {
362         struct _sipc_header *h = 0;
363
364         if (!_check_channel_info(ch))
365                 return -1;
366
367         SIPC_CHECK_DATA_RANGE(t, SIPC_DATA_TYPE_SYNC, SIPC_DATA_TYPE_ASYNC, -1);
368
369         h = _create_header(ch, (sipc_command_e) t, 0, in_data_len);
370
371         return _channel_send(ch->fd, h, in_d, out_d);
372 }
373
374 gboolean sipc_channel_close(struct _sipc_channel *ch, struct _sipc_channel_key *k)
375 {
376         if (!_check_key_info(k))
377                 return FALSE;
378
379         if (!_check_channel_info(ch))
380                 return FALSE;
381
382         sipc_channel_send(ch, 0, 0, NULL, SIPC_DEREGISTER_CHANNEL);
383
384         close(ch->fd);
385
386         return TRUE;
387 }
388
389 gboolean sipc_channel_key_destroy(struct _sipc_channel_key *k)
390 {
391         if (!_check_key_info(k))
392                 return FALSE;
393
394         close(k->fd);
395
396         return TRUE;
397 }
398
399 unsigned int sipc_channel_get_channel_id(struct _sipc_channel *ch)
400 {
401         SIPC_CHECK_DATA_NULL( ch, -1);
402
403         return ch->id;
404 }