/* 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.
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 *);
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)
{
/* 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;
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) {
} else {
return 0;
}
+
+ }
}
NOT_REACHED();
{
struct vconn vconn;
int fd;
+ void (*connect_success_cb)(struct vconn *, int);
struct ofpbuf *rxbuf;
struct ofpbuf *txbuf;
struct poll_waiter *tx_waiter;
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;
}
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
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 **),
/* 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)
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
}
}
+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 */
}
return new_stream_vconn(name, fd, check_connection_completion(fd),
- 0, true, vconnp);
+ 0, 0, true, NULL, vconnp);
}
struct vconn_class unix_vconn_class = {
} 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 = {
/* 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
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
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)
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 *);
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;
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));