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