test_smsc.c
上传用户:gzpyjq
上传日期:2013-01-31
资源大小:1852k
文件大小:18k
源码类别:

手机WAP编程

开发平台:

WINDOWS

  1. #include <unistd.h>
  2. #include "gwlib/gwlib.h"
  3. #include "gw/smsc/smpp_pdu.h"
  4. #include <string.h>
  5. /***********************************************************************
  6.  * Configurable stuff.
  7.  */
  8. /*
  9.  * The port at which our HTTP server emulator listens.
  10.  */
  11. static long http_port = 8080;
  12. /*
  13.  * The HTTP admin port and password for Kannel, needed to do shutdown.
  14.  */
  15. static long admin_port = 13000;
  16. static char *admin_password = "bar";
  17. /*
  18.  * The port at which the SMPP SMS center emulator listens.
  19.  */
  20. static long smpp_port = 2345;
  21. /*
  22.  * Number of messages to use in the "Send N messages as fast as possible"
  23.  * benchmark.
  24.  */
  25. static long num_messages = 1;
  26. /***********************************************************************
  27.  * Events and event queues.
  28.  */
  29. typedef List EventQueue;
  30. typedef struct Event {
  31.     enum event_type {
  32. got_smsc,
  33. deliver,
  34. deliver_ack,
  35. http_request,
  36. http_response,
  37. submit,
  38. got_enquire_link
  39.     } type;
  40.     long id;
  41.     long time;
  42.     
  43.     Connection *conn;     /* SMPP: Connection for response PDU */
  44.     long sequence_number;   /* SMPP: Sequence number of resp PDU */
  45.     /* HTTP related stuff */
  46.     HTTPClient *client;
  47.     Octstr *body;
  48. } Event;
  49. static Counter *event_id_counter = NULL;
  50. static const char *eq_type(Event *e)
  51. {
  52. #define TYPE(name) case name: return #name;
  53.     switch (e->type) {
  54. TYPE(got_smsc)
  55. TYPE(deliver)
  56. TYPE(deliver_ack)
  57. TYPE(http_request)
  58. TYPE(http_response)
  59. TYPE(submit)
  60. TYPE(got_enquire_link)
  61.     }
  62. #undef TYPE
  63.     return "unknown";
  64. }
  65. static Event *eq_create_event(enum event_type type)
  66. {
  67.     Event *e;
  68.     
  69.     e = gw_malloc(sizeof(*e));
  70.     e->type = type;
  71.     e->time = date_universal_now();
  72.     e->id = counter_increase(event_id_counter);
  73.     e->conn = NULL;
  74.     e->sequence_number = -1;
  75.     e->client = NULL;
  76.     e->body = NULL;
  77.     return e;
  78. }
  79. static Event *eq_create_submit(Connection *conn, long sequence_number, 
  80.                       Octstr *body)
  81. {
  82.     Event *e;
  83.     
  84.     gw_assert(conn != NULL);
  85.     gw_assert(sequence_number >= 0);
  86.     e = eq_create_event(submit);
  87.     e->conn = conn;
  88.     e->sequence_number = sequence_number;
  89.     e->body = octstr_duplicate(body);
  90.     return e;
  91. }
  92. static Event *eq_create_http_request(HTTPClient *client, Octstr *body)
  93. {
  94.     Event *e;
  95.     
  96.     gw_assert(client != NULL);
  97.     gw_assert(body != NULL);
  98.     e = eq_create_event(http_request);
  99.     e->client = client;
  100.     e->body = octstr_duplicate(body);
  101.     return e;
  102. }
  103. static void eq_destroy_event(Event *e)
  104. {
  105.     octstr_destroy(e->body);
  106.     gw_free(e);
  107. }
  108. static EventQueue *eq_create(void)
  109. {
  110.     return list_create();
  111. }
  112. static void eq_add_producer(EventQueue *eq)
  113. {
  114.     list_add_producer(eq);
  115. }
  116. static void eq_remove_producer(EventQueue *eq)
  117. {
  118.     list_remove_producer(eq);
  119. }
  120. static void eq_destroy(EventQueue *eq)
  121. {
  122.     list_destroy(eq, NULL);
  123. }
  124. static void eq_append(EventQueue *eq, Event *e)
  125. {
  126.     list_produce(eq, e);
  127. }
  128. static Event *eq_extract(EventQueue *eq)
  129. {
  130.     return list_consume(eq);
  131. }
  132. static void eq_log(Event *e)
  133. {
  134.     info(0, "Event %ld, type %s, time %ld", e->id, eq_type(e), e->time);
  135. }
  136. static void eq_init(void)
  137. {
  138.     event_id_counter = counter_create();
  139. }
  140. static void eq_shutdown(void)
  141. {
  142.     counter_destroy(event_id_counter);
  143. }
  144. static long eq_round_trip_time(Event *e)
  145. {
  146.     long now, then;
  147.     
  148.     now = date_universal_now();
  149.     if (octstr_parse_long(&then, e->body, 0, 10) == -1)
  150.      return 0;
  151.     return now - then;
  152. }
  153. /***********************************************************************
  154.  * SMS center emulator, declarations.
  155.  */
  156. struct smsc_emu_arg {
  157.     Semaphore *sema;
  158.     EventQueue *eq;
  159. };
  160. static EventQueue *undelivered_messages = NULL;
  161. /***********************************************************************
  162.  * SMS center emulator, SMPP internals.
  163.  */
  164. enum { MAX_THREADS = 2 };
  165. enum { SMPP_MAX_QUEUE = 10 };
  166. struct smpp_emu_arg {
  167.     EventQueue *eq;
  168.     Connection *conn;
  169.     long id;
  170.     Semaphore *ok_to_send;
  171.     long writer_id;
  172.     int quit;
  173. };
  174. static Counter *smpp_emu_counter = NULL;
  175. static void smpp_emu_writer(void *arg)
  176. {
  177.     Event *e;
  178.     SMPP_PDU *pdu;
  179.     Octstr *os;
  180.     struct smpp_emu_arg *p;
  181.     p = arg;
  182.     for (;;) {
  183. semaphore_down(p->ok_to_send);
  184. e = eq_extract(undelivered_messages);
  185. if (e == NULL)
  186.     break;
  187.      e->time = date_universal_now();
  188.      eq_log(e);
  189. pdu = smpp_pdu_create(deliver_sm,
  190.       counter_increase(smpp_emu_counter));
  191.      pdu->u.deliver_sm.source_addr = octstr_create("123");
  192.      pdu->u.deliver_sm.destination_addr = octstr_create("456");
  193. pdu->u.deliver_sm.short_message = octstr_format("%ld", e->time);
  194. os = smpp_pdu_pack(pdu);
  195. conn_write(p->conn, os);
  196. octstr_destroy(os);
  197. smpp_pdu_destroy(pdu);
  198. eq_destroy_event(e);
  199.     }
  200. }
  201. static void smpp_emu_handle_pdu(struct smpp_emu_arg *p, SMPP_PDU *pdu)
  202. {
  203.     SMPP_PDU *resp;
  204.     Octstr *os;
  205.     
  206.     resp = NULL;
  207.     switch (pdu->type) {
  208.      case bind_transmitter:
  209.     resp = smpp_pdu_create(bind_transmitter_resp,
  210.    pdu->u.bind_transmitter.sequence_number);
  211.     break;
  212.      case bind_receiver:
  213.     resp = smpp_pdu_create(bind_receiver_resp,
  214.    pdu->u.bind_receiver.sequence_number);
  215.          eq_append(p->eq, eq_create_event(got_smsc));
  216.     gw_assert(p->writer_id == -1);
  217.     p->writer_id = gwthread_create(smpp_emu_writer, p);
  218.     if (p->writer_id == -1)
  219.      panic(0, "Couldn't create SMPP helper thread.");
  220.          break;
  221.      case submit_sm:
  222.     eq_append(p->eq, 
  223.      eq_create_submit(p->conn, pdu->u.submit_sm.sequence_number,
  224.            pdu->u.submit_sm.short_message));
  225.          break;
  226.      case deliver_sm_resp:
  227.     eq_append(p->eq, eq_create_event(deliver_ack));
  228.     semaphore_up(p->ok_to_send);
  229.     break;
  230.      case enquire_link:
  231.     eq_append(p->eq, eq_create_event(got_enquire_link));
  232.     resp = smpp_pdu_create(enquire_link_resp,
  233.                   pdu->u.enquire_link.sequence_number);
  234.     break;
  235.      case unbind:
  236.     resp = smpp_pdu_create(unbind_resp, 
  237.                   pdu->u.unbind.sequence_number);
  238.     break;
  239.      default:
  240.     error(0, "SMPP: Unhandled PDU type %s", pdu->type_name);
  241.     break;
  242.     }
  243.     if (resp != NULL) {
  244. os = smpp_pdu_pack(resp);
  245. conn_write(p->conn, os);
  246. octstr_destroy(os);
  247. smpp_pdu_destroy(resp);
  248.     }
  249. }
  250. static void smpp_emu_reader(void *arg)
  251. {
  252.     Octstr *os;
  253.     long len;
  254.     SMPP_PDU *pdu;
  255.     struct smpp_emu_arg *p;
  256.     p = arg;
  257.     
  258.     len = 0;
  259.     while (!p->quit && conn_wait(p->conn, -1.0) != -1) {
  260.      for (;;) {
  261.     if (len == 0) {
  262. len = smpp_pdu_read_len(p->conn);
  263. if (len == -1) {
  264.     error(0, "Client sent garbage, closing connection.");
  265.     goto error;
  266. } else if (len == 0) {
  267.     if (conn_eof(p->conn) || conn_read_error(p->conn))
  268.      goto error;
  269.     break;
  270. }
  271.     }
  272.     
  273.          gw_assert(len > 0);
  274.     os = smpp_pdu_read_data(p->conn, len);
  275.     if (os != NULL) {
  276.           len = 0;
  277. pdu = smpp_pdu_unpack(os);
  278. if (pdu == NULL) {
  279.     error(0, "PDU unpacking failed!");
  280.     octstr_dump(os, 0);
  281. } else {
  282.     smpp_emu_handle_pdu(p, pdu);
  283.     smpp_pdu_destroy(pdu);
  284. }
  285. octstr_destroy(os);
  286.     } else if (conn_eof(p->conn) || conn_read_error(p->conn))
  287.      goto error;
  288.     else
  289. break;
  290. }
  291.     }
  292. error:
  293.     if (p->writer_id != -1)
  294. gwthread_join(p->writer_id);
  295. }
  296. static void smpp_emu(void *arg)
  297. {
  298.     EventQueue *eq;
  299.     struct smsc_emu_arg *p;
  300.     int fd;
  301.     int new_fd;
  302.     Octstr *client_addr;
  303.     long i;
  304.     long num_threads;
  305.     struct smpp_emu_arg *thread[MAX_THREADS];
  306.     
  307.     p = arg;
  308.     eq = p->eq;
  309.     eq_add_producer(eq);
  310.     semaphore_up(p->sema);
  311.     
  312.     /*
  313.      * Wait for SMPP clients.
  314.      */
  315.     fd = make_server_socket(smpp_port, NULL);
  316.     if (fd == -1)
  317.      panic(0, "Couldn't create SMPP listen port.");
  318.     
  319.     num_threads = 0;
  320.     for (;;) {
  321.      new_fd = gw_accept(fd, &client_addr);
  322. if (new_fd == -1)
  323.     break;
  324.      octstr_destroy(client_addr);
  325.      if (num_threads == MAX_THREADS) {
  326.     warning(0, "Too many SMPP client connections.");
  327.     (void) close(new_fd);
  328. } else {
  329.     thread[num_threads] = gw_malloc(sizeof(*thread[0]));
  330.          thread[num_threads]->conn = conn_wrap_fd(new_fd, 0);
  331.     thread[num_threads]->eq = eq;
  332.     thread[num_threads]->quit = 0;
  333.     thread[num_threads]->writer_id = -1;
  334.     thread[num_threads]->ok_to_send = 
  335.      semaphore_create(SMPP_MAX_QUEUE);
  336.     thread[num_threads]->id = 
  337.      gwthread_create(smpp_emu_reader, thread[num_threads]);
  338.     if (thread[num_threads]->id == -1)
  339.      panic(0, "Couldn't start SMPP subthread.");
  340.          ++num_threads;
  341. }
  342.     }
  343.     
  344.     for (i = 0; i < num_threads; ++i) {
  345. thread[i]->quit = 1;
  346.      gwthread_wakeup(thread[i]->id);
  347. gwthread_join(thread[i]->id);
  348. conn_destroy(thread[i]->conn);
  349. semaphore_destroy(thread[i]->ok_to_send);
  350. gw_free(thread[i]);
  351.     }
  352.     eq_remove_producer(eq);
  353. }
  354. /***********************************************************************
  355.  * SMS center emulator, generic interface.
  356.  */
  357. static long smpp_emu_id = -1;
  358. /*
  359.  * Start all SMS center emulators.
  360.  */
  361. static void smsc_emu_create(EventQueue *eq)
  362. {
  363.     struct smsc_emu_arg *arg;
  364.     
  365.     gw_assert(smpp_emu_id == -1);
  366.     arg = gw_malloc(sizeof(*arg));
  367.     arg->sema = semaphore_create(0);
  368.     arg->eq = eq;
  369.     smpp_emu_id = gwthread_create(smpp_emu, arg);
  370.     if (smpp_emu_id == -1)
  371.      panic(0, "Couldn't start SMPP emulator thread.");
  372.     semaphore_down(arg->sema);
  373.     semaphore_destroy(arg->sema);
  374.     gw_free(arg);
  375. }
  376. static void smsc_emu_destroy(void)
  377. {
  378.     eq_remove_producer(undelivered_messages);
  379.     gw_assert(smpp_emu_id != -1);
  380.     gwthread_wakeup(smpp_emu_id);
  381.     gwthread_join(smpp_emu_id);
  382. }
  383. static void smsc_emu_deliver(void)
  384. {
  385.     eq_append(undelivered_messages, eq_create_event(deliver));
  386. }
  387. static void smsc_emu_submit_ack(Event *e)
  388. {
  389.     SMPP_PDU *resp;
  390.     Octstr *os;
  391.     resp = smpp_pdu_create(submit_sm_resp, e->sequence_number);
  392.     os = smpp_pdu_pack(resp);
  393.     conn_write(e->conn, os);
  394.     octstr_destroy(os);
  395.     smpp_pdu_destroy(resp);
  396. }
  397. static void smsc_emu_init(void)
  398. {
  399.     smpp_emu_counter = counter_create();
  400.     undelivered_messages = eq_create();
  401.     eq_add_producer(undelivered_messages);
  402. }
  403. static void smsc_emu_shutdown(void)
  404. {
  405.     counter_destroy(smpp_emu_counter);
  406.     eq_destroy(undelivered_messages);
  407. }
  408. /***********************************************************************
  409.  * HTTP server emulator.
  410.  */
  411. static List *httpd_emu_headers = NULL;
  412. struct httpd_emu_arg {
  413.     int port;
  414.     Semaphore *sema;
  415.     EventQueue *eq;
  416. };
  417. /*
  418.  * This is the HTTP server emulator thread.
  419.  */
  420. static void httpd_emu(void *arg)
  421. {
  422.     HTTPClient *client;
  423.     Octstr *ip;
  424.     Octstr *url;
  425.     List *headers;
  426.     Octstr *body;
  427.     List *cgivars;
  428.     struct httpd_emu_arg *p;
  429.     EventQueue *eq;
  430.     p = arg;
  431.     eq = p->eq;
  432.     eq_add_producer(eq);
  433.     semaphore_up(p->sema);
  434.     for (;;) {
  435. client = http_accept_request(p->port, &ip, &url, &headers, &body, 
  436.                     &cgivars);
  437. if (client == NULL)
  438.     break;
  439.     
  440. eq_append(eq, eq_create_http_request(client, 
  441.                    http_cgi_variable(cgivars, "arg")));
  442.      octstr_destroy(ip);
  443.      octstr_destroy(url);
  444. http_destroy_headers(headers);
  445.      octstr_destroy(body);
  446.      http_destroy_cgiargs(cgivars);
  447.     }
  448.     eq_remove_producer(eq);
  449.     gw_free(p);
  450. }
  451. /*
  452.  * Thread id for HTTP server emulator thread. It is needed for proper
  453.  * shutdown.
  454.  */
  455. static long httpd_emu_tid = -1;
  456. /*
  457.  * Start the HTTP server emulator thread and return when it is 
  458.  * ready to accept clients.
  459.  */
  460. static void httpd_emu_create(EventQueue *eq)
  461. {
  462.     struct httpd_emu_arg *arg;
  463.     int ssl = 0;   /* indicate if SSL-enabled server should be used */
  464.     if (http_open_port(http_port, ssl) == -1)
  465.      panic(0, "Can't open HTTP server emulator port %ld.", http_port);
  466.     gw_assert(httpd_emu_tid == -1);
  467.     arg = gw_malloc(sizeof(*arg));
  468.     arg->port = http_port;
  469.     arg->sema = semaphore_create(0);
  470.     arg->eq = eq;
  471.     httpd_emu_tid = gwthread_create(httpd_emu, arg);
  472.     if (httpd_emu_tid == -1)
  473.      panic(0, "Can't start the HTTP server emulator thread.");
  474.     semaphore_down(arg->sema);
  475.     semaphore_destroy(arg->sema);
  476. }
  477. /*
  478.  * Terminate the HTTP server emulator thread. Return when the thread
  479.  * is quite dead.
  480.  */
  481. static void httpd_emu_destroy(void)
  482. {
  483.     gw_assert(httpd_emu_tid != -1);
  484.     http_close_all_ports();
  485.     gwthread_join(httpd_emu_tid);
  486.     httpd_emu_tid = -1;
  487. }
  488. /*
  489.  * Send a reply to an HTTP response.
  490.  */
  491. static void httpd_emu_reply(Event *e)
  492. {
  493.     http_send_reply(e->client, HTTP_OK, httpd_emu_headers, e->body);
  494. }
  495. static void httpd_emu_init(void)
  496. {
  497.     httpd_emu_headers = http_create_empty_headers();
  498.     http_header_add(httpd_emu_headers, "Content-Type", "text/plain");
  499. }
  500. static void httpd_emu_shutdown(void)
  501. {
  502.     http_destroy_headers(httpd_emu_headers);
  503. }
  504. /***********************************************************************
  505.  * Main program for N SMS messages benchmark.
  506.  */
  507. static void kill_kannel(void)
  508. {
  509.     Octstr *url;
  510.     Octstr *final_url;
  511.     List *req_headers;
  512.     List *reply_headers;
  513.     Octstr *reply_body;
  514.     int ret;
  515.     
  516.     url = octstr_format("http://localhost:%ld/shutdown?password=%s",
  517.                admin_port, admin_password);
  518.     req_headers = http_create_empty_headers();
  519.     http_header_add(req_headers, "Content-Type", "text/plain");
  520.     ret = http_get_real(HTTP_METHOD_GET, url, req_headers, &final_url, 
  521.                         &reply_headers, &reply_body);
  522.     if (ret != -1) {
  523.      octstr_destroy(final_url);
  524. http_destroy_headers(reply_headers);
  525.      octstr_destroy(reply_body);
  526.     }
  527.     octstr_destroy(url);
  528.     http_destroy_headers(req_headers);
  529. }
  530. /*
  531.  * This will try to have as large a sustained level of traffic as possible.
  532.  */
  533. enum { MAX_IN_AVERAGE = 100 };
  534. enum { MAX_RTT = 1 };
  535. enum { MAX_WAITING = 100 };
  536. static void sustained_level_benchmark(void)
  537. {
  538.     EventQueue *eq;
  539.     Event *e;
  540.     long i;
  541.     long num_deliver;
  542.     long num_submit;
  543.     long rtt;
  544.     long times[MAX_IN_AVERAGE];
  545.     long next_time;
  546.     double time_sum;
  547.     long num_unanswered;
  548.     eq = eq_create();
  549.     httpd_emu_create(eq);
  550.     smsc_emu_create(eq);
  551.     
  552.     /* Wait for an SMS center client to appear. */
  553.     while ((e = eq_extract(eq)) != NULL && e->type != got_smsc)
  554.      debug("test_smsc", 0, "Discarding event of type %s", eq_type(e));
  555.     debug("test_smsc", 0, "Got event got_smsc.");
  556.     eq_destroy_event(e);
  557.     /* 
  558.      * Send message when there are at most MAX_WAITING unanswered messages
  559.      * and current average round trip time is less than MAX_RTT.
  560.      */
  561.     num_submit = 0;
  562.     for (i = 0; i < MAX_IN_AVERAGE; ++i)
  563.      times[i] = 0;
  564.     next_time = 0;
  565.     time_sum = 0.0;
  566.     num_unanswered = 0;
  567.     num_deliver = 0;
  568.     while (num_submit < num_messages) {
  569. for (;;) {
  570.     if (num_deliver >= num_messages || num_unanswered >= MAX_WAITING)
  571.      break;
  572.          if (time_sum / MAX_IN_AVERAGE >= MAX_RTT && num_unanswered > 0)
  573.      break;
  574.     smsc_emu_deliver();
  575.     ++num_unanswered;
  576.     ++num_deliver;
  577. }
  578.      e = eq_extract(eq);
  579. if (e == NULL)
  580.     break;
  581. eq_log(e);
  582. switch (e->type) {
  583. case deliver_ack:
  584.     break;
  585.     
  586. case http_request:
  587.     httpd_emu_reply(e);
  588.     break;
  589. case submit:
  590.     rtt = eq_round_trip_time(e);
  591.     time_sum -= times[next_time];
  592.     times[next_time] = rtt;
  593.     time_sum += times[next_time];
  594.     debug("", 0, "RTT = %ld", rtt);
  595.     next_time = (next_time + 1) % MAX_IN_AVERAGE;
  596.     ++num_submit;
  597.     --num_unanswered;
  598.     smsc_emu_submit_ack(e);
  599.     break;
  600.     
  601.      case got_enquire_link:
  602.     break;
  603. default:
  604.     debug("test_smsc", 0, "Ignoring event of type %s", eq_type(e));
  605.     break;
  606. }
  607. eq_destroy_event(e);
  608.     }
  609.     kill_kannel();
  610.     debug("test_smsc", 0, "Terminating benchmark.");
  611.     smsc_emu_destroy();
  612.     httpd_emu_destroy();
  613.     eq_destroy(eq);
  614. }
  615. /*
  616.  * This will send `num_messages' SMS messages as quickly as possible.
  617.  */
  618. enum { MAX_IN_QUEUE = 1000 };
  619. static void n_messages_benchmark(void)
  620. {
  621.     EventQueue *eq;
  622.     Event *e;
  623.     long i;
  624.     long num_submit;
  625.     long num_in_queue;
  626.     long num_deliver;
  627.     eq = eq_create();
  628.     httpd_emu_create(eq);
  629.     smsc_emu_create(eq);
  630.     
  631.     /* Wait for an SMS center client to appear. */
  632.     while ((e = eq_extract(eq)) != NULL && e->type != got_smsc)
  633.      debug("test_smsc", 0, "Discarding event of type %s", eq_type(e));
  634.     debug("test_smsc", 0, "Got event got_smsc.");
  635.     eq_destroy_event(e);
  636.     /* Send the SMS messages, or at least fill the send queue. */
  637.     for (i = 0; i < num_messages && i < MAX_IN_QUEUE; ++i)
  638.      smsc_emu_deliver();
  639.     num_in_queue = i;
  640.     num_deliver = i;
  641.     /* 
  642.      * Wait for results to be processed. When send queue is not full,
  643.      * fill it.
  644.      */
  645.     num_submit = 0;
  646.     while (num_submit < num_messages && (e = eq_extract(eq)) != NULL) {
  647.      while (num_deliver < num_messages && num_in_queue < MAX_IN_QUEUE) {
  648.     smsc_emu_deliver();
  649.     ++num_in_queue;
  650.     ++num_deliver;
  651. }
  652. eq_log(e);
  653. switch (e->type) {
  654. case deliver_ack:
  655.     break;
  656.     
  657. case http_request:
  658.     httpd_emu_reply(e);
  659.     break;
  660. case submit:
  661.     debug("", 0, "RTT = %ld", eq_round_trip_time(e));
  662.     smsc_emu_submit_ack(e);
  663.     ++num_submit;
  664.     --num_in_queue;
  665.     break;
  666.     
  667.      case got_enquire_link:
  668.     break;
  669. default:
  670.     debug("test_smsc", 0, "Ignoring event of type %s", eq_type(e));
  671.     break;
  672. }
  673. eq_destroy_event(e);
  674.     }
  675.     kill_kannel();
  676.     debug("test_smsc", 0, "Terminating benchmark.");
  677.     smsc_emu_destroy();
  678.     httpd_emu_destroy();
  679.     eq_destroy(eq);
  680. }
  681. /***********************************************************************
  682.  * Main program.
  683.  */
  684. int main(int argc, char **argv)
  685. {
  686.     int opt;
  687.     char *main_name;
  688.     int i;
  689.     static struct {
  690. char *name;
  691. void (*func)(void);
  692.     } tab[] = {
  693. { "n_messages", n_messages_benchmark },
  694. { "sustained_level", sustained_level_benchmark },
  695.     };
  696.     gwlib_init();
  697.     eq_init();
  698.     httpd_emu_init();
  699.     smsc_emu_init();
  700.     main_name = "n_messages_benchmark";
  701.     while ((opt = getopt(argc, argv, "m:r:")) != EOF) {
  702. switch (opt) {
  703. case 'm':
  704.     main_name = optarg;
  705.     break;
  706. case 'r':
  707.     num_messages = atoi(optarg);
  708.     break;
  709. }
  710.     }
  711.     for (i = 0; (size_t) i < sizeof(tab) / sizeof(tab[0]); ++i) {
  712. if (strcmp(main_name, tab[i].name) == 0) {
  713.     tab[i].func();
  714.     break;
  715. }
  716.     }
  717.     smsc_emu_shutdown();
  718.     httpd_emu_shutdown();
  719.     eq_shutdown();
  720.     gwlib_shutdown();
  721.     return 0;
  722. }