Merge "master" into "next".
[cascardo/ovs.git] / lib / stream.c
index 1a0ea7b..db6ec61 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.
@@ -48,11 +48,17 @@ enum stream_state {
 static struct stream_class *stream_classes[] = {
     &tcp_stream_class,
     &unix_stream_class,
+#ifdef HAVE_OPENSSL
+    &ssl_stream_class,
+#endif
 };
 
 static struct pstream_class *pstream_classes[] = {
     &ptcp_pstream_class,
     &punix_pstream_class,
+#ifdef HAVE_OPENSSL
+    &pssl_pstream_class,
+#endif
 };
 
 /* Check the validity of the stream class structures. */
@@ -66,7 +72,8 @@ check_stream_classes(void)
         struct stream_class *class = stream_classes[i];
         assert(class->name != NULL);
         assert(class->open != NULL);
-        if (class->close || class->recv || class->send || class->wait) {
+        if (class->close || class->recv || class->send || class->run
+            || class->run_wait || class->wait) {
             assert(class->close != NULL);
             assert(class->recv != NULL);
             assert(class->send != NULL);
@@ -94,7 +101,8 @@ check_stream_classes(void)
 /* Prints information on active (if 'active') and passive (if 'passive')
  * connection methods supported by the stream. */
 void
-stream_usage(const char *name, bool active, bool passive)
+stream_usage(const char *name, bool active, bool passive,
+             bool bootstrap OVS_UNUSED)
 {
     /* Really this should be implemented via callbacks into the stream
      * providers, but that seems too heavy-weight to bother with at the
@@ -105,6 +113,10 @@ stream_usage(const char *name, bool active, bool passive)
         printf("Active %s connection methods:\n", name);
         printf("  tcp:IP:PORT             "
                "PORT at remote IP\n");
+#ifdef HAVE_OPENSSL
+        printf("  ssl:IP:PORT             "
+               "SSL PORT at remote IP\n");
+#endif
         printf("  unix:FILE               "
                "Unix domain socket named FILE\n");
     }
@@ -113,9 +125,24 @@ stream_usage(const char *name, bool active, bool passive)
         printf("Passive %s connection methods:\n", name);
         printf("  ptcp:PORT[:IP]          "
                "listen to TCP PORT on IP\n");
+#ifdef HAVE_OPENSSL
+        printf("  pssl:PORT[:IP]          "
+               "listen for SSL on PORT on IP\n");
+#endif
         printf("  punix:FILE              "
                "listen on Unix domain socket FILE\n");
     }
+
+#ifdef HAVE_OPENSSL
+    printf("PKI configuration (required to use SSL):\n"
+           "  -p, --private-key=FILE  file with private key\n"
+           "  -c, --certificate=FILE  file with certificate for private key\n"
+           "  -C, --ca-cert=FILE      file with peer CA certificate\n");
+    if (bootstrap) {
+        printf("  --bootstrap-ca-cert=FILE  file with peer CA certificate "
+               "to read or create\n");
+    }
+#endif
 }
 
 /* Attempts to connect a stream to a remote peer.  'name' is a connection name
@@ -166,6 +193,8 @@ stream_open_block(const char *name, struct stream **streamp)
 
     error = stream_open(name, &stream);
     while (error == EAGAIN) {
+        stream_run(stream);
+        stream_run_wait(stream);
         stream_connect_wait(stream);
         poll_block();
         error = stream_connect(stream);
@@ -312,6 +341,28 @@ stream_send(struct stream *stream, const void *buffer, size_t n)
             : (stream->class->send)(stream, buffer, n));
 }
 
+/* Allows 'stream' to perform maintenance activities, such as flushing
+ * output buffers. */
+void
+stream_run(struct stream *stream)
+{
+    if (stream->class->run) {
+        (stream->class->run)(stream);
+    }
+}
+
+/* Arranges for the poll loop to wake up when 'stream' needs to perform
+ * maintenance activities. */
+void
+stream_run_wait(struct stream *stream)
+{
+    if (stream->class->run_wait) {
+        (stream->class->run_wait)(stream);
+    }
+}
+
+/* Arranges for the poll loop to wake up when 'stream' is ready to take an
+ * action of the given 'type'. */
 void
 stream_wait(struct stream *stream, enum stream_wait_type wait)
 {
@@ -422,6 +473,27 @@ pstream_accept(struct pstream *pstream, struct stream **new_stream)
     return retval;
 }
 
+/* Tries to accept a new connection on 'pstream'.  If successful, stores the
+ * new connection in '*new_stream' and returns 0.  Otherwise, returns a
+ * positive errno value.
+ *
+ * pstream_accept_block() blocks until a connection is ready or until an error
+ * occurs.  It will not return EAGAIN. */
+int
+pstream_accept_block(struct pstream *pstream, struct stream **new_stream)
+{
+    int error;
+
+    while ((error = pstream_accept(pstream, new_stream)) == EAGAIN) {
+        pstream_wait(pstream);
+        poll_block();
+    }
+    if (error) {
+        *new_stream = NULL;
+    }
+    return error;
+}
+
 void
 pstream_wait(struct pstream *pstream)
 {
@@ -455,6 +527,7 @@ stream_init(struct stream *stream, struct stream_class *class,
                     : SCS_DISCONNECTED);
     stream->error = connect_status;
     stream->name = xstrdup(name);
+    assert(stream->state != SCS_CONNECTING || class->connect);
 }
 
 void