Fix protocol probe. Will detect ADC and TLS handshake - any other request

will simply cause the hub to close the connection.
Fix problems with write events not being processed due to a read event taking presendence.
Fix bug #86: Windows does not have "getrlimit()".
This commit is contained in:
Jan Vidar Krey 2009-10-07 17:37:31 +02:00
parent 11e5683a79
commit 2910c571b0
16 changed files with 267 additions and 106 deletions

View File

@ -135,6 +135,7 @@ libuhub_SOURCES := \
src/core/hubevent.c \ src/core/hubevent.c \
src/core/hubio.c \ src/core/hubio.c \
src/core/inf.c \ src/core/inf.c \
src/core/probe.c \
src/util/ipcalc.c \ src/util/ipcalc.c \
src/util/list.c \ src/util/list.c \
src/util/log.c \ src/util/log.c \

View File

@ -434,9 +434,10 @@ const char* acl_password_generate_challenge(struct acl_handle* acl, struct hub_u
char buf[32]; char buf[32];
uint64_t tiger_res[3]; uint64_t tiger_res[3];
static char tiger_buf[MAX_CID_LEN+1]; static char tiger_buf[MAX_CID_LEN+1];
snprintf(buf, 32, "%d%d%d", (int) user->tm_connected, (int) user->id.sid, (int) user->connection->sd); // FIXME: Generate a better nonce scheme.
snprintf(buf, 32, "%p%d%d", user, (int) user->id.sid, (int) user->connection->sd);
tiger((uint64_t*) buf, strlen(buf), (uint64_t*) tiger_res); tiger((uint64_t*) buf, strlen(buf), (uint64_t*) tiger_res);
base32_encode((unsigned char*) tiger_res, TIGERSIZE, tiger_buf); base32_encode((unsigned char*) tiger_res, TIGERSIZE, tiger_buf);
tiger_buf[MAX_CID_LEN] = 0; tiger_buf[MAX_CID_LEN] = 0;

View File

@ -417,7 +417,7 @@ void dump_config(struct hub_config* config, int ignore_defaults)
DUMP_BOOL(registered_users_only, DEF_REGISTERED_USERS_ONLY); DUMP_BOOL(registered_users_only, DEF_REGISTERED_USERS_ONLY);
#ifdef SSL_SUPPORT #ifdef SSL_SUPPORT
DUMP_BOOL(tls_enable, DEF_TLS_ENABLE); DUMP_BOOL(tls_enable, DEF_TLS_ENABLE);
DUMP_BOOL(tls_require, DEF_TLS_REQUIRE); DUMP_BOOL(tls_require, DEF_TLS_REQUIRE);
DUMP_STR (tls_certificate, DEF_TLS_CERTIFICATE); DUMP_STR (tls_certificate, DEF_TLS_CERTIFICATE);
DUMP_STR (tls_private_key, DEF_TLS_PRIVATE_KEY); DUMP_STR (tls_private_key, DEF_TLS_PRIVATE_KEY);

View File

@ -555,7 +555,7 @@ struct hub_info* hub_start_service(struct hub_config* config)
net_close(server_tcp); net_close(server_tcp);
return 0; return 0;
} }
event_set(&hub->ev_accept, hub->fd_tcp, EV_READ | EV_PERSIST, net_on_accept, hub); event_set(&hub->ev_accept, hub->fd_tcp, EV_READ | EV_PERSIST, net_on_accept, hub);
if (event_add(&hub->ev_accept, NULL) == -1) if (event_add(&hub->ev_accept, NULL) == -1)
{ {
@ -572,7 +572,7 @@ struct hub_info* hub_start_service(struct hub_config* config)
net_close(server_tcp); net_close(server_tcp);
return 0; return 0;
} }
hub->recvbuf = hub_malloc(MAX_RECV_BUF); hub->recvbuf = hub_malloc(MAX_RECV_BUF);
hub->sendbuf = hub_malloc(MAX_SEND_BUF); hub->sendbuf = hub_malloc(MAX_SEND_BUF);
if (!hub->recvbuf || !hub->sendbuf) if (!hub->recvbuf || !hub->sendbuf)
@ -650,7 +650,7 @@ void hub_set_variables(struct hub_info* hub, struct acl_handle* acl)
adc_msg_add_named_argument(hub->command_info, ADC_INF_FLAG_DESCRIPTION, tmp); adc_msg_add_named_argument(hub->command_info, ADC_INF_FLAG_DESCRIPTION, tmp);
hub_free(tmp); hub_free(tmp);
} }
/* (Re-)read the message of the day */ /* (Re-)read the message of the day */
hub->command_motd = 0; hub->command_motd = 0;
fd = open(hub->config->file_motd, 0); fd = open(hub->config->file_motd, 0);
@ -1033,7 +1033,11 @@ void hub_disconnect_user(struct hub_info* hub, struct hub_user* user, int reason
/* stop reading from user */ /* stop reading from user */
net_shutdown_r(user->connection->sd); net_shutdown_r(user->connection->sd);
net_con_close(user->connection); if (net_con_close(user->connection))
{
hub_free(user->connection);
}
user->connection = 0;
LOG_TRACE("hub_disconnect_user(), user=%p, reason=%d, state=%d", user, reason, user->state); LOG_TRACE("hub_disconnect_user(), user=%p, reason=%d, state=%d", user, reason, user->state);

View File

@ -146,58 +146,21 @@ void hub_sendq_remove(struct hub_sendq* q, struct adc_message* msg)
q->offset = 0; q->offset = 0;
} }
int hub_sendq_send(struct hub_sendq* q, hub_recvq_write w, void* data) int hub_sendq_send(struct hub_sendq* q, struct hub_user* user)
{ {
int ret = 0;
size_t bytes = 0;
size_t offset = q->offset; // offset into first message.
size_t remain = 0;
size_t length = 0;
char* sbuf = g_hub->sendbuf;
size_t max_send_buf = 4096;
/* Copy as many messages possible into global send queue */
struct adc_message* msg = list_get_first(q->queue); struct adc_message* msg = list_get_first(q->queue);
while (msg) if (!msg) return 0;
{
length = MIN(msg->length - offset, (max_send_buf-1) - bytes);
memcpy(sbuf + bytes, msg->cache + offset, length);
bytes += length;
if (length < (msg->length - offset))
break;
offset = 0;
msg = list_get_next(q->queue);
}
msg = list_get_first(q->queue); int ret = net_con_send(user->connection, msg->cache + q->offset, msg->length - q->offset);
/* Send as much as possible */
ret = w(data, sbuf, bytes);
if (ret > 0) if (ret > 0)
{ {
#ifdef SSL_SUPPORT q->offset += ret;
q->last_send = ret; if (msg->length - q->offset > 0)
#endif return 0;
/* Remove messages sent */ hub_sendq_remove(q, msg);
offset = q->offset; return 1;
remain = ret;
while (msg)
{
length = msg->length - offset;
if (length >= remain)
{
q->offset += remain;
break;
}
remain -= length;
hub_sendq_remove(q, msg);
msg = list_get_next(q->queue);
offset = 0;
}
} }
return ret; return ret;
} }

View File

@ -58,10 +58,9 @@ extern void hub_sendq_add(struct hub_sendq*, struct adc_message* msg);
/** /**
* Process the send queue, and send as many messages as possible. * Process the send queue, and send as many messages as possible.
* @returns the number of bytes sent. * @returns -1 on error, 0 if unable to send more, 1 if more can be sent.
* FIXME: send error not handled here!
*/ */
extern int hub_sendq_send(struct hub_sendq*, hub_recvq_write, void* data); extern int hub_sendq_send(struct hub_sendq*, struct hub_user*);
/** /**
* @returns 1 if send queue is empty, 0 otherwise. * @returns 1 if send queue is empty, 0 otherwise.

View File

@ -17,8 +17,9 @@
* *
*/ */
#include "uhub.h" #include <uhub.h>
#include "hubio.h" #include "hubio.h"
#include "probe.h"
/* FIXME: This should not be needed! */ /* FIXME: This should not be needed! */
extern struct hub_info* g_hub; extern struct hub_info* g_hub;
@ -52,21 +53,6 @@ void debug_sendq_recv(struct hub_user* user, int received, int max, const char*
} }
#endif #endif
int net_user_send(void* ptr, const void* buf, size_t len)
{
struct hub_user* user = (struct hub_user*) ptr;
int ret = net_con_send(user->connection, buf, len);
#ifdef DEBUG_SENDQ
debug_sendq_send(user, ret, len);
#endif
if (ret > 0)
return ret;
if (ret == 0)
return -2;
else
return -1;
}
int net_user_recv(void* ptr, void* buf, size_t len) int net_user_recv(void* ptr, void* buf, size_t len)
{ {
struct hub_user* user = (struct hub_user*) ptr; struct hub_user* user = (struct hub_user*) ptr;
@ -161,13 +147,11 @@ int handle_net_write(struct hub_user* user)
int ret = 0; int ret = 0;
while (hub_sendq_get_bytes(user->send_queue)) while (hub_sendq_get_bytes(user->send_queue))
{ {
ret = hub_sendq_send(user->send_queue, net_user_send, user); ret = hub_sendq_send(user->send_queue, user);
if (ret <= 0) if (ret <= 0)
break; break;
} }
if (ret == -1)
return quit_disconnected;
if (ret < 0) if (ret < 0)
return quit_socket_error; return quit_socket_error;
@ -189,9 +173,12 @@ void net_event(struct net_connection* con, int event, void *arg)
if (event == NET_EVENT_DESTROYED) if (event == NET_EVENT_DESTROYED)
{ {
printf("NET_EVENT_DESTROYED\n"); printf("NET_EVENT_DESTROYED: con=%p, user=%p\n", con, user);
hub_free(user->connection); if (user)
user->connection = 0; {
user->connection = 0;
}
hub_free(con);
return; return;
} }
@ -217,26 +204,32 @@ void net_event(struct net_connection* con, int event, void *arg)
return; return;
} }
} }
else if (event & NET_EVENT_READ)
if (event & NET_EVENT_READ)
{ {
flag_close = handle_net_read(user); flag_close = handle_net_read(user);
} if (flag_close)
else if (event & NET_EVENT_WRITE) {
{ hub_disconnect_user(g_hub, user, flag_close);
flag_close = handle_net_write(user); return;
}
} }
if (flag_close) if (event & NET_EVENT_WRITE)
{ {
hub_disconnect_user(g_hub, user, flag_close); flag_close = handle_net_write(user);
return; if (flag_close)
{
hub_disconnect_user(g_hub, user, flag_close);
return;
}
} }
} }
void net_on_accept(int server_fd, short event, void *arg) void net_on_accept(int server_fd, short event, void *arg)
{ {
struct hub_info* hub = (struct hub_info*) arg; struct hub_info* hub = (struct hub_info*) arg;
struct hub_user* user = 0; struct hub_probe* probe = 0;
struct ip_addr_encap ipaddr; struct ip_addr_encap ipaddr;
const char* addr; const char* addr;
@ -269,17 +262,13 @@ void net_on_accept(int server_fd, short event, void *arg)
continue; continue;
} }
user = user_create(hub, fd, &ipaddr); probe = probe_create(hub, fd, &ipaddr);
if (!user) if (!probe)
{ {
LOG_ERROR("Unable to create user after socket accepted. Out of memory?"); LOG_ERROR("Unable to create probe after socket accepted. Out of memory?");
net_close(fd); net_close(fd);
break; break;
} }
#ifdef SSL_SUPPORT
net_con_ssl_handshake(&user->net.connection, NET_CON_SSL_MODE_SERVER);
#endif
} }
} }

115
src/core/probe.c Normal file
View File

@ -0,0 +1,115 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2009, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "uhub.h"
#include "probe.h"
#define PROBE_RECV_SIZE 12
static char probe_recvbuf[PROBE_RECV_SIZE];
static void probe_net_event(struct net_connection* con, int events, void *arg)
{
struct hub_probe* probe = (struct hub_probe*) con->ptr;
if (events == NET_EVENT_DESTROYED)
{
if (probe)
{
probe->connection = 0;
}
hub_free(con);
return;
}
if (events == NET_EVENT_SOCKERROR || events == NET_EVENT_CLOSED || events == NET_EVENT_TIMEOUT)
{
probe_destroy(probe);
return;
}
if (events & NET_EVENT_READ)
{
int bytes = net_con_peek(con, probe_recvbuf, PROBE_RECV_SIZE);
if (bytes < 0)
{
probe_destroy(probe);
return;
}
if (bytes >= 4)
{
if (memcmp(probe_recvbuf, "HSUP", 4) == 0)
{
LOG_TRACE("Probed ADC");
if (user_create(probe->hub, probe->connection, &probe->addr))
{
probe->connection = 0;
}
probe_destroy(probe);
return;
}
#ifdef SSL_SUPPORT
if (bytes >= 11
probe_recvbuf[0] == 22 &&
probe_recvbuf[1] == 3 && /* protocol major version */
probe_recvbuf[5] == 1 && /* message type */
probe_recvbuf[9] == probe_recvbuf[1] &&
probe_recvbuf[10] == probe_recvbuf[2])
{
LOG_TRACE("Probed TLS %d.%d connection", (int) probe_recvbuf[1], (int) probe_recvbuf[2]);
net_con_ssl_handshake(con, NET_CON_SSL_MODE_SERVER);
return;
}
#endif
probe_destroy(probe);
return;
}
}
}
struct hub_probe* probe_create(struct hub_info* hub, int sd, struct ip_addr_encap* addr)
{
struct hub_probe* probe = (struct hub_probe*) hub_malloc_zero(sizeof(struct hub_probe));
if (probe == NULL)
return NULL; /* OOM */
probe->hub = hub;
probe->connection = (struct net_connection*) hub_malloc(sizeof(struct net_connection));
net_con_initialize(probe->connection, sd, probe_net_event, probe, NET_EVENT_READ);
net_con_set_timeout(probe->connection, TIMEOUT_CONNECTED);
memcpy(&probe->addr, addr, sizeof(struct ip_addr_encap));
return probe;
}
void probe_destroy(struct hub_probe* probe)
{
if (probe->connection)
{
if (net_con_close(probe->connection))
{
hub_free(probe->connection);
}
probe->connection = 0;
}
hub_free(probe);
}

35
src/core/probe.h Normal file
View File

@ -0,0 +1,35 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2009, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef HAVE_UHUB_PROBE_H
#define HAVE_UHUB_PROBE_H
#include "uhub.h"
struct hub_probe
{
struct hub_info* hub; /** The hub instance this probe belong to */
struct net_connection* connection; /** Connection data */
struct ip_addr_encap addr; /** IP address */
};
extern struct hub_probe* probe_create(struct hub_info* hub, int sd, struct ip_addr_encap* addr);
extern void probe_destroy(struct hub_probe* probe);
#endif /* HAVE_UHUB_PROBE_H */

View File

@ -97,6 +97,9 @@ int route_to_user(struct hub_info* hub, struct hub_user* user, struct adc_messag
free(data); free(data);
#endif #endif
if (!user->connection)
return 0;
if (hub_sendq_is_empty(user->send_queue) && !user_flag_get(user, flag_pipeline)) if (hub_sendq_is_empty(user->send_queue) && !user_flag_get(user, flag_pipeline))
{ {
/* Perform oportunistic write */ /* Perform oportunistic write */

View File

@ -35,27 +35,24 @@ static const char* user_log_str(struct hub_user* user)
} }
#endif #endif
struct hub_user* user_create(struct hub_info* hub, int sd, struct ip_addr_encap* addr) struct hub_user* user_create(struct hub_info* hub, struct net_connection* con, struct ip_addr_encap* addr)
{ {
struct hub_user* user = NULL; struct hub_user* user = NULL;
LOG_TRACE("user_create(), hub=%p, sd=%d", hub, sd); LOG_TRACE("user_create(), hub=%p, con[sd=%d]", hub, con->sd);
user = (struct hub_user*) hub_malloc_zero(sizeof(struct hub_user)); user = (struct hub_user*) hub_malloc_zero(sizeof(struct hub_user));
if (user == NULL) if (user == NULL)
return NULL; /* OOM */ return NULL; /* OOM */
user->tm_connected = time(NULL);
user->send_queue = hub_sendq_create(); user->send_queue = hub_sendq_create();
user->recv_queue = hub_recvq_create(); user->recv_queue = hub_recvq_create();
user->connection = (struct net_connection*) hub_malloc(sizeof(struct net_connection)); user->connection = con;
net_con_initialize(user->connection, sd, net_event, user, NET_EVENT_READ); net_con_reinitialize(user->connection, net_event, user, NET_EVENT_READ);
net_con_set_timeout(user->connection, TIMEOUT_CONNECTED);
memcpy(&user->id.addr, addr, sizeof(struct ip_addr_encap)); memcpy(&user->id.addr, addr, sizeof(struct ip_addr_encap));
user_set_state(user, state_protocol); user_set_state(user, state_protocol);
return user; return user;
} }

View File

@ -111,7 +111,6 @@ struct hub_user
struct hub_recvq* recv_queue; struct hub_recvq* recv_queue;
struct hub_sendq* send_queue; struct hub_sendq* send_queue;
struct net_connection* connection; /** Connection data */ struct net_connection* connection; /** Connection data */
time_t tm_connected; /** time when user connected */
struct hub_user_limits limits; /** Data used for limitation */ struct hub_user_limits limits; /** Data used for limitation */
enum user_quit_reason quit_reason; /** Quit reason (see user_quit_reason) */ enum user_quit_reason quit_reason; /** Quit reason (see user_quit_reason) */
@ -128,7 +127,7 @@ struct hub_user
* @param sd socket descriptor associated with the user * @param sd socket descriptor associated with the user
* @return User object or NULL if not enough memory is available. * @return User object or NULL if not enough memory is available.
*/ */
extern struct hub_user* user_create(struct hub_info* hub, int sd, struct ip_addr_encap* addr); extern struct hub_user* user_create(struct hub_info* hub, struct net_connection* con, struct ip_addr_encap* addr);
/** /**
* Delete a user. * Delete a user.

View File

@ -180,7 +180,13 @@ void net_con_initialize(struct net_connection* con, int sd, net_connection_cb ca
#endif #endif
} }
void net_con_reinitialize(struct net_connection* con, net_connection_cb callback, const void* ptr, int events)
{
uhub_assert(con);
con->callback = callback;
con->ptr = (void*) ptr;
net_con_update(con, events);
}
void net_con_update(struct net_connection* con, int ev) void net_con_update(struct net_connection* con, int ev)
{ {
@ -393,6 +399,41 @@ ssize_t net_con_recv(struct net_connection* con, void* buf, size_t len)
#endif #endif
} }
ssize_t net_con_peek(struct net_connection* con, void* buf, size_t len)
{
uhub_assert(con);
#ifdef SSL_SUPPORT
if (!con->ssl)
{
#endif
int ret = net_recv(con->sd, buf, len, MSG_PEEK);
#ifdef NETWORK_DUMP_DEBUG
LOG_PROTO("net_recv: ret=%d (MSG_PEEK)", ret);
#endif
if (ret > 0)
{
con->last_recv = time(0);
}
else if (ret == -1 && (net_error() == EWOULDBLOCK || net_error() == EINTR))
{
return 0;
}
else
{
return -1;
}
return ret;
#ifdef SSL_SUPPORT
}
else
{
// FIXME: Not able to do this!
return 0;
}
#endif
}
void net_con_set_timeout(struct net_connection* con, int seconds) void net_con_set_timeout(struct net_connection* con, int seconds)
{ {
uhub_assert(con); uhub_assert(con);

View File

@ -64,6 +64,7 @@ struct net_connection
}; };
extern void net_con_initialize(struct net_connection* con, int sd, net_connection_cb callback, const void* ptr, int events); extern void net_con_initialize(struct net_connection* con, int sd, net_connection_cb callback, const void* ptr, int events);
extern void net_con_reinitialize(struct net_connection* con, net_connection_cb callback, const void* ptr, int events);
extern void net_con_update(struct net_connection* con, int events); extern void net_con_update(struct net_connection* con, int events);
/** /**
@ -92,6 +93,13 @@ extern ssize_t net_con_send(struct net_connection* con, const void* buf, size_t
*/ */
extern ssize_t net_con_recv(struct net_connection* con, void* buf, size_t len); extern ssize_t net_con_recv(struct net_connection* con, void* buf, size_t len);
/**
* Receive data without removing them from the recv() buffer.
* NOTE: This does not currently work for SSL connections after the SSL handshake has been
* performed.
*/
extern ssize_t net_con_peek(struct net_connection* con, void* buf, size_t len);
/** /**
* Set timeout for connetion. * Set timeout for connetion.
* *

View File

@ -80,9 +80,14 @@ size_t net_get_max_sockets()
} }
LOG_ERROR("getrlimit() failed"); LOG_ERROR("getrlimit() failed");
#else #else
LOG_ERROR("System does not have getrlimit(): constrained to 1024 sockets"); #ifdef WIN32
#endif /* HAVE_GETRLIMIT */ LOG_WARN("Windows system, limited to 4096 connections.");
return 4096;
#else
LOG_WARN("System does not have getrlimit(): constrained to 1024 sockets");
return 1024; return 1024;
#endif
#endif /* HAVE_GETRLIMIT */
} }

View File

@ -337,6 +337,7 @@ void runloop(size_t clients)
{ {
ADC_client_destroy(client[n]); ADC_client_destroy(client[n]);
free(client[n]); free(client[n]);
client[n] = 0;
} }
} }