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);
    }
}
Exemple #2
0
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);
  }
}
Exemple #3
0
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);
    }
  }
}
Exemple #4
0
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);
    }
}
Exemple #7
0
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;
  }
}
Exemple #8
0
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;
  }
}
Exemple #9
0
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);
			}
		}
	}