logger_t *logger;
httpd_callbacks_t callbacks;
- int use_rtsp;
-
int max_connections;
int open_connections;
http_connection_t *connections;
thread_handle_t thread;
mutex_handle_t run_mutex;
- /* Server fd for accepting connections */
- int server_fd;
+ /* Server fds for accepting connections */
+ int server_fd4;
+ int server_fd6;
};
httpd_t *
-httpd_init(logger_t *logger, httpd_callbacks_t *callbacks, int max_connections, int use_rtsp)
+httpd_init(logger_t *logger, httpd_callbacks_t *callbacks, int max_connections)
{
httpd_t *httpd;
return NULL;
}
- httpd->use_rtsp = !!use_rtsp;
httpd->max_connections = max_connections;
httpd->connections = calloc(max_connections, sizeof(http_connection_t));
if (!httpd->connections) {
}
}
if (i == httpd->max_connections) {
- logger_log(httpd->logger, LOGGER_INFO, "Max connections reached\n");
+ /* This code should never be reached, we do not select server_fds when full */
+ logger_log(httpd->logger, LOGGER_INFO, "Max connections reached");
shutdown(fd, SHUT_RDWR);
closesocket(fd);
return;
httpd->connections[i].user_data = httpd->callbacks.conn_init(httpd->callbacks.opaque, local, local_len, remote, remote_len);
}
+static int
+httpd_accept_connection(httpd_t *httpd, int server_fd, int is_ipv6)
+{
+ struct sockaddr_storage remote_saddr;
+ socklen_t remote_saddrlen;
+ struct sockaddr_storage local_saddr;
+ socklen_t local_saddrlen;
+ unsigned char *local, *remote;
+ int local_len, remote_len;
+ int ret, fd;
+
+ remote_saddrlen = sizeof(remote_saddr);
+ fd = accept(server_fd, (struct sockaddr *)&remote_saddr, &remote_saddrlen);
+ if (fd == -1) {
+ /* FIXME: Error happened */
+ return -1;
+ }
+
+ local_saddrlen = sizeof(local_saddr);
+ ret = getsockname(fd, (struct sockaddr *)&local_saddr, &local_saddrlen);
+ if (ret == -1) {
+ closesocket(fd);
+ return 0;
+ }
+
+ logger_log(httpd->logger, LOGGER_INFO, "Accepted %s client on socket %d",
+ (is_ipv6 ? "IPv6" : "IPv4"), fd);
+ local = netutils_get_address(&local_saddr, &local_len);
+ remote = netutils_get_address(&remote_saddr, &remote_len);
+
+ httpd_add_connection(httpd, fd, local, local_len, remote, remote_len);
+ return 1;
+}
+
static void
httpd_remove_connection(httpd_t *httpd, http_connection_t *connection)
{
/* Get the correct nfds value and set rfds */
FD_ZERO(&rfds);
if (httpd->open_connections < httpd->max_connections) {
- FD_SET(httpd->server_fd, &rfds);
- nfds = httpd->server_fd+1;
+ if (httpd->server_fd4 != -1) {
+ FD_SET(httpd->server_fd4, &rfds);
+ if (nfds <= httpd->server_fd4) {
+ nfds = httpd->server_fd4+1;
+ }
+ }
+ if (httpd->server_fd6 != -1) {
+ FD_SET(httpd->server_fd6, &rfds);
+ if (nfds <= httpd->server_fd6) {
+ nfds = httpd->server_fd6+1;
+ }
+ }
}
for (i=0; i<httpd->max_connections; i++) {
int socket_fd;
continue;
} else if (ret == -1) {
/* FIXME: Error happened */
- logger_log(httpd->logger, LOGGER_INFO, "Error in select\n");
+ logger_log(httpd->logger, LOGGER_INFO, "Error in select");
break;
}
- if (FD_ISSET(httpd->server_fd, &rfds)) {
- struct sockaddr_storage remote_saddr;
- socklen_t remote_saddrlen;
- struct sockaddr_storage local_saddr;
- socklen_t local_saddrlen;
- unsigned char *local, *remote;
- int local_len, remote_len;
- int fd;
-
- remote_saddrlen = sizeof(remote_saddr);
- fd = accept(httpd->server_fd, (struct sockaddr *)&remote_saddr, &remote_saddrlen);
- if (fd == -1) {
- /* FIXME: Error happened */
+ if (httpd->open_connections < httpd->max_connections &&
+ httpd->server_fd4 != -1 && FD_ISSET(httpd->server_fd4, &rfds)) {
+ ret = httpd_accept_connection(httpd, httpd->server_fd4, 0);
+ if (ret == -1) {
break;
+ } else if (ret == 0) {
+ continue;
}
-
- local_saddrlen = sizeof(local_saddr);
- ret = getsockname(fd, (struct sockaddr *)&local_saddr, &local_saddrlen);
+ }
+ if (httpd->open_connections < httpd->max_connections &&
+ httpd->server_fd6 != -1 && FD_ISSET(httpd->server_fd6, &rfds)) {
+ ret = httpd_accept_connection(httpd, httpd->server_fd6, 1);
if (ret == -1) {
- closesocket(fd);
+ break;
+ } else if (ret == 0) {
continue;
}
-
- logger_log(httpd->logger, LOGGER_INFO, "Accepted client on socket %d\n", fd);
- local = netutils_get_address(&local_saddr, &local_len);
- remote = netutils_get_address(&remote_saddr, &remote_len);
-
- httpd_add_connection(httpd, fd, local, local_len, remote, remote_len);
}
for (i=0; i<httpd->max_connections; i++) {
http_connection_t *connection = &httpd->connections[i];
/* If not in the middle of request, allocate one */
if (!connection->request) {
- connection->request = http_request_init(httpd->use_rtsp);
+ connection->request = http_request_init();
assert(connection->request);
}
- logger_log(httpd->logger, LOGGER_DEBUG, "Receiving on socket %d\n", connection->socket_fd);
+ logger_log(httpd->logger, LOGGER_DEBUG, "Receiving on socket %d", connection->socket_fd);
ret = recv(connection->socket_fd, buffer, sizeof(buffer), 0);
if (ret == 0) {
- logger_log(httpd->logger, LOGGER_INFO, "Connection closed for socket %d\n", connection->socket_fd);
+ logger_log(httpd->logger, LOGGER_INFO, "Connection closed for socket %d", connection->socket_fd);
httpd_remove_connection(httpd, connection);
continue;
}
/* Parse HTTP request from data read from connection */
http_request_add_data(connection->request, buffer, ret);
if (http_request_has_error(connection->request)) {
- logger_log(httpd->logger, LOGGER_INFO, "Error in parsing: %s\n", http_request_get_error_name(connection->request));
+ logger_log(httpd->logger, LOGGER_INFO, "Error in parsing: %s", http_request_get_error_name(connection->request));
httpd_remove_connection(httpd, connection);
continue;
}
ret = send(connection->socket_fd, data+written, datalen-written, 0);
if (ret == -1) {
/* FIXME: Error happened */
- logger_log(httpd->logger, LOGGER_INFO, "Error in sending data\n");
+ logger_log(httpd->logger, LOGGER_INFO, "Error in sending data");
break;
}
written += ret;
}
+
+ if (http_response_get_disconnect(response)) {
+ logger_log(httpd->logger, LOGGER_INFO, "Disconnecting on software request");
+ httpd_remove_connection(httpd, connection);
+ }
} else {
- logger_log(httpd->logger, LOGGER_INFO, "Didn't get response\n");
+ logger_log(httpd->logger, LOGGER_INFO, "Didn't get response");
}
http_response_destroy(response);
+ } else {
+ logger_log(httpd->logger, LOGGER_DEBUG, "Request not complete, waiting for more data...");
}
}
}
if (!connection->connected) {
continue;
}
- logger_log(httpd->logger, LOGGER_INFO, "Removing connection for socket %d\n", connection->socket_fd);
+ logger_log(httpd->logger, LOGGER_INFO, "Removing connection for socket %d", connection->socket_fd);
httpd_remove_connection(httpd, connection);
}
- logger_log(httpd->logger, LOGGER_INFO, "Exiting HTTP thread\n");
+ /* Close server sockets since they are not used any more */
+ if (httpd->server_fd4 != -1) {
+ closesocket(httpd->server_fd4);
+ httpd->server_fd4 = -1;
+ }
+ if (httpd->server_fd6 != -1) {
+ closesocket(httpd->server_fd6);
+ httpd->server_fd6 = -1;
+ }
+
+ logger_log(httpd->logger, LOGGER_INFO, "Exiting HTTP thread");
return 0;
}
int
httpd_start(httpd_t *httpd, unsigned short *port)
{
+ /* How many connection attempts are kept in queue */
+ int backlog = 5;
+
assert(httpd);
assert(port);
return 0;
}
- httpd->server_fd = netutils_init_socket(port, 1, 0);
- if (httpd->server_fd == -1) {
- logger_log(httpd->logger, LOGGER_INFO, "Error initialising socket %d\n", SOCKET_GET_ERROR());
+ httpd->server_fd4 = netutils_init_socket(port, 0, 0);
+ if (httpd->server_fd4 == -1) {
+ logger_log(httpd->logger, LOGGER_ERR, "Error initialising socket %d", SOCKET_GET_ERROR());
MUTEX_UNLOCK(httpd->run_mutex);
return -1;
}
- if (listen(httpd->server_fd, 5) == -1) {
- logger_log(httpd->logger, LOGGER_INFO, "Error listening to socket\n");
+ httpd->server_fd6 = netutils_init_socket(port, 1, 0);
+ if (httpd->server_fd6 == -1) {
+ logger_log(httpd->logger, LOGGER_WARNING, "Error initialising IPv6 socket %d", SOCKET_GET_ERROR());
+ logger_log(httpd->logger, LOGGER_WARNING, "Continuing without IPv6 support");
+ }
+
+ if (httpd->server_fd4 != -1 && listen(httpd->server_fd4, backlog) == -1) {
+ logger_log(httpd->logger, LOGGER_ERR, "Error listening to IPv4 socket");
+ closesocket(httpd->server_fd4);
+ closesocket(httpd->server_fd6);
+ MUTEX_UNLOCK(httpd->run_mutex);
+ return -2;
+ }
+ if (httpd->server_fd6 != -1 && listen(httpd->server_fd6, backlog) == -1) {
+ logger_log(httpd->logger, LOGGER_ERR, "Error listening to IPv6 socket");
+ closesocket(httpd->server_fd4);
+ closesocket(httpd->server_fd6);
MUTEX_UNLOCK(httpd->run_mutex);
return -2;
}
- logger_log(httpd->logger, LOGGER_INFO, "Initialized server socket\n");
+ logger_log(httpd->logger, LOGGER_INFO, "Initialized server socket(s)");
/* Set values correctly and create new thread */
httpd->running = 1;