aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/rconn.c29
-rw-r--r--lib/rconn.h5
-rw-r--r--lib/vconn-provider.h10
-rw-r--r--lib/vconn-ssl.c20
-rw-r--r--lib/vconn-stream.c20
-rw-r--r--lib/vconn-stream.h6
-rw-r--r--lib/vconn-tcp.c23
-rw-r--r--lib/vconn-unix.c4
-rw-r--r--lib/vconn.c49
-rw-r--r--lib/vconn.h5
-rw-r--r--secchan/in-band.c4
11 files changed, 151 insertions, 24 deletions
diff --git a/lib/rconn.c b/lib/rconn.c
index b18a2e59..1301f25c 100644
--- a/lib/rconn.c
+++ b/lib/rconn.c
@@ -638,9 +638,34 @@ rconn_failure_duration(const struct rconn *rconn)
/* 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 known. */
uint32_t
-rconn_get_ip(const struct rconn *rconn)
+rconn_get_remote_ip(const struct rconn *rconn)
{
- return rconn->vconn ? vconn_get_ip(rconn->vconn) : 0;
+ return rconn->vconn ? vconn_get_remote_ip(rconn->vconn) : 0;
+}
+
+/* Returns the transport port of the peer, or 0 if the peer does not
+ * contain a port or if the port is not known. */
+uint16_t
+rconn_get_remote_port(const struct rconn *rconn)
+{
+ return rconn->vconn ? vconn_get_remote_port(rconn->vconn) : 0;
+}
+
+/* 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
+ * known. */
+uint32_t
+rconn_get_local_ip(const struct rconn *rconn)
+{
+ return rconn->vconn ? vconn_get_local_ip(rconn->vconn) : 0;
+}
+
+/* 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 known. */
+uint16_t
+rconn_get_local_port(const struct rconn *rconn)
+{
+ return rconn->vconn ? vconn_get_local_port(rconn->vconn) : 0;
}
/* If 'rconn' can't connect to the peer, it could be for any number of reasons.
diff --git a/lib/rconn.h b/lib/rconn.h
index 1249b844..ed0780a3 100644
--- a/lib/rconn.h
+++ b/lib/rconn.h
@@ -72,7 +72,10 @@ bool rconn_is_connected(const struct rconn *);
int rconn_failure_duration(const struct rconn *);
bool rconn_is_connectivity_questionable(struct rconn *);
-uint32_t rconn_get_ip(const struct rconn *);
+uint32_t rconn_get_remote_ip(const struct rconn *);
+uint16_t rconn_get_remote_port(const struct rconn *);
+uint32_t rconn_get_local_ip(const struct rconn *);
+uint16_t rconn_get_local_port(const struct rconn *);
const char *rconn_get_state(const struct rconn *);
unsigned int rconn_get_attempted_connections(const struct rconn *);
diff --git a/lib/vconn-provider.h b/lib/vconn-provider.h
index ada61368..0b25dee8 100644
--- a/lib/vconn-provider.h
+++ b/lib/vconn-provider.h
@@ -34,13 +34,19 @@ struct vconn {
int error;
int min_version;
int version;
- uint32_t ip;
+ uint32_t remote_ip;
+ uint16_t remote_port;
+ uint32_t local_ip;
+ uint16_t local_port;
char *name;
bool reconnectable;
};
void vconn_init(struct vconn *, struct vconn_class *, int connect_status,
- uint32_t ip, const char *name, bool reconnectable);
+ uint32_t remote_ip, uint16_t remote_port,
+ const char *name, bool reconnectable);
+void vconn_set_local_ip(struct vconn *, uint32_t local_ip);
+void vconn_set_local_port(struct vconn *, uint16_t local_port);
static inline void vconn_assert_class(const struct vconn *vconn,
const struct vconn_class *class)
{
diff --git a/lib/vconn-ssl.c b/lib/vconn-ssl.c
index 905996fb..d4dbc9f7 100644
--- a/lib/vconn-ssl.c
+++ b/lib/vconn-ssl.c
@@ -238,8 +238,8 @@ new_ssl_vconn(const char *name, int fd, enum session_type type,
/* Create and return the ssl_vconn. */
sslv = xmalloc(sizeof *sslv);
- vconn_init(&sslv->vconn, &ssl_vconn_class, EAGAIN, sin->sin_addr.s_addr,
- name, true);
+ vconn_init(&sslv->vconn, &ssl_vconn_class, EAGAIN,
+ sin->sin_addr.s_addr, sin->sin_port, name, true);
sslv->state = state;
sslv->type = type;
sslv->fd = fd;
@@ -426,7 +426,19 @@ ssl_connect(struct vconn *vconn)
sslv->state = STATE_SSL_CONNECTING;
/* Fall through. */
- case STATE_SSL_CONNECTING:
+ case STATE_SSL_CONNECTING: {
+ struct sockaddr_in local_addr;
+ socklen_t addrlen = sizeof(local_addr);
+
+ /* Get the local IP and port information */
+ retval = getsockname(sslv->fd, (struct sockaddr *)&local_addr,
+ &addrlen);
+ if (retval) {
+ memset(&local_addr, 0, sizeof local_addr);
+ }
+ vconn_set_local_ip(vconn, local_addr.sin_addr.s_addr);
+ vconn_set_local_port(vconn, local_addr.sin_port);
+
retval = (sslv->type == CLIENT
? SSL_connect(sslv->ssl) : SSL_accept(sslv->ssl));
if (retval != 1) {
@@ -458,6 +470,8 @@ ssl_connect(struct vconn *vconn)
} else {
return 0;
}
+
+ }
}
NOT_REACHED();
diff --git a/lib/vconn-stream.c b/lib/vconn-stream.c
index a9fcd98d..46279e57 100644
--- a/lib/vconn-stream.c
+++ b/lib/vconn-stream.c
@@ -41,6 +41,7 @@ struct stream_vconn
{
struct vconn vconn;
int fd;
+ void (*connect_success_cb)(struct vconn *, int);
struct ofpbuf *rxbuf;
struct ofpbuf *txbuf;
struct poll_waiter *tx_waiter;
@@ -54,17 +55,21 @@ static void stream_clear_txbuf(struct stream_vconn *);
int
new_stream_vconn(const char *name, int fd, int connect_status,
- uint32_t ip, bool reconnectable, struct vconn **vconnp)
+ uint32_t remote_ip, uint16_t remote_port,
+ bool reconnectable,
+ connect_success_cb_func *connect_success_cb,
+ struct vconn **vconnp)
{
struct stream_vconn *s;
s = xmalloc(sizeof *s);
- vconn_init(&s->vconn, &stream_vconn_class, connect_status, ip, name,
- reconnectable);
+ vconn_init(&s->vconn, &stream_vconn_class, connect_status, remote_ip,
+ remote_port, name, reconnectable);
s->fd = fd;
s->txbuf = NULL;
s->tx_waiter = NULL;
s->rxbuf = NULL;
+ s->connect_success_cb = connect_success_cb;
*vconnp = &s->vconn;
return 0;
}
@@ -91,7 +96,14 @@ static int
stream_connect(struct vconn *vconn)
{
struct stream_vconn *s = stream_vconn_cast(vconn);
- return check_connection_completion(s->fd);
+ int retval = check_connection_completion(s->fd);
+ if (retval) {
+ return retval;
+ }
+ if (s->connect_success_cb) {
+ s->connect_success_cb(vconn, s->fd);
+ }
+ return 0;
}
static int
diff --git a/lib/vconn-stream.h b/lib/vconn-stream.h
index 10e30bed..efebdd84 100644
--- a/lib/vconn-stream.h
+++ b/lib/vconn-stream.h
@@ -25,8 +25,12 @@ struct vconn;
struct pvconn;
struct sockaddr;
+typedef void connect_success_cb_func(struct vconn *, int);
+
int new_stream_vconn(const char *name, int fd, int connect_status,
- uint32_t ip, bool reconnectable, struct vconn **vconnp);
+ uint32_t remote_ip, uint16_t remote_port,
+ bool reconnectable, connect_success_cb_func *,
+ struct vconn **vconnp);
int new_pstream_pvconn(const char *name, int fd,
int (*accept_cb)(int fd, const struct sockaddr *,
size_t sa_len, struct vconn **),
diff --git a/lib/vconn-tcp.c b/lib/vconn-tcp.c
index 911fe6d8..50367806 100644
--- a/lib/vconn-tcp.c
+++ b/lib/vconn-tcp.c
@@ -36,6 +36,8 @@
/* Active TCP. */
+void tcp_connect_success_cb(struct vconn *vconn, int fd);
+
static int
new_tcp_vconn(const char *name, int fd, int connect_status,
const struct sockaddr_in *sin, struct vconn **vconnp)
@@ -50,8 +52,9 @@ new_tcp_vconn(const char *name, int fd, int connect_status,
return errno;
}
- return new_stream_vconn(name, fd, connect_status, sin->sin_addr.s_addr,
- true, vconnp);
+ return new_stream_vconn(name, fd, connect_status,
+ sin->sin_addr.s_addr, sin->sin_port,
+ true, tcp_connect_success_cb, vconnp);
}
static int
@@ -105,6 +108,22 @@ tcp_open(const char *name, char *suffix, struct vconn **vconnp)
}
}
+void
+tcp_connect_success_cb(struct vconn *vconn, int fd)
+{
+ int retval;
+ struct sockaddr_in local_addr;
+ socklen_t addrlen = sizeof(local_addr);
+
+ /* Get the local IP and port information */
+ retval = getsockname(fd, (struct sockaddr *)&local_addr, &addrlen);
+ if (retval) {
+ memset(&local_addr, 0, sizeof local_addr);
+ }
+ vconn_set_local_ip(vconn, local_addr.sin_addr.s_addr);
+ vconn_set_local_port(vconn, local_addr.sin_port);
+}
+
struct vconn_class tcp_vconn_class = {
"tcp", /* name */
tcp_open, /* open */
diff --git a/lib/vconn-unix.c b/lib/vconn-unix.c
index aec2e31d..fddf6e85 100644
--- a/lib/vconn-unix.c
+++ b/lib/vconn-unix.c
@@ -60,7 +60,7 @@ unix_open(const char *name, char *suffix, struct vconn **vconnp)
}
return new_stream_vconn(name, fd, check_connection_completion(fd),
- 0, true, vconnp);
+ 0, 0, true, NULL, vconnp);
}
struct vconn_class unix_vconn_class = {
@@ -105,7 +105,7 @@ punix_accept(int fd, const struct sockaddr *sa, size_t sa_len,
} else {
strcpy(name, "unix");
}
- return new_stream_vconn(name, fd, 0, 0, true, vconnp);
+ return new_stream_vconn(name, fd, 0, 0, 0, true, NULL, vconnp);
}
struct pvconn_class punix_pvconn_class = {
diff --git a/lib/vconn.c b/lib/vconn.c
index a006efbe..2940c114 100644
--- a/lib/vconn.c
+++ b/lib/vconn.c
@@ -251,9 +251,34 @@ vconn_get_name(const struct vconn *vconn)
/* 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
-vconn_get_ip(const struct vconn *vconn)
+vconn_get_remote_ip(const struct vconn *vconn)
{
- return vconn->ip;
+ return vconn->remote_ip;
+}
+
+/* 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
+vconn_get_remote_port(const struct vconn *vconn)
+{
+ return vconn->remote_port;
+}
+
+/* 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
+vconn_get_local_ip(const struct vconn *vconn)
+{
+ return vconn->local_ip;
+}
+
+/* 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
+vconn_get_local_port(const struct vconn *vconn)
+{
+ return vconn->local_port;
}
static void
@@ -1382,7 +1407,8 @@ normalize_match(struct ofp_match *m)
void
vconn_init(struct vconn *vconn, struct vconn_class *class, int connect_status,
- uint32_t ip, const char *name, bool reconnectable)
+ uint32_t remote_ip, uint16_t remote_port, const char *name,
+ bool reconnectable)
{
vconn->class = class;
vconn->state = (connect_status == EAGAIN ? VCS_CONNECTING
@@ -1391,11 +1417,26 @@ vconn_init(struct vconn *vconn, struct vconn_class *class, int connect_status,
vconn->error = connect_status;
vconn->version = -1;
vconn->min_version = -1;
- vconn->ip = ip;
+ vconn->remote_ip = remote_ip;
+ vconn->remote_port = remote_port;
+ vconn->local_ip = 0;
+ vconn->local_port = 0;
vconn->name = xstrdup(name);
vconn->reconnectable = reconnectable;
}
+void
+vconn_set_local_ip(struct vconn *vconn, uint32_t ip)
+{
+ vconn->local_ip = ip;
+}
+
+void
+vconn_set_local_port(struct vconn *vconn, uint16_t port)
+{
+ vconn->local_port = port;
+}
+
void
pvconn_init(struct pvconn *pvconn, struct pvconn_class *class,
const char *name)
diff --git a/lib/vconn.h b/lib/vconn.h
index b94eeb3c..9e012bcf 100644
--- a/lib/vconn.h
+++ b/lib/vconn.h
@@ -38,7 +38,10 @@ void vconn_usage(bool active, bool passive, bool bootstrap);
int vconn_open(const char *name, int min_version, struct vconn **);
void vconn_close(struct vconn *);
const char *vconn_get_name(const struct vconn *);
-uint32_t vconn_get_ip(const struct vconn *);
+uint32_t vconn_get_remote_ip(const struct vconn *);
+uint16_t vconn_get_remote_port(const struct vconn *);
+uint32_t vconn_get_local_ip(const struct vconn *);
+uint16_t vconn_get_local_port(const struct vconn *);
int vconn_connect(struct vconn *);
int vconn_recv(struct vconn *, struct ofpbuf **);
int vconn_send(struct vconn *, struct ofpbuf *);
diff --git a/secchan/in-band.c b/secchan/in-band.c
index 9dccf5f1..7cbcaa99 100644
--- a/secchan/in-band.c
+++ b/secchan/in-band.c
@@ -92,7 +92,7 @@ get_controller_mac(struct in_band *ib)
time_t now = time_now();
uint32_t ip;
- ip = rconn_get_ip(ib->controller);
+ ip = rconn_get_remote_ip(ib->controller);
if (ip != ib->ip || now >= ib->next_refresh) {
bool have_mac;
@@ -165,7 +165,7 @@ in_band_status_cb(struct status_reply *sr, void *in_band_)
ETH_ADDR_ARGS(local_mac));
}
- controller_ip = rconn_get_ip(in_band->controller);
+ controller_ip = rconn_get_remote_ip(in_band->controller);
if (controller_ip) {
status_reply_put(sr, "controller-ip="IP_FMT,
IP_ARGS(&controller_ip));