فهرست منبع

ncd: modules: sys_request_server: add support for listening on TCP

ambrop7 14 سال پیش
والد
کامیت
87084f233d
1فایلهای تغییر یافته به همراه105 افزوده شده و 18 حذف شده
  1. 105 18
      ncd/modules/sys_request_server.c

+ 105 - 18
ncd/modules/sys_request_server.c

@@ -31,7 +31,7 @@
  * A simple a IPC interface for NCD to talk to other processes over a Unix socket.
  * 
  * Synopsis:
- *   sys.request_server(string socket_path, string request_handler_template, list args)
+ *   sys.request_server(listen_address, string request_handler_template, list args)
  * 
  * Description:
  *   Initializes a request server on the given socket path. Requests are served by
@@ -45,6 +45,13 @@
  *   finish() will immediately initiate termination of the handler process.
  *   Requests can be sent to NCD using the badvpn-ncd-request program.
  * 
+ *   The listen_address argument must be one of:
+ *   - {"unix", socket_path}
+ *     Listens on a Unix socket.
+ *   - {"tcp", ip_address, port_number}
+ *     Listens on a TCP socket. The address must be numeric and not a name.
+ *     For IPv6, the address must be enclosed in [].
+ * 
  * Synopsis:
  *   sys.request_server.request::reply(reply_data)
  * 
@@ -62,10 +69,12 @@
 #include <misc/offset.h>
 #include <misc/debug.h>
 #include <misc/byteorder.h>
+#include <misc/parse_number.h>
 #include <protocol/packetproto.h>
 #include <protocol/requestproto.h>
 #include <structure/LinkedList0.h>
 #include <system/BConnection.h>
+#include <system/BAddr.h>
 #include <flow/PacketProtoDecoder.h>
 #include <flow/PacketStreamSender.h>
 #include <flow/PacketPassFifoQueue.h>
@@ -85,7 +94,7 @@
 
 struct instance {
     NCDModuleInst *i;
-    char *socket_path;
+    char *unix_socket_path;
     char *request_handler_template;
     NCDValue *args;
     BListener listener;
@@ -148,6 +157,7 @@ static struct reply * reply_init (struct connection *c, uint32_t request_id, NCD
 static void reply_start (struct reply *r, uint32_t type);
 static void reply_free (struct reply *r);
 static void reply_send_qflow_if_handler_done (struct reply *r);
+static int init_listen (struct instance *o, NCDValue *listen_addr_arg);
 static void instance_free (struct instance *o);
 
 static void listener_handler (struct instance *o)
@@ -589,6 +599,90 @@ static void reply_send_qflow_if_handler_done (struct reply *r)
     reply_free(r);
 }
 
+static int init_listen (struct instance *o, NCDValue *listen_addr_arg)
+{
+    if (NCDValue_Type(listen_addr_arg) != NCDVALUE_LIST) {
+        goto bad;
+    }
+    
+    if (NCDValue_ListCount(listen_addr_arg) < 1) {
+        goto bad;
+    }
+    NCDValue *type_arg = NCDValue_ListFirst(listen_addr_arg);
+    
+    if (NCDValue_Type(type_arg) != NCDVALUE_STRING) {
+        goto bad;
+    }
+    const char *type = NCDValue_StringValue(type_arg);
+    
+    o->unix_socket_path = NULL;
+    
+    if (!strcmp(type, "unix")) {
+        NCDValue *socket_path_arg;
+        if (!NCDValue_ListRead(listen_addr_arg, 2, &type_arg, &socket_path_arg)) {
+            goto bad;
+        }
+        
+        if (NCDValue_Type(socket_path_arg) != NCDVALUE_STRING) {
+            goto bad;
+        }
+        
+        // remember socket path
+        o->unix_socket_path = NCDValue_StringValue(socket_path_arg);
+        
+        // make sure socket file doesn't exist
+        if (unlink(o->unix_socket_path) < 0 && errno != ENOENT) {
+            ModuleLog(o->i, BLOG_ERROR, "unlink failed");
+            return 0;
+        }
+        
+        // init listener
+        if (!BListener_InitUnix(&o->listener, o->unix_socket_path, o->i->params->reactor, o, (BListener_handler)listener_handler)) {
+            ModuleLog(o->i, BLOG_ERROR, "BListener_InitUnix failed");
+            return 0;
+        }
+    }
+    else if (!strcmp(type, "tcp")) {
+        NCDValue *ip_address_arg;
+        NCDValue *port_number_arg;
+        if (!NCDValue_ListRead(listen_addr_arg, 3, &type_arg, &ip_address_arg, &port_number_arg)) {
+            goto bad;
+        }
+        
+        if (NCDValue_Type(ip_address_arg) != NCDVALUE_STRING || NCDValue_Type(port_number_arg) != NCDVALUE_STRING) {
+            goto bad;
+        }
+        
+        BIPAddr ipaddr;
+        if (!BIPAddr_Resolve(&ipaddr, NCDValue_StringValue(ip_address_arg), 1)) {
+            goto bad;
+        }
+        
+        uintmax_t port;
+        if (!parse_unsigned_integer(NCDValue_StringValue(port_number_arg), &port) || port > UINT16_MAX) {
+            goto bad;
+        }
+        
+        BAddr addr;
+        BAddr_InitFromIpaddrAndPort(&addr, ipaddr, hton16(port));
+        
+        // init listener
+        if (!BListener_Init(&o->listener, addr, o->i->params->reactor, o, (BListener_handler)listener_handler)) {
+            ModuleLog(o->i, BLOG_ERROR, "BListener_InitUnix failed");
+            return 0;
+        }
+    }
+    else {
+        goto bad;
+    }
+    
+    return 1;
+    
+bad:
+    ModuleLog(o->i, BLOG_ERROR, "bad listen address argument");
+    return 0;
+}
+
 static void func_new (NCDModuleInst *i)
 {
     // allocate structure
@@ -601,31 +695,22 @@ static void func_new (NCDModuleInst *i)
     NCDModuleInst_Backend_SetUser(i, o);
     
     // check arguments
-    NCDValue *socket_path_arg;
+    NCDValue *listen_addr_arg;
     NCDValue *request_handler_template_arg;
     NCDValue *args_arg;
-    if (!NCDValue_ListRead(i->args, 3, &socket_path_arg, &request_handler_template_arg, &args_arg)) {
+    if (!NCDValue_ListRead(i->args, 3, &listen_addr_arg, &request_handler_template_arg, &args_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (NCDValue_Type(socket_path_arg) != NCDVALUE_STRING || NCDValue_Type(request_handler_template_arg) != NCDVALUE_STRING ||
-        NCDValue_Type(args_arg) != NCDVALUE_LIST) {
+    if (NCDValue_Type(request_handler_template_arg) != NCDVALUE_STRING || NCDValue_Type(args_arg) != NCDVALUE_LIST) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
-    o->socket_path = NCDValue_StringValue(socket_path_arg);
     o->request_handler_template = NCDValue_StringValue(request_handler_template_arg);
     o->args = args_arg;
     
-    // make sure socket file doesn't exist
-    if (unlink(o->socket_path) < 0 && errno != ENOENT) {
-        ModuleLog(o->i, BLOG_ERROR, "unlink failed");
-        goto fail1;
-    }
-    
     // init listener
-    if (!BListener_InitUnix(&o->listener, o->socket_path, i->params->reactor, o, (BListener_handler)listener_handler)) {
-        ModuleLog(o->i, BLOG_ERROR, "BListener_InitUnix failed");
+    if (!init_listen(o, listen_addr_arg)) {
         goto fail1;
     }
     
@@ -667,9 +752,11 @@ static void func_die (void *vo)
     // free listener
     BListener_Free(&o->listener);
     
-    // remove socket file
-    if (unlink(o->socket_path)) {
-        ModuleLog(o->i, BLOG_ERROR, "unlink failed");
+    if (o->unix_socket_path) {
+        // remove socket file
+        if (unlink(o->unix_socket_path)) {
+            ModuleLog(o->i, BLOG_ERROR, "unlink failed");
+        }
     }
     
     // terminate connections