Started splitting up ADC rush. Need a test client before we can proceed anyway.
This commit is contained in:
parent
29d6d59d36
commit
52cbec24b6
13
GNUmakefile
13
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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
||||
|
|
@ -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,15 +291,11 @@ 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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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 */
|
||||
};
|
||||
|
Loading…
Reference in New Issue