Ver Fonte

ncd: modules: add rimp_call

ambrop7 há 14 anos atrás
pai
commit
91a540df96

+ 1 - 0
blog_channels.txt

@@ -21,6 +21,7 @@ ncd_run 4
 ncd_runonce 4
 ncd_spawn 4
 ncd_call 4
+ncd_rimp_call 4
 ncd_ref 4
 ncd_index 4
 ncd_alias 4

+ 4 - 0
generated/blog_channel_ncd_rimp_call.h

@@ -0,0 +1,4 @@
+#ifdef BLOG_CURRENT_CHANNEL
+#undef BLOG_CURRENT_CHANNEL
+#endif
+#define BLOG_CURRENT_CHANNEL BLOG_CHANNEL_ncd_rimp_call

+ 76 - 75
generated/blog_channels_defines.h

@@ -21,78 +21,79 @@
 #define BLOG_CHANNEL_ncd_runonce 20
 #define BLOG_CHANNEL_ncd_spawn 21
 #define BLOG_CHANNEL_ncd_call 22
-#define BLOG_CHANNEL_ncd_ref 23
-#define BLOG_CHANNEL_ncd_index 24
-#define BLOG_CHANNEL_ncd_alias 25
-#define BLOG_CHANNEL_ncd_process_manager 26
-#define BLOG_CHANNEL_ncd_ondemand 27
-#define BLOG_CHANNEL_ncd_foreach 28
-#define BLOG_CHANNEL_ncd_choose 29
-#define BLOG_CHANNEL_ncd_net_backend_waitdevice 30
-#define BLOG_CHANNEL_ncd_net_backend_waitlink 31
-#define BLOG_CHANNEL_ncd_net_backend_badvpn 32
-#define BLOG_CHANNEL_ncd_net_backend_wpa_supplicant 33
-#define BLOG_CHANNEL_ncd_net_backend_rfkill 34
-#define BLOG_CHANNEL_ncd_net_up 35
-#define BLOG_CHANNEL_ncd_net_dns 36
-#define BLOG_CHANNEL_ncd_net_iptables 37
-#define BLOG_CHANNEL_ncd_net_ipv4_addr 38
-#define BLOG_CHANNEL_ncd_net_ipv4_route 39
-#define BLOG_CHANNEL_ncd_net_ipv4_dhcp 40
-#define BLOG_CHANNEL_ncd_net_ipv4_arp_probe 41
-#define BLOG_CHANNEL_ncd_net_watch_interfaces 42
-#define BLOG_CHANNEL_ncd_sys_watch_input 43
-#define BLOG_CHANNEL_ncd_sys_watch_usb 44
-#define BLOG_CHANNEL_ncd_sys_evdev 45
-#define BLOG_CHANNEL_ncd_sys_watch_directory 46
-#define BLOG_CHANNEL_StreamPeerIO 47
-#define BLOG_CHANNEL_DatagramPeerIO 48
-#define BLOG_CHANNEL_BReactor 49
-#define BLOG_CHANNEL_BSignal 50
-#define BLOG_CHANNEL_FragmentProtoAssembler 51
-#define BLOG_CHANNEL_BPredicate 52
-#define BLOG_CHANNEL_ServerConnection 53
-#define BLOG_CHANNEL_Listener 54
-#define BLOG_CHANNEL_DataProto 55
-#define BLOG_CHANNEL_FrameDecider 56
-#define BLOG_CHANNEL_BSocksClient 57
-#define BLOG_CHANNEL_BDHCPClientCore 58
-#define BLOG_CHANNEL_BDHCPClient 59
-#define BLOG_CHANNEL_NCDIfConfig 60
-#define BLOG_CHANNEL_BUnixSignal 61
-#define BLOG_CHANNEL_BProcess 62
-#define BLOG_CHANNEL_PRStreamSink 63
-#define BLOG_CHANNEL_PRStreamSource 64
-#define BLOG_CHANNEL_PacketProtoDecoder 65
-#define BLOG_CHANNEL_DPRelay 66
-#define BLOG_CHANNEL_BThreadWork 67
-#define BLOG_CHANNEL_DPReceive 68
-#define BLOG_CHANNEL_BInputProcess 69
-#define BLOG_CHANNEL_NCDUdevMonitorParser 70
-#define BLOG_CHANNEL_NCDUdevMonitor 71
-#define BLOG_CHANNEL_NCDUdevCache 72
-#define BLOG_CHANNEL_NCDUdevManager 73
-#define BLOG_CHANNEL_BTime 74
-#define BLOG_CHANNEL_BEncryption 75
-#define BLOG_CHANNEL_SPProtoDecoder 76
-#define BLOG_CHANNEL_LineBuffer 77
-#define BLOG_CHANNEL_BTap 78
-#define BLOG_CHANNEL_lwip 79
-#define BLOG_CHANNEL_NCDConfigTokenizer 80
-#define BLOG_CHANNEL_NCDConfigParser 81
-#define BLOG_CHANNEL_nsskey 82
-#define BLOG_CHANNEL_addr 83
-#define BLOG_CHANNEL_PasswordListener 84
-#define BLOG_CHANNEL_NCDInterfaceMonitor 85
-#define BLOG_CHANNEL_NCDRfkillMonitor 86
-#define BLOG_CHANNEL_udpgw 87
-#define BLOG_CHANNEL_UdpGwClient 88
-#define BLOG_CHANNEL_SocksUdpGwClient 89
-#define BLOG_CHANNEL_BNetwork 90
-#define BLOG_CHANNEL_BConnection 91
-#define BLOG_CHANNEL_BSSLConnection 92
-#define BLOG_CHANNEL_BDatagram 93
-#define BLOG_CHANNEL_PeerChat 94
-#define BLOG_CHANNEL_BArpProbe 95
-#define BLOG_CHANNEL_NCDModuleIndex 96
-#define BLOG_NUM_CHANNELS 97
+#define BLOG_CHANNEL_ncd_rimp_call 23
+#define BLOG_CHANNEL_ncd_ref 24
+#define BLOG_CHANNEL_ncd_index 25
+#define BLOG_CHANNEL_ncd_alias 26
+#define BLOG_CHANNEL_ncd_process_manager 27
+#define BLOG_CHANNEL_ncd_ondemand 28
+#define BLOG_CHANNEL_ncd_foreach 29
+#define BLOG_CHANNEL_ncd_choose 30
+#define BLOG_CHANNEL_ncd_net_backend_waitdevice 31
+#define BLOG_CHANNEL_ncd_net_backend_waitlink 32
+#define BLOG_CHANNEL_ncd_net_backend_badvpn 33
+#define BLOG_CHANNEL_ncd_net_backend_wpa_supplicant 34
+#define BLOG_CHANNEL_ncd_net_backend_rfkill 35
+#define BLOG_CHANNEL_ncd_net_up 36
+#define BLOG_CHANNEL_ncd_net_dns 37
+#define BLOG_CHANNEL_ncd_net_iptables 38
+#define BLOG_CHANNEL_ncd_net_ipv4_addr 39
+#define BLOG_CHANNEL_ncd_net_ipv4_route 40
+#define BLOG_CHANNEL_ncd_net_ipv4_dhcp 41
+#define BLOG_CHANNEL_ncd_net_ipv4_arp_probe 42
+#define BLOG_CHANNEL_ncd_net_watch_interfaces 43
+#define BLOG_CHANNEL_ncd_sys_watch_input 44
+#define BLOG_CHANNEL_ncd_sys_watch_usb 45
+#define BLOG_CHANNEL_ncd_sys_evdev 46
+#define BLOG_CHANNEL_ncd_sys_watch_directory 47
+#define BLOG_CHANNEL_StreamPeerIO 48
+#define BLOG_CHANNEL_DatagramPeerIO 49
+#define BLOG_CHANNEL_BReactor 50
+#define BLOG_CHANNEL_BSignal 51
+#define BLOG_CHANNEL_FragmentProtoAssembler 52
+#define BLOG_CHANNEL_BPredicate 53
+#define BLOG_CHANNEL_ServerConnection 54
+#define BLOG_CHANNEL_Listener 55
+#define BLOG_CHANNEL_DataProto 56
+#define BLOG_CHANNEL_FrameDecider 57
+#define BLOG_CHANNEL_BSocksClient 58
+#define BLOG_CHANNEL_BDHCPClientCore 59
+#define BLOG_CHANNEL_BDHCPClient 60
+#define BLOG_CHANNEL_NCDIfConfig 61
+#define BLOG_CHANNEL_BUnixSignal 62
+#define BLOG_CHANNEL_BProcess 63
+#define BLOG_CHANNEL_PRStreamSink 64
+#define BLOG_CHANNEL_PRStreamSource 65
+#define BLOG_CHANNEL_PacketProtoDecoder 66
+#define BLOG_CHANNEL_DPRelay 67
+#define BLOG_CHANNEL_BThreadWork 68
+#define BLOG_CHANNEL_DPReceive 69
+#define BLOG_CHANNEL_BInputProcess 70
+#define BLOG_CHANNEL_NCDUdevMonitorParser 71
+#define BLOG_CHANNEL_NCDUdevMonitor 72
+#define BLOG_CHANNEL_NCDUdevCache 73
+#define BLOG_CHANNEL_NCDUdevManager 74
+#define BLOG_CHANNEL_BTime 75
+#define BLOG_CHANNEL_BEncryption 76
+#define BLOG_CHANNEL_SPProtoDecoder 77
+#define BLOG_CHANNEL_LineBuffer 78
+#define BLOG_CHANNEL_BTap 79
+#define BLOG_CHANNEL_lwip 80
+#define BLOG_CHANNEL_NCDConfigTokenizer 81
+#define BLOG_CHANNEL_NCDConfigParser 82
+#define BLOG_CHANNEL_nsskey 83
+#define BLOG_CHANNEL_addr 84
+#define BLOG_CHANNEL_PasswordListener 85
+#define BLOG_CHANNEL_NCDInterfaceMonitor 86
+#define BLOG_CHANNEL_NCDRfkillMonitor 87
+#define BLOG_CHANNEL_udpgw 88
+#define BLOG_CHANNEL_UdpGwClient 89
+#define BLOG_CHANNEL_SocksUdpGwClient 90
+#define BLOG_CHANNEL_BNetwork 91
+#define BLOG_CHANNEL_BConnection 92
+#define BLOG_CHANNEL_BSSLConnection 93
+#define BLOG_CHANNEL_BDatagram 94
+#define BLOG_CHANNEL_PeerChat 95
+#define BLOG_CHANNEL_BArpProbe 96
+#define BLOG_CHANNEL_NCDModuleIndex 97
+#define BLOG_NUM_CHANNELS 98

+ 1 - 0
generated/blog_channels_list.h

@@ -21,6 +21,7 @@
 {.name = "ncd_runonce", .loglevel = 4},
 {.name = "ncd_spawn", .loglevel = 4},
 {.name = "ncd_call", .loglevel = 4},
+{.name = "ncd_rimp_call", .loglevel = 4},
 {.name = "ncd_ref", .loglevel = 4},
 {.name = "ncd_index", .loglevel = 4},
 {.name = "ncd_alias", .loglevel = 4},

+ 1 - 0
ncd/CMakeLists.txt

@@ -56,6 +56,7 @@ add_executable(badvpn-ncd
     modules/runonce.c
     modules/spawn.c
     modules/call.c
+    modules/rimp_call.c
     modules/ref.c
     modules/index.c
     modules/alias.c

+ 2 - 0
ncd/modules/modules.h

@@ -45,6 +45,7 @@ extern const struct NCDModuleGroup ncdmodule_run;
 extern const struct NCDModuleGroup ncdmodule_runonce;
 extern const struct NCDModuleGroup ncdmodule_spawn;
 extern const struct NCDModuleGroup ncdmodule_call;
+extern const struct NCDModuleGroup ncdmodule_rimp_call;
 extern const struct NCDModuleGroup ncdmodule_ref;
 extern const struct NCDModuleGroup ncdmodule_index;
 extern const struct NCDModuleGroup ncdmodule_alias;
@@ -95,6 +96,7 @@ static const struct NCDModuleGroup *ncd_modules[] = {
     &ncdmodule_runonce,
     &ncdmodule_spawn,
     &ncdmodule_call,
+    &ncdmodule_rimp_call,
     &ncdmodule_ref,
     &ncdmodule_index,
     &ncdmodule_alias,

+ 270 - 0
ncd/modules/rimp_call.c

@@ -0,0 +1,270 @@
+/**
+ * @file rimp_call.c
+ * @author Ambroz Bizjak <ambrop7@gmail.com>
+ * 
+ * @section LICENSE
+ * 
+ * This file is part of BadVPN.
+ * 
+ * BadVPN is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ * 
+ * BadVPN is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * @section DESCRIPTION
+ * 
+ * Reverse imperative call.
+ * 
+ * Synopsis:
+ *   rimp_call(string template_name, list args)
+ *   rimp_call_timeout(string template_name, list args, string timeout_ms)
+ * 
+ * Description:
+ *   Goes up immediately. On deinitialization, does the following, in order:
+ *     1. starts a template process from the given template and arguments
+ *        and waits for it to completely initialize, or for the timeout to
+ *        elapse, then
+ *     2. requests termination of the process and waits for it to terminate,
+ *        then finally
+ *     3. deinitializes.
+ * 
+ *   WARNING: if there's a bug in the NCD program and the started template
+ *            process never initializes completely, rimp_call() will never
+ *            terminate, and you will have to kill the NCD process by force.
+ */
+
+#include <stdlib.h>
+
+#include <misc/parse_number.h>
+#include <ncd/NCDModule.h>
+
+#include <generated/blog_channel_ncd_rimp_call.h>
+
+#define ModuleLog(i, ...) NCDModuleInst_Backend_Log((i), BLOG_CURRENT_CHANNEL, __VA_ARGS__)
+
+#define STATE_UP 1
+#define STATE_WORKING 2
+#define STATE_CLEANING 3
+
+struct instance {
+    NCDModuleInst *i;
+    char *template_name;
+    NCDValue *args;
+    int have_timeout;
+    BTimer timer;
+    NCDModuleProcess process;
+    int state;
+};
+
+static void instance_free (struct instance *o);
+
+static void process_handler_event (struct instance *o, int event)
+{
+    switch (event) {
+        case NCDMODULEPROCESS_EVENT_UP: {
+            ASSERT(o->state == STATE_WORKING)
+            
+            // stop timer
+            if (o->have_timeout) {
+                BReactor_RemoveTimer(o->i->reactor, &o->timer);
+            }
+            
+            // start terminating
+            NCDModuleProcess_Terminate(&o->process);
+            
+            // set state cleaning
+            o->state = STATE_CLEANING;
+        } break;
+        
+        case NCDMODULEPROCESS_EVENT_TERMINATED: {
+            ASSERT(o->state == STATE_CLEANING)
+            
+            // free process
+            NCDModuleProcess_Free(&o->process);
+            
+            // free instance
+            instance_free(o);
+            return;
+        } break;
+        
+        default: ASSERT(0);
+    }
+}
+
+static void timer_handler (struct instance *o)
+{
+    ASSERT(o->have_timeout)
+    ASSERT(o->state == STATE_WORKING)
+    
+    ModuleLog(o->i, BLOG_ERROR, "rimp_call timeout elapsed");
+    
+    // start terminating
+    NCDModuleProcess_Terminate(&o->process);
+    
+    // set state cleaning
+    o->state = STATE_CLEANING;
+}
+
+static void func_new (NCDModuleInst *i)
+{
+    // allocate instance
+    struct instance *o = malloc(sizeof(*o));
+    if (!o) {
+        ModuleLog(i, BLOG_ERROR, "failed to allocate instance");
+        goto fail0;
+    }
+    NCDModuleInst_Backend_SetUser(i, o);
+    
+    // init arguments
+    o->i = i;
+    
+    // check arguments
+    NCDValue *template_name_arg;
+    if (!NCDValue_ListRead(i->args, 2, &template_name_arg, &o->args)) {
+        ModuleLog(i, BLOG_ERROR, "wrong arity");
+        goto fail1;
+    }
+    if (NCDValue_Type(template_name_arg) != NCDVALUE_STRING || NCDValue_Type(o->args) != NCDVALUE_LIST) {
+        ModuleLog(i, BLOG_ERROR, "wrong type");
+        goto fail1;
+    }
+    o->template_name = NCDValue_StringValue(template_name_arg);
+    
+    // set have no timeout
+    o->have_timeout = 0;
+    
+    // signal up
+    NCDModuleInst_Backend_Up(i);
+    
+    // set state up
+    o->state = STATE_UP;
+    return;
+    
+fail1:
+    free(o);
+fail0:
+    NCDModuleInst_Backend_SetError(i);
+    NCDModuleInst_Backend_Dead(i);
+}
+
+static void func_new_timeout (NCDModuleInst *i)
+{
+    // allocate instance
+    struct instance *o = malloc(sizeof(*o));
+    if (!o) {
+        ModuleLog(i, BLOG_ERROR, "failed to allocate instance");
+        goto fail0;
+    }
+    NCDModuleInst_Backend_SetUser(i, o);
+    
+    // init arguments
+    o->i = i;
+    
+    // check arguments
+    NCDValue *template_name_arg;
+    NCDValue *timeout_arg;
+    if (!NCDValue_ListRead(i->args, 3, &template_name_arg, &o->args, &timeout_arg)) {
+        ModuleLog(i, BLOG_ERROR, "wrong arity");
+        goto fail1;
+    }
+    if (NCDValue_Type(template_name_arg) != NCDVALUE_STRING || NCDValue_Type(o->args) != NCDVALUE_LIST ||
+        NCDValue_Type(timeout_arg) != NCDVALUE_STRING) {
+        ModuleLog(i, BLOG_ERROR, "wrong type");
+        goto fail1;
+    }
+    o->template_name = NCDValue_StringValue(template_name_arg);
+    
+    // parse timeout
+    uintmax_t timeout;
+    if (!parse_unsigned_integer(NCDValue_StringValue(timeout_arg), &timeout) || timeout > UINT64_MAX) {
+        ModuleLog(i, BLOG_ERROR, "wrong timeout");
+        goto fail1;
+    }
+    
+    // set have timeout
+    o->have_timeout = 1;
+    
+    // init timer
+    BTimer_Init(&o->timer, timeout, (BTimer_handler)timer_handler, o);
+    
+    // signal up
+    NCDModuleInst_Backend_Up(i);
+    
+    // set state up
+    o->state = STATE_UP;
+    return;
+    
+fail1:
+    free(o);
+fail0:
+    NCDModuleInst_Backend_SetError(i);
+    NCDModuleInst_Backend_Dead(i);
+}
+
+void instance_free (struct instance *o)
+{
+    NCDModuleInst *i = o->i;
+    
+    // free instance
+    free(o);
+    
+    NCDModuleInst_Backend_Dead(i);
+}
+
+static void func_die (void *vo)
+{
+    struct instance *o = vo;
+    ASSERT(o->state == STATE_UP)
+    
+    // copy arguments
+    NCDValue args;
+    if (!NCDValue_InitCopy(&args, o->args)) {
+        ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitCopy failed");
+        goto fail;
+    }
+    
+    // create process
+    if (!NCDModuleProcess_Init(&o->process, o->i, o->template_name, args, o, (NCDModuleProcess_handler_event)process_handler_event)) {
+        ModuleLog(o->i, BLOG_ERROR, "NCDModuleProcess_Init failed");
+        NCDValue_Free(&args);
+        goto fail;
+    }
+    
+    // start timer if used
+    if (o->have_timeout) {
+        BReactor_SetTimer(o->i->reactor, &o->timer);
+    }
+    
+    // set state working
+    o->state = STATE_WORKING;
+    return;
+    
+fail:
+    instance_free(o);
+}
+
+static const struct NCDModule modules[] = {
+    {
+        .type = "rimp_call",
+        .func_new = func_new,
+        .func_die = func_die
+    }, {
+        .type = "rimp_call_timeout",
+        .func_new = func_new_timeout,
+        .func_die = func_die
+    }, {
+        .type = NULL
+    }
+};
+
+const struct NCDModuleGroup ncdmodule_rimp_call = {
+    .modules = modules
+};