net: arrange base port management 80/152080/3
authorMunkyu Im <munkyu.im@samsung.com>
Sun, 17 Sep 2017 05:42:24 +0000 (14:42 +0900)
committerMunkyu Im <munkyu.im@samsung.com>
Mon, 25 Sep 2017 08:27:30 +0000 (17:27 +0900)
This commit apply the port management of latest version.
fix error that multiple emulators connect to the same port.
qemu_socket() turns on SOCK_CLOEXEC option.
Remove unused functions.

Change-Id: Id0a9c92a24f9e364bf56ca784a5d9fd847ec5f11
Signed-off-by: Munkyu Im <munkyu.im@samsung.com>
(cherry picked from commit 4a241901bc06ff35c2a60225f03856fd30398f1f)

tizen/src/ecs/ecs.c
tizen/src/emulator.c
tizen/src/util/sdb.c
tizen/src/util/sdb.h

index 85cf5b4..d7fa5ea 100644 (file)
@@ -548,40 +548,6 @@ static void alive_checker(void *opaque) {
 
 }
 
-static int socket_initialize(ECS_State *cs, QemuOpts *opts) {
-    int fd = -1;
-    Error *local_err = NULL;
-
-    fd = inet_listen_opts(opts, 0, &local_err);
-    if (0 > fd || error_is_set(&local_err)) {
-        qerror_report_err(local_err);
-        error_free(local_err);
-        return -1;
-    }
-
-    INFO("Listen fd is %d\n", fd);
-
-    qemu_set_nonblock(fd);
-
-    cs->listen_fd = fd;
-
-#ifdef CONFIG_LINUX
-    epoll_init(cs);
-#else
-    FD_ZERO(&cs->reads);
-    FD_SET(fd, &cs->reads);
-#endif
-
-    make_keep_alive_msg();
-
-    cs->alive_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, alive_checker, cs);
-
-    timer_mod(cs->alive_timer,
-            qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + get_ticks_per_sec() * TIMER_ALIVE_S);
-
-    return 0;
-}
-
 #ifdef CONFIG_LINUX
 static int ecs_loop(ECS_State *cs) {
     int i, nfds;
@@ -668,14 +634,35 @@ static int ecs_loop(ECS_State *cs)
 
 #endif
 
+static int socket_initialize(ECS_State *cs) {
+    LOG_INFO("Listen fd is %d\n", emul_vm_base_socket);
+    g_assert(emul_vm_base_socket >= 0);
+
+    cs->listen_fd = emul_vm_base_socket;
+
+#ifdef CONFIG_LINUX
+    epoll_init(cs);
+#else
+    FD_ZERO(&cs->reads);
+    FD_SET(cs->listen_fd, &cs->reads);
+#endif
+
+    make_keep_alive_msg();
+
+    cs->alive_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, alive_checker, cs);
+
+    timer_mod(cs->alive_timer,
+            qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + get_ticks_per_sec() * TIMER_ALIVE_S);
+
+    return 0;
+}
+
 static void* ecs_initialize(void* args) {
     int ret = 1;
     ECS_State *cs = NULL;
     QemuOpts *opts = NULL;
     Error *local_err = NULL;
     Monitor* mon = NULL;
-    char host_port[16];
-    int port = 0;
 
     INFO("ecs starts initializing.\n");
 
@@ -693,12 +680,10 @@ static void* ecs_initialize(void* args) {
         ERR("ECS_State allocation failed.\n");
         return NULL;
     }
-    port = get_emul_ecs_port();
-    INFO("ecs port: %d\n", port);
-    sprintf(host_port, "%d", port);
 
-    qemu_opt_set(opts, "port", host_port);
-    ret = socket_initialize(cs, opts);
+    cs->listen_fd = -1;
+    ret = socket_initialize(cs);
+
     if (ret < 0) {
         ERR("Socket initialization is failed.\n");
         ecs_close(cs);
index 93dda3d..bd5cb3e 100644 (file)
@@ -188,13 +188,10 @@ static void prepare_basic_features(gchar * const kernel_cmdline)
         socks_proxy[PROXY_BUFFER_LEN] = { 0, },
         dns[PROXY_BUFFER_LEN] = { 0, };
 
-    set_base_port();
-
 #if defined(CONFIG_SPICE) && defined(CONFIG_LINUX)
     clean_websocket_port(SIGKILL);
 #endif
 
-
     get_host_proxy(http_proxy, https_proxy, ftp_proxy, socks_proxy);
     /* using "DNS" provided by default QEMU */
     g_strlcpy(dns, DEFAULT_QEMU_DNS_IP, strlen(DEFAULT_QEMU_DNS_IP) + 1);
@@ -272,6 +269,8 @@ const char *prepare_maru(const gchar * const kernel_cmdline)
 
     /* Prepare basic features */
     LOG_INFO("Prepare_basic_features\n");
+    init_sdb_and_vm_base_port();
+
     prepare_basic_features(maru_kernel_cmdline);
 
     /* Prepare GL acceleration */
@@ -290,8 +289,6 @@ void prepare_maru_after_device_init(void)
     maru_device_hotplug_init();
     qemu_add_opts(&qemu_ecs_opts);
     start_ecs();
-    start_sdb_noti_server(get_device_serial_number() + SDB_UDP_SENSOR_INDEX);
-    sdb_setup();
 }
 
 #if defined(CONFIG_SDL) || defined(CONFIG_USE_SHM)
index c76d4fd..a4ce07c 100644 (file)
 
 MULTI_DEBUG_CHANNEL(qemu, sdb);
 
-#ifdef _WIN32
-#include "qemu/main-loop.h"
-
-static void socket_close_handler( void*  _fd )
-{
-    int   fd = (int)_fd;
-    int   ret;
-    char  buff[64];
-
-    /* we want to drain the read side of the socket before closing it */
-    do {
-        ret = recv( fd, buff, sizeof(buff), 0 );
-    } while (ret < 0 && WSAGetLastError() == WSAEINTR);
-
-    if (ret < 0 && WSAGetLastError() == EWOULDBLOCK)
-        return;
-
-    qemu_set_fd_handler( fd, NULL, NULL, NULL );
-    closesocket( fd );
-}
-
-void socket_close( int  fd )
-{
-    int  old_errno = errno;
-
-    shutdown( fd, SD_BOTH );
-    /* we want to drain the socket before closing it */
-    qemu_set_fd_handler( fd, socket_close_handler, NULL, (void*)fd );
-
-    errno = old_errno;
-}
-
-#else /* !_WIN32 */
-
-#include <unistd.h>
+#define BUF_SIZE 64
 
-void socket_close( int  fd )
-{
-    int  old_errno = errno;
-
-    shutdown( fd, SHUT_RDWR );
-    close( fd );
-
-    errno = old_errno;
-}
-
-#endif /* !_WIN32 */
-
-int inet_strtoip(const char*  str, uint32_t  *ip)
-{
-    int  comp[4];
-
-    if (sscanf(str, "%d.%d.%d.%d", &comp[0], &comp[1], &comp[2], &comp[3]) != 4)
-        return -1;
-
-    if ((unsigned)comp[0] >= 256 ||
-            (unsigned)comp[1] >= 256 ||
-            (unsigned)comp[2] >= 256 ||
-            (unsigned)comp[3] >= 256)
-        return -1;
-
-    *ip = (uint32_t)((comp[0] << 24) | (comp[1] << 16) |
-            (comp[2] << 8)  |  comp[3]);
-    return 0;
-}
+int emul_vm_base_socket;
 
 int check_port_bind_listen(uint32_t port)
 {
     struct sockaddr_in addr;
-    int s = 0;
     int ret = -1;
-    socklen_t addrlen = sizeof(addr);
-    memset(&addr, 0, addrlen);
-
     addr.sin_family = AF_INET;
-    addr.sin_addr.s_addr = htonl(INADDR_ANY);
     addr.sin_port = htons(port);
+    addr.sin_addr.s_addr = INADDR_ANY;
 
-    s = qemu_socket(AF_INET, SOCK_STREAM, 0);
-    if (s < 0) {
-        INFO("failed to create a socket\n");
+    ret = qemu_socket(PF_INET, SOCK_STREAM, 0);
+    if (ret < 0) {
+        LOG_SEVERE("socket creation failed.\n");
         return -1;
     }
 
-#ifndef _WIN32
-    int opt = 1;
-    ret = setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
-                    (char *)&opt, sizeof(int));
-    if (ret < 0) {
-        INFO("setsockopt failure\n");
-        close(s);
+    qemu_set_nonblock(ret);
+
+    if (socket_set_fast_reuse(ret) != 0) {
+        LOG_SEVERE("It cannot be reach here.\n");
+        closesocket(ret);
         return -1;
     }
-#endif
 
-    if ((bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) ||
-        (listen(s, 1) < 0)) {
-        /* failure */
-        ret = -1;
-        INFO("port(%d) listen failure\n", port);
-    } else {
-        /* success */
-        ret = 1;
-        INFO("port(%d) listen success\n", port);
+    if (bind(ret, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
+        LOG_INFO("bind failed for port: %d, errno: %d\n", port, errno);
+        closesocket(ret);
+        return -1;
     }
 
-#ifdef _WIN32
-    closesocket(s);
-#else
-    close(s);
-#endif
+    if (listen(ret, 1) != 0) {
+        LOG_SEVERE("listen failed :%s-%d\n", strerror(errno), errno);
+        closesocket(ret);
+        return -1;
+    }
 
     return ret;
 }
 
-#define ECS_INDEX 3
-#define SDB_GUEST_PORT 26101
-void set_base_port(void)
+static int prepare_network_port(uint32_t base_port)
 {
-    int   tries     = 10;
-    int   success   = 0;
-    uint32_t port = 26100;
-    int base_port;
-
-    base_port = get_emul_vm_base_port();
-
-    if (base_port == 0) {
-
-        for ( ; tries > 0; tries--, port += 10 ) {
-            if (check_port_bind_listen(port + ECS_INDEX) < 0)
-                continue;
+    int ret = -1;
+       char buf[64] = {0,};
+    if ((ret = check_port_bind_listen(base_port + ECS_TCP_INDEX)) < 0) {
+        LOG_INFO("TCP port %"PRIu32" is aleady occupied.\n",
+                base_port + ECS_TCP_INDEX);
 
-            success = 1;
-            break;
-        }
+        return -1;
+    }
 
-        if (!success) {
-            INFO( "it seems too many emulator instances are running on this machine. Aborting\n" );
-            exit(1);
-        }
+    g_assert(ret >= 0);
 
-        base_port = port;
-        INFO( "emulator base port is %d\n", base_port);
+    sprintf(buf, "tcp:%d::26101", base_port + SDB_TCP_INDEX);
+    if (net_slirp_redir((char*)buf) < 0) {
+        LOG_WARNING("failed to redirect rule %s", buf);
+        return -1;
     }
+    // save ecs socket fd as global variable
+    // FIXME: should not use global variable.
+    emul_vm_base_socket = ret;
 
-    set_emul_vm_base_port(base_port);
+    return ret;
 }
 
-void sdb_setup(void)
-{
-    int   tries     = 10;
-    int   success   = 0;
-    char buf[64] = {0,};
-    int number;
+static void start_sdb_noti_server(int server_port);
 
-    number = get_device_serial_number();
+void init_sdb_and_vm_base_port(void)
+{
+    uint32_t port = -1;
 
-    for ( ; tries > 0; tries--, number += 10 ) {
-        sprintf(buf, "tcp:%d::%d", number, SDB_GUEST_PORT);
-        if (net_slirp_redir((char*)buf) < 0)
+    for (port = START_VM_BASE_PORT ; port < END_VM_BASE_PORT; port += 10) {
+        if (prepare_network_port(port) < 0) {
             continue;
+        }
 
-        INFO( "SDBD established on port %d\n", number);
-        success = 1;
         break;
     }
 
-    INFO("redirect [%s] success\n", buf);
-    if (!success) {
-        INFO( "it seems too many emulator instances are running on this machine. Aborting\n" );
+    if (port >= END_VM_BASE_PORT) {
+        error_report("It seems too many emulator instances are "
+                "running on this machine. Aborting.");
         exit(1);
     }
+    LOG_INFO("Emulator base port is %"PRIu32".\n", port);
+
+    start_sdb_noti_server(port + SDB_UDP_NOTI_PORT_INDEX);
+    start_sdb_noti_server(port + SDB_UDP_SENSOR_INDEX);
 
-    INFO( "Port(%d/tcp) listen for SDB\n", number);
+    set_emul_vm_base_port(port);
 }
 
 /*
@@ -267,10 +184,10 @@ static void send_to_sdb_client(SDB_Client* client, int state)
     struct sockaddr_in sock_addr;
     int s, slen = sizeof(sock_addr);
     int serial_len = 0;
-    char buf[64];
+    char buf[BUF_SIZE];
 
-    if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1){
-          INFO("socket creation error! %d\n", errno);
+    if ((s = qemu_socket(AF_INET, SOCK_STREAM, 0)) == -1){
+          LOG_INFO("socket creation error! %d\n", errno);
           return;
     }
 
@@ -281,9 +198,9 @@ static void send_to_sdb_client(SDB_Client* client, int state)
     sock_addr.sin_addr = (client->addr).sin_addr;
 
     if (connect(s, (struct sockaddr*)&sock_addr, slen) == -1) {
-        INFO("connect error! remove this client.\n");
+        LOG_INFO("connect error! remove this client.\n");
         remove_sdb_client(client);
-        close(s);
+        closesocket(s);
         return;
     }
 
@@ -294,15 +211,15 @@ static void send_to_sdb_client(SDB_Client* client, int state)
     // send message "[4 digit message length]host:sync:emulator-26101:[0|1]"
     sprintf(buf, "%04xhost:sync:%s:%01d", (serial_len + 12), client->serial, state);
 
-    INFO("send %s to client %s\n", buf, inet_ntoa(client->addr.sin_addr));
+    LOG_INFO("send %s to client %s\n", buf, inet_ntoa(client->addr.sin_addr));
 
     if (send(s, buf, sizeof(buf), 0) == -1)
     {
-        INFO("send error! remove this client.\n");
+        LOG_INFO("send error! remove this client.\n");
         remove_sdb_client(client);
     }
 
-    close(s);
+    closesocket(s);
 }
 
 void notify_all_sdb_clients(int state)
index 7be0ee3..bfa9bbf 100644 (file)
 
 #define SDB_HOST_PORT 26099
 
-#define SDB_TCP_EMULD_INDEX  2    /* emulator daemon port */
-#define SDB_TCP_OPENGL_INDEX  3   /* opengl server port */
-#define SDB_UDP_SENSOR_INDEX  2   /* sensor server port */
+#define START_VM_BASE_PORT 26100
+#define END_VM_BASE_PORT 26200
 
-void sdb_setup(void);
-void set_base_port(void);
-int inet_strtoip(const char*  str, uint32_t  *ip);
+#define SDB_TCP_INDEX 1
+#define GDB_TCP_INDEX 2
+#define ECS_TCP_INDEX 3
+#define SPICE_TCP_INDEX 3
+#define SDB_UDP_SENSOR_INDEX 2
+#define SDB_UDP_NOTI_PORT_INDEX 3
+
+#define SDB_GUEST_PORT  (START_VM_BASE_PORT + SDB_TCP_INDEX)
+#define GDB_GUEST_PORT  (START_VM_BASE_PORT + GDB_TCP_INDEX)
+
+void init_sdb_and_vm_base_port(void);
 int socket_send(int fd, const void*  buf, int  buflen);
 void socket_close(int fd);
 int check_port_bind_listen(uint32_t port);
-
-void start_sdb_noti_server(int server_port);
+extern int emul_vm_base_socket;
 
 #define STATE_RUNNING 0
 #define STATE_SUSPEND 1