From 666eedb9e858b6eb507a283012fc3bb215953f0e Mon Sep 17 00:00:00 2001
From: "Jay Freeman (saurik)" <saurik@saurik.com>
Date: Tue, 10 Sep 2013 12:28:55 -0700
Subject: [PATCH] Allow for connections from the client to the server.

---
 Console.cpp | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 Handler.mm  | 52 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 108 insertions(+)

diff --git a/Console.cpp b/Console.cpp
index 3dede2f..fe03c31 100644
--- a/Console.cpp
+++ b/Console.cpp
@@ -47,9 +47,11 @@
 #include <errno.h>
 #include <unistd.h>
 
+#include <sys/socket.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
+#include <netdb.h>
 
 #include <sys/types.h>
 #include <sys/socket.h>
@@ -616,6 +618,9 @@ int Main(int argc, char const * const argv[], char const * const envp[]) {
     pid_t pid(_not(pid_t));
 #endif
 
+    const char *host(NULL);
+    const char *port(NULL);
+
     apr_getopt_t *state;
     _aprcall(apr_getopt_init(&state, pool, argc, argv));
 
@@ -628,6 +633,7 @@ int Main(int argc, char const * const argv[], char const * const envp[]) {
 #ifdef CY_ATTACH
             "p:"
 #endif
+            "r:"
             "s"
         , &opt, &arg));
 
@@ -641,6 +647,7 @@ int Main(int argc, char const * const argv[], char const * const envp[]) {
 #ifdef CY_ATTACH
                     " [-p <pid|name>]"
 #endif
+                    " [-r <host:port>]"
                     " [<script> [<arg>...]]\n"
                 );
                 return 1;
@@ -728,6 +735,27 @@ int Main(int argc, char const * const argv[], char const * const envp[]) {
             } break;
 #endif
 
+            case 'r': {
+                //size_t size(strlen(arg));
+
+                char *colon(strrchr(arg, ':'));
+                if (colon == NULL) {
+                    fprintf(stderr, "missing colon in hostspec\n");
+                    return 1;
+                }
+
+                /*char *end;
+                port = strtoul(colon + 1, &end, 10);
+                if (end != arg + size) {
+                    fprintf(stderr, "invalid port in hostspec\n");
+                    return 1;
+                }*/
+
+                host = arg;
+                *colon = '\0';
+                port = colon + 1;
+            } break;
+
             case 's':
                 strict_ = true;
             break;
@@ -800,6 +828,34 @@ int Main(int argc, char const * const argv[], char const * const envp[]) {
     client_ = -1;
 #endif
 
+    if (client_ == -1 && host != NULL && port != NULL) {
+        struct addrinfo hints;
+        memset(&hints, 0, sizeof(hints));
+        hints.ai_family = AF_UNSPEC;
+        hints.ai_socktype = SOCK_STREAM;
+        hints.ai_protocol = 0;
+        hints.ai_flags = 0;
+
+        struct addrinfo *infos;
+        _syscall(getaddrinfo(host, port, &hints, &infos));
+
+        _assert(infos != NULL); try {
+            for (struct addrinfo *info(infos); info != NULL; info = info->ai_next) {
+                int client(_syscall(socket(info->ai_family, info->ai_socktype, info->ai_protocol))); try {
+                    _syscall(connect(client, info->ai_addr, info->ai_addrlen));
+                    client_ = client;
+                    break;
+                } catch (...) {
+                    _syscall(close(client));
+                    throw;
+                }
+            }
+        } catch (...) {
+            freeaddrinfo(infos);
+            throw;
+        }
+    }
+
     if (script == NULL && tty)
         Console(options);
     else {
diff --git a/Handler.mm b/Handler.mm
index d15eb6a..e7b2c3b 100644
--- a/Handler.mm
+++ b/Handler.mm
@@ -172,3 +172,55 @@ extern "C" void CYHandleServer(pid_t pid) {
         fprintf(stderr, "%s\n", error.PoolCString(pool));
     }
 }
+
+struct CYServer {
+    pthread_t thread_;
+    uint16_t port_;
+    int socket_;
+
+    CYServer(uint16_t port) :
+        port_(port),
+        socket_(-1)
+    {
+    }
+
+    ~CYServer() {
+        if (socket_ != -1)
+            _syscall(close(socket_));
+    }
+
+    void Listen() {
+        socket_ = _syscall(::socket(PF_INET, SOCK_STREAM, 0)); try {
+            sockaddr_in address;
+            address.sin_family = AF_INET;
+            address.sin_addr.s_addr = INADDR_ANY;
+            address.sin_port = htons(port_);
+            _syscall(::bind(socket_, reinterpret_cast<sockaddr *>(&address), sizeof(address)));
+
+            _syscall(::listen(socket_, -1));
+
+            for (;;) {
+                socklen_t length(sizeof(address));
+                int socket(_syscall(::accept(socket_, reinterpret_cast<sockaddr *>(&address), &length)));
+                CYHandleClient(socket);
+            }
+        } catch (const CYException &error) {
+            CYPool pool;
+            fprintf(stderr, "%s\n", error.PoolCString(pool));
+        }
+    }
+};
+
+static void *OnServer(void *data) {
+    CYServer *server(reinterpret_cast<CYServer *>(data));
+    server->Listen();
+    delete server;
+    return NULL;
+}
+
+extern "C" void CYListenServer(short port) {
+    CYInitializeDynamic();
+
+    CYServer *server(new CYServer(port));
+    _assert(pthread_create(&server->thread_, NULL, &OnServer, server) == 0);
+}
-- 
2.47.2