Synchronize shell window size with remote shell.
authorKim Gunsoo <gunsoo83.kim@samsung.com>
Thu, 23 Jul 2015 09:07:39 +0000 (18:07 +0900)
committerKim Gunsoo <gunsoo83.kim@samsung.com>
Mon, 3 Aug 2015 10:29:30 +0000 (19:29 +0900)
Change-Id: I661cd1500ead0daacaaacb2bb4e3007f2b5665d8
Signed-off-by: Kim Gunsoo <gunsoo83.kim@samsung.com>
src/command_function.c
src/command_function.h
src/commandline.c
src/sockets.c
src/utils.c
src/utils.h
src/utils_backend.h
src/utils_unix.c
src/utils_windows.c

index aef04cc2520ea709e7715782a8639e46759acf8b..0e19b6d5a22ffab175565e26e75736342fa316b8 100644 (file)
@@ -726,7 +726,6 @@ int uninstall(int argc, char **argv) {
     return 0;
 }
 
-#define CAPBUF_SIZE 4096
 int get_capability(int argc, char ** argv) {
     char full_cmd[16] = {0,};
     char cap_buffer[CAPBUF_SIZE] = {0,};
index 866ecaf663b00bf51228b4c04de3bb6c9fcba374..60ea086a97870731cec75e234df80c14f083ff32 100644 (file)
@@ -34,6 +34,8 @@
 #define PATH_MAX 4096
 #endif
 
+#define CAPBUF_SIZE 4096
+
 int da(int argc, char ** argv);
 int oprofile(int argc, char ** argv);
 int profile(int argc, char ** argv);
index 93ed88da4268151d35e7cfe9f7d039e0caf4f816..50ef64439f0d49695450f3957c3cb332fd1addf7 100755 (executable)
@@ -52,6 +52,10 @@ static void create_opt_list(LIST_NODE** opt_list);
 static void create_cmd_list(LIST_NODE** cmd_list);
 static int do_cmd(transport_type ttype, char* serial, char *cmd, ...);
 
+static int ishell_fd = -1;
+static int enable_sync_winsz = 0;
+static void sync_winsz(void);
+
 #ifdef HAVE_TERMIO_H
 
 static __inline__ void stdin_raw_init(int fd, struct termios* tio_save);
@@ -98,7 +102,7 @@ static __inline__ void stdin_raw_init(void** args) {
         return;
     }
 
-    if(!SetConsoleMode(input_t_handle, 0)) {
+    if(!SetConsoleMode(input_t_handle, ENABLE_MOUSE_INPUT)) {
         fprintf(stdout, "error: fail to set console mode\n");
         return;
     }
@@ -251,6 +255,12 @@ static void *stdin_read_thread(void *x)
                     }
                     buf = NULL;
                 }
+            } else if(i_record.EventType == MOUSE_EVENT) {
+                if (i_record.Event.MouseEvent.dwEventFlags == 0) {
+                    if (enable_sync_winsz == 1) {
+                        sync_winsz();
+                    }
+                }
             }
         }
     }
@@ -288,6 +298,17 @@ static int get_screensize(int* lines, int* columns)
 
     return 0;
 }
+
+static void sig_winch_handler(int sig) {
+    if (sig != SIGWINCH) {
+        return;
+    }
+
+    if (enable_sync_winsz == 1) {
+        sync_winsz();
+    }
+}
+
 #else // for Windows
 static int get_screensize(int* lines, int* columns)
 {
@@ -310,6 +331,110 @@ static int get_screensize(int* lines, int* columns)
 }
 #endif
 
+static void sync_winsz() {
+    int lines, columns;
+    int fd = -1;
+    int remote_id = -1;
+    char full_cmd[64] = {0,};
+    char *ret_str;
+    struct sockaddr_in addr;
+    int sockaddr_len = sizeof(addr);
+
+    if (get_screensize(&lines, &columns) == 0) {
+        memset(&addr, 0, sizeof(addr));
+        if (sdb_getsockname(ishell_fd, (struct sockaddr *)&addr, &sockaddr_len) < 0) {
+            D("failed to get sock name. errno=%d, %s\n", errno, strerror(errno));
+            return;
+        }
+
+        snprintf(full_cmd, sizeof(full_cmd), "host:get-remote-id:%d:%d",
+                            addr.sin_port, addr.sin_addr.s_addr);
+        ret_str = sdb_query(full_cmd);
+        if(ret_str == NULL) {
+            D("failed to sdb query.\n");
+            return;
+        }
+
+        if (sscanf(ret_str, "remote-id:%d", &remote_id) != 1 || remote_id == -1) {
+            D("failed to get remote-id\n");
+            return;
+        }
+
+        memset(full_cmd, 0, sizeof(full_cmd));
+        snprintf(full_cmd, sizeof(full_cmd), "shellconf:syncwinsz:%d:%d:%d", remote_id, lines, columns);
+        fd = sdb_connect(full_cmd);
+        if(fd < 0) {
+            enable_sync_winsz = 0;
+            D("failed to syncwinsz.\n");
+            return;
+        }
+
+        sdb_close(fd);
+    }
+}
+
+static int match_capability_key_value(char* cap, char* key, char* value) {
+    char *p_str = NULL;
+    int offset = 0;
+    char *k = NULL;
+    char *v = NULL;
+    int matched = -1;
+
+    if (cap == NULL || key == NULL || value == NULL) {
+        return -1;
+    }
+
+    while ((p_str = strchr(cap+offset, ':')) != NULL) {
+        p_str[0] = 0;
+        k = cap+offset;
+        offset += strlen(cap+offset)+1;
+
+        p_str = strchr(cap+offset, '\n');
+        if (p_str != NULL) {
+            p_str[0] = 0;
+            v = cap+offset;
+            offset += strlen(cap+offset)+1;
+        }
+
+        if (k == NULL || v == NULL) {
+            k = NULL;
+            v = NULL;
+            continue;
+        }
+
+        if (!strcmp(k, key) && !strcmp(v, value)) {
+            matched = 1;
+            break;
+        }
+
+        k = NULL;
+        v = NULL;
+    }
+
+    return matched;
+}
+
+static int check_syncwinsz_support() {
+    char full_cmd[16] = {0,};
+    char cap_buffer[CAPBUF_SIZE] = {0,};
+    uint16_t len = 0;
+    int supported = -1;
+
+    snprintf(full_cmd, sizeof(full_cmd), "capability:");
+    int fd = sdb_connect(full_cmd);
+    if (fd >= 0) {
+        readx(fd, &len, sizeof(uint16_t));
+        if (len > CAPBUF_SIZE-1) {
+            len = CAPBUF_SIZE-1;
+        }
+        readx(fd, cap_buffer, len);
+        sdb_close(fd);
+
+        supported = match_capability_key_value(cap_buffer, "syncwinsz_support", "enabled");
+    }
+    return supported;
+}
+
 int interactive_shell()
 {
     sdb_thread_t thr;
@@ -317,7 +442,7 @@ int interactive_shell()
     int lines, columns;
     int fd = -1;
 
-    if (get_screensize(&lines, &columns) == 0) {
+    if(get_screensize(&lines, &columns) == 0) {
         snprintf(eshell+7, sizeof(eshell)-7, "%d:%d", lines, columns);
         D("interactive shell : eshell command=%s\n", eshell);
         fd = sdb_connect(eshell);
@@ -335,6 +460,11 @@ int interactive_shell()
 
     int* fd_p = malloc(sizeof(int));
     *fd_p = fd;
+    ishell_fd = fd;
+    if(check_syncwinsz_support() == 1) {
+        D("Support sync window size with remote\n");
+        enable_sync_winsz = 1;
+    }
 
 #ifdef HAVE_TERMIO_H
     void** args = (void**)malloc(sizeof(void*)*2);
@@ -343,6 +473,15 @@ int interactive_shell()
     struct termios* tio_save_p = (struct termios*)malloc(sizeof(struct termios));
     memcpy(tio_save_p, &tio_save, sizeof(struct termios));
     args[1] = tio_save_p;
+
+    // register SIGWINCH signal handler.
+    struct sigaction sa_winch;
+    sigemptyset(&sa_winch.sa_mask);
+    sa_winch.sa_flags = 0;
+    sa_winch.sa_handler = sig_winch_handler;
+    if (sigaction(SIGWINCH, &sa_winch, NULL) < -1) {
+        D("failed to register the SIGWINCH signal handler.\n");
+    }
 #else
     void** args = (void**)malloc(sizeof(void*)*3);
     stdin_raw_init(args);
index 361a28621f545760240bbd924f548783ad1a4870..b42d4eb8dc878183014069f5896d77981d367cea 100755 (executable)
@@ -862,6 +862,33 @@ static void unregister_all_tcp_transports()
     sdb_mutex_unlock(&transport_lock, "transport unregister_all_tcp_transports");
 }
 
+static int find_remote_id(int port, int ip)
+{
+    int remote_id = -1;
+    struct sockaddr_in peer_addr;
+    int sockaddr_len = sizeof(peer_addr);
+
+    LIST_NODE* curptr = local_socket_list;
+    while(curptr != NULL) {
+        SDB_SOCKET* s = curptr->data;
+        curptr = curptr->next_ptr;
+
+        memset(&peer_addr, 0, sizeof(peer_addr));
+        if (sdb_getpeername(s->fd, (struct sockaddr *)&peer_addr, &sockaddr_len) < 0) {
+            LOG_ERROR("Failed to get peer name. errno=%d, %s\n", errno, strerror(errno));
+            return -1;
+        }
+
+        if (port == peer_addr.sin_port && ip == peer_addr.sin_addr.s_addr) {
+            LOG_DEBUG("get-remote-id : remote_id=%d\n", s->remote_id);
+            remote_id = s->remote_id;
+            break;
+        }
+    }
+
+    return remote_id;
+}
+
 static int handle_host_request(char *service, SDB_SOCKET* socket)
 {
     LOG_INFO("LS(%X)\n", socket->fd);
@@ -907,6 +934,23 @@ static int handle_host_request(char *service, SDB_SOCKET* socket)
         return 0;
     }
 
+    // return a remote id
+    if (!strncmp(service, "get-remote-id:", 14)) {
+        int remote_id = -1;
+        int port = -1;
+        int ip = -1;
+
+        if (sscanf(service+14, "%d:%d", &port, &ip) == 2) {
+            remote_id = find_remote_id(port, ip);
+        } else {
+            LOG_ERROR("Invalid argument\n");
+        }
+
+        snprintf(cmd_buf, cbuf_size, "remote-id:%d", remote_id);
+        sendokmsg(socket->fd, cmd_buf);
+        return 0;
+    }
+
     // add a new TCP transport, device or emulator
     if (!strncmp(service, "connect:", 8)) {
         char* host = service + 8;
index cddd915d1035fbfc5d67cae8b3e82cdcf6eaf75a..bf26b09590f94e03a5459f9bee7b45c56257f635 100755 (executable)
@@ -295,6 +295,14 @@ void disable_tcp_nagle(int fd) {
     return utils_backend->disable_tcp_nagle(fd);
 }
 
+int sdb_getsockname(int fd, struct sockaddr *addr, int *sockaddr_len) {
+    return utils_backend->sdb_getsockname(fd, addr, sockaddr_len);
+}
+
+int sdb_getpeername(int fd, struct sockaddr *addr, int *sockaddr_len) {
+    return utils_backend->sdb_getpeername(fd, addr, sockaddr_len);
+}
+
 int sdb_thread_create(sdb_thread_t *pthread, sdb_thread_func_t start, void* arg) {
     return utils_backend->sdb_thread_create(pthread, start, arg);
 }
index 2889f57334b042b26a01f19226e8bcd97a6cde3b..73b72c77643a14f1a94db4512d25c7f19b6a9c8a 100755 (executable)
@@ -128,6 +128,8 @@ char* sdb_dirstart(const char* path);
 char* sdb_dirstop(const char* path);
 int sdb_socket_setbufsize(int fd, int bufsize);
 void disable_tcp_nagle(int fd);
+int sdb_getsockname(int fd, struct sockaddr *addr, int *sockaddr_len);
+int sdb_getpeername(int fd, struct sockaddr *addr, int *sockaddr_len);
 
 // sockets
 #define LISTEN_BACKLOG 4
index c0f9ef916fa42a874da184abc8fb2b829283eaf5..b7c8b172f1a47ff5d0e63fa19895e39b4c4d55c3 100755 (executable)
@@ -75,6 +75,8 @@ struct utils_os_backend {
     char* (*sdb_dirstop)(const char* path);
     int (*sdb_socket_setbufsize)(int fd, int bufsize);
     void (*disable_tcp_nagle)(int fd);
+    int (*sdb_getsockname)(int fd, struct sockaddr *addr, int *sockaddr_len);
+    int (*sdb_getpeername)(int fd, struct sockaddr *addr, int *sockaddr_len);
     // simple implementation of pthread
     int (*sdb_thread_create)(sdb_thread_t *pthread, sdb_thread_func_t start, void* arg);
     int (*sdb_mutex_lock)(sdb_mutex_t *mutex);
index f05441d4426bae214dc2b8ee6f4c396ee4f079de..96dda832252d01055883548dfe0494b230a0a76e 100755 (executable)
@@ -259,6 +259,14 @@ static void _disable_tcp_nagle(int fd)
         LOG_ERROR("failed to set the file descriptor '%d': %s\n", fd, strerror(errno));
 }
 
+int _sdb_getsockname(int fd, struct sockaddr *addr, int *sockaddr_len) {
+    return getsockname(fd, addr, sockaddr_len);
+}
+
+int _sdb_getpeername(int fd, struct sockaddr *addr, int *sockaddr_len) {
+    return getpeername(fd, addr, sockaddr_len);
+}
+
 static int  _sdb_thread_create( sdb_thread_t  *pthread, sdb_thread_func_t  start, void*  arg )
 {
     pthread_attr_t   attr;
@@ -439,6 +447,8 @@ const struct utils_os_backend utils_unix_backend = {
     .sdb_dirstop = _sdb_dirstop,
     .sdb_socket_setbufsize = _sdb_socket_setbufsize,
     .disable_tcp_nagle = _disable_tcp_nagle,
+    .sdb_getsockname = _sdb_getsockname,
+    .sdb_getpeername = _sdb_getpeername,
     // simple pthread implementations
     .sdb_thread_create = _sdb_thread_create,
     .sdb_mutex_lock = _sdb_mutex_lock,
index 4af013a0b3c256c391ee481fd530f7e0004bfcd5..ef18f775d0443f5fa004b0d5b2b4c6b87bb31263 100755 (executable)
@@ -537,6 +537,18 @@ static int _sdb_socket_setbufsize(int fd, int bufsize) {
     return setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char*) &opt, sizeof(opt));
 }
 
+int _sdb_getsockname(int fd, struct sockaddr *addr, int *sockaddr_len) {
+    SDB_HANDLE* sdb_handle = sdb_handle_map_get(fd);
+    SOCKET s = sdb_handle->u.socket;
+    return getsockname(s, (SOCKADDR *)addr, sockaddr_len);
+}
+
+int _sdb_getpeername(int fd, struct sockaddr *addr, int *sockaddr_len) {
+    SDB_HANDLE* sdb_handle = sdb_handle_map_get(fd);
+    SOCKET s = sdb_handle->u.socket;
+    return getpeername(s, (SOCKADDR *)addr, sockaddr_len);
+}
+
 static char* _sdb_dirstart(const char* path) {
     char* p = strchr(path, '/');
     char* p2 = strchr(path, '\\');
@@ -1006,6 +1018,8 @@ const struct utils_os_backend utils_windows_backend = {
     .sdb_dirstop = _sdb_dirstop,
     .sdb_socket_setbufsize = _sdb_socket_setbufsize,
     .disable_tcp_nagle = _disable_tcp_nagle,
+    .sdb_getsockname = _sdb_getsockname,
+    .sdb_getpeername = _sdb_getpeername,
 // simple pthread implementations
     .sdb_thread_create = _sdb_thread_create,
     .sdb_mutex_lock = _pthread_mutex_lock,