1 /* ====================================================================
2 * The Kannel Software License, Version 1.0
3 *
4 * Copyright (c) 2001-2014 Kannel Group
5 * Copyright (c) 1998-2001 WapIT Ltd.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * 3. The end-user documentation included with the redistribution,
21 * if any, must include the following acknowledgment:
22 * "This product includes software developed by the
23 * Kannel Group (http://www.kannel.org/)."
24 * Alternately, this acknowledgment may appear in the software itself,
25 * if and wherever such third-party acknowledgments normally appear.
26 *
27 * 4. The names "Kannel" and "Kannel Group" must not be used to
28 * endorse or promote products derived from this software without
29 * prior written permission. For written permission, please
30 * contact org@kannel.org.
31 *
32 * 5. Products derived from this software may not be called "Kannel",
33 * nor may "Kannel" appear in their name, without prior written
34 * permission of the Kannel Group.
35 *
36 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39 * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
40 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
41 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
42 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
46 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47 * ====================================================================
48 *
49 * This software consists of voluntary contributions made by many
50 * individuals on behalf of the Kannel Group. For more information on
51 * the Kannel Group, please see <http://www.kannel.org/>.
52 *
53 * Portions of this software are based upon software originally written at
54 * WapIT Ltd., Helsinki, Finland for the Kannel project.
55 */
56
57 #include <unistd.h>
58 #include "gwlib/gwlib.h"
59 #include "gw/smsc/smpp_pdu.h"
60 #include <string.h>
61
62 /***********************************************************************
63 * Configurable stuff.
64 */
65
66
67 /*
68 * The port at which our HTTP server emulator listens.
69 */
70 static long http_port = 8080;
71
72
73 /*
74 * The HTTP admin port and password for Kannel, needed to do shutdown.
75 */
76 static long admin_port = 13000;
77 static char *admin_password = "bar";
78
79
80 /*
81 * The port at which the SMPP SMS center emulator listens.
82 */
83 static long smpp_port = 2345;
84
85
86 /*
87 * Number of messages to use in the "Send N messages as fast as possible"
88 * benchmark.
89 */
90 static long num_messages = 1;
91
92
93 /***********************************************************************
94 * Events and event queues.
95 */
96
97 typedef List EventQueue;
98
99
100 typedef struct Event {
101 enum event_type {
102 got_smsc,
103 deliver,
104 deliver_ack,
105 http_request,
106 http_response,
107 submit,
108 got_enquire_link
109 } type;
110 long id;
111 long time;
112
113 Connection *conn; /* SMPP: Connection for response PDU */
114 long sequence_number; /* SMPP: Sequence number of resp PDU */
115
116 /* HTTP related stuff */
117 HTTPClient *client;
118 Octstr *body;
119 } Event;
120
121
122 static Counter *event_id_counter = NULL;
123
124
eq_type(Event * e)125 static const char *eq_type(Event *e)
126 {
127 #define TYPE(name) case name: return #name;
128 switch (e->type) {
129 TYPE(got_smsc)
130 TYPE(deliver)
131 TYPE(deliver_ack)
132 TYPE(http_request)
133 TYPE(http_response)
134 TYPE(submit)
135 TYPE(got_enquire_link)
136 }
137 #undef TYPE
138 return "unknown";
139 }
140
141
eq_create_event(enum event_type type)142 static Event *eq_create_event(enum event_type type)
143 {
144 Event *e;
145
146 e = gw_malloc(sizeof(*e));
147 e->type = type;
148 e->time = date_universal_now();
149 e->id = counter_increase(event_id_counter);
150 e->conn = NULL;
151 e->sequence_number = -1;
152 e->client = NULL;
153 e->body = NULL;
154 return e;
155 }
156
157
eq_create_submit(Connection * conn,long sequence_number,Octstr * body)158 static Event *eq_create_submit(Connection *conn, long sequence_number,
159 Octstr *body)
160 {
161 Event *e;
162
163 gw_assert(conn != NULL);
164 gw_assert(sequence_number >= 0);
165
166 e = eq_create_event(submit);
167 e->conn = conn;
168 e->sequence_number = sequence_number;
169 e->body = octstr_duplicate(body);
170 return e;
171 }
172
173
eq_create_http_request(HTTPClient * client,Octstr * body)174 static Event *eq_create_http_request(HTTPClient *client, Octstr *body)
175 {
176 Event *e;
177
178 gw_assert(client != NULL);
179 gw_assert(body != NULL);
180
181 e = eq_create_event(http_request);
182 e->client = client;
183 e->body = octstr_duplicate(body);
184 return e;
185 }
186
187
eq_destroy_event(Event * e)188 static void eq_destroy_event(Event *e)
189 {
190 octstr_destroy(e->body);
191 gw_free(e);
192 }
193
194
eq_create(void)195 static EventQueue *eq_create(void)
196 {
197 return gwlist_create();
198 }
199
200
eq_add_producer(EventQueue * eq)201 static void eq_add_producer(EventQueue *eq)
202 {
203 gwlist_add_producer(eq);
204 }
205
206
eq_remove_producer(EventQueue * eq)207 static void eq_remove_producer(EventQueue *eq)
208 {
209 gwlist_remove_producer(eq);
210 }
211
212
eq_destroy(EventQueue * eq)213 static void eq_destroy(EventQueue *eq)
214 {
215 gwlist_destroy(eq, NULL);
216 }
217
218
eq_append(EventQueue * eq,Event * e)219 static void eq_append(EventQueue *eq, Event *e)
220 {
221 gwlist_produce(eq, e);
222 }
223
224
eq_extract(EventQueue * eq)225 static Event *eq_extract(EventQueue *eq)
226 {
227 return gwlist_consume(eq);
228 }
229
230
eq_log(Event * e)231 static void eq_log(Event *e)
232 {
233 info(0, "Event %ld, type %s, time %ld", e->id, eq_type(e), e->time);
234 }
235
236
eq_init(void)237 static void eq_init(void)
238 {
239 event_id_counter = counter_create();
240 }
241
242
eq_shutdown(void)243 static void eq_shutdown(void)
244 {
245 counter_destroy(event_id_counter);
246 }
247
248
eq_round_trip_time(Event * e)249 static long eq_round_trip_time(Event *e)
250 {
251 long now, then;
252
253 now = date_universal_now();
254 if (octstr_parse_long(&then, e->body, 0, 10) == -1)
255 return 0;
256 return now - then;
257 }
258
259
260 /***********************************************************************
261 * SMS center emulator, declarations.
262 */
263
264
265 struct smsc_emu_arg {
266 Semaphore *sema;
267 EventQueue *eq;
268 };
269
270
271 static EventQueue *undelivered_messages = NULL;
272
273
274 /***********************************************************************
275 * SMS center emulator, SMPP internals.
276 */
277
278
279 enum { MAX_THREADS = 2 };
280 enum { SMPP_MAX_QUEUE = 10 };
281
282
283 struct smpp_emu_arg {
284 EventQueue *eq;
285 Connection *conn;
286 long id;
287 Semaphore *ok_to_send;
288 long writer_id;
289 int quit;
290 };
291
292
293 static Counter *smpp_emu_counter = NULL;
294
295
smpp_emu_writer(void * arg)296 static void smpp_emu_writer(void *arg)
297 {
298 Event *e;
299 SMPP_PDU *pdu;
300 Octstr *os;
301 struct smpp_emu_arg *p;
302
303 p = arg;
304 for (;;) {
305 semaphore_down(p->ok_to_send);
306 e = eq_extract(undelivered_messages);
307 if (e == NULL)
308 break;
309 e->time = date_universal_now();
310 eq_log(e);
311 pdu = smpp_pdu_create(deliver_sm,
312 counter_increase(smpp_emu_counter));
313 pdu->u.deliver_sm.source_addr = octstr_create("123");
314 pdu->u.deliver_sm.destination_addr = octstr_create("456");
315 pdu->u.deliver_sm.short_message = octstr_format("%ld", e->time);
316 os = smpp_pdu_pack(NULL, pdu);
317 conn_write(p->conn, os);
318 octstr_destroy(os);
319 smpp_pdu_destroy(pdu);
320 eq_destroy_event(e);
321 }
322 }
323
324
smpp_emu_handle_pdu(struct smpp_emu_arg * p,SMPP_PDU * pdu)325 static void smpp_emu_handle_pdu(struct smpp_emu_arg *p, SMPP_PDU *pdu)
326 {
327 SMPP_PDU *resp;
328 Octstr *os;
329
330 resp = NULL;
331 switch (pdu->type) {
332 case bind_transmitter:
333 resp = smpp_pdu_create(bind_transmitter_resp,
334 pdu->u.bind_transmitter.sequence_number);
335 break;
336
337 case bind_receiver:
338 resp = smpp_pdu_create(bind_receiver_resp,
339 pdu->u.bind_receiver.sequence_number);
340 eq_append(p->eq, eq_create_event(got_smsc));
341 gw_assert(p->writer_id == -1);
342 p->writer_id = gwthread_create(smpp_emu_writer, p);
343 if (p->writer_id == -1)
344 panic(0, "Couldn't create SMPP helper thread.");
345 break;
346
347 case submit_sm:
348 eq_append(p->eq,
349 eq_create_submit(p->conn, pdu->u.submit_sm.sequence_number,
350 pdu->u.submit_sm.short_message));
351 break;
352
353 case deliver_sm_resp:
354 eq_append(p->eq, eq_create_event(deliver_ack));
355 semaphore_up(p->ok_to_send);
356 break;
357
358 case enquire_link:
359 eq_append(p->eq, eq_create_event(got_enquire_link));
360 resp = smpp_pdu_create(enquire_link_resp,
361 pdu->u.enquire_link.sequence_number);
362 break;
363
364 case unbind:
365 resp = smpp_pdu_create(unbind_resp,
366 pdu->u.unbind.sequence_number);
367 break;
368
369 default:
370 error(0, "SMPP: Unhandled PDU type %s", pdu->type_name);
371 break;
372 }
373
374 if (resp != NULL) {
375 os = smpp_pdu_pack(NULL, resp);
376 conn_write(p->conn, os);
377 octstr_destroy(os);
378 smpp_pdu_destroy(resp);
379 }
380 }
381
382
smpp_emu_reader(void * arg)383 static void smpp_emu_reader(void *arg)
384 {
385 Octstr *os;
386 long len;
387 SMPP_PDU *pdu;
388 struct smpp_emu_arg *p;
389
390 p = arg;
391
392 len = 0;
393 while (!p->quit && conn_wait(p->conn, -1.0) != -1) {
394 for (;;) {
395 if (len == 0) {
396 len = smpp_pdu_read_len(p->conn);
397 if (len == -1) {
398 error(0, "Client sent garbage, closing connection.");
399 goto error;
400 } else if (len == 0) {
401 if (conn_eof(p->conn) || conn_error(p->conn))
402 goto error;
403 break;
404 }
405 }
406
407 gw_assert(len > 0);
408 os = smpp_pdu_read_data(p->conn, len);
409 if (os != NULL) {
410 len = 0;
411 pdu = smpp_pdu_unpack(NULL, os);
412 if (pdu == NULL) {
413 error(0, "PDU unpacking failed!");
414 octstr_dump(os, 0);
415 } else {
416 smpp_emu_handle_pdu(p, pdu);
417 smpp_pdu_destroy(pdu);
418 }
419 octstr_destroy(os);
420 } else if (conn_eof(p->conn) || conn_error(p->conn))
421 goto error;
422 else
423 break;
424 }
425 }
426
427 error:
428 if (p->writer_id != -1)
429 gwthread_join(p->writer_id);
430 }
431
432
smpp_emu(void * arg)433 static void smpp_emu(void *arg)
434 {
435 EventQueue *eq;
436 struct smsc_emu_arg *p;
437 int fd;
438 int new_fd;
439 Octstr *client_addr;
440 long i;
441 long num_threads;
442 struct smpp_emu_arg *thread[MAX_THREADS];
443
444 p = arg;
445 eq = p->eq;
446 eq_add_producer(eq);
447 semaphore_up(p->sema);
448
449 /*
450 * Wait for SMPP clients.
451 */
452 fd = make_server_socket(smpp_port, NULL);
453 if (fd == -1)
454 panic(0, "Couldn't create SMPP listen port.");
455
456 num_threads = 0;
457 for (;;) {
458 new_fd = gw_accept(fd, &client_addr);
459 if (new_fd == -1)
460 break;
461 octstr_destroy(client_addr);
462 if (num_threads == MAX_THREADS) {
463 warning(0, "Too many SMPP client connections.");
464 (void) close(new_fd);
465 } else {
466 thread[num_threads] = gw_malloc(sizeof(*thread[0]));
467 thread[num_threads]->conn = conn_wrap_fd(new_fd, 0);
468 thread[num_threads]->eq = eq;
469 thread[num_threads]->quit = 0;
470 thread[num_threads]->writer_id = -1;
471 thread[num_threads]->ok_to_send =
472 semaphore_create(SMPP_MAX_QUEUE);
473 thread[num_threads]->id =
474 gwthread_create(smpp_emu_reader, thread[num_threads]);
475 if (thread[num_threads]->id == -1)
476 panic(0, "Couldn't start SMPP subthread.");
477 ++num_threads;
478 }
479 }
480
481 for (i = 0; i < num_threads; ++i) {
482 thread[i]->quit = 1;
483 gwthread_wakeup(thread[i]->id);
484 gwthread_join(thread[i]->id);
485 conn_destroy(thread[i]->conn);
486 semaphore_destroy(thread[i]->ok_to_send);
487 gw_free(thread[i]);
488 }
489
490 eq_remove_producer(eq);
491 }
492
493
494 /***********************************************************************
495 * SMS center emulator, generic interface.
496 */
497
498
499 static long smpp_emu_id = -1;
500
501
502 /*
503 * Start all SMS center emulators.
504 */
smsc_emu_create(EventQueue * eq)505 static void smsc_emu_create(EventQueue *eq)
506 {
507 struct smsc_emu_arg *arg;
508
509 gw_assert(smpp_emu_id == -1);
510
511 arg = gw_malloc(sizeof(*arg));
512 arg->sema = semaphore_create(0);
513 arg->eq = eq;
514 smpp_emu_id = gwthread_create(smpp_emu, arg);
515 if (smpp_emu_id == -1)
516 panic(0, "Couldn't start SMPP emulator thread.");
517 semaphore_down(arg->sema);
518 semaphore_destroy(arg->sema);
519 gw_free(arg);
520 }
521
522
smsc_emu_destroy(void)523 static void smsc_emu_destroy(void)
524 {
525 eq_remove_producer(undelivered_messages);
526 gw_assert(smpp_emu_id != -1);
527 gwthread_wakeup(smpp_emu_id);
528 gwthread_join(smpp_emu_id);
529 }
530
531
smsc_emu_deliver(void)532 static void smsc_emu_deliver(void)
533 {
534 eq_append(undelivered_messages, eq_create_event(deliver));
535 }
536
537
smsc_emu_submit_ack(Event * e)538 static void smsc_emu_submit_ack(Event *e)
539 {
540 SMPP_PDU *resp;
541 Octstr *os;
542
543 resp = smpp_pdu_create(submit_sm_resp, e->sequence_number);
544 os = smpp_pdu_pack(NULL, resp);
545 conn_write(e->conn, os);
546 octstr_destroy(os);
547 smpp_pdu_destroy(resp);
548 }
549
550
smsc_emu_init(void)551 static void smsc_emu_init(void)
552 {
553 smpp_emu_counter = counter_create();
554 undelivered_messages = eq_create();
555 eq_add_producer(undelivered_messages);
556 }
557
558
smsc_emu_shutdown(void)559 static void smsc_emu_shutdown(void)
560 {
561 counter_destroy(smpp_emu_counter);
562 eq_destroy(undelivered_messages);
563 }
564
565
566 /***********************************************************************
567 * HTTP server emulator.
568 */
569
570
571 static List *httpd_emu_headers = NULL;
572
573
574 struct httpd_emu_arg {
575 int port;
576 Semaphore *sema;
577 EventQueue *eq;
578 };
579
580
581 /*
582 * This is the HTTP server emulator thread.
583 */
httpd_emu(void * arg)584 static void httpd_emu(void *arg)
585 {
586 HTTPClient *client;
587 Octstr *ip;
588 Octstr *url;
589 List *headers;
590 Octstr *body;
591 List *cgivars;
592 struct httpd_emu_arg *p;
593 EventQueue *eq;
594
595 p = arg;
596 eq = p->eq;
597 eq_add_producer(eq);
598 semaphore_up(p->sema);
599
600 for (;;) {
601 client = http_accept_request(p->port, &ip, &url, &headers, &body,
602 &cgivars);
603 if (client == NULL)
604 break;
605
606 eq_append(eq, eq_create_http_request(client,
607 http_cgi_variable(cgivars, "arg")));
608 octstr_destroy(ip);
609 octstr_destroy(url);
610 http_destroy_headers(headers);
611 octstr_destroy(body);
612 http_destroy_cgiargs(cgivars);
613 }
614 eq_remove_producer(eq);
615 gw_free(p);
616 }
617
618
619 /*
620 * Thread id for HTTP server emulator thread. It is needed for proper
621 * shutdown.
622 */
623 static long httpd_emu_tid = -1;
624
625
626 /*
627 * Start the HTTP server emulator thread and return when it is
628 * ready to accept clients.
629 */
httpd_emu_create(EventQueue * eq)630 static void httpd_emu_create(EventQueue *eq)
631 {
632 struct httpd_emu_arg *arg;
633 int ssl = 0; /* indicate if SSL-enabled server should be used */
634
635 if (http_open_port(http_port, ssl) == -1)
636 panic(0, "Can't open HTTP server emulator port %ld.", http_port);
637
638 gw_assert(httpd_emu_tid == -1);
639 arg = gw_malloc(sizeof(*arg));
640 arg->port = http_port;
641 arg->sema = semaphore_create(0);
642 arg->eq = eq;
643 httpd_emu_tid = gwthread_create(httpd_emu, arg);
644 if (httpd_emu_tid == -1)
645 panic(0, "Can't start the HTTP server emulator thread.");
646 semaphore_down(arg->sema);
647 semaphore_destroy(arg->sema);
648 }
649
650
651 /*
652 * Terminate the HTTP server emulator thread. Return when the thread
653 * is quite dead.
654 */
httpd_emu_destroy(void)655 static void httpd_emu_destroy(void)
656 {
657 gw_assert(httpd_emu_tid != -1);
658 http_close_all_ports();
659 gwthread_join(httpd_emu_tid);
660 httpd_emu_tid = -1;
661 }
662
663
664 /*
665 * Send a reply to an HTTP response.
666 */
httpd_emu_reply(Event * e)667 static void httpd_emu_reply(Event *e)
668 {
669 http_send_reply(e->client, HTTP_OK, httpd_emu_headers, e->body);
670 }
671
672
httpd_emu_init(void)673 static void httpd_emu_init(void)
674 {
675 httpd_emu_headers = http_create_empty_headers();
676 http_header_add(httpd_emu_headers, "Content-Type", "text/plain");
677 }
678
679
httpd_emu_shutdown(void)680 static void httpd_emu_shutdown(void)
681 {
682 http_destroy_headers(httpd_emu_headers);
683 }
684
685
686 /***********************************************************************
687 * Main program for N SMS messages benchmark.
688 */
689
690
kill_kannel(void)691 static void kill_kannel(void)
692 {
693 Octstr *url;
694 Octstr *final_url;
695 List *req_headers;
696 List *reply_headers;
697 Octstr *reply_body;
698 int ret;
699
700 url = octstr_format("http://localhost:%ld/shutdown?password=%s",
701 admin_port, admin_password);
702 req_headers = http_create_empty_headers();
703 http_header_add(req_headers, "Content-Type", "text/plain");
704 ret = http_get_real(HTTP_METHOD_GET, url, req_headers, &final_url,
705 &reply_headers, &reply_body);
706 if (ret != -1) {
707 octstr_destroy(final_url);
708 http_destroy_headers(reply_headers);
709 octstr_destroy(reply_body);
710 }
711 octstr_destroy(url);
712 http_destroy_headers(req_headers);
713 }
714
715
716 /*
717 * This will try to have as large a sustained level of traffic as possible.
718 */
719
720 enum { MAX_IN_AVERAGE = 100 };
721 enum { MAX_RTT = 1 };
722 enum { MAX_WAITING = 100 };
723
sustained_level_benchmark(void)724 static void sustained_level_benchmark(void)
725 {
726 EventQueue *eq;
727 Event *e;
728 long i;
729 long num_deliver;
730 long num_submit;
731 long rtt;
732 long times[MAX_IN_AVERAGE];
733 long next_time;
734 double time_sum;
735 long num_unanswered;
736
737 eq = eq_create();
738
739 httpd_emu_create(eq);
740 smsc_emu_create(eq);
741
742 /* Wait for an SMS center client to appear. */
743 while ((e = eq_extract(eq)) != NULL && e->type != got_smsc)
744 debug("test_smsc", 0, "Discarding event of type %s", eq_type(e));
745 debug("test_smsc", 0, "Got event got_smsc.");
746 eq_destroy_event(e);
747
748 /*
749 * Send message when there are at most MAX_WAITING unanswered messages
750 * and current average round trip time is less than MAX_RTT.
751 */
752 num_submit = 0;
753 for (i = 0; i < MAX_IN_AVERAGE; ++i)
754 times[i] = 0;
755 next_time = 0;
756 time_sum = 0.0;
757 num_unanswered = 0;
758 num_deliver = 0;
759
760 while (num_submit < num_messages) {
761 for (;;) {
762 if (num_deliver >= num_messages || num_unanswered >= MAX_WAITING)
763 break;
764 if (time_sum / MAX_IN_AVERAGE >= MAX_RTT && num_unanswered > 0)
765 break;
766 smsc_emu_deliver();
767 ++num_unanswered;
768 ++num_deliver;
769 }
770
771 e = eq_extract(eq);
772 if (e == NULL)
773 break;
774 eq_log(e);
775
776 switch (e->type) {
777 case deliver_ack:
778 break;
779
780 case http_request:
781 httpd_emu_reply(e);
782 break;
783
784 case submit:
785 rtt = eq_round_trip_time(e);
786 time_sum -= times[next_time];
787 times[next_time] = rtt;
788 time_sum += times[next_time];
789 debug("", 0, "RTT = %ld", rtt);
790 next_time = (next_time + 1) % MAX_IN_AVERAGE;
791 ++num_submit;
792 --num_unanswered;
793 smsc_emu_submit_ack(e);
794 break;
795
796 case got_enquire_link:
797 break;
798
799 default:
800 debug("test_smsc", 0, "Ignoring event of type %s", eq_type(e));
801 break;
802 }
803
804 eq_destroy_event(e);
805 }
806
807 kill_kannel();
808
809 debug("test_smsc", 0, "Terminating benchmark.");
810 smsc_emu_destroy();
811 httpd_emu_destroy();
812 eq_destroy(eq);
813 }
814
815
816 /*
817 * This will send `num_messages' SMS messages as quickly as possible.
818 */
819
820 enum { MAX_IN_QUEUE = 1000 };
821
n_messages_benchmark(void)822 static void n_messages_benchmark(void)
823 {
824 EventQueue *eq;
825 Event *e;
826 long i;
827 long num_submit;
828 long num_in_queue;
829 long num_deliver;
830
831 eq = eq_create();
832
833 httpd_emu_create(eq);
834 smsc_emu_create(eq);
835
836 /* Wait for an SMS center client to appear. */
837 while ((e = eq_extract(eq)) != NULL && e->type != got_smsc)
838 debug("test_smsc", 0, "Discarding event of type %s", eq_type(e));
839 debug("test_smsc", 0, "Got event got_smsc.");
840 eq_destroy_event(e);
841
842 /* Send the SMS messages, or at least fill the send queue. */
843 for (i = 0; i < num_messages && i < MAX_IN_QUEUE; ++i)
844 smsc_emu_deliver();
845 num_in_queue = i;
846 num_deliver = i;
847
848 /*
849 * Wait for results to be processed. When send queue is not full,
850 * fill it.
851 */
852 num_submit = 0;
853 while (num_submit < num_messages && (e = eq_extract(eq)) != NULL) {
854 while (num_deliver < num_messages && num_in_queue < MAX_IN_QUEUE) {
855 smsc_emu_deliver();
856 ++num_in_queue;
857 ++num_deliver;
858 }
859
860 eq_log(e);
861
862 switch (e->type) {
863 case deliver_ack:
864 break;
865
866 case http_request:
867 httpd_emu_reply(e);
868 break;
869
870 case submit:
871 debug("", 0, "RTT = %ld", eq_round_trip_time(e));
872 smsc_emu_submit_ack(e);
873 ++num_submit;
874 --num_in_queue;
875 break;
876
877 case got_enquire_link:
878 break;
879
880 default:
881 debug("test_smsc", 0, "Ignoring event of type %s", eq_type(e));
882 break;
883 }
884
885 eq_destroy_event(e);
886 }
887
888 kill_kannel();
889
890 debug("test_smsc", 0, "Terminating benchmark.");
891 smsc_emu_destroy();
892 httpd_emu_destroy();
893 eq_destroy(eq);
894 }
895
896
897 /***********************************************************************
898 * Main program.
899 */
900
901
main(int argc,char ** argv)902 int main(int argc, char **argv)
903 {
904 int opt;
905 char *main_name;
906 int i;
907 static struct {
908 char *name;
909 void (*func)(void);
910 } tab[] = {
911 { "n_messages", n_messages_benchmark },
912 { "sustained_level", sustained_level_benchmark },
913 };
914
915 gwlib_init();
916 eq_init();
917 httpd_emu_init();
918 smsc_emu_init();
919
920 main_name = "n_messages_benchmark";
921
922 while ((opt = getopt(argc, argv, "m:r:")) != EOF) {
923 switch (opt) {
924 case 'm':
925 main_name = optarg;
926 break;
927 case 'r':
928 num_messages = atoi(optarg);
929 break;
930 }
931 }
932
933 for (i = 0; (size_t) i < sizeof(tab) / sizeof(tab[0]); ++i) {
934 if (strcmp(main_name, tab[i].name) == 0) {
935 tab[i].func();
936 break;
937 }
938 }
939
940 smsc_emu_shutdown();
941 httpd_emu_shutdown();
942 eq_shutdown();
943 gwlib_shutdown();
944 return 0;
945 }
946