Beispiel #1
0
/* XXX: hacktastic but should return a valid file from pacman's cache */
static void handle_file_request(const char *path, int client_fd)
{
    struct iobuf buf;
    struct stat st;
    int ret;

    iobuf_init(&buf, 10);
    iobuf_append(&buf, "HTTP/1.1 ", 9);
    iobuf_append(&buf, "200 ", 4);
    iobuf_append(&buf, "OK\r\n", 4);

    _cleanup_free_ char *filename = joinpath(".", path, NULL);
    _cleanup_free_ char *content_length = NULL;

    _cleanup_close_ int fd = open(filename, O_RDONLY);
    if (fd < 0)
        err(EXIT_FAILURE, "couldn't access %s", filename);
    fstat(fd, &st);

    ssize_t nbytes_w = asprintf(&content_length, "%s: %zd\r\n", "Content-Length", st.st_size);
    if (nbytes_w < 0)
        err(1, "failed to allocate memory for Content-Length");
    iobuf_append(&buf, content_length, nbytes_w);

    iobuf_append(&buf, "\r\n", 2);

    /* write out header */
    iobuf_write(&buf, client_fd);

    ret = sendfile(client_fd, fd, NULL, st.st_size);
    if (ret < 0)
        err(EXIT_FAILURE, "failed to send file %s across socket", filename);
}
Beispiel #2
0
/* TODO: this doesn't need any arguments */
static void http_request_done(void *data, const char _unused_ *at, size_t _unused_ len)
{
    struct http_data *header = data;

    /* TODO: redo how callbacks are set */
    if (header->request_type != REQUEST_URI)
        return;

    iobuf_append(&header->p.request, "Connection: Close\r\n", 19);
    iobuf_append(&header->p.request, "\r\n", 2);
}
Beispiel #3
0
static size_t ns_out(struct ns_connection *nc, const void *buf, size_t len) {
  if (nc->flags & NSF_UDP) {
    long n = sendto(nc->sock, buf, len, 0, &nc->sa.sa, sizeof(nc->sa.sin));
    DBG(("%p %d send %ld (%d %s)", nc, nc->sock, n, errno, strerror(errno)));
    return n < 0 ? 0 : n;
  } else {
    return iobuf_append(&nc->send_iobuf, buf, len);
  }
}
Beispiel #4
0
static void http_request_version(void *data, const char *at, size_t len)
{
    /* XXX: do we really need to pass this on verbatum? Lets just
     * automatically upgrade to HTTP 1.1 */
    struct http_data *header = data;

    /* TODO: redo how callbacks are set */
    if (header->request_type != REQUEST_URI)
        return;

    iobuf_append(&header->p.request, at, len + 2);
}
Beispiel #5
0
static void http_field(void *data, const char *field, size_t flen, const char *value, size_t vlen)
{
    struct http_data *header = data;

    /* TODO: redo how callbacks are set */
    if (header->request_type != REQUEST_URI)
        return;

    if (strncmp("Host", field, flen) == 0) {
        iobuf_append(&header->p.request, "Host: ", 6);
        iobuf_append(&header->p.request, header->p.hostname, strlen(header->p.hostname));
        iobuf_append(&header->p.request, "\r\n", 2);
        return;
    } else if (strncmp("If-Modified-Since", field, flen) == 0) {
        header->modified = strndup(value, vlen);
    } else if (strncmp("Proxy-Connection", field, flen) == 0) {
        return;
    }

    iobuf_append(&header->p.request, field, flen + 2);
    iobuf_append(&header->p.request, value, vlen + 2);
}
Beispiel #6
0
static void http_request_uri(void *data, const char *at, size_t len)
{
    struct http_data *header = data;

    /* *header->p.v++ = (struct iovec){ (void *)at + 2,  len - 2 + 1 }; */
    if (strncmp(at, "//", 2) == 0) {
        header->request_type = REQUEST_URI;
    } else {
        header->request_type = REQUEST_PATH;
    }

    switch (header->request_type) {
    case REQUEST_URI:
        /* TODO: properly init proxy response */
        iobuf_init(&header->p.request, 10);

        header->p.hostname = strndup(at + 2, len - 3); /** -3 to avoid the /, parser broken? */
        header->p.fd = connect_to(header->p.hostname, "http");

        iobuf_append(&header->p.request, header->method, header->method_len + 1);
        iobuf_append(&header->p.request, "/ ", 2);

        /* TODO: store the lenght to avoid the strlen later */
        header->path = strndup(at, len);

        /* TODO: check if uri or path, this should affect below */
        /* header->http_request_version = http_request_version; */
        /* header->http_field   = http_field; */
        break;
    case REQUEST_PATH:
        header->path = strndup(at, len);
        printf("requesting PATH=%s\n", header->path);
        break;
    default:
        break;
    }
}
Beispiel #7
0
static const char *test_hexdump_file(void) {
  const char *path = "test_hexdump";
  const char *want =  "0xbeef :0 -> :0 3\n"
                      "0000  66 6f 6f   "
                      "                                      foo\n\n";
  char *data, *got;
  size_t size;
  struct ns_connection *nc = (struct ns_connection *) calloc(1, sizeof(*nc));

  /* "In the GNU system, non-null pointers are printed as unsigned integers,
   * as if a `%#x' conversion were used. Null pointers print as `(nil)'.
   * (Pointers might print differently in other systems.)"
   * indeed it prints 0x0 on apple.
   */
  nc->user_data = (void *)0xbeef;
  truncate(path, 0);

  iobuf_append(&nc->send_iobuf, "foo", 3);
  iobuf_append(&nc->recv_iobuf, "bar", 3);
  ns_hexdump_connection(nc, path, 3, NS_SEND);

  iobuf_free(&nc->send_iobuf);
  iobuf_free(&nc->recv_iobuf);
  free(nc);

  ASSERT((data = read_file(path, &size)) != NULL);
  unlink(path);

  got = data;
  while(got-data < (int)size && *got++ != ' ');
  size -= got-data;
  ASSERT(strncmp(got, want, size) == 0);

  free(data);
  return NULL;
}
Beispiel #8
0
static void ns_read_from_socket(struct ns_connection *conn) {
  char buf[NS_READ_BUFFER_SIZE];
  int n = 0;

  if (conn->flags & NSF_CONNECTING) {
    int ok = 1, ret;
    socklen_t len = sizeof(ok);

    ret = getsockopt(conn->sock, SOL_SOCKET, SO_ERROR, (char *) &ok, &len);
#ifdef NS_ENABLE_SSL
    if (ret == 0 && ok == 0 && conn->ssl != NULL) {
      int res = SSL_connect(conn->ssl);
      int ssl_err = ns_ssl_err(conn, res);
      if (res == 1) {
        conn->flags |= NSF_SSL_HANDSHAKE_DONE;
      } else if (ssl_err == SSL_ERROR_WANT_READ ||
                 ssl_err == SSL_ERROR_WANT_WRITE) {
        return; /* Call us again */
      } else {
        ok = 1;
      }
    }
#endif
    conn->flags &= ~NSF_CONNECTING;
    DBG(("%p ok=%d", conn, ok));
    if (ok != 0) {
      conn->flags |= NSF_CLOSE_IMMEDIATELY;
    }
    ns_call(conn, NS_CONNECT, &ok);
    return;
  }

#ifdef NS_ENABLE_SSL
  if (conn->ssl != NULL) {
    if (conn->flags & NSF_SSL_HANDSHAKE_DONE) {
      /* SSL library may have more bytes ready to read then we ask to read.
       * Therefore, read in a loop until we read everything. Without the loop,
       * we skip to the next select() cycle which can just timeout. */
      while ((n = SSL_read(conn->ssl, buf, sizeof(buf))) > 0) {
        DBG(("%p %lu <- %d bytes (SSL)", conn, conn->flags, n));
        iobuf_append(&conn->recv_iobuf, buf, n);
        ns_call(conn, NS_RECV, &n);
      }
      ns_ssl_err(conn, n);
    } else {
      int res = SSL_accept(conn->ssl);
      int ssl_err = ns_ssl_err(conn, res);
      if (res == 1) {
        conn->flags |= NSF_SSL_HANDSHAKE_DONE;
      } else if (ssl_err == SSL_ERROR_WANT_READ ||
                 ssl_err == SSL_ERROR_WANT_WRITE) {
        return; /* Call us again */
      } else {
        conn->flags |= NSF_CLOSE_IMMEDIATELY;
      }
      return;
    }
  } else
#endif
  {
    while ((n = (int) recv(conn->sock, buf, sizeof(buf), 0)) > 0) {
      DBG(("%p %lu <- %d bytes (PLAIN)", conn, conn->flags, n));
      iobuf_append(&conn->recv_iobuf, buf, n);
      ns_call(conn, NS_RECV, &n);
    }
  }

  if (ns_is_error(n)) {
    conn->flags |= NSF_CLOSE_IMMEDIATELY;
  }
}
Beispiel #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);
			}
		}
	}