📄 drive_smpp.c
字号:
/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2004 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see <http://www.kannel.org/>. * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * drive_smpp.c - SMPP server for testing purposes * * Lars Wirzenius */#include <errno.h>#include <signal.h>#include <sys/types.h>#include <sys/socket.h>#include "gwlib/gwlib.h"#include "gw/smsc/smpp_pdu.h"#include "gw/msg.h"static int quitting = 0;static Octstr *smsc_system_id;static Octstr *smsc_source_addr;static Counter *message_id_counter;static Octstr *bearerbox_host;static int port_for_smsbox;static Counter *num_to_esme;static long max_to_esme;static Counter *num_from_bearerbox;static Counter *num_to_bearerbox;static Counter *num_from_esme;static time_t start_time = (time_t) -1;static time_t first_to_esme = (time_t) -1;static time_t last_to_esme = (time_t) -1;static time_t last_from_esme = (time_t) -1;static time_t first_from_bb = (time_t) -1;static time_t last_to_bb = (time_t) -1;static long enquire_interval = 1; /* Measured in messages, not time. */static void quit(void){ quitting = 1; gwthread_wakeup_all();}typedef struct { Connection *conn; int transmitter; int receiver;} ESME;static ESME *esme_create(Connection *conn){ ESME *esme; esme = gw_malloc(sizeof(*esme)); esme->conn = conn; esme->transmitter = 0; esme->receiver = 0; return esme;}static void esme_destroy(ESME *esme){ if (esme != NULL) { conn_destroy(esme->conn); gw_free(esme); }}static SMPP_PDU *handle_bind_transmitter(ESME *esme, SMPP_PDU *pdu){ SMPP_PDU *resp; esme->transmitter = 1; resp = smpp_pdu_create(bind_transmitter_resp, pdu->u.bind_transmitter.sequence_number);#if 0 /* XXX system_id is not implemented in the PDU at the moment */ resp->u.bind_transmitter_resp.system_id = octstr_duplicate(smsc_system_id);#endif return resp;}static SMPP_PDU *handle_bind_receiver(ESME *esme, SMPP_PDU *pdu){ SMPP_PDU *resp; esme->receiver = 1; resp = smpp_pdu_create(bind_receiver_resp, pdu->u.bind_receiver.sequence_number);#if 0 /* XXX system_id is not implemented in the PDU at the moment */ resp->u.bind_receiver_resp.system_id = octstr_duplicate(smsc_system_id);#endif return resp;}static SMPP_PDU *handle_submit_sm(ESME *esme, SMPP_PDU *pdu){ SMPP_PDU *resp; unsigned long id; debug("test.smpp", 0, "submit_sm: short_message = <%s>", octstr_get_cstr(pdu->u.submit_sm.short_message)); id = counter_increase(num_from_esme) + 1; if (id == max_to_esme) info(0, "ESME has submitted all messages to SMSC."); time(&last_from_esme); resp = smpp_pdu_create(submit_sm_resp, pdu->u.submit_sm.sequence_number);#if 0 /* XXX message_id is not implemented in the PDU at the moment */ resp->u.submit_sm_resp.message_id = octstr_format("%ld", counter_increase(message_id_counter));#endif return resp;}static SMPP_PDU *handle_deliver_sm_resp(ESME *esme, SMPP_PDU *pdu){ return NULL;}static SMPP_PDU *handle_unbind(ESME *esme, SMPP_PDU *pdu){ SMPP_PDU *resp; resp = smpp_pdu_create(unbind_resp, pdu->u.unbind.sequence_number); return resp;}static SMPP_PDU *handle_enquire_link(ESME *esme, SMPP_PDU *pdu){ return smpp_pdu_create(enquire_link_resp, pdu->u.enquire_link.sequence_number);}static SMPP_PDU *handle_enquire_link_resp(ESME *esme, SMPP_PDU *pdu){ return NULL;}static struct { unsigned long type; SMPP_PDU *(*handler)(ESME *, SMPP_PDU *);} handlers[] = { #define HANDLER(name) { name, handle_ ## name }, HANDLER(bind_transmitter) HANDLER(bind_receiver) HANDLER(submit_sm) HANDLER(deliver_sm_resp) HANDLER(unbind) HANDLER(enquire_link) HANDLER(enquire_link_resp) #undef HANDLER};static int num_handlers = sizeof(handlers) / sizeof(handlers[0]);static void handle_pdu(ESME *esme, SMPP_PDU *pdu){ SMPP_PDU *resp; Octstr *os; int i; debug("test.smpp", 0, "Handling SMPP PDU of type %s", pdu->type_name); for (i = 0; i < num_handlers; ++i) { if (handlers[i].type == pdu->type) { resp = handlers[i].handler(esme, pdu); if (resp != NULL) { os = smpp_pdu_pack(resp); conn_write(esme->conn, os); octstr_destroy(os); smpp_pdu_destroy(resp); } return; } } error(0, "Unhandled SMPP PDU."); smpp_pdu_dump(pdu);}static void send_smpp_thread(void *arg){ ESME *esme; Octstr *os; SMPP_PDU *pdu; unsigned long id; esme = arg; id = 0; while (!quitting && counter_value(num_to_esme) < max_to_esme) { id = counter_increase(num_to_esme) + 1; while (!quitting && counter_value(num_from_esme) + 500 < id) gwthread_sleep(1.0); if (quitting) break; pdu = smpp_pdu_create(deliver_sm, counter_increase(message_id_counter)); pdu->u.deliver_sm.source_addr = octstr_create("456"); pdu->u.deliver_sm.destination_addr = octstr_create("123"); pdu->u.deliver_sm.short_message = octstr_format("%ld", id); os = smpp_pdu_pack(pdu); conn_write(esme->conn, os); octstr_destroy(os); smpp_pdu_destroy(pdu); if (first_to_esme == (time_t) -1) time(&first_to_esme); debug("test.smpp", 0, "Delivered SMS %ld of %ld to bearerbox via SMPP.", id, max_to_esme); if ((id % enquire_interval) == 0) { pdu = smpp_pdu_create(enquire_link, counter_increase(message_id_counter)); os = smpp_pdu_pack(pdu); conn_write(esme->conn, os); octstr_destroy(os); smpp_pdu_destroy(pdu); debug("test.smpp", 0, "Sent enquire_link to bearerbox."); } } time(&last_to_esme); if (id == max_to_esme) info(0, "All messages sent to ESME."); debug("test.smpp", 0, "%s terminates.", __func__);}static void receive_smpp_thread(void *arg){ ESME *esme; Octstr *os; long len; long sender_id; SMPP_PDU *pdu; esme = arg; sender_id = -1; len = 0; while (!quitting && conn_wait(esme->conn, -1.0) != -1) { for (;;) { if (len == 0) { len = smpp_pdu_read_len(esme->conn); if (len == -1) { error(0, "Client sent garbage, closing connection."); goto error; } else if (len == 0) { if (conn_eof(esme->conn) || conn_error(esme->conn)) goto error; break; } } gw_assert(len > 0); os = smpp_pdu_read_data(esme->conn, len); if (os != NULL) { len = 0; pdu = smpp_pdu_unpack(os); if (pdu == NULL) { error(0, "PDU unpacking failed!"); octstr_dump(os, 0); } else { handle_pdu(esme, pdu); smpp_pdu_destroy(pdu); } octstr_destroy(os); } else if (conn_eof(esme->conn) || conn_error(esme->conn)) goto error; else break; } if (!quitting && esme->receiver && sender_id == -1) sender_id = gwthread_create(send_smpp_thread, esme); }error: if (sender_id != -1) { quit(); gwthread_join(sender_id); } esme_destroy(esme); quit(); debug("test.smpp", 0, "%s terminates.", __func__);}static void smsbox_thread(void *arg){ Connection *conn; Msg *msg; Octstr *os; Octstr *reply_msg; unsigned long count; msg = msg_create(sms); msg->sms.sender = octstr_create("123"); msg->sms.receiver = octstr_create("456"); msg->sms.msgdata = octstr_create("hello world"); reply_msg = msg_pack(msg); msg_destroy(msg); gwthread_sleep(1.0); conn = conn_open_tcp(bearerbox_host, port_for_smsbox, NULL); if (conn == NULL) { gwthread_sleep(2.0); conn = conn_open_tcp(bearerbox_host, port_for_smsbox, NULL); if (conn == NULL) panic(0, "Couldn't connect to bearerbox as smsbox"); } while (!quitting && conn_wait(conn, -1.0) != -1) { for (;;) { os = conn_read_withlen(conn); if (os == NULL) { if (conn_eof(conn) || conn_error(conn)) goto error; break; } msg = msg_unpack(os); if (msg == NULL || msg->type == wdp_datagram) error(0, "Bearerbox sent garbage to smsbox"); if (msg->type == sms) { if (first_from_bb == (time_t) -1) time(&first_from_bb); count = counter_increase(num_from_bearerbox) + 1; debug("test.smpp", 0, "Bearerbox sent sms #%ld <%s> to smsbox, sending reply.", count, octstr_get_cstr(msg->sms.msgdata)); if (count == max_to_esme) info(0, "Bearerbox has sent all messages to smsbox."); conn_write_withlen(conn, reply_msg); counter_increase(num_to_bearerbox); } msg_destroy(msg); octstr_destroy(os); time(&last_to_bb); } } error: conn_destroy(conn); octstr_destroy(reply_msg); debug("test.smpp", 0, "%s terminates.", __func__);}static void accept_thread(void *arg){ int fd; int new_fd; int port; socklen_t addrlen; struct sockaddr addr; long smsbox_thread_id; port = *(int *) arg; fd = make_server_socket(port, NULL); if (fd == -1) panic(0, "Couldn't create SMPP listen port."); smsbox_thread_id = -1; for (;;) { if (gwthread_pollfd(fd, POLLIN, -1.0) != POLLIN) break; addrlen = sizeof(addr); new_fd = accept(fd, &addr, &addrlen); if (start_time == (time_t) -1) time(&start_time); gwthread_create(receive_smpp_thread, esme_create(conn_wrap_fd(new_fd, 0))); if (smsbox_thread_id == -1) smsbox_thread_id = gwthread_create(smsbox_thread, NULL); } debug("test.smpp", 0, "%s terminates.", __func__);}static void handler(int signal){ panic(0, "Caught signal %d.", signal);}static void help(void){ info(0, "drive_smpp [-h] [-v level]燵-p port]");}int main(int argc, char **argv){ struct sigaction act; int http_port; int port; int opt; double run_time; char *log_file; gwlib_init(); act.sa_handler = handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGTERM, &act, NULL); sigaction(SIGINT, &act, NULL); port = 2345; http_port = 8080; smsc_system_id = octstr_create("kannel_smpp"); smsc_source_addr = octstr_create("123456"); message_id_counter = counter_create(); bearerbox_host = octstr_create("localhost"); port_for_smsbox = 13001; max_to_esme = 1; num_to_esme = counter_create(); num_from_esme = counter_create(); num_to_bearerbox = counter_create(); num_from_bearerbox = counter_create(); log_file = NULL; while ((opt = getopt(argc, argv, "hv:p:P:m:l:")) != EOF) { switch (opt) { case 'v': log_set_output_level(atoi(optarg)); break; case 'h': help(); exit(0); case 'm': max_to_esme = atoi(optarg); break; case 'p': port = atoi(optarg); break; case 'P': http_port = atoi(optarg); break; case 'l': log_file = optarg; break; case '?': default: error(0, "Invalid option %c", opt); help(); panic(0, "Stopping."); } } if (log_file != NULL) log_open(log_file, GW_DEBUG, GW_NON_EXCL); info(0, "Starting drive_smpp test."); gwthread_create(accept_thread, &port); gwthread_join_all(); debug("test.smpp", 0, "Program exiting normally."); run_time = difftime(last_from_esme, first_to_esme); info(0, "Number of messages sent to ESME: %ld", counter_value(num_to_esme)); info(0, "Number of messages sent to smsbox: %ld", counter_value(num_from_bearerbox)); info(0, "Number of messages sent to bearerbox: %ld", counter_value(num_to_bearerbox)); info(0, "Number of messages sent to SMSC: %ld", counter_value(num_from_esme)); info(0, "Time: %.0f secs", run_time); info(0, "Time until all sent to ESME: %.0f secs", difftime(last_to_esme, start_time)); info(0, "Time from first from bb to last to bb: %.0f secs", difftime(last_to_bb, first_from_bb)); info(0, "Time until all sent to SMSC: %.0f secs", difftime(last_from_esme, start_time)); info(0, "SMPP messages SMSC to ESME: %.1f msgs/sec", counter_value(num_to_esme) / run_time); info(0, "SMPP messages ESME to SMSC: %.1f msgs/sec", counter_value(num_from_esme) / run_time); octstr_destroy(smsc_system_id); octstr_destroy(smsc_source_addr); octstr_destroy(bearerbox_host); counter_destroy(num_to_esme); counter_destroy(num_from_esme); counter_destroy(num_to_bearerbox); counter_destroy(num_from_bearerbox); counter_destroy(message_id_counter); gwlib_shutdown(); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -