2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 #include <arpa/inet.h>
25 #include <sys/types.h>
27 #ifndef HAVE_WIN32_IPC
33 #define TRACE_TAG TRACE_TRANSPORT
39 #include "commandline_sdbd.h"
41 #include "sdbd_plugin.h"
44 #ifdef HAVE_BIG_ENDIAN
45 #define H4(x) (((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24)
46 static inline void fix_endians(apacket *p)
48 p->msg.command = H4(p->msg.command);
49 p->msg.arg0 = H4(p->msg.arg0);
50 p->msg.arg1 = H4(p->msg.arg1);
51 p->msg.data_length = H4(p->msg.data_length);
52 p->msg.data_check = H4(p->msg.data_check);
53 p->msg.magic = H4(p->msg.magic);
56 #define fix_endians(p) do {} while (0)
60 /* we keep a list of opened transports. The atransport struct knows to which
61 * local transport it is connected. The list is used to detect when we're
62 * trying to connect twice to a given local transport.
64 #define SDB_LOCAL_TRANSPORT_MAX 16
66 SDB_MUTEX_DEFINE( local_transports_lock );
68 static atransport* local_transports[ SDB_LOCAL_TRANSPORT_MAX ];
71 SDB_MUTEX_DEFINE( register_noti_lock );
73 static pthread_cond_t noti_cond = PTHREAD_COND_INITIALIZER;
76 static int remote_read(apacket *p, atransport *t)
78 if(readx(t->sfd, &p->msg, sizeof(amessage))){
79 D("remote local: read terminated (message)\n");
85 #if 0 && defined HAVE_BIG_ENDIAN
86 D("read remote packet: %04x arg0=%0x arg1=%0x data_length=%0x data_check=%0x magic=%0x\n",
87 p->msg.command, p->msg.arg0, p->msg.arg1, p->msg.data_length, p->msg.data_check, p->msg.magic);
90 D("bad header: terminated (data)\n");
94 if(readx(t->sfd, p->data, p->msg.data_length)){
95 D("remote local: terminated (data)\n");
100 D("bad data: terminated (data)\n");
107 static int remote_write(apacket *p, atransport *t)
109 int length = p->msg.data_length;
113 #if 0 && defined HAVE_BIG_ENDIAN
114 D("write remote packet: %04x arg0=%0x arg1=%0x data_length=%0x data_check=%0x magic=%0x\n",
115 p->msg.command, p->msg.arg0, p->msg.arg1, p->msg.data_length, p->msg.data_check, p->msg.magic);
117 if(writex(t->sfd, &p->msg, sizeof(amessage) + length)) {
118 D("remote local: write terminated\n");
126 int local_connect(int port, const char *device_name) {
127 return local_connect_arbitrary_ports(port-1, port, device_name);
130 int local_connect_arbitrary_ports(int console_port, int sdb_port, const char *device_name)
136 const char *host = getenv("SDBHOST");
138 fd = socket_network_client(host, sdb_port, SOCK_STREAM);
142 fd = socket_loopback_client(sdb_port, SOCK_STREAM);
146 D("client: connected on remote on fd %d\n", fd);
147 if (close_on_exec(fd) < 0) {
148 D("failed to close fd exec\n");
150 disable_tcp_nagle(fd);
151 snprintf(buf, sizeof buf, "%s%d", LOCAL_CLIENT_PREFIX, console_port);
152 register_socket_transport(fd, buf, sdb_port, 1, device_name);
158 #if SDB_HOST /* tizen specific */
159 int get_devicename_from_shdmem(int port, char *device_name)
162 #ifndef HAVE_WIN32_IPC
164 void *shared_memory = (void *)0;
166 shm_id = shmget( (key_t)port-1, 0, 0);
170 shared_memory = shmat(shm_id, (void *)0, SHM_RDONLY);
172 if (shared_memory == (void *)-1)
174 D("faild to get shdmem key (%d) : %s\n", port, strerror(errno));
178 vms = strstr((char*)shared_memory, VMS_PATH);
180 s_strncpy(device_name, vms+strlen(VMS_PATH), DEVICENAME_MAX);
182 s_strncpy(device_name, DEFAULT_DEVICENAME, DEVICENAME_MAX);
189 sprintf(s_port, "%d", port-1);
190 hMapFile = OpenFileMapping(FILE_MAP_READ, TRUE, s_port);
192 if(hMapFile == NULL) {
193 D("faild to get shdmem key (%ld) : %s\n", port, GetLastError() );
196 pBuf = (char*)MapViewOfFile(hMapFile,
202 D("Could not map view of file (%ld)\n", GetLastError());
203 CloseHandle(hMapFile);
207 vms = strstr((char*)pBuf, VMS_PATH);
209 s_strncpy(device_name, vms+strlen(VMS_PATH), DEVICENAME_MAX);
211 s_strncpy(device_name, DEFAULT_DEVICENAME, DEVICENAME_MAX);
212 CloseHandle(hMapFile);
214 D("init device name %s on port %d\n", device_name, port);
219 int read_line(const int fd, char* ptr, size_t maxlen)
226 if((rc = sdb_read(fd, c, 1)) != 1)
227 return -1; // eof or read err
235 return -1; // no space
239 static void *client_socket_thread(void *x)
242 int port = DEFAULT_SDB_LOCAL_TRANSPORT_PORT;
243 int count = SDB_LOCAL_TRANSPORT_MAX;
245 D("transport: client_socket_thread() starting\n");
247 /* try to connect to any number of running emulator instances */
248 /* this is only done when SDB starts up. later, each new emulator */
249 /* will send a message to SDB to indicate that is is starting up */
250 for ( ; count > 0; count--, port += 10 ) { /* tizen specific */
251 (void) local_connect(port, NULL);
257 static void *server_socket_thread(void * arg)
260 struct sockaddr_in addr;
264 D("transport: server_socket_thread() starting\n");
268 // socket_inaddr_any_server returns -1 if there is any error
269 serverfd = socket_inaddr_any_server(port, SOCK_STREAM);
271 D("server: cannot bind socket yet\n");
275 if (close_on_exec(serverfd) < 0) {
276 D("failed to close serverfd exec\n");
281 D("server: trying to get new connection from %d\n", port);
284 // im ready to accept new client!
285 pthread_cond_broadcast(¬i_cond);
288 fd = sdb_socket_accept(serverfd, (struct sockaddr *)&addr, &alen);
290 D("server: new connection on fd %d\n", fd);
291 if (close_on_exec(fd) < 0) {
292 D("failed to close fd exec\n");
294 disable_tcp_nagle(fd);
296 // Check the peer ip validation.
298 && !request_validity_to_plugin(PLUGIN_SYNC_CMD_VERIFY_PEERIP, inet_ntoa(addr.sin_addr))) {
302 ret = keep_alive(fd, 1, SDB_KEEPALIVE_CNT, SDB_KEEPALIVE_IDLE, SDB_KEEPALIVE_INTVL);
304 D("failed to set keep alive option. FD(%d), errno=%d\n", fd, errno);
306 D("Success to set keep alive option. FD(%d), cnt=%d, idle=%d(sec), interval=%d(sec)\n",
307 fd, SDB_KEEPALIVE_CNT, SDB_KEEPALIVE_IDLE, SDB_KEEPALIVE_INTVL);
310 register_socket_transport(fd, "host", port, 1, NULL);
313 D("failed to accept() from sdb server\n");
314 //FIXME: implements error handle for EMFILE or ENFILE
317 D("transport: server_socket_thread() exiting\n");
321 /* This is relevant only for SDB daemon running inside the emulator. */
324 * Redefine open and write for qemu_pipe.h that contains inlined references
325 * to those routines. We will redifine them back after qemu_pipe.h inclusion.
329 #define open sdb_open
330 #define write sdb_write
331 #include "qemu_pipe.h"
334 #define open ___xxx_open
335 #define write ___xxx_write
337 /* A worker thread that monitors host connections, and registers a transport for
338 * every new host connection. This thread replaces server_socket_thread on
339 * condition that sdbd daemon runs inside the emulator, and emulator uses QEMUD
340 * pipe to communicate with sdbd daemon inside the guest. This is done in order
341 * to provide more robust communication channel between SDB host and guest. The
342 * main issue with server_socket_thread approach is that it runs on top of TCP,
343 * and thus is sensitive to network disruptions. For instance, the
344 * ConnectionManager may decide to reset all network connections, in which case
345 * the connection between SDB host and guest will be lost. To make SDB traffic
346 * independent from the network, we use here 'sdb' QEMUD service to transfer data
347 * between the host, and the guest. See external/qemu/android/sdb-*.* that
348 * implements the emulator's side of the protocol. Another advantage of using
349 * QEMUD approach is that SDB will be up much sooner, since it doesn't depend
350 * anymore on network being set up.
351 * The guest side of the protocol contains the following phases:
352 * - Connect with sdb QEMUD service. In this phase a handle to 'sdb' QEMUD service
353 * is opened, and it becomes clear whether or not emulator supports that
355 * - Wait for the SDB host to create connection with the guest. This is done by
356 * sending an 'accept' request to the sdb QEMUD service, and waiting on
358 * - When new SDB host connection is accepted, the connection with sdb QEMUD
359 * service is registered as the transport, and a 'start' request is sent to the
360 * sdb QEMUD service, indicating that the guest is ready to receive messages.
361 * Note that the guest will ignore messages sent down from the emulator before
362 * the transport registration is completed. That's why we need to send the
363 * 'start' request after the transport is registered.
366 static void *qemu_socket_thread(void * arg)
368 /* 'accept' request to the sdb QEMUD service. */
369 static const char _accept_req[] = "accept";
370 /* 'start' request to the sdb QEMUD service. */
371 static const char _start_req[] = "start";
372 /* 'ok' reply from the sdb QEMUD service. */
373 static const char _ok_resp[] = "ok";
375 const int port = (int)arg;
380 D("transport: qemu_socket_thread() starting\n");
382 /* sdb QEMUD service connection request. */
383 snprintf(con_name, sizeof(con_name), "qemud:sdb:%d", port);
385 /* Connect to the sdb QEMUD service. */
386 fd = qemu_pipe_open(con_name);
388 /* This could be an older version of the emulator, that doesn't
389 * implement sdb QEMUD service. Fall back to the old TCP way. */
391 D("sdb service is not available. Falling back to TCP socket.\n");
392 sdb_thread_create(&thr, server_socket_thread, arg);
398 * Wait till the host creates a new connection.
401 /* Send the 'accept' request. */
402 res = sdb_write(fd, _accept_req, strlen(_accept_req));
403 if (res == strlen(_accept_req)) {
404 /* Wait for the response. In the response we expect 'ok' on success,
405 * or 'ko' on failure. */
406 res = sdb_read(fd, tmp, sizeof(tmp));
407 if (res != 2 || memcmp(tmp, _ok_resp, 2)) {
408 D("Accepting SDB host connection has failed.\n");
411 /* Host is connected. Register the transport, and start the
413 register_socket_transport(fd, "host", port, 1, NULL);
414 sdb_write(fd, _start_req, strlen(_start_req));
417 /* Prepare for accepting of the next SDB host connection. */
418 fd = qemu_pipe_open(con_name);
420 D("sdb service become unavailable.\n");
424 D("Unable to send the '%s' request to SDB service.\n", _accept_req);
428 D("transport: qemu_socket_thread() exiting\n");
434 int connect_nonb(int sockfd, const struct sockaddr *saptr, socklen_t salen,
441 flags = fcntl(sockfd, F_GETFL, 0);
442 if(fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) == -1) {
443 D("failed to set file O_NONBLOCK status flag for socket %d: errno:%d\n",
448 if ((n = connect(sockfd, (struct sockaddr *) saptr, salen)) < 0)
449 if (errno != EINPROGRESS)
452 /* Do whatever we want while the connect is taking place. */
456 /* connect completed immediately */
459 FD_SET(sockfd, &rset);
463 if ((n = select(sockfd + 1, &rset, &wset, NULL, nsec ? &tval : NULL))
465 sdb_close(sockfd); /* timeout */
469 if (FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset)) {
471 if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
472 return (-1); /* Solaris pending error */
474 D("select error: sockfd not set\n");
477 if(fcntl(sockfd, F_SETFL, flags) == -1) { /* restore file status flags */
478 D("failed to restore file status flag for socket %d\n",
483 sdb_close(sockfd); /* just in case */
490 static int send_msg_to_localhost_from_guest(const char *host_ip, int local_port, char *request, int sock_type) {
492 struct sockaddr_in server;
493 int connect_timeout = 1;
494 memset( &server, 0, sizeof(server) );
495 server.sin_family = AF_INET;
496 server.sin_port = htons(local_port);
497 server.sin_addr.s_addr = inet_addr(host_ip);
499 D("try to send notification to host(%s:%d) using %s:[%s]\n", host_ip, local_port, (sock_type == 0) ? "tcp" : "udp", request);
501 if (sock_type == 0) {
502 s = socket(AF_INET, SOCK_STREAM, 0);
504 s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
507 D("could not create socket\n");
510 ret = connect_nonb(s, (struct sockaddr*) &server, sizeof(server), connect_timeout);
512 D("could not connect to server\n");
516 if (writex(s, request, strlen(request)) != 0) {
517 D("could not send notification request to host\n");
522 D("sent notification request to host\n");
527 // send the "emulator" request to sdbserver
528 static void* notify_sdbd_startup_thread(void* ptr) {
532 SdbdCommandlineArgs *sdbd_args = &sdbd_commandline_args; // alias
534 // send the request to sdbserver
535 char vm_name[256]={0,};
536 char host_ip[256] = {0,};
537 char guest_ip[256] = {0,};
538 int sensors_port = sdbd_args->sensors.port;
539 int emulator_port = sdbd_args->emulator.port;
541 int r = get_emulator_name(vm_name, sizeof vm_name);
543 //int try_limit_time = -1; // try_limit_time < 0 if unlimited
544 if (sensors_port < 0 || emulator_port < 0 || r < 0) {
547 if (get_emulator_hostip(host_ip, sizeof host_ip) == -1) {
548 D("failed to get emulator host ip\n");
551 // XXX: Known issue - log collision
553 // Trial limitation reached. terminate notify thread.
554 /*if (0 <= try_limit_time && try_limit_time <= time) {
557 // If there is any connected (via TCP/IP) SDB server, sleep 10 secs
558 if (get_connected_count(kTransportLocal) > 0) {
561 D("notify_sdbd_startup() success after %d trial(s)\n", time);
567 if (get_emulator_guestip(guest_ip, sizeof guest_ip) == -1) {
568 D("failed to get emulator guest ip\n");
569 goto sleep_and_continue;
572 // tell qemu sdbd is just started with udp
573 if (send_msg_to_localhost_from_guest(host_ip, sensors_port, "2\n", 1) < 0) {
574 D("could not send sensord noti request, try again %dth\n", time+1);
575 goto sleep_and_continue;
578 // tell sdb server emulator's vms name
579 // TODO: should we use host:emulator request? let's talk about this!
581 if (!strncmp(host_ip, QEMU_FORWARD_IP, sizeof host_ip)) {
582 snprintf(request, sizeof request, "host:emulator:%d:%s", (emulator_port + 1), vm_name);
584 snprintf(request, sizeof request, "host:connect:%s:%d", guest_ip, DEFAULT_SDB_LOCAL_TRANSPORT_PORT);
586 D("[%s:%d] request:%s \n", __FUNCTION__, __LINE__, request);
587 snprintf(buffer, sizeof buffer, "%04x%s", strlen(request), request );
589 if (send_msg_to_localhost_from_guest(host_ip, DEFAULT_SDB_PORT, buffer, 0) <0) {
590 D("could not send sdbd noti request. it might sdb server has not been started yet.\n");
591 goto sleep_and_continue;
593 //LOGI("sdbd noti request sent.\n");
601 void local_init(int port)
604 void* (*func)(void *);
607 func = client_socket_thread;
610 func = server_socket_thread;
612 /* For the sdbd daemon in the system image we need to distinguish
613 * between the device, and the emulator. */
614 #if 0 /* tizen specific */
615 char is_qemu[PROPERTY_VALUE_MAX];
616 property_get("ro.kernel.qemu", is_qemu, "");
617 if (!strcmp(is_qemu, "1")) {
618 /* Running inside the emulator: use QEMUD pipe as the transport. */
619 func = qemu_socket_thread;
623 /* Running inside the device: use TCP socket as the transport. */
624 func = server_socket_thread;
629 D("transport: local %s init\n", HOST ? "client" : "server");
631 if(sdb_thread_create(&thr, func, (void *)port)) {
632 fatal_errno("cannot create local socket %s thread",
633 HOST ? "client" : "server");
637 * wait until server socket thread made!
638 * get noti from server_socket_thread
641 sdb_mutex_lock(®ister_noti_lock);
642 pthread_cond_wait(¬i_cond, ®ister_noti_lock);
645 if(sdb_thread_create(&thr, notify_sdbd_startup_thread, NULL)) {
646 fatal("cannot create notify_sdbd_startup_thread");
647 //notify_sdbd_startup(); // defensive code
649 sdb_mutex_unlock(®ister_noti_lock);
653 static void remote_kick(atransport *t)
663 sdb_mutex_lock( &local_transports_lock );
664 for (nn = 0; nn < SDB_LOCAL_TRANSPORT_MAX; nn++) {
665 if (local_transports[nn] == t) {
666 local_transports[nn] = NULL;
670 sdb_mutex_unlock( &local_transports_lock );
675 static void remote_close(atransport *t)
682 /* Only call this function if you already hold local_transports_lock. */
683 atransport* find_emulator_transport_by_sdb_port_locked(int sdb_port)
686 for (i = 0; i < SDB_LOCAL_TRANSPORT_MAX; i++) {
687 if (local_transports[i] && local_transports[i]->sdb_port == sdb_port) {
688 return local_transports[i];
694 atransport* find_emulator_transport_by_sdb_port(int sdb_port)
696 sdb_mutex_lock( &local_transports_lock );
697 atransport* result = find_emulator_transport_by_sdb_port_locked(sdb_port);
698 sdb_mutex_unlock( &local_transports_lock );
702 /* Only call this function if you already hold local_transports_lock. */
703 int get_available_local_transport_index_locked()
706 for (i = 0; i < SDB_LOCAL_TRANSPORT_MAX; i++) {
707 if (local_transports[i] == NULL) {
714 int get_available_local_transport_index()
716 sdb_mutex_lock( &local_transports_lock );
717 int result = get_available_local_transport_index_locked();
718 sdb_mutex_unlock( &local_transports_lock );
723 int init_socket_transport(atransport *t, int s, int sdb_port, int local)
727 t->kick = remote_kick;
728 t->close = remote_close;
729 t->read_from_remote = remote_read;
730 t->write_to_remote = remote_write;
733 t->connection_state = CS_OFFLINE;
734 t->type = kTransportLocal;
739 sdb_mutex_lock( &local_transports_lock );
741 t->sdb_port = sdb_port;
742 atransport* existing_transport =
743 find_emulator_transport_by_sdb_port_locked(sdb_port);
744 int index = get_available_local_transport_index_locked();
745 if (existing_transport != NULL) {
746 D("local transport for port %d already registered (%p)?\n",
747 sdb_port, existing_transport);
749 } else if (index < 0) {
750 // Too many emulators.
751 D("cannot register more emulators. Maximum is %d\n",
752 SDB_LOCAL_TRANSPORT_MAX);
755 local_transports[index] = t;
758 sdb_mutex_unlock( &local_transports_lock );