vconn: New functions vconn_verify_name(), pvconn_verify_name().
authorBen Pfaff <blp@nicira.com>
Thu, 11 Feb 2010 22:58:02 +0000 (14:58 -0800)
committerBen Pfaff <blp@nicira.com>
Fri, 12 Feb 2010 21:55:47 +0000 (13:55 -0800)
These are useful for checking that the syntax of a name is valid, so that
completely invalid names can be rejected at program startup time.

CC: Jean Tourrilhes <jt@hpl.hp.com>
lib/vconn.c
lib/vconn.h

index d2015897ec2d2aa879739b5f54b85c135ec6103e..51a51b9cd5683a353ba659d0fb9170339f94466f 100644 (file)
@@ -163,6 +163,42 @@ vconn_usage(bool active, bool passive, bool bootstrap OVS_UNUSED)
 #endif
 }
 
+/* Given 'name', a connection name in the form "TYPE:ARGS", stores the class
+ * named "TYPE" into '*classp' and returns 0.  Returns EAFNOSUPPORT and stores
+ * a null pointer into '*classp' if 'name' is in the wrong form or if no such
+ * class exists. */
+static int
+vconn_lookup_class(const char *name, struct vconn_class **classp)
+{
+    size_t prefix_len;
+
+    prefix_len = strcspn(name, ":");
+    if (name[prefix_len] != '\0') {
+        size_t i;
+
+        for (i = 0; i < ARRAY_SIZE(vconn_classes); i++) {
+            struct vconn_class *class = vconn_classes[i];
+            if (strlen(class->name) == prefix_len
+                && !memcmp(class->name, name, prefix_len)) {
+                *classp = class;
+                return 0;
+            }
+        }
+    }
+
+    *classp = NULL;
+    return EAFNOSUPPORT;
+}
+
+/* Returns 0 if 'name' is a connection name in the form "TYPE:ARGS" and TYPE is
+ * a supported connection type, otherwise EAFNOSUPPORT.  */
+int
+vconn_verify_name(const char *name)
+{
+    struct vconn_class *class;
+    return vconn_lookup_class(name, &class);
+}
+
 /* Attempts to connect to an OpenFlow device.  'name' is a connection name in
  * the form "TYPE:ARGS", where TYPE is an active vconn class's name and ARGS
  * are vconn class-specific.
@@ -177,35 +213,37 @@ vconn_usage(bool active, bool passive, bool bootstrap OVS_UNUSED)
 int
 vconn_open(const char *name, int min_version, struct vconn **vconnp)
 {
-    size_t prefix_len;
-    size_t i;
+    struct vconn_class *class;
+    struct vconn *vconn;
+    char *suffix_copy;
+    int error;
 
     COVERAGE_INC(vconn_open);
     check_vconn_classes();
 
-    *vconnp = NULL;
-    prefix_len = strcspn(name, ":");
-    if (prefix_len == strlen(name)) {
-        return EAFNOSUPPORT;
+    /* Look up the class. */
+    error = vconn_lookup_class(name, &class);
+    if (!class) {
+        goto error;
     }
-    for (i = 0; i < ARRAY_SIZE(vconn_classes); i++) {
-        struct vconn_class *class = vconn_classes[i];
-        if (strlen(class->name) == prefix_len
-            && !memcmp(class->name, name, prefix_len)) {
-            struct vconn *vconn;
-            char *suffix_copy = xstrdup(name + prefix_len + 1);
-            int retval = class->open(name, suffix_copy, &vconn);
-            free(suffix_copy);
-            if (!retval) {
-                assert(vconn->state != VCS_CONNECTING
-                       || vconn->class->connect);
-                vconn->min_version = min_version;
-                *vconnp = vconn;
-            }
-            return retval;
-        }
+
+    /* Call class's "open" function. */
+    suffix_copy = xstrdup(strchr(name, ':') + 1);
+    error = class->open(name, suffix_copy, &vconn);
+    free(suffix_copy);
+    if (error) {
+        goto error;
     }
-    return EAFNOSUPPORT;
+
+    /* Success. */
+    assert(vconn->state != VCS_CONNECTING || vconn->class->connect);
+    vconn->min_version = min_version;
+    *vconnp = vconn;
+    return 0;
+
+error:
+    *vconnp = NULL;
+    return error;
 }
 
 int
@@ -664,6 +702,42 @@ vconn_send_wait(struct vconn *vconn)
     vconn_wait(vconn, WAIT_SEND);
 }
 
+/* Given 'name', a connection name in the form "TYPE:ARGS", stores the class
+ * named "TYPE" into '*classp' and returns 0.  Returns EAFNOSUPPORT and stores
+ * a null pointer into '*classp' if 'name' is in the wrong form or if no such
+ * class exists. */
+static int
+pvconn_lookup_class(const char *name, struct pvconn_class **classp)
+{
+    size_t prefix_len;
+
+    prefix_len = strcspn(name, ":");
+    if (name[prefix_len] != '\0') {
+        size_t i;
+
+        for (i = 0; i < ARRAY_SIZE(pvconn_classes); i++) {
+            struct pvconn_class *class = pvconn_classes[i];
+            if (strlen(class->name) == prefix_len
+                && !memcmp(class->name, name, prefix_len)) {
+                *classp = class;
+                return 0;
+            }
+        }
+    }
+
+    *classp = NULL;
+    return EAFNOSUPPORT;
+}
+
+/* Returns 0 if 'name' is a connection name in the form "TYPE:ARGS" and TYPE is
+ * a supported connection type, otherwise EAFNOSUPPORT.  */
+int
+pvconn_verify_name(const char *name)
+{
+    struct pvconn_class *class;
+    return pvconn_lookup_class(name, &class);
+}
+
 /* Attempts to start listening for OpenFlow connections.  'name' is a
  * connection name in the form "TYPE:ARGS", where TYPE is an passive vconn
  * class's name and ARGS are vconn class-specific.
@@ -674,30 +748,34 @@ vconn_send_wait(struct vconn *vconn)
 int
 pvconn_open(const char *name, struct pvconn **pvconnp)
 {
-    size_t prefix_len;
-    size_t i;
+    struct pvconn_class *class;
+    struct pvconn *pvconn;
+    char *suffix_copy;
+    int error;
 
     check_vconn_classes();
 
-    *pvconnp = NULL;
-    prefix_len = strcspn(name, ":");
-    if (prefix_len == strlen(name)) {
-        return EAFNOSUPPORT;
+    /* Look up the class. */
+    error = pvconn_lookup_class(name, &class);
+    if (!class) {
+        goto error;
     }
-    for (i = 0; i < ARRAY_SIZE(pvconn_classes); i++) {
-        struct pvconn_class *class = pvconn_classes[i];
-        if (strlen(class->name) == prefix_len
-            && !memcmp(class->name, name, prefix_len)) {
-            char *suffix_copy = xstrdup(name + prefix_len + 1);
-            int retval = class->listen(name, suffix_copy, pvconnp);
-            free(suffix_copy);
-            if (retval) {
-                *pvconnp = NULL;
-            }
-            return retval;
-        }
+
+    /* Call class's "open" function. */
+    suffix_copy = xstrdup(strchr(name, ':') + 1);
+    error = class->listen(name, suffix_copy, &pvconn);
+    free(suffix_copy);
+    if (error) {
+        goto error;
     }
-    return EAFNOSUPPORT;
+
+    /* Success. */
+    *pvconnp = pvconn;
+    return 0;
+
+error:
+    *pvconnp = NULL;
+    return error;
 }
 
 /* Returns the name that was used to open 'pvconn'.  The caller must not
index 0c13744c475790fe9961448d13a2d1c55d71a529..e2a35772a364d10b89bec9a11d74323a66b35713 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010 Nicira Networks.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -35,6 +35,7 @@ struct vconn;
 void vconn_usage(bool active, bool passive, bool bootstrap);
 
 /* Active vconns: virtual connections to OpenFlow devices. */
+int vconn_verify_name(const char *name);
 int vconn_open(const char *name, int min_version, struct vconn **);
 void vconn_close(struct vconn *);
 const char *vconn_get_name(const struct vconn *);
@@ -63,6 +64,7 @@ void vconn_recv_wait(struct vconn *);
 void vconn_send_wait(struct vconn *);
 
 /* Passive vconns: virtual listeners for incoming OpenFlow connections. */
+int pvconn_verify_name(const char *name);
 int pvconn_open(const char *name, struct pvconn **);
 const char *pvconn_get_name(const struct pvconn *);
 void pvconn_close(struct pvconn *);