removing chsmack
[platform/core/system/sdbd.git] / src / transport_local.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 <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <errno.h>
21
22 #include "sysdeps.h"
23 #include <sys/types.h>
24
25 #ifndef HAVE_WIN32_IPC
26 #include <sys/ipc.h>
27 #include <sys/shm.h>
28 #include <unistd.h>
29 #endif
30
31 #define  TRACE_TAG  TRACE_TRANSPORT
32 #include "sdb.h"
33
34 #ifdef HAVE_BIG_ENDIAN
35 #define H4(x)   (((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24)
36 static inline void fix_endians(apacket *p)
37 {
38     p->msg.command     = H4(p->msg.command);
39     p->msg.arg0        = H4(p->msg.arg0);
40     p->msg.arg1        = H4(p->msg.arg1);
41     p->msg.data_length = H4(p->msg.data_length);
42     p->msg.data_check  = H4(p->msg.data_check);
43     p->msg.magic       = H4(p->msg.magic);
44 }
45 #else
46 #define fix_endians(p) do {} while (0)
47 #endif
48
49 #if SDB_HOST
50 /* we keep a list of opened transports. The atransport struct knows to which
51  * local transport it is connected. The list is used to detect when we're
52  * trying to connect twice to a given local transport.
53  */
54 #define  SDB_LOCAL_TRANSPORT_MAX  16
55
56 SDB_MUTEX_DEFINE( local_transports_lock );
57
58 static atransport*  local_transports[ SDB_LOCAL_TRANSPORT_MAX ];
59 #endif /* SDB_HOST */
60
61 static int remote_read(apacket *p, atransport *t)
62 {
63     if(readx(t->sfd, &p->msg, sizeof(amessage))){
64         D("remote local: read terminated (message)\n");
65         return -1;
66     }
67
68     fix_endians(p);
69
70 #if 0 && defined HAVE_BIG_ENDIAN
71     D("read remote packet: %04x arg0=%0x arg1=%0x data_length=%0x data_check=%0x magic=%0x\n",
72       p->msg.command, p->msg.arg0, p->msg.arg1, p->msg.data_length, p->msg.data_check, p->msg.magic);
73 #endif
74     if(check_header(p)) {
75         D("bad header: terminated (data)\n");
76         return -1;
77     }
78
79     if(readx(t->sfd, p->data, p->msg.data_length)){
80         D("remote local: terminated (data)\n");
81         return -1;
82     }
83
84     if(check_data(p)) {
85         D("bad data: terminated (data)\n");
86         return -1;
87     }
88
89     return 0;
90 }
91
92 static int remote_write(apacket *p, atransport *t)
93 {
94     int   length = p->msg.data_length;
95
96     fix_endians(p);
97
98 #if 0 && defined HAVE_BIG_ENDIAN
99     D("write remote packet: %04x arg0=%0x arg1=%0x data_length=%0x data_check=%0x magic=%0x\n",
100       p->msg.command, p->msg.arg0, p->msg.arg1, p->msg.data_length, p->msg.data_check, p->msg.magic);
101 #endif
102     if(writex(t->sfd, &p->msg, sizeof(amessage) + length)) {
103         D("remote local: write terminated\n");
104         return -1;
105     }
106
107     return 0;
108 }
109
110
111 int local_connect(int port, const char *device_name) {
112     return local_connect_arbitrary_ports(port-1, port, device_name);
113 }
114
115 int local_connect_arbitrary_ports(int console_port, int sdb_port, const char *device_name)
116 {
117     char buf[64];
118     int  fd = -1;
119
120 #if SDB_HOST
121     const char *host = getenv("SDBHOST");
122     if (host) {
123         fd = socket_network_client(host, sdb_port, SOCK_STREAM);
124     }
125 #endif
126     if (fd < 0) {
127         fd = socket_loopback_client(sdb_port, SOCK_STREAM);
128     }
129
130     if (fd >= 0) {
131         D("client: connected on remote on fd %d\n", fd);
132         if (close_on_exec(fd) < 0) {
133             D("failed to close fd exec\n");
134         }
135         disable_tcp_nagle(fd);
136         snprintf(buf, sizeof buf, "%s%d", LOCAL_CLIENT_PREFIX, console_port);
137         register_socket_transport(fd, buf, sdb_port, 1, device_name);
138         return 0;
139     }
140     return -1;
141 }
142
143 #if SDB_HOST /* tizen specific */
144 int get_devicename_from_shdmem(int port, char *device_name)
145 {
146     char *vms = NULL;
147 #ifndef HAVE_WIN32_IPC
148     int shm_id;
149     void *shared_memory = (void *)0;
150
151     shm_id = shmget( (key_t)port-1, 0, 0);
152     if (shm_id == -1)
153         return -1;
154
155     shared_memory = shmat(shm_id, (void *)0, SHM_RDONLY);
156
157     if (shared_memory == (void *)-1)
158     {
159         D("faild to get shdmem key (%d) : %s\n", port, strerror(errno));
160         return -1;
161     }
162
163     vms = strstr((char*)shared_memory, VMS_PATH);
164     if (vms != NULL)
165         strncpy(device_name, vms+strlen(VMS_PATH), DEVICENAME_MAX);
166     else
167         strncpy(device_name, DEFAULT_DEVICENAME, DEVICENAME_MAX);
168
169 #else /* _WIN32*/
170     HANDLE hMapFile;
171     char s_port[5];
172     char* pBuf;
173
174     sprintf(s_port, "%d", port-1);
175     hMapFile = OpenFileMapping(FILE_MAP_READ, TRUE, s_port);
176
177     if(hMapFile == NULL) {
178         D("faild to get shdmem key (%ld) : %s\n", port, GetLastError() );
179         return -1;
180     }
181     pBuf = (char*)MapViewOfFile(hMapFile,
182                             FILE_MAP_READ,
183                             0,
184                             0,
185                             50);
186     if (pBuf == NULL) {
187         D("Could not map view of file (%ld)\n", GetLastError());
188         CloseHandle(hMapFile);
189         return -1;
190     }
191
192     vms = strstr((char*)pBuf, VMS_PATH);
193     if (vms != NULL)
194         strncpy(device_name, vms+strlen(VMS_PATH), DEVICENAME_MAX);
195     else
196         strncpy(device_name, DEFAULT_DEVICENAME, DEVICENAME_MAX);
197     CloseHandle(hMapFile);
198 #endif
199     D("init device name %s on port %d\n", device_name, port);
200
201     return 0;
202 }
203
204 int read_line(const int fd, char* ptr, size_t maxlen)
205 {
206     unsigned int n = 0;
207     char c[2];
208     int rc;
209
210     while(n != maxlen) {
211         if((rc = sdb_read(fd, c, 1)) != 1)
212             return -1; // eof or read err
213
214         if(*c == '\n') {
215             ptr[n] = 0;
216             return n;
217         }
218         ptr[n++] = *c;
219     }
220     return -1; // no space
221 }
222 #endif
223
224 static void *client_socket_thread(void *x)
225 {
226 #if SDB_HOST
227     int  port  = DEFAULT_SDB_LOCAL_TRANSPORT_PORT;
228     int  count = SDB_LOCAL_TRANSPORT_MAX;
229
230     D("transport: client_socket_thread() starting\n");
231
232     /* try to connect to any number of running emulator instances     */
233     /* this is only done when SDB starts up. later, each new emulator */
234     /* will send a message to SDB to indicate that is is starting up  */
235     for ( ; count > 0; count--, port += 10 ) { /* tizen specific */
236         (void) local_connect(port, NULL);
237     }
238 #endif
239     return 0;
240 }
241
242 static void *server_socket_thread(void * arg)
243 {
244     int serverfd, fd;
245     struct sockaddr addr;
246     socklen_t alen;
247     int port = (int)arg;
248
249     D("transport: server_socket_thread() starting\n");
250     serverfd = -1;
251     for(;;) {
252         if(serverfd == -1) {
253             serverfd = socket_inaddr_any_server(port, SOCK_STREAM);
254             if(serverfd < 0) {
255                 D("server: cannot bind socket yet\n");
256                 sdb_sleep_ms(1000);
257                 continue;
258             }
259             if (close_on_exec(serverfd) < 0) {
260                 D("failed to close serverfd exec\n");
261             }
262         }
263
264         alen = sizeof(addr);
265         D("server: trying to get new connection from %d\n", port);
266         fd = sdb_socket_accept(serverfd, &addr, &alen);
267         if(fd >= 0) {
268             D("server: new connection on fd %d\n", fd);
269             if (close_on_exec(fd) < 0) {
270                 D("failed to close fd exec\n");
271             }
272             disable_tcp_nagle(fd);
273             register_socket_transport(fd, "host", port, 1, NULL);
274         }
275     }
276     D("transport: server_socket_thread() exiting\n");
277     return 0;
278 }
279
280 /* This is relevant only for SDB daemon running inside the emulator. */
281 #if !SDB_HOST
282 /*
283  * Redefine open and write for qemu_pipe.h that contains inlined references
284  * to those routines. We will redifine them back after qemu_pipe.h inclusion.
285  */
286 #undef open
287 #undef write
288 #define open    sdb_open
289 #define write   sdb_write
290 #include "qemu_pipe.h"
291 #undef open
292 #undef write
293 #define open    ___xxx_open
294 #define write   ___xxx_write
295
296 /* A worker thread that monitors host connections, and registers a transport for
297  * every new host connection. This thread replaces server_socket_thread on
298  * condition that sdbd daemon runs inside the emulator, and emulator uses QEMUD
299  * pipe to communicate with sdbd daemon inside the guest. This is done in order
300  * to provide more robust communication channel between SDB host and guest. The
301  * main issue with server_socket_thread approach is that it runs on top of TCP,
302  * and thus is sensitive to network disruptions. For instance, the
303  * ConnectionManager may decide to reset all network connections, in which case
304  * the connection between SDB host and guest will be lost. To make SDB traffic
305  * independent from the network, we use here 'sdb' QEMUD service to transfer data
306  * between the host, and the guest. See external/qemu/android/sdb-*.* that
307  * implements the emulator's side of the protocol. Another advantage of using
308  * QEMUD approach is that SDB will be up much sooner, since it doesn't depend
309  * anymore on network being set up.
310  * The guest side of the protocol contains the following phases:
311  * - Connect with sdb QEMUD service. In this phase a handle to 'sdb' QEMUD service
312  *   is opened, and it becomes clear whether or not emulator supports that
313  *   protocol.
314  * - Wait for the SDB host to create connection with the guest. This is done by
315  *   sending an 'accept' request to the sdb QEMUD service, and waiting on
316  *   response.
317  * - When new SDB host connection is accepted, the connection with sdb QEMUD
318  *   service is registered as the transport, and a 'start' request is sent to the
319  *   sdb QEMUD service, indicating that the guest is ready to receive messages.
320  *   Note that the guest will ignore messages sent down from the emulator before
321  *   the transport registration is completed. That's why we need to send the
322  *   'start' request after the transport is registered.
323  */
324 #if 0
325 static void *qemu_socket_thread(void * arg)
326 {
327 /* 'accept' request to the sdb QEMUD service. */
328 static const char _accept_req[] = "accept";
329 /* 'start' request to the sdb QEMUD service. */
330 static const char _start_req[]  = "start";
331 /* 'ok' reply from the sdb QEMUD service. */
332 static const char _ok_resp[]    = "ok";
333
334     const int port = (int)arg;
335     int res, fd;
336     char tmp[256];
337     char con_name[32];
338
339     D("transport: qemu_socket_thread() starting\n");
340
341     /* sdb QEMUD service connection request. */
342     snprintf(con_name, sizeof(con_name), "qemud:sdb:%d", port);
343
344     /* Connect to the sdb QEMUD service. */
345     fd = qemu_pipe_open(con_name);
346     if (fd < 0) {
347         /* This could be an older version of the emulator, that doesn't
348          * implement sdb QEMUD service. Fall back to the old TCP way. */
349         sdb_thread_t thr;
350         D("sdb service is not available. Falling back to TCP socket.\n");
351         sdb_thread_create(&thr, server_socket_thread, arg);
352         return 0;
353     }
354
355     for(;;) {
356         /*
357          * Wait till the host creates a new connection.
358          */
359
360         /* Send the 'accept' request. */
361         res = sdb_write(fd, _accept_req, strlen(_accept_req));
362         if (res == strlen(_accept_req)) {
363             /* Wait for the response. In the response we expect 'ok' on success,
364              * or 'ko' on failure. */
365             res = sdb_read(fd, tmp, sizeof(tmp));
366             if (res != 2 || memcmp(tmp, _ok_resp, 2)) {
367                 D("Accepting SDB host connection has failed.\n");
368                 sdb_close(fd);
369             } else {
370                 /* Host is connected. Register the transport, and start the
371                  * exchange. */
372                 register_socket_transport(fd, "host", port, 1, NULL);
373                 sdb_write(fd, _start_req, strlen(_start_req));
374             }
375
376             /* Prepare for accepting of the next SDB host connection. */
377             fd = qemu_pipe_open(con_name);
378             if (fd < 0) {
379                 D("sdb service become unavailable.\n");
380                 return 0;
381             }
382         } else {
383             D("Unable to send the '%s' request to SDB service.\n", _accept_req);
384             return 0;
385         }
386     }
387     D("transport: qemu_socket_thread() exiting\n");
388     return 0;
389 }
390 #endif  // !SDB_HOST
391 #endif
392
393 void local_init(int port)
394 {
395     sdb_thread_t thr;
396     void* (*func)(void *);
397
398     if(HOST) {
399         func = client_socket_thread;
400     } else {
401 #if SDB_HOST
402         func = server_socket_thread;
403 #else
404         /* For the sdbd daemon in the system image we need to distinguish
405          * between the device, and the emulator. */
406 #if 0 /* tizen specific */
407         char is_qemu[PROPERTY_VALUE_MAX];
408         property_get("ro.kernel.qemu", is_qemu, "");
409         if (!strcmp(is_qemu, "1")) {
410             /* Running inside the emulator: use QEMUD pipe as the transport. */
411             func = qemu_socket_thread;
412         } else
413 #endif
414         {
415             /* Running inside the device: use TCP socket as the transport. */
416             func = server_socket_thread;
417         }
418 #endif // !SDB_HOST
419     }
420
421     D("transport: local %s init\n", HOST ? "client" : "server");
422
423     if(sdb_thread_create(&thr, func, (void *)port)) {
424         fatal_errno("cannot create local socket %s thread",
425                     HOST ? "client" : "server");
426     }
427 }
428
429 static void remote_kick(atransport *t)
430 {
431     int fd = t->sfd;
432     t->sfd = -1;
433     sdb_shutdown(fd);
434     sdb_close(fd);
435
436 #if SDB_HOST
437     if(HOST) {
438         int  nn;
439         sdb_mutex_lock( &local_transports_lock );
440         for (nn = 0; nn < SDB_LOCAL_TRANSPORT_MAX; nn++) {
441             if (local_transports[nn] == t) {
442                 local_transports[nn] = NULL;
443                 break;
444             }
445         }
446         sdb_mutex_unlock( &local_transports_lock );
447     }
448 #endif
449 }
450
451 static void remote_close(atransport *t)
452 {
453     sdb_close(t->fd);
454 }
455
456
457 #if SDB_HOST
458 /* Only call this function if you already hold local_transports_lock. */
459 atransport* find_emulator_transport_by_sdb_port_locked(int sdb_port)
460 {
461     int i;
462     for (i = 0; i < SDB_LOCAL_TRANSPORT_MAX; i++) {
463         if (local_transports[i] && local_transports[i]->sdb_port == sdb_port) {
464             return local_transports[i];
465         }
466     }
467     return NULL;
468 }
469
470 atransport* find_emulator_transport_by_sdb_port(int sdb_port)
471 {
472     sdb_mutex_lock( &local_transports_lock );
473     atransport* result = find_emulator_transport_by_sdb_port_locked(sdb_port);
474     sdb_mutex_unlock( &local_transports_lock );
475     return result;
476 }
477
478 /* Only call this function if you already hold local_transports_lock. */
479 int get_available_local_transport_index_locked()
480 {
481     int i;
482     for (i = 0; i < SDB_LOCAL_TRANSPORT_MAX; i++) {
483         if (local_transports[i] == NULL) {
484             return i;
485         }
486     }
487     return -1;
488 }
489
490 int get_available_local_transport_index()
491 {
492     sdb_mutex_lock( &local_transports_lock );
493     int result = get_available_local_transport_index_locked();
494     sdb_mutex_unlock( &local_transports_lock );
495     return result;
496 }
497 #endif
498
499 int init_socket_transport(atransport *t, int s, int sdb_port, int local)
500 {
501     int  fail = 0;
502
503     t->kick = remote_kick;
504     t->close = remote_close;
505     t->read_from_remote = remote_read;
506     t->write_to_remote = remote_write;
507     t->sfd = s;
508     t->sync_token = 1;
509     t->connection_state = CS_OFFLINE;
510     t->type = kTransportLocal;
511     t->sdb_port = 0;
512
513 #if SDB_HOST
514     if (HOST && local) {
515         sdb_mutex_lock( &local_transports_lock );
516         {
517             t->sdb_port = sdb_port;
518             atransport* existing_transport =
519                     find_emulator_transport_by_sdb_port_locked(sdb_port);
520             int index = get_available_local_transport_index_locked();
521             if (existing_transport != NULL) {
522                 D("local transport for port %d already registered (%p)?\n",
523                 sdb_port, existing_transport);
524                 fail = -1;
525             } else if (index < 0) {
526                 // Too many emulators.
527                 D("cannot register more emulators. Maximum is %d\n",
528                         SDB_LOCAL_TRANSPORT_MAX);
529                 fail = -1;
530             } else {
531                 local_transports[index] = t;
532             }
533        }
534        sdb_mutex_unlock( &local_transports_lock );
535     }
536 #endif
537     return fail;
538 }