00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076 #include <stdlib.h>
00077 #include <stdio.h>
00078 #include <string.h>
00079 #include <errno.h>
00080 #include <ctype.h>
00081 #include <stdarg.h>
00082 #include <limits.h>
00083
00084 #include <unistd.h>
00085 #include <time.h>
00086 #include <sys/types.h>
00087 #include <sys/time.h>
00088 #include <sys/socket.h>
00089 #include <netinet/in.h>
00090 #include <arpa/inet.h>
00091
00092 #include "gwlib/gwlib.h"
00093
00094 enum { TIMESTAMP_MAXLEN = 13 };
00095
00096 unsigned char *progname;
00097
00098
00099 unsigned char *username = "foo";
00100 unsigned char *password = "bar";
00101
00102 int port = 6789;
00103
00104
00105 unsigned char *intro = "";
00106
00107 enum ACT {
00108 ACT_listen = 0,
00109 ACT_reply = 1,
00110 ACT_deliver = 2,
00111 ACT_flood = 3
00112 };
00113
00114 enum SPEW {
00115 SPEW_nothing = 0,
00116 SPEW_binary = 1,
00117 SPEW_characters = 2,
00118 SPEW_packets = 3
00119 };
00120
00121 enum LOG {
00122 LOG_nothing = 0,
00123 LOG_data = 1,
00124 LOG_packets = 2,
00125 LOG_sms = 3
00126 };
00127
00128 enum CHK {
00129 CHK_nothing = 0,
00130 CHK_packets = 1,
00131 CHK_sums = 2,
00132 CHK_protocol = 3,
00133 CHK_sms = 4
00134 };
00135
00136 int activity = ACT_listen;
00137 int spew = SPEW_nothing;
00138 int logging = LOG_nothing;
00139 int checking = CHK_nothing;
00140
00141 int max_deliveries = -1;
00142 int deliveries = 0;
00143 time_t start_time = 0;
00144
00145 int sockfd = -1;
00146
00147 Octstr *inbuffer;
00148 Octstr *outbuffer;
00149
00150
00151 enum { OUTBUFFER_LIMIT = 65536 };
00152
00153
00154
00155
00156 enum { EVIL_BUFSIZE = 1021 };
00157
00158
00159 enum CHARS {
00160 STX = 2,
00161 ETX = 3,
00162 TAB = 9,
00163 LF = 10,
00164 CR = 13
00165 };
00166
00167 static void usage(FILE *out) {
00168 fprintf(out, "Usage: %s [options...]\n"
00169 " --help Print this message\n"
00170 " --user USER Allow clients to log in with username USER (default %s)\n"
00171 " --password PASS Allow clients to log in with password PASS (default %s)\n"
00172 " --intro INTRO Send INTRO string before anything else (default nothing)\n"
00173 " --port PORT TCP port to listen on (default %d)\n"
00174 " --activity ACT Activity level of test server (default %d)\n"
00175 " ACT = 0 send nothing, just listen\n"
00176 " ACT = 1 send valid replies, do not initiate any transactions\n"
00177 " ACT = 2 attempt to deliver a random SMS every few seconds (NI)\n"
00178 " ACT = 3 deliver many random SMSes, measure throughput (NI)\n"
00179 " --spew SPEW Flood client, overrides --activity (default %d)\n"
00180 " SPEW = 0 don't spew, use --activity instead\n"
00181 " SPEW = 1 spew random binary gunk at client\n"
00182 " SPEW = 2 spew random data of the right character set at client (NI)\n"
00183 " SPEW = 3 spew valid packets with random contents at client (NI)\n"
00184 " --logging LOG Log level of test server (default %d)\n"
00185 " LOG = 0 log nothing\n"
00186 " LOG = 1 log all data\n"
00187 " LOG = 2 log summaries of valid packets\n"
00188 " LOG = 3 log successfully sent and received SMSes (NI)\n"
00189 " --checking CHK Check level of test server (default %d)\n"
00190 " CHK = 0 check nothing\n"
00191 " CHK = 1 signal invalid packets (NI)\n"
00192 " CHK = 2 signal checksum errors (NI)\n"
00193 " CHK = 3 signal protocol errors (NI)\n"
00194 " CHK = 4 signal invalid SMS contents (NI)\n"
00195 " --max MAX With high activity values, stop after MAX deliveries\n"
00196 " NI means Not Implemented\n"
00197 , progname, username, password, port,
00198 activity, spew, logging, checking);
00199 }
00200
00201 static void pretty_print(unsigned char *data, size_t length) {
00202 size_t i;
00203 int c;
00204
00205 for (i = 0; i < length; i++) {
00206 c = data[i];
00207 switch(c) {
00208 default:
00209 if (isprint(c))
00210 putchar(c);
00211 else
00212 printf("<%d>", c);
00213 break;
00214 case TAB: fputs("<TAB>", stdout); break;
00215 case LF: fputs("<LF>\n", stdout); break;
00216 case CR: fputs("<CR>", stdout); break;
00217 case STX: fputs("<STX>", stdout); break;
00218 case ETX: fputs("<ETX>\n", stdout); break;
00219 }
00220 }
00221 fflush(stdout);
00222 }
00223
00224 static void read_data(Octstr *in, int fd) {
00225 unsigned char buf[EVIL_BUFSIZE];
00226 int ret;
00227
00228 ret = read(fd, buf, sizeof(buf));
00229 if (ret > 0) {
00230 octstr_append_data(in, buf, ret);
00231 if (logging == LOG_data)
00232 pretty_print(buf, ret);
00233 } else if (ret == 0) {
00234 fprintf(stderr, "Client closed socket\n");
00235 exit(0);
00236 } else {
00237 if (errno == EINTR || errno == EAGAIN)
00238 return;
00239 error(errno, "read_data");
00240 exit(1);
00241 }
00242 }
00243
00244 static void write_data(Octstr *out, int fd) {
00245 unsigned char buf[EVIL_BUFSIZE];
00246 int len;
00247 ssize_t ret;
00248
00249 len = sizeof(buf);
00250 if (len > octstr_len(out))
00251 len = octstr_len(out);
00252 if (len == 0)
00253 return;
00254 octstr_get_many_chars(buf, out, 0, len);
00255 ret = write(fd, buf, len);
00256 if (ret > 0) {
00257 if (logging == LOG_data)
00258 pretty_print(buf, ret);
00259 octstr_delete(out, 0, ret);
00260 } else if (ret == 0) {
00261 warning(0, "empty write");
00262 } else {
00263 if (errno == EINTR || errno == EAGAIN)
00264 return;
00265 error(errno, "write_data");
00266 exit(1);
00267 }
00268 }
00269
00270 static void gen_message(Octstr *out);
00271
00272
00273
00274
00275 static long gen_data(Octstr *out) {
00276 unsigned char buf[EVIL_BUFSIZE];
00277 size_t i;
00278 long interval = -1;
00279 static int last_sms;
00280 time_t now;
00281
00282 if (max_deliveries < 0 || deliveries < max_deliveries) {
00283 switch (activity) {
00284 case ACT_deliver:
00285 now = time(NULL);
00286 if (last_sms == 0)
00287 last_sms = now;
00288 while (last_sms < now) {
00289 if (random() % 7 == 1) {
00290 gen_message(out);
00291 last_sms = now;
00292 } else
00293 last_sms++;
00294 }
00295 interval = 1000000;
00296 break;
00297 case ACT_flood:
00298 gen_message(out);
00299 break;
00300 }
00301 }
00302
00303 switch (spew) {
00304 case SPEW_binary:
00305 for (i = 0; i < sizeof(buf); i++) {
00306 buf[i] = random() % 256;
00307 }
00308 octstr_append_data(out, buf, sizeof(buf));
00309 break;
00310 }
00311
00312 return interval;
00313 }
00314
00315
00316
00317 int awaiting_response = 0;
00318
00319
00320 static void make_timestamp(unsigned char *buf, time_t fortime) {
00321
00322 struct tm tm = gw_gmtime(fortime);
00323
00324 sprintf(buf, "%02d%02d%02d%02d%02d%02d",
00325 tm.tm_year % 100, tm.tm_mon + 1, tm.tm_mday,
00326 tm.tm_hour, tm.tm_min, tm.tm_sec);
00327 }
00328
00329
00330 static void send_packet(Octstr *out, int opcode, int sequence, ...) {
00331 va_list ap;
00332 int parm;
00333 unsigned char *value;
00334 int checksum;
00335 int old_len, new_len;
00336
00337 if (activity == ACT_listen)
00338 return;
00339
00340 old_len = octstr_len(out);
00341
00342 octstr_format_append(out, "%c%02d:%03d%c", STX, opcode, sequence, TAB);
00343
00344 va_start(ap, sequence);
00345 for (parm = va_arg(ap, int); parm != 0; parm = va_arg(ap, int)) {
00346 value = va_arg(ap, unsigned char *);
00347 octstr_format_append(out, "%03d:%s\11", parm, value);
00348 }
00349 va_end(ap);
00350
00351
00352 checksum = 0;
00353 for (new_len = octstr_len(out); old_len < new_len; old_len++) {
00354 checksum = (checksum + octstr_get_char(out, old_len)) & 0xff;
00355 }
00356
00357 octstr_format_append(out, "%02X%c", checksum, ETX);
00358 }
00359
00360 static void send_error(Octstr *out, int opcode, int sequence,
00361 unsigned char *errorcode, unsigned char *errortext) {
00362 if (logging == LOG_packets)
00363 printf("SND: ERROR, %s\n", errortext);
00364
00365 send_packet(out, opcode, sequence, 900, errorcode, 901, errortext, 0);
00366 }
00367
00368 static int eat_char(Octstr *packet, int ch) {
00369 if (octstr_get_char(packet, 0) == ch) {
00370 octstr_delete(packet, 0, 1);
00371 return 0;
00372 }
00373 return -1;
00374 }
00375
00376 static Octstr *eat_string_parm(Octstr *packet, int parm, int maxlen) {
00377 long start, datastart;
00378 long tab;
00379 Octstr *result;
00380 Octstr *parmheader;
00381
00382 parmheader = octstr_format("%c%03d:", TAB, parm);
00383 start = octstr_search(packet, parmheader, 0);
00384 if (start < 0) {
00385 octstr_destroy(parmheader);
00386 return NULL;
00387 }
00388 datastart = start + octstr_len(parmheader);
00389
00390 tab = octstr_search_char(packet, TAB, datastart + 1);
00391 if (tab < 0) {
00392 tab = octstr_len(packet);
00393 }
00394
00395 result = octstr_copy(packet, datastart, tab - datastart);
00396 octstr_delete(packet, start, tab - start);
00397 octstr_destroy(parmheader);
00398 return result;
00399 }
00400
00401 static long eat_number(Octstr *ostr) {
00402 long result;
00403 long pos;
00404
00405 pos = octstr_parse_long(&result, ostr, 0, 10);
00406 if (pos < 0)
00407 return INT_MIN;
00408
00409 octstr_delete(ostr, 0, pos);
00410 return result;
00411 }
00412
00413 static long eat_int_parm(Octstr *packet, int parm, int maxlen) {
00414 Octstr *value;
00415 long result;
00416
00417 value = eat_string_parm(packet, parm, maxlen);
00418 if (!value)
00419 return INT_MIN;
00420
00421 result = eat_number(value);
00422 if (octstr_len(value) > 0)
00423 result = INT_MIN;
00424
00425 octstr_destroy(value);
00426 return result;
00427 }
00428
00429 static void eat_checksum(Octstr *packet) {
00430 int len;
00431 int ch1, ch2, ch3;
00432
00433 len = octstr_len(packet);
00434
00435 if (len < 3)
00436 return;
00437
00438 ch1 = octstr_get_char(packet, len - 3);
00439 ch2 = octstr_get_char(packet, len - 2);
00440 ch3 = octstr_get_char(packet, len - 1);
00441
00442 if (isxdigit(ch3) && isxdigit(ch2) && ch1 == TAB)
00443 octstr_delete(packet, len - 3, 3);
00444 }
00445
00446 static void handle_login(Octstr *packet, Octstr *out, int sequence) {
00447 Octstr *user = eat_string_parm(packet, 10, 32);
00448 Octstr *pass = eat_string_parm(packet, 11, 32);
00449
00450 if (user == NULL)
00451 user = octstr_create("");
00452 if (pass == NULL)
00453 pass = octstr_create("");
00454
00455 if (logging == LOG_packets)
00456 printf("RCV: Login user '%s', password '%s'\n",
00457 octstr_get_cstr(user), octstr_get_cstr(pass));
00458
00459 if (octstr_str_compare(user, username) == 0 &&
00460 octstr_str_compare(pass, password) == 0) {
00461 if (logging == LOG_packets)
00462 printf("SND: Login OK\n");
00463 send_packet(out, 51, sequence, 0);
00464 } else {
00465 send_error(out, 51, sequence, "100", "invalid login");
00466 }
00467
00468 octstr_destroy(user);
00469 octstr_destroy(pass);
00470 }
00471
00472 static void handle_logout(Octstr *packet, Octstr *out, int sequence) {
00473 if (logging == LOG_packets)
00474 printf("RCV: Logout\n");
00475 if (logging == LOG_packets)
00476 printf("SND: Logout OK\n");
00477 send_packet(out, 52, sequence, 0);
00478 }
00479
00480 static void handle_submit(Octstr *packet, Octstr *out, int sequence) {
00481 Octstr *dest_addr = eat_string_parm(packet, 21, 20);
00482 Octstr *orig_addr = eat_string_parm(packet, 23, 20);
00483 long DCS = eat_int_parm(packet, 30, 3);
00484 Octstr *UDH = eat_string_parm(packet, 32, 280);
00485 Octstr *text = eat_string_parm(packet, 33, 480);
00486 Octstr *textb = eat_string_parm(packet, 34, 280);
00487 long valid_rel = eat_int_parm(packet, 50, 3);
00488 Octstr *valid_abs = eat_string_parm(packet, 51, 12);
00489 long proto_id = eat_int_parm(packet, 52, 3);
00490 long delivery_rel = eat_int_parm(packet, 53, 3);
00491 Octstr *delivery_abs = eat_string_parm(packet, 54, 12);
00492 long reply_path = eat_int_parm(packet, 55, 1);
00493 long SRR = eat_int_parm(packet, 56, 2);
00494 long cancel = eat_int_parm(packet, 58, 1);
00495 long tariff_class = eat_int_parm(packet, 64, 2);
00496 long service_desc = eat_int_parm(packet, 65, 1);
00497 long priority = eat_int_parm(packet, 67, 1);
00498 List *other_dests = gwlist_create();
00499 Octstr *tmp;
00500
00501 while ((tmp = eat_string_parm(packet, 21, 20)))
00502 gwlist_append(other_dests, tmp);
00503
00504 if (logging == LOG_packets) {
00505 int i;
00506 printf("RCV: Submit to %s", octstr_get_cstr(dest_addr));
00507 for (i = 0; i < gwlist_len(other_dests); i++) {
00508 printf(", %s",
00509 octstr_get_cstr(gwlist_get(other_dests, i)));
00510 }
00511 printf("\n");
00512
00513 if (orig_addr)
00514 printf(" From: %s\n", octstr_get_cstr(orig_addr));
00515 if (DCS > INT_MIN)
00516 printf(" Data coding: %ld\n", DCS);
00517 if (UDH)
00518 printf(" User data header: %s\n",
00519 octstr_get_cstr(UDH));
00520 if (text)
00521 printf(" Text: %s\n", octstr_get_cstr(text));
00522 if (textb)
00523 printf(" Text (binary): %s\n",
00524 octstr_get_cstr(textb));
00525 if (valid_rel > INT_MIN)
00526 printf(" Validity period: %ld (relative)\n",
00527 valid_rel);
00528 if (valid_abs)
00529 printf(" Validity period: %s (absolute)\n",
00530 octstr_get_cstr(valid_abs));
00531 if (proto_id > INT_MIN)
00532 printf(" Protocol ID: %ld\n", proto_id);
00533 if (delivery_rel > INT_MIN)
00534 printf(" First delivery: %ld (relative)\n",
00535 delivery_rel);
00536 if (delivery_abs)
00537 printf(" First delivery: %s (absolute)\n",
00538 octstr_get_cstr(delivery_abs));
00539 if (reply_path == 0)
00540 printf(" Reply path disabled\n");
00541 else if (reply_path == 1)
00542 printf(" Reply path enabled\n");
00543 else if (reply_path > INT_MAX)
00544 printf(" Reply path: %ld\n", reply_path);
00545 if (SRR > INT_MAX)
00546 printf(" Status report flags: %ld\n", SRR);
00547 if (cancel == 0)
00548 printf(" Cancel disabled\n");
00549 else if (cancel == 1)
00550 printf(" Cancel enabled\n");
00551 else if (cancel > INT_MAX)
00552 printf(" Cancel enabled: %ld\n", cancel);
00553 if (tariff_class > INT_MAX)
00554 printf(" Tariff class: %ld\n", tariff_class);
00555 if (service_desc > INT_MAX)
00556 printf(" Service description: %ld\n", service_desc);
00557 if (priority > INT_MAX)
00558 printf(" Priority: %ld\n", priority);
00559 }
00560
00561 if (!dest_addr) {
00562 send_error(out, 53, sequence, "300", "no destination");
00563 } else if (gwlist_len(other_dests) > 0) {
00564 send_error(out, 53, sequence, "301", "too many destinations");
00565
00566 } else {
00567 unsigned char buf[TIMESTAMP_MAXLEN];
00568
00569 make_timestamp(buf, time(NULL));
00570 if (logging == LOG_packets)
00571 printf("SND: Submit OK\n");
00572 send_packet(out, 53, sequence,
00573 21, octstr_get_cstr(dest_addr),
00574 60, buf,
00575 0);
00576 }
00577
00578 octstr_destroy(dest_addr);
00579 octstr_destroy(orig_addr);
00580 octstr_destroy(UDH);
00581 octstr_destroy(text);
00582 octstr_destroy(textb);
00583 octstr_destroy(valid_abs);
00584 octstr_destroy(delivery_abs);
00585 gwlist_destroy(other_dests, octstr_destroy_item);
00586 }
00587
00588 static void handle_enquire(Octstr *packet, Octstr *out, int sequence) {
00589 Octstr *dest_addr = eat_string_parm(packet, 21, 20);
00590 Octstr *timestamp = eat_string_parm(packet, 60, 12);
00591
00592 if (logging == LOG_packets)
00593 printf("RCV: Enquire status, dest='%s', time='%s'\n",
00594 dest_addr ? octstr_get_cstr(dest_addr) : "",
00595 timestamp ? octstr_get_cstr(timestamp) : "");
00596
00597 if (!dest_addr) {
00598 send_error(out, 54, sequence, "400", "no destination");
00599 } else if (!timestamp) {
00600 send_error(out, 54, sequence, "401", "no timestamp");
00601 } else {
00602 if (logging == LOG_packets)
00603 printf("SND: Respond: status unknown\n");
00604 send_packet(out, 54, sequence,
00605 21, octstr_get_cstr(dest_addr),
00606 60, octstr_get_cstr(timestamp),
00607 61, "0",
00608 0);
00609 }
00610 octstr_destroy(dest_addr);
00611 octstr_destroy(timestamp);
00612 }
00613
00614 static void handle_delivery_request(Octstr *packet, Octstr *out, int sequence) {
00615 long mode = eat_int_parm(packet, 68, 1);
00616
00617 if (logging == LOG_packets) {
00618 switch (mode) {
00619 case 0: printf("RCV: Delivery request, messages waiting?\n");
00620 break;
00621 case 1: printf("RCV: Delivery request, one message\n");
00622 break;
00623 case 2: printf("RCV: Delivery request, all messages\n");
00624 break;
00625 case INT_MIN:
00626 printf("RCV: Delivery request, no mode\n");
00627 break;
00628 default:
00629 printf("RCV: Delivery request, mode %ld\n", mode);
00630 }
00631 }
00632
00633 if (mode == INT_MIN)
00634 mode = 1;
00635
00636 switch (mode) {
00637 case 0:
00638 if (logging == LOG_packets)
00639 printf("SND: Respond: 0 messages\n");
00640 send_packet(out, 55, sequence,
00641 66, "0",
00642 0);
00643 break;
00644
00645 case 1:
00646 send_error(out, 55, sequence, "500", "no messages available");
00647 break;
00648
00649 case 2:
00650 send_error(out, 55, sequence, "500", "no messages available");
00651 break;
00652
00653 default:
00654 send_error(out, 55, sequence, "501", "bad mode");
00655 break;
00656 }
00657 }
00658
00659 static void handle_cancel(Octstr *packet, Octstr *out, int sequence) {
00660 long mode = eat_int_parm(packet, 59, 1);
00661 Octstr *timestamp = eat_string_parm(packet, 60, 12);
00662 Octstr *destination = eat_string_parm(packet, 21, 20);
00663
00664 if (logging == LOG_packets) {
00665 printf("RCV: Cancel");
00666 if (mode != INT_MIN)
00667 printf(", mode %ld", mode);
00668 if (destination)
00669 printf(", dest '%s'", octstr_get_cstr(destination));
00670 if (timestamp)
00671 printf(", time '%s'", octstr_get_cstr(timestamp));
00672 printf("\n");
00673 }
00674
00675 if (mode < 0 || mode > 2)
00676 send_error(out, 56, sequence, "602", "bad mode");
00677 else {
00678 if (logging == LOG_packets)
00679 printf("SND: OK\n");
00680 send_packet(out, 56, sequence, 0);
00681 }
00682 }
00683
00684
00685 static void handle_set(Octstr *packet, Octstr *out, int sequence) {
00686 Octstr *pass = eat_string_parm(packet, 11, 32);
00687
00688 if (pass) {
00689 if (logging == LOG_packets)
00690 printf("RCV: Set password to '%s'\n",
00691 octstr_get_cstr(pass));
00692 send_error(out, 58, sequence,
00693 "801", "changing password not allowed");
00694 } else {
00695 if (logging == LOG_packets)
00696 printf("RCV: Set, unknown parameters\n");
00697 send_error(out, 58, sequence, "3", "cannot set");
00698 }
00699 }
00700
00701
00702 static void handle_get(Octstr *packet, Octstr *out, int sequence) {
00703 long number = eat_int_parm(packet, 500, 3);
00704
00705 if (logging == LOG_packets)
00706 printf("RCV: Get parameter #%ld\n", number);
00707
00708 if (number == INT_MIN) {
00709 send_error(out, 59, sequence, "900", "missing parameter");
00710 } else if (number == 501) {
00711 unsigned char buf[TIMESTAMP_MAXLEN];
00712 make_timestamp(buf, time(NULL));
00713 if (logging == LOG_packets)
00714 printf("SND: OK, SMSC timestamp is '%s'\n", buf);
00715 send_packet(out, 59, sequence,
00716 501, buf,
00717 0);
00718 } else {
00719 send_error(out, 59, sequence, "900", "unknown parameter");
00720 }
00721 }
00722
00723 static void handle_alive(Octstr *packet, Octstr *out, int sequence) {
00724 if (logging == LOG_packets)
00725 printf("RCV: Alive?\n");
00726 if (logging == LOG_packets)
00727 printf("SND: Alive.\n");
00728 send_packet(out, 90, sequence, 0);
00729 }
00730
00731 static void handle_deliver_response(Octstr *packet, Octstr *out, int sequence) {
00732 awaiting_response = 0;
00733 if (logging == LOG_packets)
00734 printf("RCV: Deliver response\n");
00735 deliveries++;
00736 if (max_deliveries > 0 && deliveries == max_deliveries) {
00737 time_t elapsed = time(NULL) - start_time;
00738 printf("LOG: %ld deliveries in %ld seconds\n",
00739 (long) max_deliveries, (long) elapsed);
00740 }
00741
00742 }
00743
00744 static void handle_deliver_status_report_response(Octstr *packet, Octstr *out, int sequence) {
00745 awaiting_response = 0;
00746 if (logging == LOG_packets)
00747 printf("RCV: Deliver status report response\n");
00748
00749 }
00750
00751 static void handle_alive_response(Octstr *packet, Octstr *out, int sequence) {
00752 awaiting_response = 0;
00753 if (logging == LOG_packets)
00754 printf("RCV: Alive.\n");
00755
00756 }
00757
00758 static void handle_nack(Octstr *packet, Octstr *out, int sequence) {
00759 awaiting_response = 0;
00760 if (logging == LOG_packets)
00761 printf("RCV: NACK\n");
00762
00763
00764 }
00765
00766 typedef void (*packet_handler)(Octstr *, Octstr *, int);
00767
00768 struct {
00769 int opcode;
00770 packet_handler handler;
00771 } handlers[] = {
00772 { 1, handle_login },
00773 { 2, handle_logout },
00774 { 3, handle_submit },
00775 { 4, handle_enquire },
00776 { 5, handle_delivery_request },
00777 { 6, handle_cancel },
00778 { 8, handle_set },
00779 { 9, handle_get },
00780 { 40, handle_alive },
00781 { 70, handle_deliver_response },
00782 { 73, handle_deliver_status_report_response },
00783 { 90, handle_alive_response },
00784 { 99, handle_nack },
00785 { -1, NULL },
00786 };
00787
00788 static void parse_packet(Octstr *packet, Octstr *out) {
00789 int opcode, sequence;
00790 int i;
00791
00792 eat_checksum(packet);
00793
00794 opcode = eat_number(packet);
00795 if (opcode < 0 || eat_char(packet, ':') < 0)
00796 return;
00797 sequence = eat_number(packet);
00798 if (sequence < 0)
00799 return;
00800
00801 for (i = 0; handlers[i].opcode >= 0; i++) {
00802 if (handlers[i].opcode == opcode) {
00803 (handlers[i].handler)(packet, out, sequence);
00804 break;
00805 }
00806 }
00807
00808 if (handlers[i].opcode < 0) {
00809 if (logging == LOG_packets)
00810 printf("RCV: unknown operation %ld\n",
00811 (long) handlers[i].opcode);
00812 send_error(out, 98, sequence, "1", "unexpected operation");
00813 }
00814 }
00815
00816
00817 static void parse_data(Octstr *in, Octstr *out) {
00818 int stx, etx;
00819 Octstr *packet;
00820
00821 for (;;) {
00822
00823
00824
00825 stx = octstr_search_char(in, STX, 0);
00826 if (stx < 0)
00827 octstr_delete(in, 0, octstr_len(in));
00828 else if (stx > 0)
00829 octstr_delete(in, 0, stx);
00830
00831 etx = octstr_search_char(in, ETX, 0);
00832 if (etx < 0)
00833 return;
00834
00835
00836 packet = octstr_copy(in, 1, etx - 1);
00837
00838 octstr_delete(in, 0, etx + 1);
00839
00840 parse_packet(packet, out);
00841
00842 octstr_destroy(packet);
00843 }
00844 }
00845
00846 static void random_address(unsigned char *buf, int size) {
00847 int len = random() % size;
00848
00849 while (len--) {
00850 *buf++ = '0' + random() % 10;
00851 }
00852
00853 *buf++ = '\0';
00854 }
00855
00856 static void random_message(unsigned char *buf, int size) {
00857 int len = random() % size;
00858
00859 while (len--) {
00860 do {
00861 *buf = random() % 256;
00862 } while (*buf == STX || *buf == ETX || *buf == TAB);
00863 buf++;
00864 }
00865
00866 *buf++ = '\0';
00867 }
00868
00869 static void random_hex(unsigned char *buf, int size) {
00870 int len = random() % size;
00871
00872
00873 len -= (len % 2);
00874
00875 while (len--) {
00876 int c = random() % 16;
00877 if (c < 10)
00878 *buf++ = c + '0';
00879 else
00880 *buf++ = c - 10 + 'a';
00881 }
00882
00883 *buf++ = '\0';
00884 }
00885
00886 static void gen_message(Octstr *out) {
00887 static int send_seq = 0;
00888 unsigned char dest[21];
00889 unsigned char orig[21];
00890 unsigned char scts[TIMESTAMP_MAXLEN];
00891 unsigned char message[481];
00892 unsigned char udh[281];
00893
00894 if (awaiting_response == 1)
00895 return;
00896
00897 random_address(dest, sizeof(dest));
00898 random_address(orig, sizeof(orig));
00899 make_timestamp(scts, time(NULL));
00900 random_message(message, sizeof(message));
00901 if (random() % 2 == 0)
00902 random_hex(udh, sizeof(udh));
00903 else
00904 *udh = 0;
00905
00906 if (logging == LOG_packets)
00907 printf("SND: Deliver message (random)\n");
00908
00909 if (*udh) {
00910 send_packet(out, 20, send_seq,
00911 21, dest,
00912 23, orig,
00913 60, scts,
00914 32, udh,
00915 33, message,
00916 0);
00917 } else {
00918 send_packet(out, 20, send_seq,
00919 21, dest,
00920 23, orig,
00921 60, scts,
00922 33, message,
00923 0);
00924 }
00925
00926 send_seq += 2;
00927 if (send_seq > 255)
00928 send_seq = 0;
00929
00930 awaiting_response = 1;
00931 }
00932
00933
00934
00935 static void main_loop(void) {
00936 fd_set readfds, writefds;
00937 int n;
00938 static int reported_outfull = 0;
00939 int interval = -1;
00940
00941 inbuffer = octstr_create("");
00942 outbuffer = octstr_create(intro);
00943 start_time = time(NULL);
00944
00945 for (;;) {
00946 if (octstr_len(outbuffer) < OUTBUFFER_LIMIT) {
00947 interval = gen_data(outbuffer);
00948 } else if (!reported_outfull) {
00949 warning(0, "outbuffer getting full; waiting...");
00950 reported_outfull = 1;
00951 }
00952
00953 FD_ZERO(&readfds);
00954 FD_SET(sockfd, &readfds);
00955
00956 if (octstr_len(outbuffer) > 0) {
00957 FD_ZERO(&writefds);
00958 FD_SET(sockfd, &writefds);
00959 n = select(sockfd+1, &readfds, &writefds, NULL, NULL);
00960 } else {
00961 struct timeval tv;
00962 struct timeval *tvp;
00963
00964 if (interval >= 0) {
00965 tv.tv_sec = 0;
00966 tv.tv_usec = interval;
00967 tvp = &tv;
00968 } else {
00969 tvp = NULL;
00970 }
00971 n = select(sockfd+1, &readfds, NULL, NULL, tvp);
00972 }
00973
00974 if (n < 0) {
00975 if (errno == EINTR) {
00976 warning(errno, "main loop, select");
00977 continue;
00978 }
00979 error(errno, "main loop, select");
00980 sleep(1);
00981 continue;
00982 }
00983 if (n > 0) {
00984 if (FD_ISSET(sockfd, &readfds)) {
00985 read_data(inbuffer, sockfd);
00986 parse_data(inbuffer, outbuffer);
00987 }
00988 if (octstr_len(outbuffer) > 0 &&
00989 FD_ISSET(sockfd, &writefds)) {
00990 write_data(outbuffer, sockfd);
00991 }
00992 if (octstr_len(outbuffer) < OUTBUFFER_LIMIT) {
00993 reported_outfull = 0;
00994 }
00995 }
00996 }
00997 }
00998
00999 static struct {
01000 unsigned char *option;
01001 void *location;
01002 int number;
01003 } options[] = {
01004 { "--user", &username, 0 },
01005 { "--password", &password, 0 },
01006 { "--port", &port, 1 },
01007 { "--intro", &intro, 0 },
01008 { "--activity", &activity, 1 },
01009 { "--spew", &spew, 1 },
01010 { "--logging", &logging, 1 },
01011 { "--checking", &checking, 1 },
01012 { "--max", &max_deliveries, 1 },
01013 { NULL, NULL, 0 },
01014 };
01015
01016 static int wait_for_client(int port) {
01017 struct sockaddr_in sin;
01018 socklen_t addrlen;
01019 int listenfd;
01020 int clientfd;
01021 Octstr *addr;
01022
01023 listenfd = make_server_socket(port, NULL);
01024 if (listenfd < 0) {
01025 fprintf(stderr, "%s: failed to open socket at port %d\n",
01026 progname, port);
01027 exit(1);
01028 }
01029
01030 do {
01031 addrlen = sizeof(sin);
01032 clientfd = accept(listenfd, (struct sockaddr *)&sin, &addrlen);
01033 if (clientfd < 0) {
01034 error(errno, "failed to accept new connection");
01035 }
01036 } while (clientfd < 0);
01037
01038 if (socket_set_blocking(clientfd, 0) < 0) {
01039 panic(0, "failed to make client socket nonblocking");
01040 }
01041
01042 addr = gw_netaddr_to_octstr(AF_INET, &sin.sin_addr);
01043 info(0, "Accepted client from %s:%d",
01044 octstr_get_cstr(addr), ntohs(sin.sin_port));
01045 octstr_destroy(addr);
01046
01047 close(listenfd);
01048
01049 return clientfd;
01050 }
01051
01052
01053 int main(int argc, char *argv[]) {
01054 int i;
01055 int opt;
01056
01057 gwlib_init();
01058
01059 progname = argv[0];
01060 srandom(0);
01061
01062 for (i = 1; i < argc; i++) {
01063 for (opt = 0; options[opt].option; opt++) {
01064 if (strcmp(argv[i], options[opt].option) == 0) {
01065 if (i + 1 >= argc) {
01066 fprintf(stderr, "%s: missing argument to %s",
01067 progname, argv[i]);
01068 exit(2);
01069 }
01070 if (options[opt].number) {
01071 * (int *) options[opt].location = atoi(argv[i+1]);
01072 } else {
01073 * (char **) options[opt].location = argv[i+1];
01074 }
01075 i++;
01076 break;
01077 }
01078 }
01079 if (options[opt].option)
01080 continue;
01081 if (strcmp(argv[i], "--help") == 0) {
01082 usage(stdout);
01083 exit(0);
01084 }
01085 if (argv[i][0] == '-') {
01086 fprintf(stderr, "%s: unknown option %s\n",
01087 progname, argv[i]);
01088 usage(stderr);
01089 exit(2);
01090 }
01091 }
01092
01093 sockfd = wait_for_client(port);
01094 main_loop();
01095 return 0;
01096 }
See file LICENSE for details about the license agreement for using,
modifying, copying or deriving work from this software.