Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

test_cimd2.c File Reference

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include <stdarg.h>
#include <limits.h>
#include <unistd.h>
#include <time.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "gwlib/gwlib.h"

Include dependency graph for test_cimd2.c:

Include dependency graph

Go to the source code of this file.

Typedefs

typedef void(* packet_handler )(Octstr *, Octstr *, int)

Enumerations

enum  { TIMESTAMP_MAXLEN = 13 }
enum  ACT { ACT_listen = 0, ACT_reply = 1, ACT_deliver = 2, ACT_flood = 3 }
enum  SPEW { SPEW_nothing = 0, SPEW_binary = 1, SPEW_characters = 2, SPEW_packets = 3 }
enum  LOG { LOG_nothing = 0, LOG_data = 1, LOG_packets = 2, LOG_sms = 3 }
enum  CHK {
  CHK_nothing = 0, CHK_packets = 1, CHK_sums = 2, CHK_protocol = 3,
  CHK_sms = 4
}
enum  { OUTBUFFER_LIMIT = 65536 }
enum  { EVIL_BUFSIZE = 1021 }
enum  CHARS {
  STX = 2, ETX = 3, TAB = 9, LF = 10,
  CR = 13
}

Functions

void usage (FILE *out)
void pretty_print (unsigned char *data, size_t length)
void read_data (Octstr *in, int fd)
void write_data (Octstr *out, int fd)
void gen_message (Octstr *out)
long gen_data (Octstr *out)
void make_timestamp (unsigned char *buf, time_t fortime)
void send_packet (Octstr *out, int opcode, int sequence,...)
void send_error (Octstr *out, int opcode, int sequence, unsigned char *errorcode, unsigned char *errortext)
int eat_char (Octstr *packet, int ch)
Octstreat_string_parm (Octstr *packet, int parm, int maxlen)
long eat_number (Octstr *ostr)
long eat_int_parm (Octstr *packet, int parm, int maxlen)
void eat_checksum (Octstr *packet)
void handle_login (Octstr *packet, Octstr *out, int sequence)
void handle_logout (Octstr *packet, Octstr *out, int sequence)
void handle_submit (Octstr *packet, Octstr *out, int sequence)
void handle_enquire (Octstr *packet, Octstr *out, int sequence)
void handle_delivery_request (Octstr *packet, Octstr *out, int sequence)
void handle_cancel (Octstr *packet, Octstr *out, int sequence)
void handle_set (Octstr *packet, Octstr *out, int sequence)
void handle_get (Octstr *packet, Octstr *out, int sequence)
void handle_alive (Octstr *packet, Octstr *out, int sequence)
void handle_deliver_response (Octstr *packet, Octstr *out, int sequence)
void handle_deliver_status_report_response (Octstr *packet, Octstr *out, int sequence)
void handle_alive_response (Octstr *packet, Octstr *out, int sequence)
void handle_nack (Octstr *packet, Octstr *out, int sequence)
void parse_packet (Octstr *packet, Octstr *out)
void parse_data (Octstr *in, Octstr *out)
void random_address (unsigned char *buf, int size)
void random_message (unsigned char *buf, int size)
void random_hex (unsigned char *buf, int size)
void main_loop (void)
int wait_for_client (int port)
int main (int argc, char *argv[])

Variables

unsigned char * progname
unsigned char * username = "foo"
unsigned char * password = "bar"
int port = 6789
unsigned char * intro = ""
int activity = ACT_listen
int spew = SPEW_nothing
int logging = LOG_nothing
int checking = CHK_nothing
int max_deliveries = -1
int deliveries = 0
time_t start_time = 0
int sockfd = -1
Octstrinbuffer
Octstroutbuffer
int awaiting_response = 0
struct {
   int   opcode
   packet_handler   handler
handlers []
struct {
   unsigned char *   option
   void *   location
   int   number
options []


Typedef Documentation

typedef void(* packet_handler)(Octstr *, Octstr *, int)
 

Definition at line 766 of file test_cimd2.c.


Enumeration Type Documentation

anonymous enum
 

Enumeration values:
TIMESTAMP_MAXLEN 

Definition at line 94 of file test_cimd2.c.

00094 { TIMESTAMP_MAXLEN = 13 };

anonymous enum
 

Enumeration values:
OUTBUFFER_LIMIT 

Definition at line 151 of file test_cimd2.c.

00151 { OUTBUFFER_LIMIT = 65536 };

anonymous enum
 

Enumeration values:
EVIL_BUFSIZE 

Definition at line 156 of file test_cimd2.c.

00156 { EVIL_BUFSIZE = 1021 };

enum ACT
 

Enumeration values:
ACT_listen 
ACT_reply 
ACT_deliver 
ACT_flood 

Definition at line 107 of file test_cimd2.c.

00107          {
00108     ACT_listen = 0,
00109     ACT_reply = 1,
00110     ACT_deliver = 2,
00111     ACT_flood = 3
00112 };

enum CHARS
 

Enumeration values:
STX 
ETX 
TAB 
LF 
CR 

Definition at line 159 of file test_cimd2.c.

00159            {
00160     STX = 2,
00161     ETX = 3,
00162     TAB = 9,
00163     LF = 10,
00164     CR = 13
00165 };

enum CHK
 

Enumeration values:
CHK_nothing 
CHK_packets 
CHK_sums 
CHK_protocol 
CHK_sms 

Definition at line 128 of file test_cimd2.c.

00128          {
00129     CHK_nothing = 0,
00130     CHK_packets = 1,
00131     CHK_sums = 2,
00132     CHK_protocol = 3,
00133     CHK_sms = 4
00134 };

enum LOG
 

Enumeration values:
LOG_nothing 
LOG_data 
LOG_packets 
LOG_sms 

Definition at line 121 of file test_cimd2.c.

00121          {
00122     LOG_nothing = 0,
00123     LOG_data = 1,
00124     LOG_packets = 2,
00125     LOG_sms = 3
00126 };

enum SPEW
 

Enumeration values:
SPEW_nothing 
SPEW_binary 
SPEW_characters 
SPEW_packets 

Definition at line 114 of file test_cimd2.c.

00114           {
00115     SPEW_nothing = 0,
00116     SPEW_binary = 1,
00117     SPEW_characters = 2,
00118     SPEW_packets = 3
00119 };


Function Documentation

int eat_char Octstr packet,
int  ch
[static]
 

Definition at line 368 of file test_cimd2.c.

References octstr_delete(), and octstr_get_char().

Referenced by parse_packet().

00368                                             {
00369     if (octstr_get_char(packet, 0) == ch) {
00370         octstr_delete(packet, 0, 1);
00371         return 0;
00372     }
00373     return -1;
00374 }

Here is the call graph for this function:

void eat_checksum Octstr packet  )  [static]
 

Definition at line 429 of file test_cimd2.c.

References octstr_delete(), octstr_get_char(), and octstr_len().

Referenced by parse_packet().

00429                                          {
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 }

Here is the call graph for this function:

long eat_int_parm Octstr packet,
int  parm,
int  maxlen
[static]
 

Definition at line 413 of file test_cimd2.c.

References eat_number(), eat_string_parm(), maxlen, octstr_destroy(), octstr_len(), and result.

Referenced by handle_cancel(), handle_delivery_request(), handle_get(), and handle_submit().

00413                                                                {
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 }

Here is the call graph for this function:

long eat_number Octstr ostr  )  [static]
 

Definition at line 401 of file test_cimd2.c.

References octstr_delete(), octstr_parse_long(), and result.

Referenced by eat_int_parm(), and parse_packet().

00401                                      {
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 }

Here is the call graph for this function:

Octstr* eat_string_parm Octstr packet,
int  parm,
int  maxlen
[static]
 

Definition at line 376 of file test_cimd2.c.

References octstr_copy, octstr_delete(), octstr_destroy(), octstr_format(), octstr_len(), octstr_search(), octstr_search_char(), result, and TAB.

Referenced by eat_int_parm(), handle_cancel(), handle_enquire(), handle_login(), handle_set(), and handle_submit().

00376                                                                      {
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 }

Here is the call graph for this function:

long gen_data Octstr out  )  [static]
 

Definition at line 275 of file test_cimd2.c.

References ACT_deliver, ACT_flood, deliveries, gen_message(), interval, max_deliveries, octstr_append_data(), and SPEW_binary.

Referenced by main_loop().

00275                                   {
00276     unsigned char buf[EVIL_BUFSIZE];
00277     size_t i;
00278     long interval = -1;
00279     static int last_sms;  /* Used by ACT_deliver */
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 }

Here is the call graph for this function:

void gen_message Octstr out  )  [static]
 

Definition at line 886 of file test_cimd2.c.

References awaiting_response, logging, make_timestamp(), message, random_address(), random_hex(), random_message(), and send_packet().

Referenced by gen_data().

00886                                      {
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 }

Here is the call graph for this function:

void handle_alive Octstr packet,
Octstr out,
int  sequence
[static]
 

Definition at line 723 of file test_cimd2.c.

References logging, and send_packet().

00723                                                                     {
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 }

Here is the call graph for this function:

void handle_alive_response Octstr packet,
Octstr out,
int  sequence
[static]
 

Definition at line 751 of file test_cimd2.c.

References awaiting_response, and logging.

00751                                                                              {
00752     awaiting_response = 0;
00753     if (logging == LOG_packets)
00754         printf("RCV: Alive.\n");
00755     /* No need to respond to a response */
00756 }

void handle_cancel Octstr packet,
Octstr out,
int  sequence
[static]
 

Definition at line 659 of file test_cimd2.c.

References eat_int_parm(), eat_string_parm(), logging, octstr_get_cstr, send_error(), and send_packet().

00659                                                                      {
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 }

Here is the call graph for this function:

void handle_deliver_response Octstr packet,
Octstr out,
int  sequence
[static]
 

Definition at line 731 of file test_cimd2.c.

References awaiting_response, deliveries, logging, and max_deliveries.

00731                                                                                {
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     /* No need to respond to a response */
00742 }

void handle_deliver_status_report_response Octstr packet,
Octstr out,
int  sequence
[static]
 

Definition at line 744 of file test_cimd2.c.

References awaiting_response, and logging.

00744                                                                                              {
00745     awaiting_response = 0;
00746     if (logging == LOG_packets)
00747         printf("RCV: Deliver status report response\n");
00748     /* No need to respond to a response */
00749 }

void handle_delivery_request Octstr packet,
Octstr out,
int  sequence
[static]
 

Definition at line 614 of file test_cimd2.c.

References eat_int_parm(), logging, send_error(), and send_packet().

00614                                                                                {
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 }

Here is the call graph for this function:

void handle_enquire Octstr packet,
Octstr out,
int  sequence
[static]
 

Definition at line 588 of file test_cimd2.c.

References eat_string_parm(), logging, octstr_destroy(), octstr_get_cstr, send_error(), and send_packet().

00588                                                                       {
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 }

Here is the call graph for this function:

void handle_get Octstr packet,
Octstr out,
int  sequence
[static]
 

Definition at line 702 of file test_cimd2.c.

References eat_int_parm(), logging, make_timestamp(), number, send_error(), and send_packet().

00702                                                                   {
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 }

Here is the call graph for this function:

void handle_login Octstr packet,
Octstr out,
int  sequence
[static]
 

Definition at line 446 of file test_cimd2.c.

References eat_string_parm(), logging, octstr_create, octstr_destroy(), octstr_get_cstr, octstr_str_compare(), password, send_error(), send_packet(), and username.

00446                                                                     {
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 }

Here is the call graph for this function:

void handle_logout Octstr packet,
Octstr out,
int  sequence
[static]
 

Definition at line 472 of file test_cimd2.c.

References logging, and send_packet().

00472                                                                      {
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 }

Here is the call graph for this function:

void handle_nack Octstr packet,
Octstr out,
int  sequence
[static]
 

Definition at line 758 of file test_cimd2.c.

References awaiting_response, and logging.

00758                                                                    {
00759     awaiting_response = 0;
00760     if (logging == LOG_packets)
00761         printf("RCV: NACK\n");
00762     /* TODO: We should retransmit if we get a nack, but there's
00763      * no record of what request we sent. */
00764 }

void handle_set Octstr packet,
Octstr out,
int  sequence
[static]
 

Definition at line 685 of file test_cimd2.c.

References eat_string_parm(), logging, octstr_get_cstr, and send_error().

00685                                                                   {
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 }

Here is the call graph for this function:

void handle_submit Octstr packet,
Octstr out,
int  sequence
[static]
 

Definition at line 480 of file test_cimd2.c.

References eat_int_parm(), eat_string_parm(), gwlist_append(), gwlist_create, gwlist_destroy(), gwlist_get(), gwlist_len(), logging, make_timestamp(), octstr_destroy(), octstr_destroy_item(), octstr_get_cstr, send_error(), send_packet(), and text.

00480                                                                      {
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     /* TODO: Report many other possible errors here */
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 }

Here is the call graph for this function:

int main int  argc,
char *  argv[]
 

Definition at line 1053 of file test_cimd2.c.

References gwlib_init(), main_loop(), option, options, port, progname, sockfd, usage(), and wait_for_client().

01053                                  {
01054     int i;
01055     int opt;
01056 
01057     gwlib_init();
01058 
01059     progname = argv[0];
01060     srandom(0);  /* Make "random" data reproducible */
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 }

Here is the call graph for this function:

void main_loop void   )  [static]
 

Definition at line 935 of file test_cimd2.c.

References error(), gen_data(), inbuffer, interval, intro, octstr_create, octstr_len(), outbuffer, parse_data(), read_data(), sockfd, start_time, warning(), and write_data().

Referenced by main().

00935                             {
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 }

Here is the call graph for this function:

void make_timestamp unsigned char *  buf,
time_t  fortime
[static]
 

Definition at line 320 of file test_cimd2.c.

References gw_gmtime().

Referenced by gen_message(), handle_get(), and handle_submit().

00320                                                                {
00321     /* Is there a thread-safe version of gmtime? */
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 }

Here is the call graph for this function:

void parse_data Octstr in,
Octstr out
[static]
 

Definition at line 817 of file test_cimd2.c.

References ETX, Octstr, octstr_copy, octstr_delete(), octstr_destroy(), octstr_len(), octstr_search_char(), parse_packet(), and STX.

Referenced by main_loop(), parse_array_element(), and parse_data().

00817                                                 {
00818     int stx, etx;
00819     Octstr *packet;
00820 
00821     for (;;) {
00822         /* Look for start of packet.  Delete everything up to the start
00823          * marker.  (CIMD2 section 3.1 says we can ignore any data
00824          * transmitted between packets.) */
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;  /* Incomplete packet; wait for more data. */
00834 
00835         /* Copy the data between stx and etx */
00836         packet = octstr_copy(in, 1, etx - 1);
00837         /* Then cut the packet (including stx and etx) from inbuffer */
00838         octstr_delete(in, 0, etx + 1);
00839 
00840         parse_packet(packet, out);
00841 
00842         octstr_destroy(packet);
00843     }
00844 }

Here is the call graph for this function:

void parse_packet Octstr packet,
Octstr out
[static]
 

Definition at line 788 of file test_cimd2.c.

References eat_char(), eat_checksum(), eat_number(), handlers, logging, opcode, and send_error().

Referenced by parse_data().

00788                                                       {
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) { /* Loop failed */
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 }

Here is the call graph for this function:

void pretty_print unsigned char *  data,
size_t  length
[static]
 

Definition at line 201 of file test_cimd2.c.

References CR, data, ETX, LF, STX, and TAB.

Referenced by read_data(), and write_data().

00201                                                              {
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 }

void random_address unsigned char *  buf,
int  size
[static]
 

Definition at line 846 of file test_cimd2.c.

Referenced by gen_message().

00846                                                          {
00847     int len = random() % size;
00848 
00849     while (len--) {
00850         *buf++ = '0' + random() % 10;
00851     }
00852 
00853     *buf++ = '\0';
00854 }

void random_hex unsigned char *  buf,
int  size
[static]
 

Definition at line 869 of file test_cimd2.c.

Referenced by gen_message().

00869                                                      {
00870     int len = random() % size;
00871 
00872     /* Make even */
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 }

void random_message unsigned char *  buf,
int  size
[static]
 

Definition at line 856 of file test_cimd2.c.

References ETX, and STX.

Referenced by gen_message().

00856                                                          {
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 }

void read_data Octstr in,
int  fd
[static]
 

Definition at line 224 of file test_cimd2.c.

References error(), logging, octstr_append_data(), and pretty_print().

Referenced by main_loop().

00224                                           {
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 }

Here is the call graph for this function:

void send_error Octstr out,
int  opcode,
int  sequence,
unsigned char *  errorcode,
unsigned char *  errortext
[static]
 

Definition at line 360 of file test_cimd2.c.

References logging, opcode, and send_packet().

Referenced by handle_cancel(), handle_delivery_request(), handle_enquire(), handle_get(), handle_login(), handle_set(), handle_submit(), and parse_packet().

00361                                                                 {
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 }

Here is the call graph for this function:

void send_packet Octstr out,
int  opcode,
int  sequence,
  ...
[static]
 

Definition at line 330 of file test_cimd2.c.

References activity, ETX, octstr_format_append(), octstr_get_char(), octstr_len(), opcode, STX, and TAB.

Referenced by gen_message(), handle_alive(), handle_cancel(), handle_delivery_request(), handle_enquire(), handle_get(), handle_login(), handle_logout(), handle_submit(), and send_error().

00330                                                                     {
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     /* Calculate checksum */
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 }

Here is the call graph for this function:

void usage FILE *  out  )  [static]
 

Definition at line 167 of file test_cimd2.c.

References activity, checking, logging, password, port, progname, spew, and username.

00167                              {
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 }

int wait_for_client int  port  )  [static]
 

Definition at line 1016 of file test_cimd2.c.

References error(), gw_netaddr_to_octstr(), info(), make_server_socket(), Octstr, octstr_destroy(), octstr_get_cstr, panic, port, progname, and socket_set_blocking().

Referenced by main().

01016                                      {
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 }

Here is the call graph for this function:

void write_data Octstr out,
int  fd
[static]
 

Definition at line 244 of file test_cimd2.c.

References error(), logging, octstr_delete(), octstr_get_many_chars(), octstr_len(), pretty_print(), and warning().

Referenced by main_loop().

00244                                             {
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 }

Here is the call graph for this function:


Variable Documentation

int activity = ACT_listen
 

Definition at line 136 of file test_cimd2.c.

Referenced by send_packet(), and usage().

int awaiting_response = 0
 

Definition at line 317 of file test_cimd2.c.

Referenced by gen_message(), handle_alive_response(), handle_deliver_response(), handle_deliver_status_report_response(), and handle_nack().

int checking = CHK_nothing
 

Definition at line 139 of file test_cimd2.c.

Referenced by usage().

int deliveries = 0
 

Definition at line 142 of file test_cimd2.c.

Referenced by gen_data(), and handle_deliver_response().

packet_handler handler
 

Definition at line 770 of file test_cimd2.c.

struct { ... } handlers[]
 

Referenced by parse_packet().

Octstr* inbuffer
 

Definition at line 147 of file test_cimd2.c.

Referenced by main_loop().

unsigned char* intro = ""
 

Definition at line 105 of file test_cimd2.c.

Referenced by main_loop().

void* location
 

Definition at line 1001 of file test_cimd2.c.

Referenced by at2_read_pending_incoming_messages().

int logging = LOG_nothing
 

Definition at line 138 of file test_cimd2.c.

Referenced by gen_message(), handle_alive(), handle_alive_response(), handle_cancel(), handle_deliver_response(), handle_deliver_status_report_response(), handle_delivery_request(), handle_enquire(), handle_get(), handle_login(), handle_logout(), handle_nack(), handle_set(), handle_submit(), parse_packet(), read_data(), send_error(), usage(), and write_data().

int max_deliveries = -1
 

Definition at line 141 of file test_cimd2.c.

Referenced by gen_data(), and handle_deliver_response().

int number
 

Definition at line 1002 of file test_cimd2.c.

int opcode
 

Definition at line 769 of file test_cimd2.c.

Referenced by parse_packet(), send_error(), and send_packet().

unsigned char* option
 

Definition at line 1000 of file test_cimd2.c.

Referenced by main(), and parse_options().

struct { ... } options[] [static]
 

Referenced by main().

Octstr* outbuffer
 

Definition at line 148 of file test_cimd2.c.

Referenced by main_loop().

unsigned char* password = "bar"
 

Definition at line 100 of file test_cimd2.c.

Referenced by authorise_username(), cimd_open(), emi_open(), handle_login(), http_add_basic_auth(), http_use_proxy(), httpd_check_authorization(), init_wapbox(), main(), make_url(), pack_credentials(), parse_cgivars_for_password(), password_matches(), proxy_unpack_credentials(), push_headers_create(), read_test_ppg_config(), receive_push_reply(), smpp_create(), smsc_open(), smsc_smpp_create(), unpack_credentials(), usage(), and wap_push_ppg_pushuser_authenticate().

int port = 6789
 

Definition at line 102 of file test_cimd2.c.

unsigned char* progname
 

Definition at line 96 of file test_cimd2.c.

Referenced by badusage(), build_box_arglist(), do_stop(), fatal(), main(), print_usage(), rebind_standard_streams(), usage(), wait_for_client(), and write_pidfile().

int sockfd = -1
 

Definition at line 145 of file test_cimd2.c.

Referenced by conn_open_tcp_nb_with_port(), conn_open_tcp_with_port(), main(), and main_loop().

int spew = SPEW_nothing
 

Definition at line 137 of file test_cimd2.c.

Referenced by usage().

time_t start_time = 0
 

Definition at line 143 of file test_cimd2.c.

unsigned char* username = "foo"
 

Definition at line 99 of file test_cimd2.c.

Referenced by authorise_username(), cimd_open(), emi_open(), handle_login(), http_add_basic_auth(), http_use_proxy(), main(), make_url(), ota_tokenize_settings(), pap_request_thread(), parse_cgivars_for_username(), push_headers_create(), read_test_ppg_config(), receive_push_reply(), set_dlr_url(), set_smsbox_id(), set_smsc_id(), smpp_create(), smsc_open(), smsc_smpp_create(), usage(), user_find_by_username(), wap_push_ppg_pushuser_authenticate(), wap_push_ppg_pushuser_client_phone_number_acceptable(), wap_push_ppg_pushuser_dlr_url_get(), wap_push_ppg_pushuser_smsbox_id_get(), and wap_push_ppg_pushuser_smsc_id_get().

See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.