Started splitting up ADC rush. Need a test client before we can proceed anyway.

This commit is contained in:
Jan Vidar Krey 2009-08-28 14:29:19 +02:00
parent 29d6d59d36
commit 52cbec24b6
6 changed files with 580 additions and 498 deletions

View File

@ -164,9 +164,11 @@ libuhub_SOURCES := \
uhub_SOURCES := src/core/main.c uhub_SOURCES := src/core/main.c
libucadc_SOURCES := src/tools/adcclient.c
adcrush_SOURCES := src/tools/adcrush.c adcrush_SOURCES := src/tools/adcrush.c
admin_SOURCES := src/admin.c admin_SOURCES := src/tools/admin.c
uhub_HEADERS := \ uhub_HEADERS := \
src/adc/adcconst.h \ src/adc/adcconst.h \
@ -211,6 +213,7 @@ autotest_OBJECTS = autotest.o
# Source to objects # Source to objects
libuhub_OBJECTS := $(libuhub_SOURCES:.c=.o) libuhub_OBJECTS := $(libuhub_SOURCES:.c=.o)
libucadc_OBJECTS:= $(libucadc_SOURCES:.c=.o)
uhub_OBJECTS := $(uhub_SOURCES:.c=.o) uhub_OBJECTS := $(uhub_SOURCES:.c=.o)
adcrush_OBJECTS := $(adcrush_SOURCES:.c=.o) adcrush_OBJECTS := $(adcrush_SOURCES:.c=.o)
admin_OBJECTS := $(admin_SOURCES:.c=.o) admin_OBJECTS := $(admin_SOURCES:.c=.o)
@ -218,6 +221,7 @@ admin_OBJECTS := $(admin_SOURCES:.c=.o)
all_OBJECTS := $(libuhub_OBJECTS) $(uhub_OBJECTS) $(adcrush_OBJECTS) $(autotest_OBJECTS) $(admin_OBJECTS) all_OBJECTS := $(libuhub_OBJECTS) $(uhub_OBJECTS) $(adcrush_OBJECTS) $(autotest_OBJECTS) $(admin_OBJECTS)
LIBUHUB=libuhub.a LIBUHUB=libuhub.a
LIBUCADC=libucadc.a
uhub_BINARY=uhub$(BIN_EXT) uhub_BINARY=uhub$(BIN_EXT)
adcrush_BINARY=adcrush$(BIN_EXT) adcrush_BINARY=adcrush$(BIN_EXT)
admin_BINARY=uhub-admin$(BIN_EXT) admin_BINARY=uhub-admin$(BIN_EXT)
@ -231,8 +235,8 @@ all: $(uhub_BINARY) $(PCH)
$(adcrush_BINARY): $(PCH) $(LIBUHUB) $(adcrush_OBJECTS) $(adcrush_BINARY): $(PCH) $(LIBUHUB) $(adcrush_OBJECTS)
$(MSG_LD) $(CC) -o $@ $(adcrush_OBJECTS) $(LIBUHUB) $(LDFLAGS) $(LDLIBS) $(MSG_LD) $(CC) -o $@ $(adcrush_OBJECTS) $(LIBUHUB) $(LDFLAGS) $(LDLIBS)
$(admin_BINARY): $(PCH) $(LIBUHUB) $(admin_OBJECTS) $(admin_BINARY): $(PCH) $(LIBUCADC) $(LIBUHUB) $(admin_OBJECTS)
$(MSG_LD) $(CC) -o $@ $(admin_OBJECTS) $(LIBUHUB) $(LDFLAGS) $(LDLIBS) $(MSG_LD) $(CC) -o $@ $(admin_OBJECTS) $(LIBUCADC) $(LIBUHUB) $(LDFLAGS) $(LDLIBS)
$(uhub_BINARY): $(PCH) $(LIBUHUB) $(uhub_OBJECTS) $(uhub_BINARY): $(PCH) $(LIBUHUB) $(uhub_OBJECTS)
$(MSG_LD) $(CC) -o $@ $(uhub_OBJECTS) $(LIBUHUB) $(LDFLAGS) $(LDLIBS) $(MSG_LD) $(CC) -o $@ $(uhub_OBJECTS) $(LIBUHUB) $(LDFLAGS) $(LDLIBS)
@ -240,6 +244,9 @@ $(uhub_BINARY): $(PCH) $(LIBUHUB) $(uhub_OBJECTS)
$(LIBUHUB): $(libuhub_OBJECTS) $(LIBUHUB): $(libuhub_OBJECTS)
$(MSG_AR) $(AR) rc $@ $^ && $(RANLIB) $@ $(MSG_AR) $(AR) rc $@ $^ && $(RANLIB) $@
$(LIBUCADC): $(libucadc_OBJECTS)
$(MSG_AR) $(AR) rc $@ $^ && $(RANLIB) $@
ifeq ($(USE_PCH),YES) ifeq ($(USE_PCH),YES)
$(PCH): $(uhub_HEADERS) $(PCH): $(uhub_HEADERS)
$(MSG_PCH) $(CC) $(CFLAGS) -o $@ $(PCHSRC) $(MSG_PCH) $(CC) $(CFLAGS) -o $@ $(PCHSRC)

405
src/tools/adcclient.c Normal file
View File

@ -0,0 +1,405 @@
/*
* 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 "adcclient.h"
#define ADC_HANDSHAKE "HSUP ADBASE ADTIGR\n"
#define ADC_CID_SIZE 39
#define BIG_BUFSIZE 32768
#define TIGERSIZE 24
static void ADC_client_debug(struct ADC_client* client, const char* format, ...)
{
char logmsg[1024];
va_list args;
va_start(args, format);
vsnprintf(logmsg, 1024, format, args);
va_end(args);
fprintf(stdout, "* [%p] %s\n", client, logmsg);
}
static void ADC_client_set_state(struct ADC_client* client, enum ADC_client_state state)
{
client->state = state;
}
static ssize_t ADC_client_recv(struct ADC_client* client);
static void ADC_client_send_info(struct ADC_client* client);
static void ADC_client_on_connected(struct ADC_client* client);
static void ADC_client_on_disconnected(struct ADC_client* client);
static void ADC_client_on_login(struct ADC_client* client);
static int ADC_client_parse_address(struct ADC_client* client, const char* arg);
static void adc_cid_pid(struct ADC_client* client)
{
char seed[64];
char pid[64];
char cid[64];
uint64_t tiger_res1[3];
uint64_t tiger_res2[3];
/* create cid+pid pair */
memset(seed, 0, 64);
snprintf(seed, 64, VERSION "%p", client);
tiger((uint64_t*) seed, strlen(seed), tiger_res1);
base32_encode((unsigned char*) tiger_res1, TIGERSIZE, pid);
tiger((uint64_t*) tiger_res1, TIGERSIZE, tiger_res2);
base32_encode((unsigned char*) tiger_res2, TIGERSIZE, cid);
cid[ADC_CID_SIZE] = 0;
pid[ADC_CID_SIZE] = 0;
strcat(client->info, " PD");
strcat(client->info, pid);
strcat(client->info, " ID");
strcat(client->info, cid);
}
static void timer_callback(struct net_timer* t, void* arg)
{
}
static void event_callback(struct net_connection* con, int events, void *arg)
{
struct ADC_client* client = (struct ADC_client*) arg;
if (events == NET_EVENT_SOCKERROR || events == NET_EVENT_CLOSED)
{
client->callbacks.connection(client, -1, "Closed/socket error");
return;
}
if (events == NET_EVENT_TIMEOUT)
{
if (client->state == ps_conn)
{
client->callbacks.connection(client, -2, "Connection timed out");
}
}
if (events & NET_EVENT_READ)
{
if (ADC_client_recv(client) == -1)
{
ADC_client_on_disconnected(client);
}
}
if (events & NET_EVENT_WRITE)
{
if (client->state == ps_conn)
{
ADC_client_connect(client, 0);
}
else
{
/* FIXME: Call send again */
}
}
}
static ssize_t ADC_client_recv(struct ADC_client* client)
{
ssize_t size = net_con_recv(client->con, &client->recvbuf[client->r_offset], ADC_BUFSIZE - client->r_offset);
if (size <= 0)
return size;
client->recvbuf[client->r_offset + size] = 0;
char* start = client->recvbuf;
char* pos;
char* lastPos = 0;
while ((pos = strchr(start, '\n')))
{
lastPos = pos;
pos[0] = 0;
ADC_client_debug(client, "- RECV: '%s'", start);
fourcc_t cmd = 0;
if (strlen(start) < 4)
{
ADC_client_debug(client, "Unexpected response from hub: '%s'", start);
start = &pos[1];
continue;
}
cmd = FOURCC(start[0], start[1], start[2], start[3]);
switch (cmd)
{
case ADC_CMD_ISUP:
break;
case ADC_CMD_ISID:
if (client->state == ps_protocol)
{
client->sid = string_to_sid(&start[5]);
ADC_client_set_state(client, ps_identify);
ADC_client_send_info(client);
}
break;
case ADC_CMD_IINF:
break;
case ADC_CMD_BSCH:
case ADC_CMD_FSCH:
{
break;
}
case ADC_CMD_BINF:
{
if (strlen(start) > 9)
{
char t = start[9]; start[9] = 0; sid_t sid = string_to_sid(&start[5]); start[9] = t;
if (sid == client->sid)
{
if (client->state == ps_verify || client->state == ps_identify)
{
ADC_client_on_login(client);
}
}
}
break;
}
case ADC_CMD_ISTA:
if (strncmp(start, "ISTA 000", 8))
{
ADC_client_debug(client, "status: '%s'\n", (start + 9));
}
break;
default:
break;
}
start = &pos[1];
}
if (lastPos)
{
client->r_offset = strlen(lastPos);
memmove(client->recvbuf, lastPos, strlen(lastPos));
memset(&client->recvbuf[client->r_offset], 0, ADC_BUFSIZE-client->r_offset);
}
else
{
// client->r_offset = size;
}
return 0;
}
void ADC_client_send(struct ADC_client* client, char* msg)
{
int ret = net_con_send(client->con, msg, strlen(msg));
#ifdef ADC_CLIENT_DEBUG_PROTO
char* dump = strdup(msg);
dump[strlen(msg) - 1] = 0;
ADC_client_debug(client, "- SEND: '%s'", dump);
free(dump);
#endif
if (ret != strlen(msg))
{
if (ret == -1)
{
if (net_error() != EWOULDBLOCK)
ADC_client_on_disconnected(client);
}
else
{
/* FIXME: Not all data sent! */
printf("ret (%d) != msg->length (%d)\n", ret, (int) strlen(msg));
}
}
}
void ADC_client_send_info(struct ADC_client* client)
{
client->info[0] = 0;
strcat(client->info, "BINF ");
strcat(client->info, sid_to_string(client->sid));
strcat(client->info, " NI");
strcat(client->info, client->nick); /* FIXME: no escaping */
strcat(client->info, "_");
strcat(client->info, uhub_itoa(client->sid));
strcat(client->info, " VE" VERSION);
if (client->desc)
{
strcat(client->info, " DE");
strcat(client->info, client->desc); /* FIXME: no escaping */
}
strcat(client->info, " I40.0.0.0");
strcat(client->info, " EMuhub@extatic.org");
strcat(client->info, " SL3");
strcat(client->info, " HN1");
strcat(client->info, " HR1");
strcat(client->info, " HO1");
adc_cid_pid(client);
strcat(client->info, "\n");
ADC_client_send(client, client->info);
}
int ADC_client_create(struct ADC_client* client, const char* nickname, const char* description)
{
memset(client, 0, sizeof(struct ADC_client));
int sd = net_socket_create(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sd == -1) return -1;
client->con = hub_malloc(sizeof(struct net_connection));
client->timer = hub_malloc(sizeof(struct net_timer));
net_con_initialize(client->con, sd, 0, event_callback, client, 0);
net_timer_initialize(client->timer, timer_callback, client);
ADC_client_set_state(client, ps_none);
client->nick = hub_strdup(nickname);
client->desc = hub_strdup(description);
return 0;
}
void ADC_client_destroy(struct ADC_client* client)
{
ADC_client_disconnect(client);
net_timer_shutdown(client->timer);
hub_free(client->nick);
hub_free(client->desc);
hub_free(client->hub_address);
}
int ADC_client_connect(struct ADC_client* client, const char* address)
{
if (!client->hub_address)
{
if (!ADC_client_parse_address(client, address))
return 0;
client->hub_address = hub_strdup(address);
}
int ret = net_connect(client->con->sd, (struct sockaddr*) &client->addr, sizeof(struct sockaddr_in));
if (ret == 0 || (ret == -1 && net_error() == EISCONN))
{
ADC_client_on_connected(client);
}
else if (ret == -1 && (net_error() == EALREADY || net_error() == EINPROGRESS || net_error() == EWOULDBLOCK || net_error() == EINTR))
{
if (client->state != ps_conn)
{
net_con_update(client->con, NET_EVENT_READ | NET_EVENT_WRITE);
ADC_client_set_state(client, ps_conn);
ADC_client_debug(client, "connecting...");
}
}
else
{
ADC_client_on_disconnected(client);
return 0;
}
return 1;
}
static void ADC_client_on_connected(struct ADC_client* client)
{
net_con_update(client->con, NET_EVENT_READ);
ADC_client_send(client, ADC_HANDSHAKE);
ADC_client_set_state(client, ps_protocol);
ADC_client_debug(client, "connected.");
}
static void ADC_client_on_disconnected(struct ADC_client* client)
{
net_con_close(client->con);
hub_free(client->con);
client->con = 0;
ADC_client_debug(client, "disconnected.");
ADC_client_set_state(client, ps_none);
}
static void ADC_client_on_login(struct ADC_client* client)
{
ADC_client_debug(client, "logged in.");
ADC_client_set_state(client, ps_normal);
}
void ADC_client_disconnect(struct ADC_client* client)
{
if (client->con->sd != -1)
{
net_con_close(client->con);
ADC_client_debug(client, "disconnected.");
}
}
static int ADC_client_parse_address(struct ADC_client* client, const char* arg)
{
char* split;
struct hostent* dns;
struct in_addr* addr;
if (!arg)
return 0;
/* Minimum length of a valid address */
if (strlen(arg) < 9)
return 0;
/* Check for ADC or ADCS */
if (strncmp(arg, "adc://", 6) != 0 && strncmp(arg, "adcs://", 7) != 0)
return 0;
/* Split hostname and port (if possible) */
split = strrchr(arg+6, ':');
if (split == 0 || strlen(split) < 2 || strlen(split) > 6)
return 0;
/* Ensure port number is valid */
int port = strtol(split+1, NULL, 10);
if (port <= 0 || port > 65535)
return 0;
split[0] = 0;
/* Resolve IP address (FIXME: blocking call) */
dns = gethostbyname(arg+6);
if (dns)
{
addr = (struct in_addr*) dns->h_addr_list[0];
}
// Initialize the sockaddr struct.
memset(&client->addr, 0, sizeof(client->addr));
client->addr.sin_family = AF_INET;
client->addr.sin_port = htons(port);
memcpy(&client->addr.sin_addr, &addr, sizeof(struct in_addr));
return 1;
}

92
src/tools/adcclient.h Normal file
View File

@ -0,0 +1,92 @@
/*
* 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_ADC_CLIENT_H
#define HAVE_UHUB_ADC_CLIENT_H
#define ADC_BUFSIZE 16384
#define ADC_SIDSIZE 4
enum ADC_client_state
{
ps_none = 0x00, /* Not connected */
ps_conn = 0x01, /* Connecting... */
ps_protocol = 0x02, /* Have sent HSUP */
ps_identify = 0x04, /* Have sent BINF */
ps_verify = 0x08, /* Have sent HPAS */
ps_normal = 0x10, /* Are fully logged in */
};
struct ADC_client;
typedef void (*adc_client_connection_status_cb)(struct ADC_client*, int code, const char* data);
typedef void (*adc_client_message_cb)(struct ADC_client*, const char* msg, int flags);
typedef void (*adc_client_status_cb)(struct ADC_client*, const char* status, int code);
struct ADC_client_callbacks
{
adc_client_connection_status_cb connection;
adc_client_message_cb message;
adc_client_status_cb status;
};
struct ADC_client
{
sid_t sid;
enum ADC_client_state state;
char info[ADC_BUFSIZE];
char recvbuf[ADC_BUFSIZE];
char sendbuf[ADC_BUFSIZE];
size_t s_offset;
size_t r_offset;
size_t timeout;
struct net_connection* con;
struct net_timer* timer;
struct ADC_client_callbacks callbacks;
struct sockaddr_in addr;
char* hub_address;
char* nick;
char* desc;
};
/**
* Create/Allocate/Initialize an ADC_client struct
* NOTE: If this is successful, one must call ADC_client_destroy to cleanup afterwards.
*/
extern int ADC_client_create(struct ADC_client* client, const char* nickname, const char* description);
/**
* Destroy an ADC_client struct.
*/
extern void ADC_client_destroy(struct ADC_client* client);
extern int ADC_client_connect(struct ADC_client* client, const char* address);
extern void ADC_client_disconnect(struct ADC_client* client);
/**
* Send a message (ADC command)
*/
extern void ADC_client_send(struct ADC_client* client, char* msg);
#endif /* HAVE_UHUB_ADC_CLIENT_H */

View File

@ -2,19 +2,16 @@
* An ADC client emulator. * An ADC client emulator.
*/ */
#include "uhub.h" #include "adcclient.h"
#define ADC_CLIENTS_DEFAULT 100 #define ADC_CLIENTS_DEFAULT 100
#define ADC_MAX_CLIENTS 25000 #define ADC_MAX_CLIENTS 25000
#define ADC_BUFSIZE 16384
#define ADC_SIDSIZE 4
#define ADC_CID_SIZE 39 #define ADC_CID_SIZE 39
#define BIG_BUFSIZE 32768 #define BIG_BUFSIZE 32768
#define TIGERSIZE 24 #define TIGERSIZE 24
#define ADC_HANDSHAKE "HSUP ADBASE ADTIGR\n"
#define ADCRUSH "adcrush/0.2" #define ADCRUSH "adcrush/0.2"
#define ADC_NICK "[BOT]adcrush" #define ADC_NICK "[BOT]adcrush"
#define ADC_DESC "crash\\stest\\sdummy" #define ADC_DESC "crash\\stest\\sdummy"
@ -23,16 +20,6 @@
#define LVL_DEBUG 2 #define LVL_DEBUG 2
#define LVL_VERBOSE 3 #define LVL_VERBOSE 3
struct ADC_client;
static void ADC_client_on_disconnected(struct ADC_client*);
static void ADC_client_on_connected(struct ADC_client*);
static void ADC_client_on_login(struct ADC_client*);
static void ADC_client_connect(struct ADC_client*);
static void ADC_client_disconnect(struct ADC_client*);
static int ADC_client_create(struct ADC_client* client, int num);
static void ADC_client_destroy(struct ADC_client* client);
static int cfg_mode = 0; // See enum operationMode static int cfg_mode = 0; // See enum operationMode
static char* cfg_host = 0; static char* cfg_host = 0;
static int cfg_port = 0; static int cfg_port = 0;
@ -46,35 +33,6 @@ static int running = 1;
static struct sockaddr_in saddr; static struct sockaddr_in saddr;
enum commandMode
{
cm_bcast = 0x01, /* B - broadcast */
cm_dir = 0x02, /* D - direct message */
cm_echo = 0x04, /* E - echo message */
cm_fcast = 0x08, /* F - feature cast message */
cm_c2h = 0x10, /* H - client to hub message */
cm_h2c = 0x20, /* I - hub to client message */
cm_c2c = 0x40, /* C - client to client message */
cm_udp = 0x80, /* U - udp message (client to client) */
};
enum commandValidity
{
cv_protocol = 0x01,
cv_identify = 0x02,
cv_verify = 0x04,
cv_normal = 0x08,
};
enum protocolState
{
ps_none = 0x00, /* none or disconnected */
ps_conn = 0x01, /* connecting... */
ps_protocol = 0x02,
ps_identify = 0x04,
ps_verify = 0x08,
ps_normal = 0x10,
};
enum operationMode enum operationMode
{ {
@ -91,20 +49,6 @@ struct commandPattern
unsigned char validity; /* see enum commandValidity */ unsigned char validity; /* see enum commandValidity */
}; };
const struct commandPattern patterns[] =
{
{ cm_c2h | cm_c2c | cm_h2c, "SUP", cv_protocol | cv_normal }, /* protocol support */
{ cm_bcast | cm_h2c | cm_c2c, "INF", cv_identify | cv_verify | cv_normal }, /* info message */
{ cm_bcast | cm_h2c | cm_c2c | cm_c2h | cm_udp, "STA", cv_protocol | cv_identify | cv_verify | cv_normal }, /* status message */
{ cm_bcast | cm_dir | cm_echo | cm_h2c, "MSG", cv_normal }, /* chat message */
{ cm_bcast | cm_dir | cm_echo | cm_fcast, "SCH", cv_normal }, /* search */
{ cm_dir | cm_udp, "RES", cv_normal }, /* search result */
{ cm_dir | cm_echo, "CTM", cv_normal }, /* connect to me */
{ cm_dir | cm_echo, "RCM", cv_normal }, /* reversed, connect to me */
{ cm_h2c, "QUI", cv_normal }, /* quit message */
{ cm_h2c, "GPA", cv_identify }, /* password request */
{ cm_c2h, "PAS", cv_verify } /* password response */
};
#define MAX_CHAT_MSGS 35 #define MAX_CHAT_MSGS 35
const char* chat_messages[MAX_CHAT_MSGS] = { const char* chat_messages[MAX_CHAT_MSGS] = {
@ -159,21 +103,6 @@ const char* search_messages[MAX_SEARCH_MSGS] = {
"ANburnout ANps3 TOauto", "ANburnout ANps3 TOauto",
}; };
struct ADC_client
{
int num;
sid_t sid;
enum protocolState state;
char info[ADC_BUFSIZE];
char recvbuf[BIG_BUFSIZE];
char sendbuf[BIG_BUFSIZE];
size_t s_offset;
size_t r_offset;
size_t timeout;
struct net_connection* con;
struct net_timer* timer;
};
static void bot_output(struct ADC_client* client, int level, const char* format, ...) static void bot_output(struct ADC_client* client, int level, const char* format, ...)
@ -191,36 +120,10 @@ static void bot_output(struct ADC_client* client, int level, const char* format,
else else
{ {
if (cfg_debug >= level) if (cfg_debug >= level)
fprintf(stdout, "* [%4d] %s\n", client->num, logmsg); fprintf(stdout, "* [%p] %s\n", client, logmsg);
} }
} }
static void adc_cid_pid(struct ADC_client* client)
{
char seed[64];
char pid[64];
char cid[64];
uint64_t tiger_res1[3];
uint64_t tiger_res2[3];
/* create cid+pid pair */
memset(seed, 0, 64);
snprintf(seed, 64, ADCRUSH "%p/%d", client, client->num);
tiger((uint64_t*) seed, strlen(seed), tiger_res1);
base32_encode((unsigned char*) tiger_res1, TIGERSIZE, pid);
tiger((uint64_t*) tiger_res1, TIGERSIZE, tiger_res2);
base32_encode((unsigned char*) tiger_res2, TIGERSIZE, cid);
cid[ADC_CID_SIZE] = 0;
pid[ADC_CID_SIZE] = 0;
strcat(client->info, " PD");
strcat(client->info, pid);
strcat(client->info, " ID");
strcat(client->info, cid);
}
static size_t get_wait_rand(size_t max) static size_t get_wait_rand(size_t max)
{ {
static size_t next = 0; static size_t next = 0;
@ -229,317 +132,8 @@ static size_t get_wait_rand(size_t max)
return ((size_t )(next / 65536) % max); return ((size_t )(next / 65536) % max);
} }
static void client_reschedule_timeout(struct ADC_client* client)
{
size_t next_timeout = 0;
switch (client->state)
{
case ps_conn: next_timeout = 30; break;
case ps_protocol: next_timeout = 30; break;
case ps_identify: next_timeout = 30; break;
case ps_verify: next_timeout = 30; break;
case ps_normal: next_timeout = 120; break;
case ps_none: next_timeout = 120; break;
}
if (client->state == ps_normal || client->state == ps_none)
{
switch (cfg_level)
{
case 0: /* polite */
next_timeout *= 4;
break;
case 1: /* normal */
break;
case 2: /* aggressive */
next_timeout /= 8;
break;
case 3: /* excessive */
next_timeout /= 16;
case 4: /* excessive */
next_timeout /= 32;
}
}
if (client->state == ps_conn)
client->timeout = MAX(next_timeout, 1);
else
client->timeout = get_wait_rand(MAX(next_timeout, 1));
if (!client->timeout) client->timeout++;
net_timer_reset(client->timer, client->timeout);
}
static void set_state_timeout(struct ADC_client* client, enum protocolState state)
{
client->state = state;
client_reschedule_timeout(client);
}
static void send_client(struct ADC_client* client, char* msg)
{
int ret = net_con_send(client->con, msg, strlen(msg));
if (cfg_debug > 1)
{
char* dump = strdup(msg);
dump[strlen(msg) - 1] = 0;
bot_output(client, LVL_INFO, "- SEND: '%s'", dump);
free(dump);
}
if (ret != strlen(msg))
{
if (ret == -1)
{
if (net_error() != EWOULDBLOCK)
ADC_client_on_disconnected(client);
}
else
{
/* FIXME: Not all data sent! */
printf("ret (%d) != msg->length (%d)\n", ret, (int) strlen(msg));
}
}
}
static void ADC_client_on_connected(struct ADC_client* client)
{
net_con_update(client->con, NET_EVENT_READ);
send_client(client, ADC_HANDSHAKE);
set_state_timeout(client, ps_protocol);
bot_output(client, LVL_INFO, "connected.");
}
static void ADC_client_on_disconnected(struct ADC_client* client)
{
net_con_close(client->con);
hub_free(client->con);
client->con = 0;
bot_output(client, LVL_INFO, "disconnected.");
set_state_timeout(client, ps_none);
}
static void ADC_client_on_login(struct ADC_client* client)
{
bot_output(client, LVL_INFO, "logged in.");
set_state_timeout(client, ps_normal);
}
static void send_client_info(struct ADC_client* client)
{
client->info[0] = 0;
strcat(client->info, "BINF ");
strcat(client->info, sid_to_string(client->sid));
strcat(client->info, " NI" ADC_NICK);
if (cfg_clients > 1)
{
strcat(client->info, "_");
strcat(client->info, uhub_itoa(client->num));
}
strcat(client->info, " VE" ADCRUSH);
strcat(client->info, " DE" ADC_DESC);
strcat(client->info, " I40.0.0.0");
strcat(client->info, " EMuhub@extatic.org");
strcat(client->info, " SL3");
strcat(client->info, " HN1");
strcat(client->info, " HR1");
strcat(client->info, " HO1");
adc_cid_pid(client);
strcat(client->info, "\n");
send_client(client, client->info);
}
static void perf_result(struct ADC_client* client, sid_t target, const char* what, const char* token); static void perf_result(struct ADC_client* client, sid_t target, const char* what, const char* token);
static int recv_client(struct ADC_client* client)
{
ssize_t size = 0;
if (cfg_mode != mode_performance || (cfg_mode == mode_performance && (get_wait_rand(100) < (90 - (15 * cfg_level)))))
{
size = net_con_recv(client->con, &client->recvbuf[client->r_offset], ADC_BUFSIZE - client->r_offset);
}
else
{
if (get_wait_rand(1000) == 99)
return -1; /* Can break tings badly! :-) */
else
return 0;
}
if (size == 0 || ((size == -1 && net_error() != EWOULDBLOCK)))
return -1;
client->recvbuf[client->r_offset + size] = 0;
char* start = client->recvbuf;
char* pos;
char* lastPos = 0;
while ((pos = strchr(start, '\n')))
{
lastPos = pos;
pos[0] = 0;
bot_output(client, LVL_VERBOSE, "- RECV: '%s'", start);
fourcc_t cmd = 0;
if (strlen(start) < 4)
{
bot_output(client, LVL_INFO, "Unexpected response from hub: '%s'", start);
start = &pos[1];
continue;
}
cmd = FOURCC(start[0], start[1], start[2], start[3]);
switch (cmd)
{
case ADC_CMD_ISUP:
break;
case ADC_CMD_ISID:
if (client->state == ps_protocol)
{
client->sid = string_to_sid(&start[5]);
client->state = ps_identify;
send_client_info(client);
}
break;
case ADC_CMD_IINF:
break;
case ADC_CMD_BSCH:
case ADC_CMD_FSCH:
{
if (get_wait_rand(100) > (90 - (10 * cfg_level)) && cfg_mode == mode_performance)
{
sid_t target = string_to_sid(&start[5]);
const char* what = strstr(&start[5], " AN");
const char* token = strstr(&start[5], " TO");
char* split = 0;
if (!token || !what) break;
token += 3;
what += 3;
split = strchr(what, ' ');
if (!split) break;
else split[0] = '0';
split = strchr(token, ' ');
if (split) split[0] = '0';
perf_result(client, target, what, token);
}
break;
}
case ADC_CMD_BINF:
{
if (strlen(start) > 9)
{
char t = start[9]; start[9] = 0; sid_t sid = string_to_sid(&start[5]); start[9] = t;
if (sid == client->sid)
{
if (client->state == ps_verify || client->state == ps_identify)
{
ADC_client_on_login(client);
}
}
}
break;
}
case ADC_CMD_ISTA:
if (strncmp(start, "ISTA 000", 8))
{
bot_output(client, LVL_INFO, "status: '%s'\n", (start + 9));
}
break;
default:
break;
}
start = &pos[1];
}
if (lastPos)
{
client->r_offset = strlen(lastPos);
memmove(client->recvbuf, lastPos, strlen(lastPos));
memset(&client->recvbuf[client->r_offset], 0, ADC_BUFSIZE-client->r_offset);
}
else
{
// client->r_offset = size;
}
return 0;
}
void ADC_client_connect(struct ADC_client* client)
{
int ret = net_connect(client->con->sd, (struct sockaddr*) &saddr, sizeof(struct sockaddr_in));
if (ret == 0 || (ret == -1 && net_error() == EISCONN))
{
ADC_client_on_connected(client);
}
else if (ret == -1 && (net_error() == EALREADY || net_error() == EINPROGRESS || net_error() == EWOULDBLOCK || net_error() == EINTR))
{
if (client->state != ps_conn)
{
net_con_update(client->con, NET_EVENT_READ | NET_EVENT_WRITE);
set_state_timeout(client, ps_conn);
bot_output(client, LVL_INFO, "connecting...");
}
}
else
{
ADC_client_on_disconnected(client);
}
}
void ADC_client_wait_connect(struct ADC_client* client)
{
set_state_timeout(client, ps_none);
}
void ADC_client_disconnect(struct ADC_client* client)
{
if (client->con->sd != -1)
{
net_con_close(client->con);
bot_output(client, LVL_INFO, "disconnected.");
if (running)
{
ADC_client_destroy(client);
ADC_client_create(client, client->num);
ADC_client_connect(client);
}
}
}
static void perf_chat(struct ADC_client* client, int priv) static void perf_chat(struct ADC_client* client, int priv)
{ {
char buf[1024] = { 0, }; char buf[1024] = { 0, };
@ -564,7 +158,7 @@ static void perf_chat(struct ADC_client* client, int priv)
hub_free(msg); hub_free(msg);
strcat(buf, "\n"); strcat(buf, "\n");
send_client(client, buf); ADC_client_send(client, buf);
} }
static void perf_search(struct ADC_client* client) static void perf_search(struct ADC_client* client)
@ -587,7 +181,7 @@ static void perf_search(struct ADC_client* client)
} }
strcat(buf, search_messages[r]); strcat(buf, search_messages[r]);
strcat(buf, "\n"); strcat(buf, "\n");
send_client(client, buf); ADC_client_send(client, buf);
} }
static void perf_result(struct ADC_client* client, sid_t target, const char* what, const char* token) static void perf_result(struct ADC_client* client, sid_t target, const char* what, const char* token)
@ -606,7 +200,7 @@ static void perf_result(struct ADC_client* client, sid_t target, const char* wha
strcat(buf, " TO"); strcat(buf, " TO");
strcat(buf, token); strcat(buf, token);
strcat(buf, "\n"); strcat(buf, "\n");
send_client(client, buf); ADC_client_send(client, buf);
} }
static void perf_ctm(struct ADC_client* client) static void perf_ctm(struct ADC_client* client)
@ -621,7 +215,7 @@ static void perf_ctm(struct ADC_client* client)
strcat(buf, " TOKEN111"); strcat(buf, " TOKEN111");
strcat(buf, sid_to_string(client->sid)); strcat(buf, sid_to_string(client->sid));
strcat(buf, "\n"); strcat(buf, "\n");
send_client(client, buf); ADC_client_send(client, buf);
} }
@ -636,7 +230,7 @@ static void perf_update(struct ADC_client* client)
strcat(buf, uhub_itoa(n)); strcat(buf, uhub_itoa(n));
strcat(buf, "\n"); strcat(buf, "\n");
send_client(client, buf); ADC_client_send(client, buf);
} }
@ -685,80 +279,8 @@ static void perf_normal_action(struct ADC_client* client)
break; break;
} }
client_reschedule_timeout(client);
} }
void timer_callback(struct net_timer* t, void* arg)
{
struct ADC_client* client = (struct ADC_client*) arg;
if (client->state == ps_none)
{
ADC_client_create(client, client->num);
ADC_client_connect(client);
}
}
void event_callback(struct net_connection* con, int events, void *arg)
{
struct ADC_client* client = (struct ADC_client*) arg;
if (events == NET_EVENT_SOCKERROR || events == NET_EVENT_CLOSED)
{
ADC_client_on_disconnected(client);
}
if (events == NET_EVENT_TIMEOUT)
{
if (client->state == ps_none)
{
ADC_client_connect(client);
}
}
if (events & NET_EVENT_READ)
{
if (recv_client(client) == -1)
{
ADC_client_on_disconnected(client);
}
}
if (events & NET_EVENT_WRITE)
{
if (client->state == ps_conn)
{
ADC_client_connect(client);
}
else
{
/* FIXME: Call send again */
}
}
}
int ADC_client_create(struct ADC_client* client, int num)
{
memset(client, 0, sizeof(struct ADC_client));
client->num = num;
int sd = net_socket_create(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sd == -1) return -1;
client->con = hub_malloc(sizeof(struct net_connection));
client->timer = hub_malloc(sizeof(struct net_timer));
net_con_initialize(client->con, sd, 0, event_callback, client, 0);
net_timer_initialize(client->timer, timer_callback, client);
set_state_timeout(client, ps_none);
return 0;
}
void ADC_client_destroy(struct ADC_client* client)
{
ADC_client_disconnect(client);
net_timer_shutdown(client->timer);
}
void runloop(size_t clients) void runloop(size_t clients)
{ {
size_t n = 0; size_t n = 0;
@ -769,17 +291,13 @@ void runloop(size_t clients)
struct ADC_client* c = malloc(sizeof(struct ADC_client)); struct ADC_client* c = malloc(sizeof(struct ADC_client));
client[n] = c; client[n] = c;
ADC_client_create(c, n); char nick[20];
if (n == 0) snprintf(nick, 20, "adcrush_%d", (int) n);
{
ADC_client_connect(c); ADC_client_create(c, nick, "stresstester");
} ADC_client_connect(c, "adc://adc.extatic.org:1511");
else
{
ADC_client_wait_connect(c);
}
} }
event_dispatch(); event_dispatch();
for (n = 0; n < clients; n++) for (n = 0; n < clients; n++)

25
src/tools/admin.c Normal file
View File

@ -0,0 +1,25 @@
/**
* A remote uhub admin client.
*/
#include "uhub.h"
#include "adcclient.h"
#include "network/connection.h"
int main(int argc, char** argv)
{
struct ADC_client client;
net_initialize();
ADC_client_create(&client, "uhub-admin", "stresstester");
ADC_client_connect(&client, "adc://adc.extatic.org:1511");
event_dispatch();
ADC_client_destroy(&client);
net_destroy();
return 0;
}

35
src/tools/fuzzer.h Normal file
View File

@ -0,0 +1,35 @@
enum commandMode
{
cm_bcast = 0x01, /* B - broadcast */
cm_dir = 0x02, /* D - direct message */
cm_echo = 0x04, /* E - echo message */
cm_fcast = 0x08, /* F - feature cast message */
cm_c2h = 0x10, /* H - client to hub message */
cm_h2c = 0x20, /* I - hub to client message */
cm_c2c = 0x40, /* C - client to client message */
cm_udp = 0x80, /* U - udp message (client to client) */
};
enum commandValidity
{
cv_protocol = 0x01,
cv_identify = 0x02,
cv_verify = 0x04,
cv_normal = 0x08,
};
const struct commandPattern patterns[] =
{
{ cm_c2h | cm_c2c | cm_h2c, "SUP", cv_protocol | cv_normal }, /* protocol support */
{ cm_bcast | cm_h2c | cm_c2c, "INF", cv_identify | cv_verify | cv_normal }, /* info message */
{ cm_bcast | cm_h2c | cm_c2c | cm_c2h | cm_udp, "STA", cv_protocol | cv_identify | cv_verify | cv_normal }, /* status message */
{ cm_bcast | cm_dir | cm_echo | cm_h2c, "MSG", cv_normal }, /* chat message */
{ cm_bcast | cm_dir | cm_echo | cm_fcast, "SCH", cv_normal }, /* search */
{ cm_dir | cm_udp, "RES", cv_normal }, /* search result */
{ cm_dir | cm_echo, "CTM", cv_normal }, /* connect to me */
{ cm_dir | cm_echo, "RCM", cv_normal }, /* reversed, connect to me */
{ cm_h2c, "QUI", cv_normal }, /* quit message */
{ cm_h2c, "GPA", cv_identify }, /* password request */
{ cm_c2h, "PAS", cv_verify } /* password response */
};