X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;ds=sidebyside;f=lib%2Fstream.c;h=667a23ff370facf6d8266aa976afc993bd992d6b;hb=f4b6076acab233cfe02e7eaefdeafbb69dfae556;hp=7d00cafe7cac59efbb6254d24b8dc161dc46d694;hpb=766407ea9011d347d577a3409acb0f8d34cc72e1;p=openvswitch diff --git a/lib/stream.c b/lib/stream.c index 7d00cafe..667a23ff 100644 --- a/lib/stream.c +++ b/lib/stream.c @@ -25,6 +25,7 @@ #include #include "coverage.h" #include "dynamic-string.h" +#include "fatal-signal.h" #include "flow.h" #include "ofp-print.h" #include "ofpbuf.h" @@ -237,6 +238,8 @@ stream_open_block(int error, struct stream **streamp) { struct stream *stream = *streamp; + fatal_signal_run(); + while (error == EAGAIN) { stream_run(stream); stream_run_wait(stream); @@ -570,6 +573,7 @@ pstream_accept_block(struct pstream *pstream, struct stream **new_stream) { int error; + fatal_signal_run(); while ((error = pstream_accept(pstream, new_stream)) == EAGAIN) { pstream_wait(pstream); poll_block(); @@ -647,3 +651,133 @@ pstream_init(struct pstream *pstream, struct pstream_class *class, pstream->class = class; pstream->name = xstrdup(name); } + +static int +count_fields(const char *s_) +{ + char *s, *field, *save_ptr; + int n = 0; + + save_ptr = NULL; + s = xstrdup(s_); + for (field = strtok_r(s, ":", &save_ptr); field != NULL; + field = strtok_r(NULL, ":", &save_ptr)) { + n++; + } + free(s); + + return n; +} + +/* Like stream_open(), but for tcp streams the port defaults to + * 'default_tcp_port' if no port number is given and for SSL streams the port + * defaults to 'default_ssl_port' if no port number is given. */ +int +stream_open_with_default_ports(const char *name_, + uint16_t default_tcp_port, + uint16_t default_ssl_port, + struct stream **streamp) +{ + char *name; + int error; + + if (!strncmp(name_, "tcp:", 4) && count_fields(name_) < 3) { + name = xasprintf("%s:%d", name_, default_tcp_port); + } else if (!strncmp(name_, "ssl:", 4) && count_fields(name_) < 3) { + name = xasprintf("%s:%d", name_, default_ssl_port); + } else { + name = xstrdup(name_); + } + error = stream_open(name, streamp); + free(name); + + return error; +} + +/* Like pstream_open(), but for ptcp streams the port defaults to + * 'default_ptcp_port' if no port number is given and for passive SSL streams + * the port defaults to 'default_pssl_port' if no port number is given. */ +int +pstream_open_with_default_ports(const char *name_, + uint16_t default_ptcp_port, + uint16_t default_pssl_port, + struct pstream **pstreamp) +{ + char *name; + int error; + + if (!strncmp(name_, "ptcp:", 5) && count_fields(name_) < 2) { + name = xasprintf("%s%d", name_, default_ptcp_port); + } else if (!strncmp(name_, "pssl:", 5) && count_fields(name_) < 2) { + name = xasprintf("%s%d", name_, default_pssl_port); + } else { + name = xstrdup(name_); + } + error = pstream_open(name, pstreamp); + free(name); + + return error; +} + +/* Attempts to guess the content type of a stream whose first few bytes were + * the 'size' bytes of 'data'. */ +static enum stream_content_type +stream_guess_content(const uint8_t *data, size_t size) +{ + if (size >= 2) { +#define PAIR(A, B) (((A) << 8) | (B)) + switch (PAIR(data[0], data[1])) { + case PAIR(0x16, 0x03): /* Handshake, version 3. */ + return STREAM_SSL; + case PAIR('{', '"'): + return STREAM_JSONRPC; + case PAIR(OFP_VERSION, OFPT_HELLO): + return STREAM_OPENFLOW; + } + } + + return STREAM_UNKNOWN; +} + +/* Returns a string represenation of 'type'. */ +static const char * +stream_content_type_to_string(enum stream_content_type type) +{ + switch (type) { + case STREAM_UNKNOWN: + default: + return "unknown"; + + case STREAM_JSONRPC: + return "JSON-RPC"; + + case STREAM_OPENFLOW: + return "OpenFlow"; + + case STREAM_SSL: + return "SSL"; + } +} + +/* Attempts to guess the content type of a stream whose first few bytes were + * the 'size' bytes of 'data'. If this is done successfully, and the guessed + * content type is other than 'expected_type', then log a message in vlog + * module 'module', naming 'stream_name' as the source, explaining what + * content was expected and what was actually received. */ +void +stream_report_content(const void *data, size_t size, + enum stream_content_type expected_type, + enum vlog_module module, const char *stream_name) +{ + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5); + enum stream_content_type actual_type; + + actual_type = stream_guess_content(data, size); + if (actual_type != expected_type && actual_type != STREAM_UNKNOWN) { + vlog_rate_limit(module, VLL_WARN, &rl, + "%s: received %s data on %s channel", + stream_name, + stream_content_type_to_string(expected_type), + stream_content_type_to_string(actual_type)); + } +}