diff --git a/GNUmakefile b/GNUmakefile index 87205a5..9da323c 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -164,9 +164,11 @@ libuhub_SOURCES := \ uhub_SOURCES := src/core/main.c +libucadc_SOURCES := src/tools/adcclient.c + adcrush_SOURCES := src/tools/adcrush.c -admin_SOURCES := src/admin.c +admin_SOURCES := src/tools/admin.c uhub_HEADERS := \ src/adc/adcconst.h \ @@ -211,6 +213,7 @@ autotest_OBJECTS = autotest.o # Source to objects libuhub_OBJECTS := $(libuhub_SOURCES:.c=.o) +libucadc_OBJECTS:= $(libucadc_SOURCES:.c=.o) uhub_OBJECTS := $(uhub_SOURCES:.c=.o) adcrush_OBJECTS := $(adcrush_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) LIBUHUB=libuhub.a +LIBUCADC=libucadc.a uhub_BINARY=uhub$(BIN_EXT) adcrush_BINARY=adcrush$(BIN_EXT) admin_BINARY=uhub-admin$(BIN_EXT) @@ -231,8 +235,8 @@ all: $(uhub_BINARY) $(PCH) $(adcrush_BINARY): $(PCH) $(LIBUHUB) $(adcrush_OBJECTS) $(MSG_LD) $(CC) -o $@ $(adcrush_OBJECTS) $(LIBUHUB) $(LDFLAGS) $(LDLIBS) -$(admin_BINARY): $(PCH) $(LIBUHUB) $(admin_OBJECTS) - $(MSG_LD) $(CC) -o $@ $(admin_OBJECTS) $(LIBUHUB) $(LDFLAGS) $(LDLIBS) +$(admin_BINARY): $(PCH) $(LIBUCADC) $(LIBUHUB) $(admin_OBJECTS) + $(MSG_LD) $(CC) -o $@ $(admin_OBJECTS) $(LIBUCADC) $(LIBUHUB) $(LDFLAGS) $(LDLIBS) $(uhub_BINARY): $(PCH) $(LIBUHUB) $(uhub_OBJECTS) $(MSG_LD) $(CC) -o $@ $(uhub_OBJECTS) $(LIBUHUB) $(LDFLAGS) $(LDLIBS) @@ -240,6 +244,9 @@ $(uhub_BINARY): $(PCH) $(LIBUHUB) $(uhub_OBJECTS) $(LIBUHUB): $(libuhub_OBJECTS) $(MSG_AR) $(AR) rc $@ $^ && $(RANLIB) $@ +$(LIBUCADC): $(libucadc_OBJECTS) + $(MSG_AR) $(AR) rc $@ $^ && $(RANLIB) $@ + ifeq ($(USE_PCH),YES) $(PCH): $(uhub_HEADERS) $(MSG_PCH) $(CC) $(CFLAGS) -o $@ $(PCHSRC) diff --git a/src/tools/adcclient.c b/src/tools/adcclient.c new file mode 100644 index 0000000..c345a9c --- /dev/null +++ b/src/tools/adcclient.c @@ -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 . + * + */ + +#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; +} + diff --git a/src/tools/adcclient.h b/src/tools/adcclient.h new file mode 100644 index 0000000..6e52b91 --- /dev/null +++ b/src/tools/adcclient.h @@ -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 . + * + */ + +#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 */ + + diff --git a/src/tools/adcrush.c b/src/tools/adcrush.c index 1f363ff..ca492ac 100644 --- a/src/tools/adcrush.c +++ b/src/tools/adcrush.c @@ -2,19 +2,16 @@ * An ADC client emulator. */ -#include "uhub.h" +#include "adcclient.h" #define ADC_CLIENTS_DEFAULT 100 #define ADC_MAX_CLIENTS 25000 -#define ADC_BUFSIZE 16384 -#define ADC_SIDSIZE 4 #define ADC_CID_SIZE 39 #define BIG_BUFSIZE 32768 #define TIGERSIZE 24 -#define ADC_HANDSHAKE "HSUP ADBASE ADTIGR\n" #define ADCRUSH "adcrush/0.2" #define ADC_NICK "[BOT]adcrush" #define ADC_DESC "crash\\stest\\sdummy" @@ -23,16 +20,6 @@ #define LVL_DEBUG 2 #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 char* cfg_host = 0; static int cfg_port = 0; @@ -46,35 +33,6 @@ static int running = 1; 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 { @@ -91,20 +49,6 @@ struct commandPattern 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 const char* chat_messages[MAX_CHAT_MSGS] = { @@ -159,21 +103,6 @@ const char* search_messages[MAX_SEARCH_MSGS] = { "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, ...) @@ -191,36 +120,10 @@ static void bot_output(struct ADC_client* client, int level, const char* format, else { 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 next = 0; @@ -229,317 +132,8 @@ static size_t get_wait_rand(size_t 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 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) { char buf[1024] = { 0, }; @@ -564,7 +158,7 @@ static void perf_chat(struct ADC_client* client, int priv) hub_free(msg); strcat(buf, "\n"); - send_client(client, buf); + ADC_client_send(client, buf); } 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, "\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) @@ -606,7 +200,7 @@ static void perf_result(struct ADC_client* client, sid_t target, const char* wha strcat(buf, " TO"); strcat(buf, token); strcat(buf, "\n"); - send_client(client, buf); + ADC_client_send(client, buf); } 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, sid_to_string(client->sid)); 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, "\n"); - send_client(client, buf); + ADC_client_send(client, buf); } @@ -685,80 +279,8 @@ static void perf_normal_action(struct ADC_client* client) 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) { size_t n = 0; @@ -769,17 +291,13 @@ void runloop(size_t clients) struct ADC_client* c = malloc(sizeof(struct ADC_client)); client[n] = c; - ADC_client_create(c, n); - if (n == 0) - { - ADC_client_connect(c); - } - else - { - ADC_client_wait_connect(c); - } + char nick[20]; + snprintf(nick, 20, "adcrush_%d", (int) n); + + ADC_client_create(c, nick, "stresstester"); + ADC_client_connect(c, "adc://adc.extatic.org:1511"); } - + event_dispatch(); for (n = 0; n < clients; n++) diff --git a/src/tools/admin.c b/src/tools/admin.c new file mode 100644 index 0000000..a33f750 --- /dev/null +++ b/src/tools/admin.c @@ -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; +} + + diff --git a/src/tools/fuzzer.h b/src/tools/fuzzer.h new file mode 100644 index 0000000..b3f7d81 --- /dev/null +++ b/src/tools/fuzzer.h @@ -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 */ +}; +