Example #1
0
int HTTPServerListen(HTTPServerRef const server, strarg_t const address, strarg_t const port) {
	if(!server) return 0;
	assertf(!server->socket->data, "HTTPServer already listening");
	int rc;
	rc = uv_tcp_init(async_loop, server->socket);
	if(rc < 0) return rc;
	server->socket->data = server;

	struct addrinfo const hints = {
		.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG | AI_NUMERICSERV | AI_PASSIVE,
		.ai_family = AF_UNSPEC,
		.ai_socktype = SOCK_STREAM,
		.ai_protocol = 0, // ???
	};
	struct addrinfo *info;
	rc = async_getaddrinfo(address, port, &hints, &info);
	if(rc < 0) {
		HTTPServerClose(server);
		return rc;
	}
	int bound = 0;
	rc = 0;
	for(struct addrinfo *each = info; each; each = each->ai_next) {
		rc = uv_tcp_bind(server->socket, each->ai_addr, 0);
		if(rc >= 0) bound++;
	}
	uv_freeaddrinfo(info);
	if(!bound) {
		HTTPServerClose(server);
		if(rc < 0) return rc;
		return UV_EADDRNOTAVAIL;
	}
	rc = uv_listen((uv_stream_t *)server->socket, 511, connection_cb);
	if(rc < 0) {
		HTTPServerClose(server);
		return rc;
	}
	return 0;
}
int HTTPServerListenSecure(HTTPServerRef const server, strarg_t const address, strarg_t const port, struct tls **const tlsptr) {
	if(!server) return 0;
	int rc = HTTPServerListen(server, address, port);
	if(rc < 0) return rc;
	server->secure = *tlsptr; *tlsptr = NULL;
	return 0;
}
void HTTPServerClose(HTTPServerRef const server) {
	if(!server) return;
	if(!server->socket->data) return;
	if(server->secure) tls_close(server->secure);
	tls_free(server->secure); server->secure = NULL;
	async_close((uv_handle_t *)server->socket);
}

static void connection(uv_stream_t *const socket) {
	HTTPServerRef const server = socket->data;
	HTTPConnectionRef conn;
	int rc = HTTPConnectionCreateIncomingSecure(socket, server->secure, 0, &conn);
	if(rc < 0) {
		fprintf(stderr, "HTTP server connection error %s\n", uv_strerror(rc));
		return;
	}
	assert(conn);

	for(;;) {
		server->listener(server->context, server, conn);
		rc = HTTPConnectionDrainMessage(conn);
		if(rc < 0) break;
	}

	HTTPConnectionFree(&conn);
}
Example #2
0
int HTTPConnectionCreateOutgoing(strarg_t const domain, unsigned const flags, HTTPConnectionRef *const out) {
	str_t host[1023+1];
	str_t service[15+1];
	host[0] = '\0';
	service[0] = '\0';
	int matched = sscanf(domain, "%1023[^:]:%15[0-9]", host, service);
	if(matched < 1) return UV_EINVAL;
	if('\0' == host[0]) return UV_EINVAL;

	static struct addrinfo const hints = {
		.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG | AI_NUMERICSERV,
		.ai_family = AF_UNSPEC,
		.ai_socktype = SOCK_STREAM,
		.ai_protocol = 0, // ???
	};
	struct addrinfo *info = NULL;
	HTTPConnectionRef conn = NULL;
	int rc;

	rc = async_getaddrinfo(host, service[0] ? service : "80", &hints, &info);
	if(rc < 0) goto cleanup;

	conn = calloc(1, sizeof(struct HTTPConnection));
	if(!conn) rc = UV_ENOMEM;
	if(rc < 0) goto cleanup;

	rc = UV_EADDRNOTAVAIL;
	for(struct addrinfo *each = info; each; each = each->ai_next) {
		rc = uv_tcp_init(async_loop, conn->stream);
		if(rc < 0) break;

		rc = async_tcp_connect(conn->stream, each->ai_addr);
		if(rc >= 0) break;

		async_close((uv_handle_t *)conn->stream);
	}
	if(rc < 0) goto cleanup;

	http_parser_init(conn->parser, HTTP_RESPONSE);
	conn->parser->data = conn;
	*out = conn; conn = NULL;

cleanup:
	uv_freeaddrinfo(info); info = NULL;
	HTTPConnectionFree(&conn);
	return rc;
}
void HTTPConnectionFree(HTTPConnectionRef *const connptr) {
	HTTPConnectionRef conn = *connptr;
	if(!conn) return;

	async_close((uv_handle_t *)conn->stream);

	// http_parser does not need to be freed, closed or destroyed.
	memset(conn->parser, 0, sizeof(*conn->parser));

	FREE(&conn->buf);
	*conn->raw = uv_buf_init(NULL, 0);

	conn->type = HTTPNothing;
	*conn->out = uv_buf_init(NULL, 0);

	conn->flags = 0;

	assert_zeroed(conn, 1);
	FREE(connptr); conn = NULL;
}