static int ssl_connect(struct stream *stream) { struct ssl_stream *sslv = ssl_stream_cast(stream); int retval; switch (sslv->state) { case STATE_TCP_CONNECTING: retval = check_connection_completion(sslv->fd); if (retval) { return retval; } sslv->state = STATE_SSL_CONNECTING; setsockopt_tcp_nodelay(sslv->fd); /* Fall through. */ case STATE_SSL_CONNECTING: /* Capture the first few bytes of received data so that we can guess * what kind of funny data we've been sent if SSL negotiation fails. */ if (sslv->n_head <= 0) { sslv->n_head = recv(sslv->fd, sslv->head, sizeof sslv->head, MSG_PEEK); } retval = (sslv->type == CLIENT ? SSL_connect(sslv->ssl) : SSL_accept(sslv->ssl)); if (retval != 1) { int error = SSL_get_error(sslv->ssl, retval); if (retval < 0 && ssl_wants_io(error)) { return EAGAIN; } else { int unused; interpret_ssl_error((sslv->type == CLIENT ? "SSL_connect" : "SSL_accept"), retval, error, &unused); shutdown(sslv->fd, SHUT_RDWR); stream_report_content(sslv->head, sslv->n_head, STREAM_SSL, THIS_MODULE, stream_get_name(stream)); return EPROTO; } } else if (bootstrap_ca_cert) { return do_ca_cert_bootstrap(stream); } else if (verify_peer_cert && ((SSL_get_verify_mode(sslv->ssl) & (SSL_VERIFY_NONE | SSL_VERIFY_PEER)) != SSL_VERIFY_PEER)) { /* Two or more SSL connections completed at the same time while we * were in bootstrap mode. Only one of these can finish the * bootstrap successfully. The other one(s) must be rejected * because they were not verified against the bootstrapped CA * certificate. (Alternatively we could verify them against the CA * certificate, but that's more trouble than it's worth. These * connections will succeed the next time they retry, assuming that * they have a certificate against the correct CA.) */ VLOG_INFO("rejecting SSL connection during bootstrap race window"); return EPROTO; } else { return 0; } } OVS_NOT_REACHED(); }
/* Attempts to receive a message from 'rpc'. * * If successful, stores the received message in '*msgp' and returns 0. The * caller takes ownership of '*msgp' and must eventually destroy it with * jsonrpc_msg_destroy(). * * Otherwise, stores NULL in '*msgp' and returns one of the following: * * - EAGAIN: No message has been received. * * - EOF: The remote end closed the connection gracefully. * * - Otherwise an errno value that represents a JSON-RPC protocol violation * or another error fatal to the connection. 'rpc' will not send or * receive any more messages. */ int jsonrpc_recv(struct jsonrpc *rpc, struct jsonrpc_msg **msgp) { int i; *msgp = NULL; if (rpc->status) { return rpc->status; } for (i = 0; i < 50; i++) { if (rpc->received) { *msgp = rpc->received; rpc->received = NULL; return 0; } else if (byteq_is_empty(&rpc->input)) { size_t chunk; int retval; chunk = byteq_headroom(&rpc->input); retval = stream_recv(rpc->stream, byteq_head(&rpc->input), chunk); if (retval < 0) { if (retval == -EAGAIN) { return EAGAIN; } else { VLOG_WARN_RL(&rl, "%s: receive error: %s", rpc->name, ovs_strerror(-retval)); jsonrpc_error(rpc, -retval); return rpc->status; } } else if (retval == 0) { jsonrpc_error(rpc, EOF); return EOF; } byteq_advance_head(&rpc->input, retval); } else { size_t n, used; if (!rpc->parser) { rpc->parser = json_parser_create(0); } n = byteq_tailroom(&rpc->input); used = json_parser_feed(rpc->parser, (char *) byteq_tail(&rpc->input), n); byteq_advance_tail(&rpc->input, used); if (json_parser_is_done(rpc->parser)) { jsonrpc_received(rpc); if (rpc->status) { const struct byteq *q = &rpc->input; if (q->head <= q->size) { stream_report_content(q->buffer, q->head, STREAM_JSONRPC, THIS_MODULE, rpc->name); } return rpc->status; } } } } return EAGAIN; }
/* Attempts to receive a message from 'rpc'. * * If successful, stores the received message in '*msgp' and returns 0. The * caller takes ownership of '*msgp' and must eventually destroy it with * jsonrpc_msg_destroy(). * * Otherwise, stores NULL in '*msgp' and returns one of the following: * * - EAGAIN: No message has been received. * * - EOF: The remote end closed the connection gracefully. * * - Otherwise an errno value that represents a JSON-RPC protocol violation * or another error fatal to the connection. 'rpc' will not send or * receive any more messages. */ int jsonrpc_recv(struct jsonrpc *rpc, struct jsonrpc_msg **msgp) { int i; *msgp = NULL; if (rpc->status) { return rpc->status; } for (i = 0; i < 50; i++) { size_t n, used; /* Fill our input buffer if it's empty. */ if (byteq_is_empty(&rpc->input)) { size_t chunk; int retval; chunk = byteq_headroom(&rpc->input); retval = stream_recv(rpc->stream, byteq_head(&rpc->input), chunk); if (retval < 0) { if (retval == -EAGAIN) { return EAGAIN; } else { VLOG_WARN_RL(&rl, "%s: receive error: %s", rpc->name, ovs_strerror(-retval)); jsonrpc_error(rpc, -retval); return rpc->status; } } else if (retval == 0) { jsonrpc_error(rpc, EOF); return EOF; } byteq_advance_head(&rpc->input, retval); } /* We have some input. Feed it into the JSON parser. */ if (!rpc->parser) { rpc->parser = json_parser_create(0); } n = byteq_tailroom(&rpc->input); used = json_parser_feed(rpc->parser, (char *) byteq_tail(&rpc->input), n); byteq_advance_tail(&rpc->input, used); /* If we have complete JSON, attempt to parse it as JSON-RPC. */ if (json_parser_is_done(rpc->parser)) { *msgp = jsonrpc_parse_received_message(rpc); if (*msgp) { return 0; } if (rpc->status) { const struct byteq *q = &rpc->input; if (q->head <= q->size) { stream_report_content(q->buffer, q->head, STREAM_JSONRPC, THIS_MODULE, rpc->name); } return rpc->status; } } } return EAGAIN; }