static void client_handler(struct ns_connection *conn, enum ns_event ev, void *p) { struct iobuf *io = &conn->recv_iobuf; (void) p; if (ev == NS_CONNECT) { if (conn->flags & NSF_CLOSE_IMMEDIATELY) { printf("%s\n", "Error connecting to server!"); exit(EXIT_FAILURE); } printf("%s\n", "Connected to server. Type a message and press enter."); } else if (ev == NS_RECV) { if (conn->flags & NSF_USER_1) { // Received data from the stdin, forward it to the server struct ns_connection *c = (struct ns_connection *) conn->user_data; ns_send(c, io->buf, io->len); iobuf_remove(io, io->len); } else { // Received data from server connection, print it fwrite(io->buf, io->len, 1, stdout); iobuf_remove(io, io->len); } } else if (ev == NS_CLOSE) { // Connection has closed, most probably cause server has stopped exit(EXIT_SUCCESS); } }
static void ns_write_to_socket(struct ns_connection *conn) { struct iobuf *io = &conn->send_iobuf; int n = 0; #ifdef NS_ENABLE_SSL if (conn->ssl != NULL) { n = SSL_write(conn->ssl, io->buf, io->len); if (n <= 0) { int ssl_err = ns_ssl_err(conn, n); if (ssl_err == SSL_ERROR_WANT_READ || ssl_err == SSL_ERROR_WANT_WRITE) { return; /* Call us again */ } else { conn->flags |= NSF_CLOSE_IMMEDIATELY; } } } else #endif { n = (int) send(conn->sock, io->buf, io->len, 0); } DBG(("%p %lu -> %d bytes", conn, conn->flags, n)); ns_call(conn, NS_SEND, &n); if (ns_is_error(n)) { conn->flags |= NSF_CLOSE_IMMEDIATELY; } else if (n > 0) { iobuf_remove(io, n); } }
static void choose_backend(struct ns_connection *nc) { struct http_message hm; struct iobuf *io = &nc->recv_iobuf; int req_len = ns_parse_http(io->buf, io->len, &hm); if (req_len < 0 || (req_len == 0 && io->len >= NS_MAX_HTTP_REQUEST_SIZE)) { /* Invalid, or too large request */ nc->flags |= NSF_CLOSE_IMMEDIATELY; } else if (req_len == 0) { /* Do nothing, request is not yet fully buffered */ } else { /* * Got HTTP request, look which backend to use. Round-robin over the * backends with the same uri_prefix and vhost. */ struct ns_str vhost = *ns_get_http_header(&hm, "host"); const char *vhost_end = vhost.p; while(vhost_end < vhost.p + vhost.len && *vhost_end != ':') { vhost_end++; } vhost.len = vhost_end - vhost.p; int i, chosen = -1; for (i = 0; i < s_num_http_backends; i++) { if (has_prefix(&hm.uri, s_http_backends[i].uri_prefix) && matches_vhost(&vhost, s_http_backends[i].vhost) && (chosen == -1 || s_http_backends[i].usage_counter < s_http_backends[chosen].usage_counter)) { chosen = i; } } if (chosen == -1) { /* No backend with given uri_prefix found, bail out */ ns_printf(nc, "%s%s\r\n", s_error_404, s_content_len_0); } else if (s_http_backends[chosen].redirect != 0) { ns_printf(nc, "HTTP/1.1 302 Found\r\nLocation: %s\r\n\r\n", s_http_backends[chosen].host_port); nc->flags |= NSF_SEND_AND_CLOSE; } else if ((nc->proto_data = ns_connect(nc->mgr, s_http_backends[chosen].host_port, ev_handler)) == NULL) { /* Connection to backend failed */ ns_printf(nc, "%s%s\r\n", s_error_500, s_content_len_0); } else { /* * Forward request to the backend. Note that we can insert extra headers * to pass information to the backend. * Store backend index as user_data for the backend connection. */ ((struct ns_connection *) nc->proto_data)->proto_data = nc; ((struct ns_connection *) nc->proto_data)->user_data = (void *) (long) chosen; s_http_backends[chosen].usage_counter++; ns_send(nc->proto_data, io->buf, io->len); iobuf_remove(io, io->len); } } }
static void js_discard(struct v7 *v7, struct v7_val *this_obj, struct v7_val *result, struct v7_val **args, int num_args) { struct ns_connection *nc = get_nc(this_obj); (void) v7; (void) result; if (num_args == 1 && args[0]->type == V7_NUM) { iobuf_remove(&nc->recv_iobuf, args[0]->v.num); } }
static void ev_handler(struct ns_connection *nc, int ev, void *p) { struct iobuf *io = &nc->recv_iobuf; (void) p; switch (ev) { case NS_RECV: ns_send(nc, io->buf, io->len); // Echo message back iobuf_remove(io, io->len); // Discard message from recv buffer break; default: break; } }
static void server_handler(struct ns_connection *nc, enum ns_event ev, void *p) { (void) p; if (ev == NS_RECV) { // Push received message to all ncections struct iobuf *io = &nc->recv_iobuf; struct ns_connection *c; for (c = ns_next(nc->mgr, NULL); c != NULL; c = ns_next(nc->mgr, c)) { ns_send(c, io->buf, io->len); } iobuf_remove(io, io->len); } }
static void eh1(struct ns_connection *nc, int ev, void *ev_data) { struct iobuf *io = &nc->recv_iobuf; switch (ev) { case NS_CONNECT: ns_printf(nc, "%d %s there", * (int *) ev_data, "hi"); break; case NS_RECV: if (nc->listener != NULL) { ns_printf(nc, "%d", (int) io->len); iobuf_remove(io, io->len); } else if (io->len == 2 && memcmp(io->buf, "10", 2) == 0) { sprintf((char *) nc->user_data, "%s", "ok!"); nc->flags |= NSF_CLOSE_IMMEDIATELY; } break; default: break; } }
static void ev_handler(struct ns_connection *nc, int ev, void *ev_data) { struct iobuf *io = &nc->recv_iobuf; struct ns_connection *peer = (struct ns_connection *) nc->proto_data; switch (ev) { case NS_CONNECT: if (* (int *) ev_data != 0) { /* TODO(lsm): mark backend as defunct, try it later on */ fprintf(stderr, "connect(%s) failed\n", s_http_backends[(int) nc->user_data].host_port); ns_printf(nc->proto_data, "%s%s\r\n", s_error_500, s_content_len_0); } break; case NS_RECV: /* * For incoming client connection, nc->proto_data points to the respective * backend connection. For backend connection, nc->proto_data points * to the respective incoming client connection. */ if (peer == NULL) { choose_backend(nc); } else { /* Forward data to peer */ ns_send(peer, io->buf, io->len); iobuf_remove(io, io->len); } break; case NS_CLOSE: /* We're closing, detach our peer */ if (peer != NULL) { peer->proto_data = NULL; peer->flags |= NSF_SEND_AND_CLOSE; } break; } }
void uv_custom_poll_cb(uv_poll_t *req, int status, int events) { /* * Make sure we execute in the main thread */ const uv_thread_t pth_cur_id = uv_thread_self(); assert(uv_thread_equal(&pth_main_id, &pth_cur_id)); struct uv_custom_poll_t *custom_poll_data = NULL; struct iobuf_t *send_io = NULL; char buffer[BUFFER_SIZE]; uv_os_fd_t fd = 0; long int fromlen = 0; int r = 0, n = 0; custom_poll_data = req->data; if(custom_poll_data == NULL) { uv_poll_stop(req); return; } /* * Status == -9: Socket is unreachable * Events == 0: Client-end got disconnected */ r = uv_fileno((uv_handle_t *)req, &fd); if(status < 0 || events == 0) { if(status == -9) { logprintf(LOG_ERR, "uv_custom_poll_cb: socket not responding"); } else { logprintf(LOG_ERR, "uv_custom_poll_cb: %s", uv_strerror(status)); } if(custom_poll_data->close_cb != NULL) { custom_poll_data->close_cb(req); } if(!uv_is_closing((uv_handle_t *)req)) { uv_poll_stop(req); } if(fd > 0) { close(fd); } return; } custom_poll_data->started = 1; send_io = &custom_poll_data->send_iobuf; memset(&buffer, 0, BUFFER_SIZE); if(uv_is_closing((uv_handle_t *)req)) { return; } r = uv_fileno((uv_handle_t *)req, &fd); if(r != 0) { logprintf(LOG_ERR, "uv_fileno: %s", uv_strerror(r)); return; } if(custom_poll_data->is_ssl == 1 && custom_poll_data->ssl.init == 0) { custom_poll_data->ssl.init = 1; struct mbedtls_ssl_config *ssl_conf = &ssl_client_conf; if(custom_poll_data->is_server == 1) { custom_poll_data->ssl.handshake = 1; ssl_conf = &ssl_server_conf; } if((r = mbedtls_ssl_setup(&custom_poll_data->ssl.ctx, ssl_conf)) < 0) { mbedtls_strerror(r, (char *)&buffer, BUFFER_SIZE); logprintf(LOG_ERR, "mbedtls_ssl_setup: %s", buffer); FREE(req); return; } if((r = mbedtls_ssl_session_reset(&custom_poll_data->ssl.ctx)) < 0) { mbedtls_strerror(r, (char *)&buffer, BUFFER_SIZE); logprintf(LOG_ERR, "mbedtls_ssl_session_reset: %s", buffer); FREE(req); return; } // mbedtls_debug_set_threshold(2); mbedtls_ssl_set_bio(&custom_poll_data->ssl.ctx, &fd, mbedtls_net_send, mbedtls_net_recv, NULL); mbedtls_ssl_conf_dbg(ssl_conf, my_debug, stdout); if(custom_poll_data->host != NULL) { mbedtls_ssl_set_hostname(&custom_poll_data->ssl.ctx, custom_poll_data->host); } } if(custom_poll_data->is_ssl == 1 && custom_poll_data->ssl.handshake == 0) { n = mbedtls_ssl_handshake(&custom_poll_data->ssl.ctx); if(n == MBEDTLS_ERR_SSL_WANT_READ) { custom_poll_data->doread = 1; custom_poll_data->dowrite = 0; goto end; } else if(n == MBEDTLS_ERR_SSL_WANT_WRITE) { /*LCOV_EXCL_START*/ custom_poll_data->dowrite = 1; custom_poll_data->doread = 0; goto end; /*LCOV_EXCL_STOP*/ } if(n == MBEDTLS_ERR_SSL_WANT_READ || n == MBEDTLS_ERR_SSL_WANT_WRITE) { } else if(n < 0) { /*LCOV_EXCL_START*/ mbedtls_strerror(n, (char *)&buffer, BUFFER_SIZE); logprintf(LOG_NOTICE, "mbedtls_ssl_handshake: %s", buffer); uv_poll_stop(req); return; /*LCOV_EXCL_STOP*/ } else { custom_poll_data->ssl.handshake = 1; } custom_poll_data->dowrite = 1; goto end; } if(events & UV_WRITABLE) { if(send_io->len > 0) { if(custom_poll_data->is_ssl == 1) { n = mbedtls_ssl_write(&custom_poll_data->ssl.ctx, (unsigned char *)send_io->buf, send_io->len); if(n == MBEDTLS_ERR_SSL_WANT_READ) { /*LCOV_EXCL_START*/ custom_poll_data->doread = 1; custom_poll_data->dowrite = 0; goto end; /*LCOV_EXCL_STOP*/ } else if(n == MBEDTLS_ERR_SSL_WANT_WRITE) { /*LCOV_EXCL_START*/ custom_poll_data->dowrite = 1; custom_poll_data->doread = 0; goto end; /*LCOV_EXCL_STOP*/ } if(n == MBEDTLS_ERR_SSL_WANT_READ || n == MBEDTLS_ERR_SSL_WANT_WRITE) { } else if(n < 0) { /*LCOV_EXCL_START*/ mbedtls_strerror(n, (char *)&buffer, BUFFER_SIZE); logprintf(LOG_NOTICE, "mbedtls_ssl_handshake: %s", buffer); uv_poll_stop(req); return; /*LCOV_EXCL_STOP*/ } } else { n = (int)send((unsigned int)fd, send_io->buf, send_io->len, 0); } if(n > 0) { iobuf_remove(send_io, n); if(send_io->len > 0) { custom_poll_data->dowrite = 1; } else { custom_poll_data->dowrite = 0; if(custom_poll_data->doclose == 1 && send_io->len == 0) { custom_poll_data->doread = 0; goto end; } else { custom_poll_data->dowrite = 0; if(custom_poll_data->write_cb != NULL) { custom_poll_data->write_cb(req); } } } } else if(n == 0) { } else if(custom_poll_data->is_ssl == 0 && n < 0 && errno != EAGAIN && errno != EINTR) { if(errno == ECONNRESET) { uv_poll_stop(req); return; } else { uv_poll_stop(req); return; } } } else { custom_poll_data->dowrite = 0; if(custom_poll_data->doclose == 1 && send_io->len == 0) { custom_poll_data->doread = 0; goto end; } else { custom_poll_data->dowrite = 0; if(custom_poll_data->write_cb != NULL) { custom_poll_data->write_cb(req); } } } } if(send_io->len > 0) { custom_poll_data->dowrite = 1; } if(events & UV_READABLE) { if(custom_poll_data->is_ssl == 1) { n = mbedtls_ssl_read(&custom_poll_data->ssl.ctx, (unsigned char *)buffer, BUFFER_SIZE); if(n == MBEDTLS_ERR_SSL_WANT_READ) { custom_poll_data->doread = 1; custom_poll_data->dowrite = 0; goto end; } else if(n == MBEDTLS_ERR_SSL_WANT_WRITE) { /*LCOV_EXCL_START*/ custom_poll_data->dowrite = 1; custom_poll_data->doread = 0; goto end; /*LCOV_EXCL_STOP*/ } else if(n == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { custom_poll_data->doread = 0; if(custom_poll_data->read_cb != NULL) { custom_poll_data->read_cb(req, &custom_poll_data->recv_iobuf.len, custom_poll_data->recv_iobuf.buf); } } if(n == MBEDTLS_ERR_SSL_WANT_READ || n == MBEDTLS_ERR_SSL_WANT_WRITE) { } else if(n < 0) { if(n == MBEDTLS_ERR_NET_RECV_FAILED) { /* * FIXME: New client not yet accepted */ if(custom_poll_data->read_cb != NULL) { one = 1; custom_poll_data->read_cb(req, &one, NULL); } } else if(n != MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { mbedtls_strerror(n, (char *)&buffer, BUFFER_SIZE); logprintf(LOG_NOTICE, "mbedtls_ssl_handshake: %s", buffer); uv_poll_stop(req); } return; } } else { if(custom_poll_data->custom_recv == 0) { if(custom_poll_data->is_udp == 1) { n = (int)recv((unsigned int)fd, buffer, BUFFER_SIZE, 0); } else { #ifdef _WIN32 n = recvfrom((SOCKET)fd, buffer, BUFFER_SIZE, 0, NULL, (socklen_t *)&fromlen); #else n = recvfrom(fd, buffer, BUFFER_SIZE, 0, NULL, (socklen_t *)&fromlen); #endif } } } if(custom_poll_data->custom_recv == 0) { if(n > 0) { iobuf_append(&custom_poll_data->recv_iobuf, buffer, n); custom_poll_data->doread = 0; if(custom_poll_data->read_cb != NULL) { custom_poll_data->read_cb(req, &custom_poll_data->recv_iobuf.len, custom_poll_data->recv_iobuf.buf); } } else if(n < 0 && errno != EINTR) { #ifdef _WIN32 switch(WSAGetLastError()) { case WSAENOTCONN: if(custom_poll_data->read_cb != NULL) { one = 1; custom_poll_data->read_cb(req, &one, NULL); } break; case WSAEWOULDBLOCK: #else switch(errno) { case ENOTCONN: if(custom_poll_data->read_cb != NULL) { one = 1; custom_poll_data->read_cb(req, &one, NULL); } break; #if defined EAGAIN case EAGAIN: #endif #if defined EWOULDBLOCK && EWOULDBLOCK != EAGAIN case EWOULDBLOCK: #endif #endif custom_poll_data->doread = 1; break; default: break; } /* * Client was disconnected */ } else if(n == 0) { custom_poll_data->doclose = 1; custom_poll_data->doread = 0; goto end; } } else { custom_poll_data->doread = 0; if(custom_poll_data->read_cb != NULL) { zero = 0; custom_poll_data->read_cb(req, &zero, NULL); } } }