80c8f56c5b6c558846d3c8686042a592edf763cf
[sliver-openvswitch.git] / lib / vconn-tcp.c
1 /* Copyright (c) 2008 The Board of Trustees of The Leland Stanford
2  * Junior University
3  * 
4  * We are making the OpenFlow specification and associated documentation
5  * (Software) available for public use and benefit with the expectation
6  * that others will use, modify and enhance the Software and contribute
7  * those enhancements back to the community. However, since we would
8  * like to make the Software available for broadest use, with as few
9  * restrictions as possible permission is hereby granted, free of
10  * charge, to any person obtaining a copy of this Software to deal in
11  * the Software under the copyrights without restriction, including
12  * without limitation the rights to use, copy, modify, merge, publish,
13  * distribute, sublicense, and/or sell copies of the Software, and to
14  * permit persons to whom the Software is furnished to do so, subject to
15  * the following conditions:
16  * 
17  * The above copyright notice and this permission notice shall be
18  * included in all copies or substantial portions of the Software.
19  * 
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
24  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
25  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27  * SOFTWARE.
28  * 
29  * The name and trademarks of copyright holder(s) may NOT be used in
30  * advertising or publicity pertaining to the Software or any
31  * derivatives without specific, written prior permission.
32  */
33
34 #include "vconn.h"
35 #include <assert.h>
36 #include <errno.h>
37 #include <inttypes.h>
38 #include <netdb.h>
39 #include <poll.h>
40 #include <sys/types.h>
41 #include <netinet/in.h>
42 #include <netinet/tcp.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <unistd.h>
46 #include "buffer.h"
47 #include "socket-util.h"
48 #include "util.h"
49 #include "openflow.h"
50 #include "ofp-print.h"
51 #include "packets.h"
52 #include "poll-loop.h"
53
54 #include "vlog.h"
55 #define THIS_MODULE VLM_vconn_tcp
56
57 /* Active TCP. */
58
59 struct tcp_vconn
60 {
61     struct vconn vconn;
62     int fd;
63     struct buffer *rxbuf;
64     struct buffer *txbuf;
65     struct poll_waiter *tx_waiter;
66 };
67
68 static int
69 new_tcp_vconn(const char *name, int fd, int connect_status,
70               const struct sockaddr_in *sin, struct vconn **vconnp)
71 {
72     struct tcp_vconn *tcp;
73     int on = 1;
74     int retval;
75
76     retval = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof on);
77     if (retval) {
78         VLOG_ERR("%s: setsockopt(TCP_NODELAY): %s", name, strerror(errno));
79         close(fd);
80         return errno;
81     }
82
83     tcp = xmalloc(sizeof *tcp);
84     tcp->vconn.class = &tcp_vconn_class;
85     tcp->vconn.connect_status = connect_status;
86     tcp->vconn.ip = sin->sin_addr.s_addr;
87     tcp->fd = fd;
88     tcp->txbuf = NULL;
89     tcp->tx_waiter = NULL;
90     tcp->rxbuf = NULL;
91     *vconnp = &tcp->vconn;
92     return 0;
93 }
94
95 static struct tcp_vconn *
96 tcp_vconn_cast(struct vconn *vconn)
97 {
98     assert(vconn->class == &tcp_vconn_class);
99     return CONTAINER_OF(vconn, struct tcp_vconn, vconn);
100 }
101
102
103 static int
104 tcp_open(const char *name, char *suffix, struct vconn **vconnp)
105 {
106     char *save_ptr;
107     const char *host_name;
108     const char *port_string;
109     struct sockaddr_in sin;
110     int retval;
111     int fd;
112
113     /* Glibc 2.7 has a bug in strtok_r when compiling with optimization that
114      * can cause segfaults here:
115      * http://sources.redhat.com/bugzilla/show_bug.cgi?id=5614.
116      * Using "::" instead of the obvious ":" works around it. */
117     host_name = strtok_r(suffix, "::", &save_ptr);
118     port_string = strtok_r(NULL, "::", &save_ptr);
119     if (!host_name) {
120         error(0, "%s: bad peer name format", name);
121         return EAFNOSUPPORT;
122     }
123
124     memset(&sin, 0, sizeof sin);
125     sin.sin_family = AF_INET;
126     if (lookup_ip(host_name, &sin.sin_addr)) {
127         return ENOENT;
128     }
129     sin.sin_port = htons(port_string ? atoi(port_string) : OFP_TCP_PORT);
130
131     fd = socket(AF_INET, SOCK_STREAM, 0);
132     if (fd < 0) {
133         VLOG_ERR("%s: socket: %s", name, strerror(errno));
134         return errno;
135     }
136
137     retval = set_nonblocking(fd);
138     if (retval) {
139         close(fd);
140         return retval;
141     }
142
143     retval = connect(fd, (struct sockaddr *) &sin, sizeof sin);
144     if (retval < 0) {
145         if (errno == EINPROGRESS) {
146             return new_tcp_vconn(name, fd, EAGAIN, &sin, vconnp);
147         } else {
148             int error = errno;
149             VLOG_ERR("%s: connect: %s", name, strerror(error));
150             close(fd);
151             return error;
152         }
153     } else {
154         return new_tcp_vconn(name, fd, 0, &sin, vconnp);
155     }
156 }
157
158 static void
159 tcp_close(struct vconn *vconn)
160 {
161     struct tcp_vconn *tcp = tcp_vconn_cast(vconn);
162     poll_cancel(tcp->tx_waiter);
163     close(tcp->fd);
164     free(tcp);
165 }
166
167 static int
168 tcp_connect(struct vconn *vconn)
169 {
170     struct tcp_vconn *tcp = tcp_vconn_cast(vconn);
171     return check_connection_completion(tcp->fd);
172 }
173
174 static int
175 tcp_recv(struct vconn *vconn, struct buffer **bufferp)
176 {
177     struct tcp_vconn *tcp = tcp_vconn_cast(vconn);
178     struct buffer *rx;
179     size_t want_bytes;
180     ssize_t retval;
181
182     if (tcp->rxbuf == NULL) {
183         tcp->rxbuf = buffer_new(1564);
184     }
185     rx = tcp->rxbuf;
186
187 again:
188     if (sizeof(struct ofp_header) > rx->size) {
189         want_bytes = sizeof(struct ofp_header) - rx->size;
190     } else {
191         struct ofp_header *oh = rx->data;
192         size_t length = ntohs(oh->length);
193         if (length < sizeof(struct ofp_header)) {
194             VLOG_ERR("received too-short ofp_header (%zu bytes)", length);
195             return EPROTO;
196         }
197         want_bytes = length - rx->size;
198         if (!want_bytes) {
199             *bufferp = rx;
200             tcp->rxbuf = NULL;
201             return 0;
202         }
203     }
204     buffer_prealloc_tailroom(rx, want_bytes);
205
206     retval = read(tcp->fd, buffer_tail(rx), want_bytes);
207     if (retval > 0) {
208         rx->size += retval;
209         if (retval == want_bytes) {
210             if (rx->size > sizeof(struct ofp_header)) {
211                 *bufferp = rx;
212                 tcp->rxbuf = NULL;
213                 return 0;
214             } else {
215                 goto again;
216             }
217         }
218         return EAGAIN;
219     } else if (retval == 0) {
220         if (rx->size) {
221             VLOG_ERR("connection dropped mid-packet");
222             return EPROTO;
223         } else {
224             return EOF; 
225         }
226     } else {
227         return retval ? errno : EAGAIN;
228     }
229 }
230
231 static void
232 tcp_clear_txbuf(struct tcp_vconn *tcp)
233 {
234     buffer_delete(tcp->txbuf);
235     tcp->txbuf = NULL;
236     tcp->tx_waiter = NULL;
237 }
238
239 static void
240 tcp_do_tx(int fd UNUSED, short int revents UNUSED, void *vconn_)
241 {
242     struct vconn *vconn = vconn_;
243     struct tcp_vconn *tcp = tcp_vconn_cast(vconn);
244     ssize_t n = write(tcp->fd, tcp->txbuf->data, tcp->txbuf->size);
245     if (n < 0) {
246         if (errno != EAGAIN) {
247             VLOG_ERR("send: %s", strerror(errno));
248             tcp_clear_txbuf(tcp);
249             return;
250         }
251     } else if (n > 0) {
252         buffer_pull(tcp->txbuf, n);
253         if (!tcp->txbuf->size) {
254             tcp_clear_txbuf(tcp);
255             return;
256         }
257     }
258     tcp->tx_waiter = poll_fd_callback(tcp->fd, POLLOUT, tcp_do_tx, vconn);
259 }
260
261 static int
262 tcp_send(struct vconn *vconn, struct buffer *buffer)
263 {
264     struct tcp_vconn *tcp = tcp_vconn_cast(vconn);
265     ssize_t retval;
266
267     if (tcp->txbuf) {
268         return EAGAIN;
269     }
270
271     retval = write(tcp->fd, buffer->data, buffer->size);
272     if (retval == buffer->size) {
273         buffer_delete(buffer);
274         return 0;
275     } else if (retval >= 0 || errno == EAGAIN) {
276         tcp->txbuf = buffer;
277         if (retval > 0) {
278             buffer_pull(buffer, retval);
279         }
280         tcp->tx_waiter = poll_fd_callback(tcp->fd, POLLOUT, tcp_do_tx, vconn);
281         return 0;
282     } else {
283         return errno;
284     }
285 }
286
287 static void
288 tcp_wait(struct vconn *vconn, enum vconn_wait_type wait)
289 {
290     struct tcp_vconn *tcp = tcp_vconn_cast(vconn);
291     switch (wait) {
292     case WAIT_CONNECT:
293         poll_fd_wait(tcp->fd, POLLOUT);
294         break;
295
296     case WAIT_SEND:
297         if (!tcp->txbuf) {
298             poll_fd_wait(tcp->fd, POLLOUT);
299         } else {
300             /* Nothing to do: need to drain txbuf first. */
301         }
302         break;
303
304     case WAIT_RECV:
305         poll_fd_wait(tcp->fd, POLLIN);
306         break;
307
308     default:
309         NOT_REACHED();
310     }
311 }
312
313 struct vconn_class tcp_vconn_class = {
314     .name = "tcp",
315     .open = tcp_open,
316     .close = tcp_close,
317     .connect = tcp_connect,
318     .recv = tcp_recv,
319     .send = tcp_send,
320     .wait = tcp_wait,
321 };
322 \f
323 /* Passive TCP. */
324
325 struct ptcp_vconn
326 {
327     struct vconn vconn;
328     int fd;
329 };
330
331 static struct ptcp_vconn *
332 ptcp_vconn_cast(struct vconn *vconn)
333 {
334     assert(vconn->class == &ptcp_vconn_class);
335     return CONTAINER_OF(vconn, struct ptcp_vconn, vconn);
336 }
337
338 static int
339 ptcp_open(const char *name, char *suffix, struct vconn **vconnp)
340 {
341     struct sockaddr_in sin;
342     struct ptcp_vconn *ptcp;
343     int retval;
344     int fd;
345     unsigned int yes  = 1;
346
347     fd = socket(AF_INET, SOCK_STREAM, 0);
348     if (fd < 0) {
349         VLOG_ERR("%s: socket: %s", name, strerror(errno));
350         return errno;
351     }
352
353     if ( setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,&yes,sizeof(yes)) < 0) {
354         VLOG_ERR("%s: setsockopt::SO_REUSEADDR: %s", name, strerror(errno));
355         return errno;
356     }
357
358
359     memset(&sin, 0, sizeof sin);
360     sin.sin_family = AF_INET;
361     sin.sin_addr.s_addr = htonl(INADDR_ANY);
362     sin.sin_port = htons(atoi(suffix) ? atoi(suffix) : OFP_TCP_PORT);
363     retval = bind(fd, (struct sockaddr *) &sin, sizeof sin);
364     if (retval < 0) {
365         int error = errno;
366         VLOG_ERR("%s: bind: %s", name, strerror(error));
367         close(fd);
368         return error;
369     }
370
371     retval = listen(fd, 10);
372     if (retval < 0) {
373         int error = errno;
374         VLOG_ERR("%s: listen: %s", name, strerror(error));
375         close(fd);
376         return error;
377     }
378
379     retval = set_nonblocking(fd);
380     if (retval) {
381         close(fd);
382         return retval;
383     }
384
385     ptcp = xmalloc(sizeof *ptcp);
386     ptcp->vconn.class = &ptcp_vconn_class;
387     ptcp->vconn.connect_status = 0;
388     ptcp->fd = fd;
389     *vconnp = &ptcp->vconn;
390     return 0;
391 }
392
393 static void
394 ptcp_close(struct vconn *vconn)
395 {
396     struct ptcp_vconn *ptcp = ptcp_vconn_cast(vconn);
397     close(ptcp->fd);
398     free(ptcp);
399 }
400
401 static int
402 ptcp_accept(struct vconn *vconn, struct vconn **new_vconnp)
403 {
404     struct ptcp_vconn *ptcp = ptcp_vconn_cast(vconn);
405     struct sockaddr_in sin;
406     socklen_t sin_len = sizeof sin;
407     char name[128];
408     int new_fd;
409     int error;
410
411     new_fd = accept(ptcp->fd, &sin, &sin_len);
412     if (new_fd < 0) {
413         int error = errno;
414         if (error != EAGAIN) {
415             VLOG_DBG("accept: %s", strerror(error));
416         }
417         return error;
418     }
419
420     error = set_nonblocking(new_fd);
421     if (error) {
422         close(new_fd);
423         return error;
424     }
425
426     sprintf(name, "tcp:"IP_FMT, IP_ARGS(&sin.sin_addr));
427     if (sin.sin_port != htons(OFP_TCP_PORT)) {
428         sprintf(strchr(name, '\0'), ":%"PRIu16, ntohs(sin.sin_port));
429     }
430     return new_tcp_vconn(name, new_fd, 0, &sin, new_vconnp);
431 }
432
433 static void
434 ptcp_wait(struct vconn *vconn, enum vconn_wait_type wait)
435 {
436     struct ptcp_vconn *ptcp = ptcp_vconn_cast(vconn);
437     assert(wait == WAIT_ACCEPT);
438     poll_fd_wait(ptcp->fd, POLLIN);
439 }
440
441 struct vconn_class ptcp_vconn_class = {
442     .name = "ptcp",
443     .open = ptcp_open,
444     .close = ptcp_close,
445     .accept = ptcp_accept,
446     .wait = ptcp_wait
447 };
448