X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fstream.c;h=37b611000ee9a64698a54bc302d30fca4369ffa7;hb=54ebd8ea7dfdd53e36ef4e0cd0877d52dd95a8ad;hp=43b73af0adf9f7f542019a031e57b3515a799298;hpb=b302749b70bd8b487bdfe0ffcdacbf730da8b6ca;p=sliver-openvswitch.git diff --git a/lib/stream.c b/lib/stream.c index 43b73af0a..37b611000 100644 --- a/lib/stream.c +++ b/lib/stream.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, 2010 Nicira Networks. + * Copyright (c) 2008, 2009, 2010, 2011 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,10 +35,13 @@ #include "poll-loop.h" #include "random.h" #include "util.h" - -#define THIS_MODULE VLM_stream #include "vlog.h" +VLOG_DEFINE_THIS_MODULE(stream); + +COVERAGE_DEFINE(pstream_open); +COVERAGE_DEFINE(stream_open); + /* State of an active stream.*/ enum stream_state { SCS_CONNECTING, /* Underlying stream is not connected. */ @@ -240,14 +243,16 @@ stream_open_block(int error, struct stream **streamp) fatal_signal_run(); - while (error == EAGAIN) { - stream_run(stream); - stream_run_wait(stream); - stream_connect_wait(stream); - poll_block(); - error = stream_connect(stream); + if (!error) { + while ((error = stream_connect(stream)) == EAGAIN) { + stream_run(stream); + stream_run_wait(stream); + stream_connect_wait(stream); + poll_block(); + } assert(error != EINPROGRESS); } + if (error) { stream_close(stream); *streamp = NULL; @@ -278,7 +283,7 @@ stream_get_name(const struct stream *stream) /* Returns the IP address of the peer, or 0 if the peer is not connected over * an IP-based protocol or if its IP address is not yet known. */ -uint32_t +ovs_be32 stream_get_remote_ip(const struct stream *stream) { return stream->remote_ip; @@ -286,7 +291,7 @@ stream_get_remote_ip(const struct stream *stream) /* Returns the transport port of the peer, or 0 if the connection does not * contain a port or if the port is not yet known. */ -uint16_t +ovs_be16 stream_get_remote_port(const struct stream *stream) { return stream->remote_port; @@ -294,7 +299,7 @@ stream_get_remote_port(const struct stream *stream) /* Returns the IP address used to connect to the peer, or 0 if the connection * is not an IP-based protocol or if its IP address is not yet known. */ -uint32_t +ovs_be32 stream_get_local_ip(const struct stream *stream) { return stream->local_ip; @@ -302,7 +307,7 @@ stream_get_local_ip(const struct stream *stream) /* Returns the transport port used to connect to the peer, or 0 if the * connection does not contain a port or if the port is not yet known. */ -uint16_t +ovs_be16 stream_get_local_port(const struct stream *stream) { return stream->local_port; @@ -321,10 +326,10 @@ scs_connecting(struct stream *stream) } } -/* Tries to complete the connection on 'stream', which must be an active - * stream. If 'stream''s connection is complete, returns 0 if the connection - * was successful or a positive errno value if it failed. If the - * connection is still in progress, returns EAGAIN. */ +/* Tries to complete the connection on 'stream'. If 'stream''s connection is + * complete, returns 0 if the connection was successful or a positive errno + * value if it failed. If the connection is still in progress, returns + * EAGAIN. */ int stream_connect(struct stream *stream) { @@ -621,25 +626,25 @@ stream_init(struct stream *stream, struct stream_class *class, } void -stream_set_remote_ip(struct stream *stream, uint32_t ip) +stream_set_remote_ip(struct stream *stream, ovs_be32 ip) { stream->remote_ip = ip; } void -stream_set_remote_port(struct stream *stream, uint16_t port) +stream_set_remote_port(struct stream *stream, ovs_be16 port) { stream->remote_port = port; } void -stream_set_local_ip(struct stream *stream, uint32_t ip) +stream_set_local_ip(struct stream *stream, ovs_be32 ip) { stream->local_ip = ip; } void -stream_set_local_port(struct stream *stream, uint16_t port) +stream_set_local_port(struct stream *stream, ovs_be16 port) { stream->local_port = port; } @@ -718,5 +723,66 @@ pstream_open_with_default_ports(const char *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, ssize_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, ssize_t size, + enum stream_content_type expected_type, + struct 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(actual_type), + stream_content_type_to_string(expected_type)); + } +}