+/* 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.
+ *
+ * Returns 0 if successful, otherwise a positive errno value. If successful,
+ * stores a pointer to the new connection in '*pvconnp', otherwise a null
+ * pointer. */
+int
+pvconn_open(const char *name, struct pvconn **pvconnp)
+{
+ size_t prefix_len;
+ size_t i;
+
+ check_vconn_classes();
+
+ *pvconnp = NULL;
+ prefix_len = strcspn(name, ":");
+ if (prefix_len == strlen(name)) {
+ return EAFNOSUPPORT;
+ }
+ 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;
+ }
+ }
+ return EAFNOSUPPORT;
+}
+
+/* Closes 'pvconn'. */
+void
+pvconn_close(struct pvconn *pvconn)
+{
+ if (pvconn != NULL) {
+ char *name = pvconn->name;
+ (pvconn->class->close)(pvconn);
+ free(name);
+ }
+}
+
+/* Tries to accept a new connection on 'pvconn'. If successful, stores the new
+ * connection in '*new_vconn' and returns 0. Otherwise, returns a positive
+ * errno value.
+ *
+ * pvconn_accept() will not block waiting for a connection. If no connection
+ * is ready to be accepted, it returns EAGAIN immediately. */
+int
+pvconn_accept(struct pvconn *pvconn, struct vconn **new_vconn)
+{
+ int retval = (pvconn->class->accept)(pvconn, new_vconn);
+ if (retval) {
+ *new_vconn = NULL;
+ } else {
+ assert((*new_vconn)->connect_status == 0
+ || (*new_vconn)->class->connect);
+ }
+ return retval;
+}
+
+void
+pvconn_wait(struct pvconn *pvconn)
+{
+ (pvconn->class->wait)(pvconn);
+}
+