From 6ed1440acca05fdb74f20d8fcbd009c02c9a6fe0 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Wed, 30 Jul 2008 15:45:04 -0700 Subject: [PATCH] vconn: Use vconn_stream to factor out code from vconn_tcp. --- lib/vconn-tcp.c | 293 ++++-------------------------------------------- 1 file changed, 19 insertions(+), 274 deletions(-) diff --git a/lib/vconn-tcp.c b/lib/vconn-tcp.c index 7fbec081e..be4cd9574 100644 --- a/lib/vconn-tcp.c +++ b/lib/vconn-tcp.c @@ -33,44 +33,29 @@ #include #include "vconn.h" -#include #include #include -#include -#include #include #include #include #include #include #include -#include "buffer.h" +#include "packets.h" #include "socket-util.h" #include "util.h" #include "openflow.h" -#include "ofp-print.h" -#include "packets.h" -#include "poll-loop.h" +#include "vconn-stream.h" #include "vlog.h" #define THIS_MODULE VLM_vconn_tcp /* Active TCP. */ -struct tcp_vconn -{ - struct vconn vconn; - int fd; - struct buffer *rxbuf; - struct buffer *txbuf; - struct poll_waiter *tx_waiter; -}; - static int new_tcp_vconn(const char *name, int fd, int connect_status, const struct sockaddr_in *sin, struct vconn **vconnp) { - struct tcp_vconn *tcp; int on = 1; int retval; @@ -81,26 +66,10 @@ new_tcp_vconn(const char *name, int fd, int connect_status, return errno; } - tcp = xmalloc(sizeof *tcp); - tcp->vconn.class = &tcp_vconn_class; - tcp->vconn.connect_status = connect_status; - tcp->vconn.ip = sin->sin_addr.s_addr; - tcp->fd = fd; - tcp->txbuf = NULL; - tcp->tx_waiter = NULL; - tcp->rxbuf = NULL; - *vconnp = &tcp->vconn; - return 0; + return new_stream_vconn(name, fd, connect_status, sin->sin_addr.s_addr, + vconnp); } -static struct tcp_vconn * -tcp_vconn_cast(struct vconn *vconn) -{ - assert(vconn->class == &tcp_vconn_class); - return CONTAINER_OF(vconn, struct tcp_vconn, vconn); -} - - static int tcp_open(const char *name, char *suffix, struct vconn **vconnp) { @@ -156,191 +125,20 @@ tcp_open(const char *name, char *suffix, struct vconn **vconnp) } } -static void -tcp_close(struct vconn *vconn) -{ - struct tcp_vconn *tcp = tcp_vconn_cast(vconn); - poll_cancel(tcp->tx_waiter); - close(tcp->fd); - free(tcp); -} - -static int -tcp_connect(struct vconn *vconn) -{ - struct tcp_vconn *tcp = tcp_vconn_cast(vconn); - return check_connection_completion(tcp->fd); -} - -static int -tcp_recv(struct vconn *vconn, struct buffer **bufferp) -{ - struct tcp_vconn *tcp = tcp_vconn_cast(vconn); - struct buffer *rx; - size_t want_bytes; - ssize_t retval; - - if (tcp->rxbuf == NULL) { - tcp->rxbuf = buffer_new(1564); - } - rx = tcp->rxbuf; - -again: - if (sizeof(struct ofp_header) > rx->size) { - want_bytes = sizeof(struct ofp_header) - rx->size; - } else { - struct ofp_header *oh = rx->data; - size_t length = ntohs(oh->length); - if (length < sizeof(struct ofp_header)) { - VLOG_ERR("received too-short ofp_header (%zu bytes)", length); - return EPROTO; - } - want_bytes = length - rx->size; - if (!want_bytes) { - *bufferp = rx; - tcp->rxbuf = NULL; - return 0; - } - } - buffer_prealloc_tailroom(rx, want_bytes); - - retval = read(tcp->fd, buffer_tail(rx), want_bytes); - if (retval > 0) { - rx->size += retval; - if (retval == want_bytes) { - if (rx->size > sizeof(struct ofp_header)) { - *bufferp = rx; - tcp->rxbuf = NULL; - return 0; - } else { - goto again; - } - } - return EAGAIN; - } else if (retval == 0) { - if (rx->size) { - VLOG_ERR("connection dropped mid-packet"); - return EPROTO; - } else { - return EOF; - } - } else { - return retval ? errno : EAGAIN; - } -} - -static void -tcp_clear_txbuf(struct tcp_vconn *tcp) -{ - buffer_delete(tcp->txbuf); - tcp->txbuf = NULL; - tcp->tx_waiter = NULL; -} - -static void -tcp_do_tx(int fd UNUSED, short int revents UNUSED, void *vconn_) -{ - struct vconn *vconn = vconn_; - struct tcp_vconn *tcp = tcp_vconn_cast(vconn); - ssize_t n = write(tcp->fd, tcp->txbuf->data, tcp->txbuf->size); - if (n < 0) { - if (errno != EAGAIN) { - VLOG_ERR("send: %s", strerror(errno)); - tcp_clear_txbuf(tcp); - return; - } - } else if (n > 0) { - buffer_pull(tcp->txbuf, n); - if (!tcp->txbuf->size) { - tcp_clear_txbuf(tcp); - return; - } - } - tcp->tx_waiter = poll_fd_callback(tcp->fd, POLLOUT, tcp_do_tx, vconn); -} - -static int -tcp_send(struct vconn *vconn, struct buffer *buffer) -{ - struct tcp_vconn *tcp = tcp_vconn_cast(vconn); - ssize_t retval; - - if (tcp->txbuf) { - return EAGAIN; - } - - retval = write(tcp->fd, buffer->data, buffer->size); - if (retval == buffer->size) { - buffer_delete(buffer); - return 0; - } else if (retval >= 0 || errno == EAGAIN) { - tcp->txbuf = buffer; - if (retval > 0) { - buffer_pull(buffer, retval); - } - tcp->tx_waiter = poll_fd_callback(tcp->fd, POLLOUT, tcp_do_tx, vconn); - return 0; - } else { - return errno; - } -} - -static void -tcp_wait(struct vconn *vconn, enum vconn_wait_type wait) -{ - struct tcp_vconn *tcp = tcp_vconn_cast(vconn); - switch (wait) { - case WAIT_CONNECT: - poll_fd_wait(tcp->fd, POLLOUT); - break; - - case WAIT_SEND: - if (!tcp->txbuf) { - poll_fd_wait(tcp->fd, POLLOUT); - } else { - /* Nothing to do: need to drain txbuf first. */ - } - break; - - case WAIT_RECV: - poll_fd_wait(tcp->fd, POLLIN); - break; - - default: - NOT_REACHED(); - } -} - struct vconn_class tcp_vconn_class = { .name = "tcp", .open = tcp_open, - .close = tcp_close, - .connect = tcp_connect, - .recv = tcp_recv, - .send = tcp_send, - .wait = tcp_wait, }; /* Passive TCP. */ -struct ptcp_vconn -{ - struct vconn vconn; - int fd; -}; - -static struct ptcp_vconn * -ptcp_vconn_cast(struct vconn *vconn) -{ - assert(vconn->class == &ptcp_vconn_class); - return CONTAINER_OF(vconn, struct ptcp_vconn, vconn); -} +static int ptcp_accept(int fd, const struct sockaddr *sa, size_t sa_len, + struct vconn **vconnp); static int ptcp_open(const char *name, char *suffix, struct vconn **vconnp) { struct sockaddr_in sin; - struct ptcp_vconn *ptcp; int retval; int fd; unsigned int yes = 1; @@ -351,12 +149,11 @@ ptcp_open(const char *name, char *suffix, struct vconn **vconnp) return errno; } - if ( setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,&yes,sizeof(yes)) < 0) { - VLOG_ERR("%s: setsockopt::SO_REUSEADDR: %s", name, strerror(errno)); + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes) < 0) { + VLOG_ERR("%s: setsockopt(SO_REUSEADDR): %s", name, strerror(errno)); return errno; } - memset(&sin, 0, sizeof sin); sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(INADDR_ANY); @@ -369,81 +166,29 @@ ptcp_open(const char *name, char *suffix, struct vconn **vconnp) return error; } - retval = listen(fd, 10); - if (retval < 0) { - int error = errno; - VLOG_ERR("%s: listen: %s", name, strerror(error)); - close(fd); - return error; - } - - retval = set_nonblocking(fd); - if (retval) { - close(fd); - return retval; - } - - ptcp = xmalloc(sizeof *ptcp); - ptcp->vconn.class = &ptcp_vconn_class; - ptcp->vconn.connect_status = 0; - ptcp->fd = fd; - *vconnp = &ptcp->vconn; - return 0; -} - -static void -ptcp_close(struct vconn *vconn) -{ - struct ptcp_vconn *ptcp = ptcp_vconn_cast(vconn); - close(ptcp->fd); - free(ptcp); + return new_pstream_vconn("ptcp", fd, ptcp_accept, vconnp); } static int -ptcp_accept(struct vconn *vconn, struct vconn **new_vconnp) +ptcp_accept(int fd, const struct sockaddr *sa, size_t sa_len, + struct vconn **vconnp) { - struct ptcp_vconn *ptcp = ptcp_vconn_cast(vconn); - struct sockaddr_in sin; - socklen_t sin_len = sizeof sin; + const struct sockaddr_in *sin = (const struct sockaddr_in *) sa; char name[128]; - int new_fd; - int error; - new_fd = accept(ptcp->fd, &sin, &sin_len); - if (new_fd < 0) { - int error = errno; - if (error != EAGAIN) { - VLOG_DBG("accept: %s", strerror(error)); + if (sa_len == sizeof(struct sockaddr_in) && sin->sin_family == AF_INET) { + sprintf(name, "tcp:"IP_FMT, IP_ARGS(&sin->sin_addr)); + if (sin->sin_port != htons(OFP_TCP_PORT)) { + sprintf(strchr(name, '\0'), ":%"PRIu16, ntohs(sin->sin_port)); } - return error; - } - - error = set_nonblocking(new_fd); - if (error) { - close(new_fd); - return error; - } - - sprintf(name, "tcp:"IP_FMT, IP_ARGS(&sin.sin_addr)); - if (sin.sin_port != htons(OFP_TCP_PORT)) { - sprintf(strchr(name, '\0'), ":%"PRIu16, ntohs(sin.sin_port)); + } else { + strcpy(name, "tcp"); } - return new_tcp_vconn(name, new_fd, 0, &sin, new_vconnp); -} - -static void -ptcp_wait(struct vconn *vconn, enum vconn_wait_type wait) -{ - struct ptcp_vconn *ptcp = ptcp_vconn_cast(vconn); - assert(wait == WAIT_ACCEPT); - poll_fd_wait(ptcp->fd, POLLIN); + return new_tcp_vconn(name, fd, 0, sin, vconnp); } struct vconn_class ptcp_vconn_class = { .name = "ptcp", .open = ptcp_open, - .close = ptcp_close, - .accept = ptcp_accept, - .wait = ptcp_wait }; -- 2.43.0