1 /*
2  * uhub - A tiny ADC p2p connection hub
3  * Copyright (C) 2007-2014, Jan Vidar Krey
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  *
18  */
19 
20 #include "adcclient.h"
21 
22 #define ADC_CLIENTS_DEFAULT 100
23 #define ADC_MAX_CLIENTS 25000
24 #define ADC_CID_SIZE 39
25 #define BIG_BUFSIZE 32768
26 #define TIGERSIZE 24
27 #define STATS_INTERVAL 3
28 #define ADCRUSH "adcrush/0.3"
29 #define ADC_NICK "[BOT]adcrush"
30 #define ADC_DESC "crash\\stest\\sdummy"
31 
32 
33 #define LVL_INFO 1
34 #define LVL_DEBUG 2
35 #define LVL_VERBOSE 3
36 
37 static const char* cfg_uri = 0; /* address */
38 static int cfg_debug       = 0; /* debug level */
39 static int cfg_level       = 1; /* activity level (0..3) */
40 static int cfg_chat        = 0; /* chat mode, allow sending chat messages */
41 static int cfg_quiet       = 0; /* quiet mode (no output) */
42 static int cfg_clients     = ADC_CLIENTS_DEFAULT; /* number of clients */
43 static int cfg_netstats_interval = STATS_INTERVAL;
44 static int running         = 1;
45 static int logged_in       = 0;
46 static int blank           = 0;
47 static struct net_statistics* stats_intermediate;
48 static struct net_statistics* stats_total;
49 
50 static int handle(struct ADC_client* client, enum ADC_client_callback_type type, struct ADC_client_callback_data* data);
51 static void timer_callback(struct timeout_evt* t);
52 
do_blank(int n)53 static void do_blank(int n)
54 {
55 	n++;
56 	while (n > 0)
57 	{
58 		fprintf(stdout, " ");
59 		n--;
60 	}
61 }
62 
63 struct AdcFuzzUser
64 {
65 	struct ADC_client* client;
66 	struct timeout_evt* timer;
67 	int logged_in;
68 };
69 
70 #define MAX_CHAT_MSGS 35
71 const char* chat_messages[MAX_CHAT_MSGS] = {
72 	"hello",
73 	"I'm an annoying robot, configured to chat in order to measure performance of the hub.",
74 	"I apologize for the inconvenience.",
75 	".",
76 	":)",
77 	"can anyone help me, pls?",
78 	"wtf?",
79 	"bullshit",
80 	"resistance is futile.",
81 	"You crossed the line first, sir. You squeezed them, you hammered them to the point of desperation. And in their desperation they turned to a man they didn't fully understand.",
82 	"beam me up, scotty",
83 	"morning",
84 	"You know where Harvey is? You know who he is?",
85 	"gtg",
86 	"thanks",
87 	"*punt*",
88 	"*nudge*",
89 	"that's ok",
90 	"...anyway",
91 	"hola",
92 	"hey",
93 	"hi",
94 	"nevermind",
95 	"i think so",
96 	"dunno",
97 	"debian ftw",
98 	"oops",
99 	"how do I search?",
100 	"how do I enable active mode?",
101 	"home, sweet home...",
102 	"later",
103 	"Good evening, ladies and gentlemen. We are tonight's entertainment! I only have one question. Where is Harvey Dent?",
104 	"You know where I can find Harvey? I need to talk to him about something. Just something, a little.",
105 	"We really should stop fighting, we'll miss the fireworks!",
106 	"Wanna know how I got these scars?",
107 };
108 
109 #define MAX_SEARCH_MSGS 10
110 const char* search_messages[MAX_SEARCH_MSGS] = {
111 	"ANmp3 TOauto",
112 	"ANxxx TOauto",
113 	"ANdivx TOauto",
114 	"ANtest ANfoo TOauto",
115 	"ANwmv TO1289718",
116 	"ANbabe TO8981884",
117 	"ANpr0n TOauto",
118 	"ANmusic TOauto",
119 	"ANvideo TOauto",
120 	"ANburnout ANps3 TOauto",
121 };
122 
123 
124 
bot_output(struct ADC_client * client,int level,const char * format,...)125 static void bot_output(struct ADC_client* client, int level, const char* format, ...)
126 {
127 	char logmsg[1024];
128 	va_list args;
129 	va_start(args, format);
130 	vsnprintf(logmsg, 1024, format, args);
131 	va_end(args);
132 
133 	if (cfg_debug >= level)
134 	{
135 		int num = fprintf(stdout, "* [%p] %s", client, logmsg);
136 		do_blank(blank - num);
137 		fprintf(stdout, "\n");
138 	}
139 }
140 
141 
get_wait_rand(size_t max)142 static size_t get_wait_rand(size_t max)
143 {
144 	static size_t next = 0;
145 	if (next == 0) next = (size_t) time(0);
146 	next = (next * 1103515245) + 12345;
147 	return ((size_t )(next / 65536) % max);
148 }
149 
get_next_timeout_evt()150 static size_t get_next_timeout_evt()
151 {
152 	switch (cfg_level)
153 	{
154 		case 0: return get_wait_rand(120);
155 		case 1: return get_wait_rand(60);
156 		case 2: return get_wait_rand(15);
157 		case 3: return get_wait_rand(5);
158 	}
159 	return 0;
160 }
161 
162 
163 static void perf_result(struct ADC_client* client, sid_t target, const char* what, const char* token);
164 
perf_chat(struct ADC_client * client,int priv)165 static void perf_chat(struct ADC_client* client, int priv)
166 {
167 	size_t r = get_wait_rand(MAX_CHAT_MSGS-1);
168 	char* msg = adc_msg_escape(chat_messages[r]);
169 	struct adc_message* cmd = NULL;
170 
171 	if (priv)
172 		cmd = adc_msg_construct_source_dest(ADC_CMD_DMSG, ADC_client_get_sid(client), ADC_client_get_sid(client), strlen(msg));
173 	else
174 		cmd = adc_msg_construct_source(ADC_CMD_BMSG, ADC_client_get_sid(client), strlen(msg));
175 	hub_free(msg);
176 
177 	ADC_client_send(client, cmd);
178 }
179 
perf_search(struct ADC_client * client)180 static void perf_search(struct ADC_client* client)
181 {
182 	size_t r = get_wait_rand(MAX_SEARCH_MSGS-1);
183 	size_t pst = get_wait_rand(100);
184 	struct adc_message* cmd = NULL;
185 
186 	if (pst > 80)
187 	{
188 		cmd = adc_msg_construct_source(ADC_CMD_FSCH, ADC_client_get_sid(client), strlen(search_messages[r]) + 6);
189 		adc_msg_add_argument(cmd, "+TCP4");
190 	}
191 	else
192 	{
193 		cmd = adc_msg_construct_source(ADC_CMD_BSCH, ADC_client_get_sid(client), strlen(search_messages[r]) + 6);
194 		adc_msg_add_argument(cmd, "+TCP4");
195 	}
196 	ADC_client_send(client, cmd);
197 }
198 
perf_result(struct ADC_client * client,sid_t target,const char * what,const char * token)199 static void perf_result(struct ADC_client* client, sid_t target, const char* what, const char* token)
200 {
201 	char tmp[256];
202 	struct adc_message* cmd = adc_msg_construct_source_dest(ADC_CMD_DRES, ADC_client_get_sid(client), target, strlen(what) + strlen(token) + 64);
203 
204 	snprintf(tmp, sizeof(tmp), "FNtest/%s.dat", what);
205 	adc_msg_add_argument(cmd, tmp);
206 
207 	adc_msg_add_argument(cmd, "SL0");
208 	adc_msg_add_argument(cmd, "SI1209818412");
209 	adc_msg_add_argument(cmd, "TR5T6YJYKO3WECS52BKWVSOP5VUG4IKNSZBZ5YHBA");
210 	snprintf(tmp, sizeof(tmp), "TO%s", token);
211 	adc_msg_add_argument(cmd, tmp);
212 
213 	ADC_client_send(client, cmd);
214 }
215 
perf_ctm(struct ADC_client * client)216 static void perf_ctm(struct ADC_client* client)
217 {
218 	char buf[1024] = { 0, };
219 	struct adc_message* cmd = adc_msg_construct_source_dest(ADC_CMD_DCTM, ADC_client_get_sid(client), ADC_client_get_sid(client), 32);
220 	adc_msg_add_argument(cmd, "ADC/1.0");
221 	adc_msg_add_argument(cmd, "TOKEN123456");
222 	adc_msg_add_argument(cmd, sid_to_string(ADC_client_get_sid(client)));
223 	ADC_client_send(client, cmd);
224 }
225 
226 
perf_update(struct ADC_client * client)227 static void perf_update(struct ADC_client* client)
228 {
229 	char buf[16] = { 0, };
230 	int n = (int) get_wait_rand(10)+1;
231 	struct adc_message* cmd = adc_msg_construct_source(ADC_CMD_BINF, ADC_client_get_sid(client), 32);
232 	snprintf(buf, sizeof(buf), "HN%d", n);
233 	adc_msg_add_argument(cmd, buf);
234 	ADC_client_send(client, cmd);
235 }
236 
client_disconnect(struct AdcFuzzUser * c)237 static void client_disconnect(struct AdcFuzzUser* c)
238 {
239 		ADC_client_destroy(c->client);
240 		c->client = 0;
241 
242 		timeout_queue_remove(net_backend_get_timeout_queue(), c->timer);
243 		hub_free(c->timer);
244 		c->timer = 0;
245 
246 		c->logged_in = 0;
247 }
248 
client_connect(struct AdcFuzzUser * c,const char * nick,const char * description)249 static void client_connect(struct AdcFuzzUser* c, const char* nick, const char* description)
250 {
251 	size_t timeout = get_next_timeout_evt();
252 	struct ADC_client* client = ADC_client_create(nick, description, c);
253 
254 	c->client = client;
255 	c->timer = (struct timeout_evt*) hub_malloc(sizeof(struct timeout_evt));
256 	timeout_evt_initialize(c->timer, timer_callback, c);
257 	timeout_queue_insert(net_backend_get_timeout_queue(), c->timer, timeout);
258 
259 	bot_output(client, LVL_VERBOSE, "Initial timeout: %d seconds", timeout);
260 	c->logged_in = 0;
261 
262 	ADC_client_set_callback(client, handle);
263 	ADC_client_connect(client, cfg_uri);
264 }
265 
perf_normal_action(struct ADC_client * client)266 static void perf_normal_action(struct ADC_client* client)
267 {
268 	struct AdcFuzzUser* user = (struct AdcFuzzUser*) ADC_client_get_ptr(client);
269 	size_t r = get_wait_rand(5);
270 	size_t p = get_wait_rand(100);
271 
272 	switch (r)
273 	{
274 		case 0:
275 			// if (p > (90 - (10 * cfg_level)))
276 			{
277 				struct ADC_client* c;
278 				char* nick = hub_strdup(ADC_client_get_nick(client));
279 				char* desc = hub_strdup(ADC_client_get_description(client));
280 
281 				bot_output(client, LVL_VERBOSE, "timeout -> disconnect");
282 				client_disconnect(user);
283 				client_connect(user, nick, desc);
284 
285 				hub_free(nick);
286 				hub_free(desc);
287 			}
288 			break;
289 
290 		case 1:
291 			if (cfg_chat)
292 			{
293 				bot_output(client, LVL_VERBOSE, "timeout -> chat");
294 				if (user->logged_in)
295 					perf_chat(client, 0);
296 
297 			}
298 			break;
299 
300 		case 2:
301 			bot_output(client, LVL_VERBOSE, "timeout -> search");
302 			if (user->logged_in)
303 				perf_search(client);
304 			break;
305 
306 		case 3:
307 			bot_output(client, LVL_VERBOSE, "timeout -> update");
308 			if (user->logged_in)
309 				perf_update(client);
310 			break;
311 
312 		case 4:
313 			bot_output(client, LVL_VERBOSE, "timeout -> privmsg");
314 			if (user->logged_in)
315 				perf_chat(client, 1);
316 			break;
317 
318 		case 5:
319 			bot_output(client, LVL_VERBOSE, "timeout -> ctm/rcm");
320 			if (user->logged_in)
321 				perf_ctm(client);
322 			break;
323 
324 	}
325 }
326 
handle(struct ADC_client * client,enum ADC_client_callback_type type,struct ADC_client_callback_data * data)327 static int handle(struct ADC_client* client, enum ADC_client_callback_type type, struct ADC_client_callback_data* data)
328 {
329 	struct AdcFuzzUser* user = (struct AdcFuzzUser*) ADC_client_get_ptr(client);
330 
331 	switch (type)
332 	{
333 		case ADC_CLIENT_CONNECTING:
334 			bot_output(client, LVL_DEBUG, "*** Connecting...");
335 			break;
336 
337 		case ADC_CLIENT_CONNECTED:
338 			// bot_output(client, LVL_DEBUG, "*** Connected.");
339 			break;
340 
341 		case ADC_CLIENT_DISCONNECTED:
342 			bot_output(client, LVL_DEBUG, "*** Disconnected.");
343 			break;
344 
345 		case ADC_CLIENT_LOGGING_IN:
346 			// bot_output(client, LVL_DEBUG, "*** Logging in...");
347 			break;
348 
349 		case ADC_CLIENT_PASSWORD_REQ:
350 			//bot_output(client, LVL_DEBUG, "*** Requesting password.");
351 			break;
352 
353 		case ADC_CLIENT_LOGGED_IN:
354 			bot_output(client, LVL_DEBUG, "*** Logged in.");
355 			user->logged_in = 1;
356 			break;
357 
358 		case ADC_CLIENT_LOGIN_ERROR:
359 			bot_output(client, LVL_DEBUG, "*** Login error");
360 			break;
361 
362 		case ADC_CLIENT_SSL_HANDSHAKE:
363 		case ADC_CLIENT_SSL_OK:
364 			break;
365 
366 		case ADC_CLIENT_MESSAGE:
367 // 			bot_output(client, LVL_DEBUG, "    <%s> %s", sid_to_string(data->chat->from_sid), data->chat->message);
368 			break;
369 
370 		case ADC_CLIENT_USER_JOIN:
371 			break;
372 
373 		case ADC_CLIENT_USER_QUIT:
374 			break;
375 
376 		case ADC_CLIENT_SEARCH_REQ:
377 			break;
378 
379 		case ADC_CLIENT_HUB_INFO:
380 			break;
381 
382 		default:
383 			bot_output(client, LVL_DEBUG, "Not handled event=%d\n", (int) type);
384 			return 0;
385 			break;
386 	}
387 	return 1;
388 }
389 
timer_callback(struct timeout_evt * t)390 static void timer_callback(struct timeout_evt* t)
391 {
392 	size_t timeout = get_next_timeout_evt();
393 	struct AdcFuzzUser* client = (struct AdcFuzzUser*) t->ptr;
394 	if (client->logged_in)
395 	{
396 		perf_normal_action(client->client);
397 		bot_output(client->client, LVL_VERBOSE, "Next timeout: %d seconds", (int) timeout);
398 	}
399 	timeout_queue_reschedule(net_backend_get_timeout_queue(), client->timer, timeout);
400 }
401 
402 static struct AdcFuzzUser client[ADC_MAX_CLIENTS];
p_status()403 void p_status()
404 {
405 	static char rxbuf[64] = { "0 B" };
406 	static char txbuf[64] = { "0 B" };
407 	int logged_in = 0;
408 	size_t n;
409 	static size_t rx = 0, tx = 0;
410 
411 	for (n = 0; n < cfg_clients; n++)
412 	{
413 		if (client[n].logged_in)
414 			logged_in++;
415 	}
416 
417 	if (difftime(time(NULL), stats_intermediate->timestamp) >= cfg_netstats_interval)
418 	{
419 		net_stats_get(&stats_intermediate, &stats_total);
420 		rx = stats_intermediate->rx / cfg_netstats_interval;
421 		tx = stats_intermediate->tx / cfg_netstats_interval;
422 		net_stats_reset();
423 		format_size(rx, rxbuf, sizeof(rxbuf));
424 		format_size(tx, txbuf, sizeof(txbuf));
425 	}
426 
427 	n = blank;
428 	blank = printf("Connected bots: %d/%d, network: rx=%s/s, tx=%s/s", logged_in, cfg_clients, rxbuf, txbuf);
429 	if (n > blank)
430 		do_blank(n-blank);
431 	printf("\r");
432 }
433 
runloop(size_t clients)434 void runloop(size_t clients)
435 {
436 	size_t n = 0;
437 	blank = 0;
438 
439 	for (n = 0; n < clients; n++)
440 	{
441 		char nick[20];
442 		snprintf(nick, 20, "adcrush_%d", (int) n);
443 		client_connect(&client[n], nick, "stresstester");
444 	}
445 
446 	while (running && net_backend_process())
447 	{
448 		p_status();
449 	}
450 
451 	for (n = 0; n < clients; n++)
452 	{
453 		struct AdcFuzzUser* c = &client[n];
454 		client_disconnect(c);
455 	}
456 }
457 
print_version()458 static void print_version()
459 {
460 	printf(ADCRUSH "\n");
461 	printf("Copyright (C) 2008-2012, Jan Vidar Krey\n");
462 	printf("\n");
463 }
464 
print_usage(const char * program)465 static void print_usage(const char* program)
466 {
467 	print_version();
468 
469 	printf("Usage: %s [adc[s]://<host>:<port>] [options]\n", program);
470 
471 	printf("\n");
472 	printf("  OPTIONS\n");
473 	printf("    -l <0-3>    Level: 0=polite, 1=normal (default), 2=aggressive, 3=excessive.\n");
474 	printf("    -n <num>    Number of concurrent connections\n");
475 	printf("    -c          Allow broadcasting chat messages.\n");
476 	printf("    -d          Enable debug output.\n");
477 	printf("    -q          Quiet mode (no output).\n");
478 	printf("    -i <num>    Average network statistics for given interval (default: 3)\n");
479 	printf("\n");
480 
481 	exit(0);
482 }
483 
parse_address(const char * arg)484 int parse_address(const char* arg)
485 {
486 	if (!arg || strlen(arg) < 9)
487 		return 0;
488 
489 	if (strncmp(arg, "adc://", 6) && strncmp(arg, "adcs://", 7))
490 		return 0;
491 
492 	cfg_uri = arg;
493 	return 1;
494 }
495 
parse_arguments(int argc,char ** argv)496 int parse_arguments(int argc, char** argv)
497 {
498 	int ok = 1;
499 	int opt;
500 	for (opt = 2; opt < argc; opt++)
501 	{
502 		if      (!strcmp(argv[opt], "-c"))
503 			cfg_chat = 1;
504 		else if (!strncmp(argv[opt], "-d", 2))
505 			cfg_debug += strlen(argv[opt]) - 1;
506 		else if (!strcmp(argv[opt], "-q"))
507 			cfg_quiet = 1;
508 		else if (!strcmp(argv[opt], "-l") && (++opt) < argc)
509 		{
510 			cfg_level = MIN(MAX(uhub_atoi(argv[opt]), 0), 3);
511 		}
512 		else if (!strcmp(argv[opt], "-i") && (++opt) < argc)
513 		{
514 			cfg_netstats_interval = MAX(uhub_atoi(argv[opt]), 1);
515 		}
516 		else if (!strcmp(argv[opt], "-n") && (++opt) < argc)
517 		{
518 			cfg_clients = MIN(MAX(uhub_atoi(argv[opt]), 1), ADC_MAX_CLIENTS);
519 		}
520 	}
521 	return ok;
522 }
523 
524 
parse_command_line(int argc,char ** argv)525 void parse_command_line(int argc, char** argv)
526 {
527 	if (argc < 2 ||
528 		!parse_address(argv[1]) ||
529 		!parse_arguments(argc, argv))
530 	{
531 		print_usage(argv[0]);
532 	}
533 }
534 
main(int argc,char ** argv)535 int main(int argc, char** argv)
536 {
537 
538 	parse_command_line(argc, argv);
539 
540 	net_initialize();
541 	net_stats_get(&stats_intermediate, &stats_total);
542 
543 	hub_log_initialize(NULL, 0);
544 	hub_set_log_verbosity(1000);
545 	setvbuf(stdout, NULL, _IONBF, 0);
546 	runloop(cfg_clients);
547 
548 	net_destroy();
549 	return 0;
550 }
551