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/hubio.c \
src/core/inf.c \
src/core/probe.c \
src/util/ipcalc.c \
src/util/list.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];
uint64_t tiger_res[3];
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);
base32_encode((unsigned char*) tiger_res, TIGERSIZE, tiger_buf);
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);
#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_STR (tls_certificate, DEF_TLS_CERTIFICATE);
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);
return 0;
}
event_set(&hub->ev_accept, hub->fd_tcp, EV_READ | EV_PERSIST, net_on_accept, hub);
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);
return 0;
}
hub->recvbuf = hub_malloc(MAX_RECV_BUF);
hub->sendbuf = hub_malloc(MAX_SEND_BUF);
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);
hub_free(tmp);
}
/* (Re-)read the message of the day */
hub->command_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 */
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);

View File

@ -146,58 +146,21 @@ void hub_sendq_remove(struct hub_sendq* q, struct adc_message* msg)
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);
while (msg)
{
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);
}
if (!msg) return 0;
msg = list_get_first(q->queue);
/* Send as much as possible */
ret = w(data, sbuf, bytes);
int ret = net_con_send(user->connection, msg->cache + q->offset, msg->length - q->offset);
if (ret > 0)
{
#ifdef SSL_SUPPORT
q->last_send = ret;
#endif
q->offset += ret;
if (msg->length - q->offset > 0)
return 0;
/* Remove messages sent */
offset = q->offset;
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;
}
hub_sendq_remove(q, msg);
return 1;
}
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.
* @returns the number of bytes sent.
* FIXME: send error not handled here!
* @returns -1 on error, 0 if unable to send more, 1 if more can be sent.
*/
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.

View File

@ -17,8 +17,9 @@
*
*/
#include "uhub.h"
#include <uhub.h>
#include "hubio.h"
#include "probe.h"
/* FIXME: This should not be needed! */
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
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)
{
struct hub_user* user = (struct hub_user*) ptr;
@ -161,13 +147,11 @@ int handle_net_write(struct hub_user* user)
int ret = 0;
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)
break;
}
if (ret == -1)
return quit_disconnected;
if (ret < 0)
return quit_socket_error;
@ -189,9 +173,12 @@ void net_event(struct net_connection* con, int event, void *arg)
if (event == NET_EVENT_DESTROYED)
{
printf("NET_EVENT_DESTROYED\n");
hub_free(user->connection);
user->connection = 0;
printf("NET_EVENT_DESTROYED: con=%p, user=%p\n", con, user);
if (user)
{
user->connection = 0;
}
hub_free(con);
return;
}
@ -217,26 +204,32 @@ void net_event(struct net_connection* con, int event, void *arg)
return;
}
}
else if (event & NET_EVENT_READ)
if (event & NET_EVENT_READ)
{
flag_close = handle_net_read(user);
}
else if (event & NET_EVENT_WRITE)
{
flag_close = handle_net_write(user);
if (flag_close)
{
hub_disconnect_user(g_hub, user, flag_close);
return;
}
}
if (flag_close)
if (event & NET_EVENT_WRITE)
{
hub_disconnect_user(g_hub, user, flag_close);
return;
flag_close = handle_net_write(user);
if (flag_close)
{
hub_disconnect_user(g_hub, user, flag_close);
return;
}
}
}
void net_on_accept(int server_fd, short event, void *arg)
{
struct hub_info* hub = (struct hub_info*) arg;
struct hub_user* user = 0;
struct hub_probe* probe = 0;
struct ip_addr_encap ipaddr;
const char* addr;
@ -269,17 +262,13 @@ void net_on_accept(int server_fd, short event, void *arg)
continue;
}
user = user_create(hub, fd, &ipaddr);
if (!user)
probe = probe_create(hub, fd, &ipaddr);
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);
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);
#endif
if (!user->connection)
return 0;
if (hub_sendq_is_empty(user->send_queue) && !user_flag_get(user, flag_pipeline))
{
/* Perform oportunistic write */

View File

@ -35,27 +35,24 @@ static const char* user_log_str(struct hub_user* user)
}
#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;
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));
if (user == NULL)
return NULL; /* OOM */
user->tm_connected = time(NULL);
user->send_queue = hub_sendq_create();
user->recv_queue = hub_recvq_create();
user->connection = (struct net_connection*) hub_malloc(sizeof(struct net_connection));
net_con_initialize(user->connection, sd, net_event, user, NET_EVENT_READ);
net_con_set_timeout(user->connection, TIMEOUT_CONNECTED);
user->connection = con;
net_con_reinitialize(user->connection, net_event, user, NET_EVENT_READ);
memcpy(&user->id.addr, addr, sizeof(struct ip_addr_encap));
user_set_state(user, state_protocol);
return user;
}

View File

@ -111,7 +111,6 @@ struct hub_user
struct hub_recvq* recv_queue;
struct hub_sendq* send_queue;
struct net_connection* connection; /** Connection data */
time_t tm_connected; /** time when user connected */
struct hub_user_limits limits; /** Data used for limitation */
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
* @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.

View File

@ -180,7 +180,13 @@ void net_con_initialize(struct net_connection* con, int sd, net_connection_cb ca
#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)
{
@ -393,6 +399,41 @@ ssize_t net_con_recv(struct net_connection* con, void* buf, size_t len)
#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)
{
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_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);
/**
@ -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);
/**
* 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.
*

View File

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

View File

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