Просмотр исходного кода

ncd: modules: sys_request_client: add support to connecting to TCP servers

ambrop7 14 лет назад
Родитель
Сommit
33891a6f63
1 измененных файлов с 86 добавлено и 8 удалено
  1. 86 8
      ncd/modules/sys_request_client.c

+ 86 - 8
ncd/modules/sys_request_client.c

@@ -29,13 +29,20 @@
  * @section DESCRIPTION
  * 
  * Synopsis:
- *   sys.request_client(string socket_path)
+ *   sys.request_client(string connect_addr)
  * 
  * Description:
- *   Connects to a request server (sys.request_server()) over a Unix socket.
+ *   Connects to a request server (sys.request_server()).
  *   Goes up when the connection, and dies with error when it is broken.
  *   When requested to die, dies immediately, breaking the connection.
  * 
+ *   The connect_addr argument must be one of:
+ *   - {"unix", socket_path}
+ *     Connects to a Unix socket.
+ *   - {"tcp", ip_address, port_number}
+ *     Connects to a TCP server. The address must be numeric and not a name.
+ *     For IPv6, the address must be enclosed in [].
+ * 
  * Synopsis:
  *   sys.request_client::request(request_data, string reply_handler, string finished_handler, list args)
  * 
@@ -75,10 +82,14 @@
 
 #include <stdlib.h>
 #include <string.h>
+#include <inttypes.h>
+#include <limits.h>
 
 #include <misc/offset.h>
+#include <misc/parse_number.h>
 #include <structure/LinkedList0.h>
 #include <structure/LinkedList1.h>
+#include <system/BAddr.h>
 #include <ncd/NCDModule.h>
 #include <ncd/NCDRequestClient.h>
 
@@ -146,6 +157,7 @@ static void request_die (struct request_instance *o, int is_error);
 static void request_free_reply (struct request_instance *o, struct reply *r, int have_value);
 static int request_init_reply_process (struct request_instance *o, NCDValue reply_data);
 static int request_init_finished_process (struct request_instance *o);
+static int get_connect_addr (struct instance *o, NCDValue *connect_addr_arg, struct NCDRequestClient_addr *out_addr);
 static void instance_free (struct instance *o, int with_error);
 static void request_instance_free (struct request_instance *o, int with_error);
 
@@ -464,6 +476,71 @@ fail0:
     return 0;
 }
 
+static int get_connect_addr (struct instance *o, NCDValue *connect_addr_arg, struct NCDRequestClient_addr *out_addr)
+{
+    if (NCDValue_Type(connect_addr_arg) != NCDVALUE_LIST) {
+        goto bad;
+    }
+    
+    if (NCDValue_ListCount(connect_addr_arg) < 1) {
+        goto bad;
+    }
+    NCDValue *type_arg = NCDValue_ListFirst(connect_addr_arg);
+    
+    if (NCDValue_Type(type_arg) != NCDVALUE_STRING) {
+        goto bad;
+    }
+    const char *type = NCDValue_StringValue(type_arg);
+    
+    if (!strcmp(type, "unix")) {
+        NCDValue *socket_path_arg;
+        if (!NCDValue_ListRead(connect_addr_arg, 2, &type_arg, &socket_path_arg)) {
+            goto bad;
+        }
+        
+        if (NCDValue_Type(socket_path_arg) != NCDVALUE_STRING) {
+            goto bad;
+        }
+        
+        *out_addr = NCDREQUESTCLIENT_UNIX_ADDR(NCDValue_StringValue(socket_path_arg));
+    }
+    else if (!strcmp(type, "tcp")) {
+        NCDValue *ip_address_arg;
+        NCDValue *port_number_arg;
+        if (!NCDValue_ListRead(connect_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));
+        
+        *out_addr = NCDREQUESTCLIENT_TCP_ADDR(addr);
+    }
+    else {
+        goto bad;
+    }
+    
+    return 1;
+    
+bad:
+    ModuleLog(o->i, BLOG_ERROR, "bad connect address argument");
+    return 0;
+}
+
 static void func_new (NCDModuleInst *i)
 {
     // allocate structure
@@ -476,19 +553,20 @@ static void func_new (NCDModuleInst *i)
     NCDModuleInst_Backend_SetUser(i, o);
     
     // check arguments
-    NCDValue *socket_path_arg;
-    if (!NCDValue_ListRead(i->args, 1, &socket_path_arg)) {
+    NCDValue *connect_addr_arg;
+    if (!NCDValue_ListRead(i->args, 1, &connect_addr_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (NCDValue_Type(socket_path_arg) != NCDVALUE_STRING) {
-        ModuleLog(o->i, BLOG_ERROR, "wrong type");
+    
+    // get address
+    struct NCDRequestClient_addr addr;
+    if (!get_connect_addr(o, connect_addr_arg, &addr)) {
         goto fail1;
     }
-    char *socket_path = NCDValue_StringValue(socket_path_arg);
     
     // init client
-    if (!NCDRequestClient_Init(&o->client, NCDREQUESTCLIENT_UNIX_ADDR(socket_path), i->params->reactor, o,
+    if (!NCDRequestClient_Init(&o->client, addr, i->params->reactor, o,
         (NCDRequestClient_handler_error)client_handler_error,
         (NCDRequestClient_handler_connected)client_handler_connected)) {
         ModuleLog(o->i, BLOG_ERROR, "NCDRequestClient_Init failed");