/* * This function is called for backends while they are connecting. * In here we check for write events and attempt to connect() to the * backend. * * Once a connection is established we set the backend handle function * pointer to the backend_handle_default() callback and setup the reads * for both the backend and the client connection we received. */ int backend_handle_connect(struct connection *c) { int ret; struct connection *src; /* We will get a write notification when we can progress. */ if (!(c->flags & CONN_WRITE_POSSIBLE)) return (KORE_RESULT_OK); kore_connection_stop_idletimer(c); /* Attempt connecting. */ ret = connect(c->fd, (struct sockaddr *)&c->addr.ipv4, sizeof(c->addr.ipv4)); /* If we failed check why, we are non blocking. */ if (ret == -1) { /* If we got a real error, disconnect. */ if (errno != EALREADY && errno != EINPROGRESS && errno != EISCONN) { kore_log(LOG_ERR, "connect(): %s", errno_s); return (KORE_RESULT_ERROR); } /* Clean the write flag, we'll be called later. */ if (errno != EISCONN) { c->flags &= ~CONN_WRITE_POSSIBLE; kore_connection_start_idletimer(c); return (KORE_RESULT_OK); } } /* The connection to the backend succeeded. */ c->handle = backend_handle_default; /* Setup read calls for both backend and its client. */ net_recv_queue(c, NETBUF_SEND_PAYLOAD_MAX, NETBUF_CALL_CB_ALWAYS, pipe_data); net_recv_queue(c->hdlr_extra, NETBUF_SEND_PAYLOAD_MAX, NETBUF_CALL_CB_ALWAYS, pipe_data); /* Allow for all events now. */ kore_connection_start_idletimer(c); kore_platform_event_all(c->fd, c); /* Allow events from source now. */ src = c->hdlr_extra; kore_platform_event_all(src->fd, src); /* Now lets start. */ return (c->handle(c)); }
void connection_setup(struct connection *c) { kore_log(LOG_NOTICE, "%p: new connection", c); /* * Setup a read command that will read up to 128 bytes and will * always call the callback connection_recv_data even if not all * 128 bytes were read. */ net_recv_queue(c, 128, NETBUF_CALL_CB_ALWAYS, connection_recv_data); /* We are responsible for setting the connection state. */ c->state = CONN_STATE_ESTABLISHED; /* Override the handle function, called when new events occur. */ c->handle = connection_handle; }
int kore_connection_handle(struct connection *c) { int r; u_int32_t len; const u_char *data; kore_debug("kore_connection_handle(%p)", c); if (c->proto != CONN_PROTO_SPDY) kore_connection_stop_idletimer(c); switch (c->state) { case CONN_STATE_SSL_SHAKE: if (c->ssl == NULL) { c->ssl = SSL_new(primary_dom->ssl_ctx); if (c->ssl == NULL) { kore_debug("SSL_new(): %s", ssl_errno_s); return (KORE_RESULT_ERROR); } SSL_set_fd(c->ssl, c->fd); SSL_set_accept_state(c->ssl); } r = SSL_accept(c->ssl); if (r <= 0) { r = SSL_get_error(c->ssl, r); switch (r) { case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: return (KORE_RESULT_OK); default: kore_debug("SSL_accept(): %s", ssl_errno_s); return (KORE_RESULT_ERROR); } } r = SSL_get_verify_result(c->ssl); if (r != X509_V_OK) { kore_debug("SSL_get_verify_result(): %s", ssl_errno_s); return (KORE_RESULT_ERROR); } SSL_get0_next_proto_negotiated(c->ssl, &data, &len); if (data) { if (!memcmp(data, "spdy/3", MIN(6, len))) { c->proto = CONN_PROTO_SPDY; net_recv_queue(c, SPDY_FRAME_SIZE, 0, NULL, spdy_frame_recv); } else if (!memcmp(data, "http/1.1", MIN(8, len))) { c->proto = CONN_PROTO_HTTP; net_recv_queue(c, HTTP_HEADER_MAX_LEN, NETBUF_CALL_CB_ALWAYS, NULL, http_header_recv); } else { kore_debug("npn: received unknown protocol"); } } else { c->proto = CONN_PROTO_HTTP; net_recv_queue(c, HTTP_HEADER_MAX_LEN, NETBUF_CALL_CB_ALWAYS, NULL, http_header_recv); } c->state = CONN_STATE_ESTABLISHED; /* FALLTHROUGH */ case CONN_STATE_ESTABLISHED: if (c->flags & CONN_READ_POSSIBLE) { if (!net_recv_flush(c)) return (KORE_RESULT_ERROR); } if (c->flags & CONN_WRITE_POSSIBLE) { if (!net_send_flush(c)) return (KORE_RESULT_ERROR); } break; case CONN_STATE_DISCONNECTING: break; default: kore_debug("unknown state on %d (%d)", c->fd, c->state); break; } if (c->proto != CONN_PROTO_SPDY) kore_connection_start_idletimer(c); return (KORE_RESULT_OK); }
/* * Connect to our target host:port and attach it to a struct connection that * Kore understands. We set the disconnect method so we get a callback * whenever either of the connections will go away so we can cleanup the * one it is attached to. */ static int ktunnel_pipe_create(struct connection *c, const char *host, const char *port) { struct sockaddr_in sin; struct connection *cpipe; u_int16_t nport; int fd, err; nport = kore_strtonum(port, 10, 1, SHRT_MAX, &err); if (err == KORE_RESULT_ERROR) { kore_log(LOG_ERR, "invalid port given %s", port); return (KORE_RESULT_ERROR); } if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { kore_log(LOG_ERR, "socket(): %s", errno_s); return (KORE_RESULT_ERROR); } memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(nport); sin.sin_addr.s_addr = inet_addr(host); kore_log(LOG_NOTICE, "Attempting to connect to %s:%s", host, port); if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) == -1) { close(fd); kore_log(LOG_ERR, "connect(): %s", errno_s); return (KORE_RESULT_ERROR); } if (!kore_connection_nonblock(fd)) { close(fd); return (KORE_RESULT_ERROR); } cpipe = kore_connection_new(c); cpipe->fd = fd; cpipe->addr.ipv4 = sin; cpipe->read = net_read; cpipe->write = net_write; cpipe->addrtype = AF_INET; cpipe->proto = CONN_PROTO_UNKNOWN; cpipe->state = CONN_STATE_ESTABLISHED; /* Don't let these connections timeout any time soon. */ cpipe->idle_timer.length = 10000000000; c->idle_timer.length = 10000000000; c->hdlr_extra = cpipe; cpipe->hdlr_extra = c; c->disconnect = ktunnel_pipe_disconnect; cpipe->disconnect = ktunnel_pipe_disconnect; kore_worker_connection_add(cpipe); kore_connection_start_idletimer(cpipe); kore_platform_event_all(cpipe->fd, cpipe); net_recv_reset(c, NETBUF_SEND_PAYLOAD_MAX, ktunnel_pipe_data); net_recv_queue(cpipe, NETBUF_SEND_PAYLOAD_MAX, NETBUF_CALL_CB_ALWAYS, ktunnel_pipe_data); printf("connection started to %s (%p -> %p)\n", host, c, cpipe); return (KORE_RESULT_OK); }