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:
parent
11e5683a79
commit
2910c571b0
@ -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 \
|
||||
|
@ -435,7 +435,8 @@ const char* acl_password_generate_challenge(struct acl_handle* acl, struct hub_u
|
||||
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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 (!msg) return 0;
|
||||
|
||||
if (length < (msg->length - offset))
|
||||
break;
|
||||
offset = 0;
|
||||
msg = list_get_next(q->queue);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
printf("NET_EVENT_DESTROYED: con=%p, user=%p\n", con, user);
|
||||
if (user)
|
||||
{
|
||||
user->connection = 0;
|
||||
}
|
||||
hub_free(con);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -217,15 +204,10 @@ 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);
|
||||
@ -233,10 +215,21 @@ void net_event(struct net_connection* con, int event, void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
if (event & NET_EVENT_WRITE)
|
||||
{
|
||||
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
115
src/core/probe.c
Normal 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
35
src/core/probe.h
Normal 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 */
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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 */
|
||||
}
|
||||
|
||||
|
||||
|
@ -337,6 +337,7 @@ void runloop(size_t clients)
|
||||
{
|
||||
ADC_client_destroy(client[n]);
|
||||
free(client[n]);
|
||||
client[n] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user