1 /* Copyright (C) 2007 Board of Trustees, Leland Stanford Jr. University.
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to
5 * deal in the Software without restriction, including without limitation the
6 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7 * sell copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
27 #include <sys/types.h>
28 #include <netinet/in.h>
29 #include <netinet/tcp.h>
34 #include "socket-util.h"
37 #include "ofp-print.h"
38 #include "poll-loop.h"
41 #define THIS_MODULE VLM_vconn_tcp
51 struct poll_waiter *tx_waiter;
55 new_tcp_vconn(const char *name, int fd, int connect_status,
56 struct vconn **vconnp)
58 struct tcp_vconn *tcp;
62 retval = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof on);
64 VLOG_ERR("%s: setsockopt(TCP_NODELAY): %s", name, strerror(errno));
69 tcp = xmalloc(sizeof *tcp);
70 tcp->vconn.class = &tcp_vconn_class;
71 tcp->vconn.connect_status = connect_status;
74 tcp->tx_waiter = NULL;
76 *vconnp = &tcp->vconn;
80 static struct tcp_vconn *
81 tcp_vconn_cast(struct vconn *vconn)
83 assert(vconn->class == &tcp_vconn_class);
84 return CONTAINER_OF(vconn, struct tcp_vconn, vconn);
89 tcp_open(const char *name, char *suffix, struct vconn **vconnp)
92 const char *host_name;
93 const char *port_string;
94 struct sockaddr_in sin;
98 /* Glibc 2.7 has a bug in strtok_r when compiling with optimization that
99 * can cause segfaults here:
100 * http://sources.redhat.com/bugzilla/show_bug.cgi?id=5614.
101 * Using "::" instead of the obvious ":" works around it. */
102 host_name = strtok_r(suffix, "::", &save_ptr);
103 port_string = strtok_r(NULL, "::", &save_ptr);
105 fatal(0, "%s: bad peer name format", name);
108 memset(&sin, 0, sizeof sin);
109 sin.sin_family = AF_INET;
110 if (lookup_ip(host_name, &sin.sin_addr)) {
113 sin.sin_port = htons(port_string ? atoi(port_string) : OFP_TCP_PORT);
115 fd = socket(AF_INET, SOCK_STREAM, 0);
117 VLOG_ERR("%s: socket: %s", name, strerror(errno));
121 retval = set_nonblocking(fd);
127 retval = connect(fd, (struct sockaddr *) &sin, sizeof sin);
129 if (errno == EINPROGRESS) {
130 return new_tcp_vconn(name, fd, EAGAIN, vconnp);
133 VLOG_ERR("%s: connect: %s", name, strerror(error));
138 return new_tcp_vconn(name, fd, 0, vconnp);
143 tcp_close(struct vconn *vconn)
145 struct tcp_vconn *tcp = tcp_vconn_cast(vconn);
146 poll_cancel(tcp->tx_waiter);
152 tcp_connect(struct vconn *vconn)
154 struct tcp_vconn *tcp = tcp_vconn_cast(vconn);
155 return check_connection_completion(tcp->fd);
159 tcp_recv(struct vconn *vconn, struct buffer **bufferp)
161 struct tcp_vconn *tcp = tcp_vconn_cast(vconn);
166 if (tcp->rxbuf == NULL) {
167 tcp->rxbuf = buffer_new(1564);
172 if (sizeof(struct ofp_header) > rx->size) {
173 want_bytes = sizeof(struct ofp_header) - rx->size;
175 struct ofp_header *oh = rx->data;
176 size_t length = ntohs(oh->length);
177 if (length < sizeof(struct ofp_header)) {
178 VLOG_ERR("received too-short ofp_header (%zu bytes)", length);
181 want_bytes = length - rx->size;
183 buffer_reserve_tailroom(rx, want_bytes);
185 retval = read(tcp->fd, buffer_tail(rx), want_bytes);
188 if (retval == want_bytes) {
189 if (rx->size > sizeof(struct ofp_header)) {
198 } else if (retval == 0) {
199 return rx->size ? EPROTO : EOF;
201 return retval ? errno : EAGAIN;
206 tcp_clear_txbuf(struct tcp_vconn *tcp)
208 buffer_delete(tcp->txbuf);
210 tcp->tx_waiter = NULL;
214 tcp_do_tx(int fd UNUSED, short int revents UNUSED, void *vconn_)
216 struct vconn *vconn = vconn_;
217 struct tcp_vconn *tcp = tcp_vconn_cast(vconn);
218 ssize_t n = write(tcp->fd, tcp->txbuf->data, tcp->txbuf->size);
220 if (errno != EAGAIN) {
221 VLOG_ERR("send: %s", strerror(errno));
222 tcp_clear_txbuf(tcp);
226 buffer_pull(tcp->txbuf, n);
227 if (!tcp->txbuf->size) {
228 tcp_clear_txbuf(tcp);
232 tcp->tx_waiter = poll_fd_callback(tcp->fd, POLLOUT, tcp_do_tx, vconn);
236 tcp_send(struct vconn *vconn, struct buffer *buffer)
238 struct tcp_vconn *tcp = tcp_vconn_cast(vconn);
245 retval = write(tcp->fd, buffer->data, buffer->size);
246 if (retval == buffer->size) {
247 buffer_delete(buffer);
249 } else if (retval >= 0 || errno == EAGAIN) {
252 buffer_pull(buffer, retval);
254 tcp->tx_waiter = poll_fd_callback(tcp->fd, POLLOUT, tcp_do_tx, vconn);
262 tcp_wait(struct vconn *vconn, enum vconn_wait_type wait)
264 struct tcp_vconn *tcp = tcp_vconn_cast(vconn);
267 poll_fd_wait(tcp->fd, POLLOUT, NULL);
272 poll_fd_wait(tcp->fd, POLLOUT, NULL);
274 /* Nothing to do: need to drain txbuf first. */
279 poll_fd_wait(tcp->fd, POLLIN, NULL);
287 struct vconn_class tcp_vconn_class = {
291 .connect = tcp_connect,
305 static struct ptcp_vconn *
306 ptcp_vconn_cast(struct vconn *vconn)
308 assert(vconn->class == &ptcp_vconn_class);
309 return CONTAINER_OF(vconn, struct ptcp_vconn, vconn);
313 ptcp_open(const char *name, char *suffix, struct vconn **vconnp)
315 struct sockaddr_in sin;
316 struct ptcp_vconn *ptcp;
319 unsigned int yes = 1;
321 fd = socket(AF_INET, SOCK_STREAM, 0);
323 VLOG_ERR("%s: socket: %s", name, strerror(errno));
327 if ( setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,&yes,sizeof(yes)) < 0) {
328 VLOG_ERR("%s: setsockopt::SO_REUSEADDR: %s", name, strerror(errno));
333 memset(&sin, 0, sizeof sin);
334 sin.sin_family = AF_INET;
335 sin.sin_addr.s_addr = htonl(INADDR_ANY);
336 sin.sin_port = htons(atoi(suffix) ? atoi(suffix) : OFP_TCP_PORT);
337 retval = bind(fd, (struct sockaddr *) &sin, sizeof sin);
340 VLOG_ERR("%s: bind: %s", name, strerror(error));
345 retval = listen(fd, 10);
348 VLOG_ERR("%s: listen: %s", name, strerror(error));
353 retval = set_nonblocking(fd);
359 ptcp = xmalloc(sizeof *ptcp);
360 ptcp->vconn.class = &ptcp_vconn_class;
361 ptcp->vconn.connect_status = 0;
363 *vconnp = &ptcp->vconn;
368 ptcp_close(struct vconn *vconn)
370 struct ptcp_vconn *ptcp = ptcp_vconn_cast(vconn);
376 ptcp_accept(struct vconn *vconn, struct vconn **new_vconnp)
378 struct ptcp_vconn *ptcp = ptcp_vconn_cast(vconn);
382 new_fd = accept(ptcp->fd, NULL, NULL);
385 if (error != EAGAIN) {
386 VLOG_DBG("accept: %s", strerror(error));
391 error = set_nonblocking(new_fd);
397 return new_tcp_vconn("tcp" /* FIXME */, new_fd, 0, new_vconnp);
401 ptcp_wait(struct vconn *vconn, enum vconn_wait_type wait)
403 struct ptcp_vconn *ptcp = ptcp_vconn_cast(vconn);
404 assert(wait == WAIT_ACCEPT);
405 poll_fd_wait(ptcp->fd, POLLIN, NULL);
408 struct vconn_class ptcp_vconn_class = {
412 .accept = ptcp_accept,