]> git.proxmox.com Git - ovs.git/blame - lib/vconn-stream.c
json: Fix error message for corner case in json_string_unescape().
[ovs.git] / lib / vconn-stream.c
CommitLineData
064af421 1/*
10a89ef0 2 * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
064af421 3 *
a14bc59f
BP
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
064af421 7 *
a14bc59f
BP
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
064af421
BP
15 */
16
17#include <config.h>
064af421
BP
18#include <errno.h>
19#include <poll.h>
20#include <stdlib.h>
21#include <string.h>
22#include <sys/types.h>
23#include <unistd.h>
56192221 24#include "fatal-signal.h"
064af421
BP
25#include "ofpbuf.h"
26#include "openflow/openflow.h"
27#include "poll-loop.h"
28#include "socket-util.h"
fe55ad15 29#include "stream.h"
064af421
BP
30#include "util.h"
31#include "vconn-provider.h"
4a1f523f 32#include "openvswitch/vconn.h"
e6211adc 33#include "openvswitch/vlog.h"
5136ce49 34
d98e6007 35VLOG_DEFINE_THIS_MODULE(vconn_stream);
064af421
BP
36
37/* Active stream socket vconn. */
38
fe55ad15 39struct vconn_stream
064af421
BP
40{
41 struct vconn vconn;
fe55ad15 42 struct stream *stream;
064af421
BP
43 struct ofpbuf *rxbuf;
44 struct ofpbuf *txbuf;
1e3c0047 45 int n_packets;
064af421
BP
46};
47
5b712636 48static const struct vconn_class stream_vconn_class;
064af421
BP
49
50static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(10, 25);
51
fe55ad15 52static void vconn_stream_clear_txbuf(struct vconn_stream *);
064af421 53
fe55ad15 54static struct vconn *
7a25bd99
SH
55vconn_stream_new(struct stream *stream, int connect_status,
56 uint32_t allowed_versions)
064af421 57{
fe55ad15 58 struct vconn_stream *s;
064af421
BP
59
60 s = xmalloc(sizeof *s);
fe55ad15 61 vconn_init(&s->vconn, &stream_vconn_class, connect_status,
7a25bd99 62 stream_get_name(stream), allowed_versions);
fe55ad15 63 s->stream = stream;
064af421 64 s->txbuf = NULL;
064af421 65 s->rxbuf = NULL;
1e3c0047 66 s->n_packets = 0;
fe55ad15
BP
67 return &s->vconn;
68}
69
70/* Creates a new vconn that will send and receive data on a stream named 'name'
71 * and stores a pointer to the vconn in '*vconnp'.
72 *
73 * Returns 0 if successful, otherwise a positive errno value. */
74static int
7a25bd99
SH
75vconn_stream_open(const char *name, uint32_t allowed_versions,
76 char *suffix OVS_UNUSED, struct vconn **vconnp, uint8_t dscp)
fe55ad15
BP
77{
78 struct stream *stream;
fe55ad15
BP
79 int error;
80
d4763d1d 81 error = stream_open_with_default_port(name, OFP_PORT, &stream, dscp);
b0bfeb3e
BP
82 if (!error) {
83 error = stream_connect(stream);
84 if (!error || error == EAGAIN) {
7a25bd99 85 *vconnp = vconn_stream_new(stream, error, allowed_versions);
b0bfeb3e
BP
86 return 0;
87 }
fe55ad15
BP
88 }
89
b0bfeb3e
BP
90 stream_close(stream);
91 return error;
064af421
BP
92}
93
fe55ad15
BP
94static struct vconn_stream *
95vconn_stream_cast(struct vconn *vconn)
064af421 96{
fe55ad15 97 return CONTAINER_OF(vconn, struct vconn_stream, vconn);
064af421
BP
98}
99
100static void
fe55ad15 101vconn_stream_close(struct vconn *vconn)
064af421 102{
fe55ad15 103 struct vconn_stream *s = vconn_stream_cast(vconn);
1e3c0047
BP
104
105 if ((vconn->error == EPROTO || s->n_packets < 1) && s->rxbuf) {
6fd6ed71 106 stream_report_content(s->rxbuf->data, s->rxbuf->size, STREAM_OPENFLOW,
1e3c0047
BP
107 THIS_MODULE, vconn_get_name(vconn));
108 }
109
fe55ad15
BP
110 stream_close(s->stream);
111 vconn_stream_clear_txbuf(s);
064af421 112 ofpbuf_delete(s->rxbuf);
064af421
BP
113 free(s);
114}
115
116static int
fe55ad15 117vconn_stream_connect(struct vconn *vconn)
064af421 118{
fe55ad15
BP
119 struct vconn_stream *s = vconn_stream_cast(vconn);
120 return stream_connect(s->stream);
064af421
BP
121}
122
123static int
c088c3be 124vconn_stream_recv__(struct vconn_stream *s, int rx_len)
064af421 125{
c088c3be
BP
126 struct ofpbuf *rx = s->rxbuf;
127 int want_bytes, retval;
064af421 128
6fd6ed71 129 want_bytes = rx_len - rx->size;
064af421 130 ofpbuf_prealloc_tailroom(rx, want_bytes);
fe55ad15 131 retval = stream_recv(s->stream, ofpbuf_tail(rx), want_bytes);
064af421 132 if (retval > 0) {
6fd6ed71 133 rx->size += retval;
c088c3be 134 return retval == want_bytes ? 0 : EAGAIN;
064af421 135 } else if (retval == 0) {
6fd6ed71 136 if (rx->size) {
064af421
BP
137 VLOG_ERR_RL(&rl, "connection dropped mid-packet");
138 return EPROTO;
064af421 139 }
c088c3be 140 return EOF;
064af421 141 } else {
fe55ad15 142 return -retval;
064af421
BP
143 }
144}
145
c088c3be
BP
146static int
147vconn_stream_recv(struct vconn *vconn, struct ofpbuf **bufferp)
148{
149 struct vconn_stream *s = vconn_stream_cast(vconn);
150 const struct ofp_header *oh;
151 int rx_len;
152
153 /* Allocate new receive buffer if we don't have one. */
154 if (s->rxbuf == NULL) {
155 s->rxbuf = ofpbuf_new(1564);
156 }
157
158 /* Read ofp_header. */
6fd6ed71 159 if (s->rxbuf->size < sizeof(struct ofp_header)) {
c088c3be
BP
160 int retval = vconn_stream_recv__(s, sizeof(struct ofp_header));
161 if (retval) {
162 return retval;
163 }
164 }
165
166 /* Read payload. */
6fd6ed71 167 oh = s->rxbuf->data;
c088c3be
BP
168 rx_len = ntohs(oh->length);
169 if (rx_len < sizeof(struct ofp_header)) {
b56042ac 170 VLOG_ERR_RL(&rl, "received too-short ofp_header (%d bytes)", rx_len);
c088c3be 171 return EPROTO;
6fd6ed71 172 } else if (s->rxbuf->size < rx_len) {
c088c3be
BP
173 int retval = vconn_stream_recv__(s, rx_len);
174 if (retval) {
175 return retval;
176 }
177 }
178
1e3c0047 179 s->n_packets++;
c088c3be
BP
180 *bufferp = s->rxbuf;
181 s->rxbuf = NULL;
182 return 0;
183}
184
064af421 185static void
fe55ad15 186vconn_stream_clear_txbuf(struct vconn_stream *s)
064af421
BP
187{
188 ofpbuf_delete(s->txbuf);
189 s->txbuf = NULL;
064af421
BP
190}
191
192static int
fe55ad15 193vconn_stream_send(struct vconn *vconn, struct ofpbuf *buffer)
064af421 194{
fe55ad15 195 struct vconn_stream *s = vconn_stream_cast(vconn);
064af421
BP
196 ssize_t retval;
197
198 if (s->txbuf) {
199 return EAGAIN;
200 }
201
6fd6ed71
PS
202 retval = stream_send(s->stream, buffer->data, buffer->size);
203 if (retval == buffer->size) {
064af421
BP
204 ofpbuf_delete(buffer);
205 return 0;
fe55ad15 206 } else if (retval >= 0 || retval == -EAGAIN) {
064af421
BP
207 s->txbuf = buffer;
208 if (retval > 0) {
209 ofpbuf_pull(buffer, retval);
210 }
064af421
BP
211 return 0;
212 } else {
fe55ad15 213 return -retval;
064af421
BP
214 }
215}
216
60cb3eb8 217static void
fe55ad15 218vconn_stream_run(struct vconn *vconn)
60cb3eb8 219{
fe55ad15
BP
220 struct vconn_stream *s = vconn_stream_cast(vconn);
221 ssize_t retval;
60cb3eb8 222
12d68589 223 stream_run(s->stream);
60cb3eb8
BP
224 if (!s->txbuf) {
225 return;
226 }
227
6fd6ed71 228 retval = stream_send(s->stream, s->txbuf->data, s->txbuf->size);
fe55ad15
BP
229 if (retval < 0) {
230 if (retval != -EAGAIN) {
10a89ef0 231 VLOG_ERR_RL(&rl, "send: %s", ovs_strerror(-retval));
fe55ad15 232 vconn_stream_clear_txbuf(s);
60cb3eb8
BP
233 return;
234 }
fe55ad15
BP
235 } else if (retval > 0) {
236 ofpbuf_pull(s->txbuf, retval);
6fd6ed71 237 if (!s->txbuf->size) {
fe55ad15 238 vconn_stream_clear_txbuf(s);
60cb3eb8
BP
239 return;
240 }
241 }
242}
243
244static void
fe55ad15 245vconn_stream_run_wait(struct vconn *vconn)
60cb3eb8 246{
fe55ad15 247 struct vconn_stream *s = vconn_stream_cast(vconn);
60cb3eb8 248
12d68589 249 stream_run_wait(s->stream);
60cb3eb8 250 if (s->txbuf) {
fe55ad15 251 stream_send_wait(s->stream);
60cb3eb8
BP
252 }
253}
254
064af421 255static void
fe55ad15 256vconn_stream_wait(struct vconn *vconn, enum vconn_wait_type wait)
064af421 257{
fe55ad15 258 struct vconn_stream *s = vconn_stream_cast(vconn);
064af421
BP
259 switch (wait) {
260 case WAIT_CONNECT:
fe55ad15 261 stream_connect_wait(s->stream);
064af421
BP
262 break;
263
264 case WAIT_SEND:
265 if (!s->txbuf) {
fe55ad15 266 stream_send_wait(s->stream);
064af421 267 } else {
fe55ad15
BP
268 /* Nothing to do: need to drain txbuf first.
269 * vconn_stream_run_wait() will arrange to wake up when there room
270 * to send data, so there's no point in calling poll_fd_wait()
271 * redundantly here. */
064af421
BP
272 }
273 break;
274
275 case WAIT_RECV:
fe55ad15 276 stream_recv_wait(s->stream);
064af421
BP
277 break;
278
279 default:
428b2edd 280 OVS_NOT_REACHED();
064af421
BP
281 }
282}
064af421
BP
283\f
284/* Passive stream socket vconn. */
285
fe55ad15 286struct pvconn_pstream
064af421
BP
287{
288 struct pvconn pvconn;
fe55ad15 289 struct pstream *pstream;
064af421
BP
290};
291
5b712636 292static const struct pvconn_class pstream_pvconn_class;
064af421 293
fe55ad15
BP
294static struct pvconn_pstream *
295pvconn_pstream_cast(struct pvconn *pvconn)
064af421 296{
fe55ad15 297 return CONTAINER_OF(pvconn, struct pvconn_pstream, pvconn);
064af421
BP
298}
299
fe55ad15
BP
300/* Creates a new pvconn named 'name' that will accept new connections using
301 * pstream_accept() and stores a pointer to the pvconn in '*pvconnp'.
56192221
BP
302 *
303 * Returns 0 if successful, otherwise a positive errno value. (The current
304 * implementation never fails.) */
fe55ad15 305static int
7a25bd99
SH
306pvconn_pstream_listen(const char *name, uint32_t allowed_versions,
307 char *suffix OVS_UNUSED, struct pvconn **pvconnp,
308 uint8_t dscp)
064af421 309{
fe55ad15
BP
310 struct pvconn_pstream *ps;
311 struct pstream *pstream;
fe55ad15
BP
312 int error;
313
d4763d1d 314 error = pstream_open_with_default_port(name, OFP_PORT, &pstream, dscp);
fe55ad15
BP
315 if (error) {
316 return error;
317 }
318
319 ps = xmalloc(sizeof *ps);
7a25bd99 320 pvconn_init(&ps->pvconn, &pstream_pvconn_class, name, allowed_versions);
fe55ad15 321 ps->pstream = pstream;
064af421
BP
322 *pvconnp = &ps->pvconn;
323 return 0;
324}
325
326static void
fe55ad15 327pvconn_pstream_close(struct pvconn *pvconn)
064af421 328{
fe55ad15
BP
329 struct pvconn_pstream *ps = pvconn_pstream_cast(pvconn);
330 pstream_close(ps->pstream);
064af421
BP
331 free(ps);
332}
333
334static int
fe55ad15 335pvconn_pstream_accept(struct pvconn *pvconn, struct vconn **new_vconnp)
064af421 336{
fe55ad15
BP
337 struct pvconn_pstream *ps = pvconn_pstream_cast(pvconn);
338 struct stream *stream;
339 int error;
340
341 error = pstream_accept(ps->pstream, &stream);
342 if (error) {
343 if (error != EAGAIN) {
344 VLOG_DBG_RL(&rl, "%s: accept: %s",
10a89ef0 345 pstream_get_name(ps->pstream), ovs_strerror(error));
064af421 346 }
fe55ad15 347 return error;
064af421
BP
348 }
349
7a25bd99 350 *new_vconnp = vconn_stream_new(stream, 0, pvconn->allowed_versions);
fe55ad15 351 return 0;
064af421
BP
352}
353
354static void
fe55ad15 355pvconn_pstream_wait(struct pvconn *pvconn)
064af421 356{
fe55ad15
BP
357 struct pvconn_pstream *ps = pvconn_pstream_cast(pvconn);
358 pstream_wait(ps->pstream);
064af421 359}
56192221 360\f
fe55ad15
BP
361/* Stream-based vconns and pvconns. */
362
740bc6a4
BP
363#define STREAM_INIT(NAME) \
364 { \
365 NAME, \
fe55ad15
BP
366 vconn_stream_open, \
367 vconn_stream_close, \
368 vconn_stream_connect, \
369 vconn_stream_recv, \
370 vconn_stream_send, \
371 vconn_stream_run, \
372 vconn_stream_run_wait, \
373 vconn_stream_wait, \
740bc6a4 374 }
fe55ad15 375
740bc6a4
BP
376#define PSTREAM_INIT(NAME) \
377 { \
378 NAME, \
fe55ad15
BP
379 pvconn_pstream_listen, \
380 pvconn_pstream_close, \
381 pvconn_pstream_accept, \
382 pvconn_pstream_wait \
740bc6a4 383 }
fe55ad15 384
5b712636
BP
385static const struct vconn_class stream_vconn_class = STREAM_INIT("stream");
386static const struct pvconn_class pstream_pvconn_class = PSTREAM_INIT("pstream");
fe55ad15 387
5b712636
BP
388const struct vconn_class tcp_vconn_class = STREAM_INIT("tcp");
389const struct pvconn_class ptcp_pvconn_class = PSTREAM_INIT("ptcp");
fe55ad15 390
5b712636
BP
391const struct vconn_class unix_vconn_class = STREAM_INIT("unix");
392const struct pvconn_class punix_pvconn_class = PSTREAM_INIT("punix");
fe55ad15
BP
393
394#ifdef HAVE_OPENSSL
5b712636
BP
395const struct vconn_class ssl_vconn_class = STREAM_INIT("ssl");
396const struct pvconn_class pssl_pvconn_class = PSTREAM_INIT("pssl");
fe55ad15 397#endif