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