99b5b33940c5e189ef2d5594ca73ae45602edec0
[platform/core/connectivity/data-router.git] / src / dr-ipc.c
1 /*
2  * Data-Router
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact:  Hocheol Seo <hocheol.seo@samsung.com>
7  *               Injun Yang <injun.yang@samsung.com>
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *              http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  */
22
23
24
25 #include <dbus/dbus.h>
26 #include <dbus/dbus-glib.h>
27 #include <dbus/dbus-glib-lowlevel.h>
28 #include <dbus/dbus-glib-bindings.h>
29 #include <glib.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <sys/socket.h>
33 #include <sys/stat.h>
34 #include <sys/un.h>
35 #include <unistd.h>
36
37 #include "dr-common.h"
38 #include "dr-usb.h"
39 #include "dr-main.h"
40 #include "dr-ipc.h"
41
42 #define SOCK_WAIT_TIME 10000
43 #define SOCK_WAIT_CNT 200
44 #define COM_SOCKET_PATH                                 "/tmp/.dr_common_stream"
45 #define BUF_SIZE                65536
46 #define NETWORK_SERIAL_INTERFACE                "Capi.Network.Serial"
47
48 DBusConnection *dbus_connection = NULL;
49
50 typedef enum {
51         SERIAL_SESSION_DISCONNECTED,
52         SERIAL_SESSION_CONNECTED
53 }dr_session_state_t;
54
55 typedef struct {
56         int server_socket;
57         int client_socket;
58         int g_watch_id_server;
59         int g_watch_id_client;
60         GIOChannel *g_io;
61         unsigned char state;
62 }dr_socket_info_t;
63
64 dr_socket_info_t serial_session = {0, };
65
66
67 static DBusHandlerResult __dbus_event_filter(DBusConnection *sys_conn,
68                                                         DBusMessage *msg, void *data)
69 {
70         const char *path = dbus_message_get_path(msg);
71
72         if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_SIGNAL)
73                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
74
75         if (path == NULL || strcmp(path, "/") == 0)
76                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
77
78         if (dbus_message_is_signal(msg, NETWORK_SERIAL_INTERFACE,
79                                                 "ready_for_serial")) {
80                 char *res = NULL;
81                 dbus_message_get_args(msg, NULL,
82                                         DBUS_TYPE_STRING, &res,
83                                         DBUS_TYPE_INVALID);
84
85                 if (g_strcmp0(res, "OK") == 0)
86                         _send_serial_status_signal(SERIAL_OPENED);
87         } else {
88                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
89         }
90
91         return DBUS_HANDLER_RESULT_HANDLED;
92 }
93
94 gboolean _init_dbus_signal(void)
95 {
96         DBG("+\n");
97         DBusGConnection *conn;
98         GError *err = NULL;
99         DBusError dbus_error;
100
101         conn = dbus_g_bus_get(DBUS_BUS_SYSTEM, &err);
102         if(!conn) {
103                 ERR(" DBUS get failed\n");
104                 g_error_free(err);
105                 return FALSE;
106         }
107         dbus_connection = dbus_g_connection_get_connection(conn);
108
109         /* Add the filter for network client functions */
110         dbus_error_init(&dbus_error);
111         dbus_connection_add_filter(dbus_connection, __dbus_event_filter, NULL, NULL);
112         dbus_bus_add_match(dbus_connection,
113                            "type=signal,interface=" NETWORK_SERIAL_INTERFACE
114                            ",member=ready_for_serial", &dbus_error);
115         if (dbus_error_is_set(&dbus_error)) {
116                 ERR("Fail to add dbus filter signal\n");
117                 dbus_error_free(&dbus_error);
118         }
119
120         DBG("-\n");
121         return TRUE;
122 }
123
124 void _send_serial_status_signal(int event)
125 {
126         DBusMessage *msg = NULL;
127         if(dbus_connection == NULL) return;
128
129         msg = dbus_message_new_signal("/DataRouter",
130                                           "User.Data.Router.Introspectable",
131                                           "serial_status");
132         if (!msg) {
133                 ERR("Unable to allocate D-Bus signal\n");
134                 return;
135         }
136
137         if (!dbus_message_append_args(msg,
138                         DBUS_TYPE_INT32, &event,
139                         DBUS_TYPE_INVALID)) {
140                 ERR("Event sending failed\n");
141                 dbus_message_unref(msg);
142                 return;
143         }
144         DBG("Send dbus signal : %s\n", event ? "SERIAL_OPENED":"SERIAL_CLOSED");
145         dbus_connection_send(dbus_connection, msg, NULL);
146         dbus_message_unref(msg);
147         return;
148 }
149
150
151 int _write_to_serial_client(char *buf, int buf_len)
152 {
153         int len;
154         if (buf == NULL || buf_len == 0) {
155                 ERR("Invalid param\n");
156                 return -1;
157         }
158         len = send(serial_session.client_socket, buf, buf_len, MSG_EOR);
159         if (len == -1) {
160                 char err_buf[ERRMSG_SIZE] = { 0, };
161                 strerror_r(errno, err_buf, ERRMSG_SIZE);
162                 ERR("Send failed\n");
163                 return -1;
164         }
165
166         return len;
167 }
168
169
170 static void __close_client_socket()
171 {
172         int ret;
173         DBG("Closing socket\n");
174         ret = close(serial_session.client_socket);
175         if (ret == -1) {
176                 perror("close error: ");
177         }
178         serial_session.state = SERIAL_SESSION_DISCONNECTED;
179         return;
180 }
181
182
183 static gboolean __g_io_server_handler(GIOChannel *io, GIOCondition cond, void *data)
184 {
185         char buffer[BUF_SIZE+1];
186         int len = 0;
187         int fd;
188         fd = g_io_channel_unix_get_fd(io);
189         memset(buffer, 0, sizeof(buffer));
190         len = recv(fd, buffer, BUF_SIZE, 0);
191         if (len <= 0) {
192                 ERR("Connection closed or Error occured : %d\n", len);
193                 g_source_remove(serial_session.g_watch_id_server);
194                 g_source_remove(serial_session.g_watch_id_client);
195                 __close_client_socket();
196                 unlink(COM_SOCKET_PATH);
197                 return FALSE;
198         }
199
200         _write_to_usb(buffer, len);
201         return TRUE;
202 }
203
204
205 static gboolean __g_io_accept_handler(GIOChannel *chan, GIOCondition cond, gpointer data)
206 {
207         int serverfd;
208         int clientfd;
209         GIOChannel *io;
210         struct sockaddr_un client_addr;
211         socklen_t addrlen;
212         addrlen = sizeof(client_addr);
213
214         if ( cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR) ) {
215                 DBG("GIOCondition %d \n", cond);
216
217                 if(serial_session.server_socket >= 0) {
218                         close(serial_session.server_socket);
219                         serial_session.server_socket = 0;
220                 }
221                 return FALSE;
222         }
223
224         if(serial_session.state == SERIAL_SESSION_CONNECTED) {
225                 DBG("Connection already exists.....\n");
226                 return FALSE;
227         }
228
229         DBG("Waiting for connection request\n");
230         serverfd = g_io_channel_unix_get_fd(chan);
231         clientfd = accept(serverfd, (struct sockaddr *)&client_addr, &addrlen);
232         if (clientfd > 0)       {
233                 DBG("serverfd:%d clientfd:%d\n", serverfd, clientfd);
234
235                 io = g_io_channel_unix_new(clientfd);
236                 g_io_channel_set_close_on_unref(io, TRUE);
237                 serial_session.g_watch_id_client = g_io_add_watch(io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
238                         __g_io_server_handler, NULL);
239                 g_io_channel_unref(io);
240
241                 serial_session.client_socket= clientfd;
242                 serial_session.state = SERIAL_SESSION_CONNECTED;
243         } else {
244                 ERR("Accept failed\n");
245                 return FALSE;
246         }
247
248         return TRUE;
249 }
250
251 static void __create_serial_server()
252 {
253         int server_socket;
254         struct sockaddr_un server_addr;
255         mode_t sock_mode;
256
257         if ((server_socket = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
258                 ERR("sock create error\n");
259                 exit(1);
260         }
261
262         bzero(&server_addr, sizeof(server_addr));
263         server_addr.sun_family = AF_UNIX;
264         g_strlcpy(server_addr.sun_path, COM_SOCKET_PATH, sizeof(server_addr.sun_path));
265         unlink(COM_SOCKET_PATH);
266
267         /*---Assign a port number to the socket---*/
268         if (bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) != 0) {
269                 perror("bind error: ");
270                 exit(1);
271         }
272
273         sock_mode = (S_IRWXU | S_IRWXG | S_IRWXO);      // has 777 permission
274         if (chmod(COM_SOCKET_PATH, sock_mode) < 0) {
275                 perror("chmod error: ");
276                 close(server_socket);
277                 exit(1);
278         }
279
280         /*---Make it a "listening socket"---*/
281         if (listen(server_socket, 1) != 0) {
282                 perror("listen error: ");
283                 close(server_socket);
284                 exit(1);
285         }
286         serial_session.server_socket = server_socket;
287         serial_session.g_io = g_io_channel_unix_new(server_socket);
288         g_io_channel_set_close_on_unref(serial_session.g_io, TRUE);
289         serial_session.g_watch_id_server = g_io_add_watch(serial_session.g_io,
290                 G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
291                 __g_io_accept_handler, NULL);
292         g_io_channel_unref(serial_session.g_io);
293
294         return;
295 }
296
297
298 void _init_serial_server(void)
299 {
300         __create_serial_server();
301 }
302
303 gboolean _deinit_serial_server(void)
304 {
305         __close_client_socket();
306
307         return TRUE;
308 }
309
310 gboolean _is_exist_serial_session(void)
311 {
312         return (serial_session.state == SERIAL_SESSION_CONNECTED) ? TRUE: FALSE;
313 }
314
315 gboolean _wait_serial_session(void)
316 {
317         int cnt = 0;
318         while (_is_exist_serial_session() == FALSE) {
319                 usleep(SOCK_WAIT_TIME);
320                 if (cnt++ > SOCK_WAIT_CNT)
321                         return FALSE;
322         }
323
324         return TRUE;
325 }