X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fstream-tcp.c;h=74db2f1e74f9cdbc607fb28642e96e067133f2f9;hb=HEAD;hp=947be9f19828a07c7e8593a8995dd8713d37bdcf;hpb=58fda1dab104041fc693032475ec4662c1a52849;p=sliver-openvswitch.git diff --git a/lib/stream-tcp.c b/lib/stream-tcp.c index 947be9f19..74db2f1e7 100644 --- a/lib/stream-tcp.c +++ b/lib/stream-tcp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009 Nicira Networks. + * Copyright (c) 2008, 2009, 2010, 2012, 2013, 2014 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,117 +21,243 @@ #include #include #include +#include #include #include +#include #include +#include "dynamic-string.h" #include "packets.h" #include "socket-util.h" #include "util.h" #include "stream-provider.h" #include "stream-fd.h" - #include "vlog.h" -#define THIS_MODULE VLM_stream_tcp + +VLOG_DEFINE_THIS_MODULE(stream_tcp); /* Active TCP. */ static int new_tcp_stream(const char *name, int fd, int connect_status, - const struct sockaddr_in *remote, struct stream **streamp) + struct stream **streamp) { - struct sockaddr_in local; + struct sockaddr_storage local; socklen_t local_len = sizeof local; int on = 1; int retval; /* Get the local IP and port information */ - retval = getsockname(fd, (struct sockaddr *)&local, &local_len); + retval = getsockname(fd, (struct sockaddr *) &local, &local_len); if (retval) { memset(&local, 0, sizeof local); } retval = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof on); if (retval) { - VLOG_ERR("%s: setsockopt(TCP_NODELAY): %s", name, strerror(errno)); - close(fd); - return errno; + int error = sock_errno(); + VLOG_ERR("%s: setsockopt(TCP_NODELAY): %s", + name, sock_strerror(error)); + closesocket(fd); + return error; } - retval = new_fd_stream(name, fd, connect_status, NULL, streamp); - if (!retval) { - struct stream *stream = *streamp; - stream_set_remote_ip(stream, remote->sin_addr.s_addr); - stream_set_remote_port(stream, remote->sin_port); - stream_set_local_ip(stream, local.sin_addr.s_addr); - stream_set_local_port(stream, local.sin_port); - } - return retval; + return new_fd_stream(name, fd, connect_status, streamp); } static int -tcp_open(const char *name, char *suffix, struct stream **streamp) +tcp_open(const char *name, char *suffix, struct stream **streamp, uint8_t dscp) { - struct sockaddr_in sin; int fd, error; - error = inet_open_active(SOCK_STREAM, suffix, 0, &sin, &fd); + error = inet_open_active(SOCK_STREAM, suffix, 0, NULL, &fd, dscp); if (fd >= 0) { - return new_tcp_stream(name, fd, error, &sin, streamp); + return new_tcp_stream(name, fd, error, streamp); } else { - VLOG_ERR("%s: connect: %s", name, strerror(error)); + VLOG_ERR("%s: connect: %s", name, ovs_strerror(error)); return error; } } -struct stream_class tcp_stream_class = { +const struct stream_class tcp_stream_class = { "tcp", /* name */ + true, /* needs_probes */ tcp_open, /* open */ NULL, /* close */ NULL, /* connect */ NULL, /* recv */ NULL, /* send */ + NULL, /* run */ + NULL, /* run_wait */ NULL, /* wait */ }; + +#ifdef _WIN32 +static int +windows_open(const char *name, char *suffix, struct stream **streamp, + uint8_t dscp) +{ + int error, port; + FILE *file; + char *suffix_new, *path; + + /* If the path does not contain a ':', assume it is relative to + * OVS_RUNDIR. */ + if (!strchr(suffix, ':')) { + path = xasprintf("%s/%s", ovs_rundir(), suffix); + } else { + path = strdup(suffix); + } + + file = fopen(path, "r"); + if (!file) { + error = errno; + VLOG_DBG("%s: could not open %s (%s)", name, suffix, + ovs_strerror(error)); + return error; + } + + error = fscanf(file, "%d", &port); + if (error != 1) { + VLOG_ERR("failed to read port from %s", suffix); + fclose(file); + return EINVAL; + } + fclose(file); + + suffix_new = xasprintf("127.0.0.1:%d", port); + + error = tcp_open(name, suffix_new, streamp, dscp); + + free(suffix_new); + free(path); + return error; +} + +const struct stream_class windows_stream_class = { + "unix", /* name */ + false, /* needs_probes */ + windows_open, /* open */ + NULL, /* close */ + NULL, /* connect */ + NULL, /* recv */ + NULL, /* send */ + NULL, /* run */ + NULL, /* run_wait */ + NULL, /* wait */ +}; +#endif /* Passive TCP. */ -static int ptcp_accept(int fd, const struct sockaddr *sa, size_t sa_len, - struct stream **streamp); +static int ptcp_accept(int fd, const struct sockaddr_storage *, + size_t, struct stream **streamp); static int -ptcp_open(const char *name UNUSED, char *suffix, struct pstream **pstreamp) +ptcp_open(const char *name OVS_UNUSED, char *suffix, struct pstream **pstreamp, + uint8_t dscp) { + char bound_name[SS_NTOP_BUFSIZE + 16]; + char addrbuf[SS_NTOP_BUFSIZE]; + struct sockaddr_storage ss; + uint16_t port; + int error; int fd; - fd = inet_open_passive(SOCK_STREAM, suffix, 0); + fd = inet_open_passive(SOCK_STREAM, suffix, -1, &ss, dscp); if (fd < 0) { return -fd; - } else { - return new_fd_pstream("ptcp", fd, ptcp_accept, NULL, pstreamp); } + + port = ss_get_port(&ss); + snprintf(bound_name, sizeof bound_name, "ptcp:%"PRIu16":%s", + port, ss_format_address(&ss, addrbuf, sizeof addrbuf)); + + error = new_fd_pstream(bound_name, fd, ptcp_accept, set_dscp, NULL, + pstreamp); + if (!error) { + pstream_set_bound_port(*pstreamp, htons(port)); + } + return error; } static int -ptcp_accept(int fd, const struct sockaddr *sa, size_t sa_len, - struct stream **streamp) +ptcp_accept(int fd, const struct sockaddr_storage *ss, + size_t ss_len OVS_UNUSED, struct stream **streamp) { - const struct sockaddr_in *sin = (const struct sockaddr_in *) sa; - char name[128]; + char name[SS_NTOP_BUFSIZE + 16]; + char addrbuf[SS_NTOP_BUFSIZE]; - if (sa_len == sizeof(struct sockaddr_in) && sin->sin_family == AF_INET) { - sprintf(name, "tcp:"IP_FMT, IP_ARGS(&sin->sin_addr)); - sprintf(strchr(name, '\0'), ":%"PRIu16, ntohs(sin->sin_port)); - } else { - strcpy(name, "tcp"); - } - return new_tcp_stream(name, fd, 0, sin, streamp); + snprintf(name, sizeof name, "tcp:%s:%"PRIu16, + ss_format_address(ss, addrbuf, sizeof addrbuf), + ss_get_port(ss)); + return new_tcp_stream(name, fd, 0, streamp); } -struct pstream_class ptcp_pstream_class = { +const struct pstream_class ptcp_pstream_class = { "ptcp", + true, ptcp_open, NULL, NULL, - NULL + NULL, + NULL, }; +#ifdef _WIN32 +static int +pwindows_open(const char *name OVS_UNUSED, char *suffix, + struct pstream **pstreamp, uint8_t dscp) +{ + int error; + char *suffix_new, *path; + FILE *file; + struct pstream *listener; + + suffix_new = xstrdup("0:127.0.0.1"); + error = ptcp_open(name, suffix_new, pstreamp, dscp); + if (error) { + goto exit; + } + listener = *pstreamp; + + /* If the path does not contain a ':', assume it is relative to + * OVS_RUNDIR. */ + if (!strchr(suffix, ':')) { + path = xasprintf("%s/%s", ovs_rundir(), suffix); + } else { + path = strdup(suffix); + } + + file = fopen(path, "w"); + if (!file) { + error = errno; + VLOG_DBG("could not open %s (%s)", path, ovs_strerror(error)); + goto exit; + } + + fprintf(file, "%d\n", ntohs(listener->bound_port)); + if (fflush(file) == EOF) { + error = EIO; + VLOG_ERR("write failed for %s", path); + fclose(file); + goto exit; + } + fclose(file); + free(path); + +exit: + free(suffix_new); + return error; +} + +const struct pstream_class pwindows_pstream_class = { + "punix", + false, + pwindows_open, + NULL, + NULL, + NULL, + NULL, +}; +#endif