# HG changeset patch # User Mychaela Falconia # Date 1691085633 28800 # Node ID e1d7db9d734c1e1cf7b5e571d340f16c7dbe853c # Parent c798a1762c7cbe1fbdda0274346670c7592cc386 smpp-test2 program written diff -r c798a1762c7c -r e1d7db9d734c .hgignore --- a/.hgignore Tue Aug 01 23:29:38 2023 -0800 +++ b/.hgignore Thu Aug 03 10:00:33 2023 -0800 @@ -21,6 +21,7 @@ ^utils/sip-rx-test$ ^utils/sip-udp-dump$ ^utils/smpp-test1$ +^utils/smpp-test2$ ^utils/tcpserv-dump$ ^utils/themwi-check-own$ ^utils/themwi-dump-numdb$ diff -r c798a1762c7c -r e1d7db9d734c utils/Makefile --- a/utils/Makefile Tue Aug 01 23:29:38 2023 -0800 +++ b/utils/Makefile Thu Aug 03 10:00:33 2023 -0800 @@ -3,7 +3,7 @@ PROGS= sip-out-test sip-rx-test sip-udp-dump themwi-check-own \ themwi-dump-numdb themwi-short-dial themwi-update-numdb \ themwi-update-outrt -NOINST= rtp-alloc-test smpp-test1 tcpserv-dump +NOINST= rtp-alloc-test smpp-test1 smpp-test2 tcpserv-dump LIBNUMDB=../libnumdb/libnumdb.a LIBRTPA=../librtpalloc/librtpalloc.a LIBSIP= ../libsip/libsip.a @@ -27,6 +27,9 @@ smpp-test1: smpp-test1.c ${CC} ${CFLAGS} -o $@ $@.c +smpp-test2: smpp-test2.c + ${CC} ${CFLAGS} -o $@ $@.c + tcpserv-dump: tcpserv-dump.c ${CC} ${CFLAGS} -o $@ $@.c diff -r c798a1762c7c -r e1d7db9d734c utils/smpp-test2.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utils/smpp-test2.c Thu Aug 03 10:00:33 2023 -0800 @@ -0,0 +1,333 @@ +/* + * This program connects to an SMPP server in the role of a client, + * sends a bind_transceiver request, and then goes into a receiving loop, + * dumping everything that comes back from the server. Received packets + * are also checked for some command opcodes to which we need to generate + * a response, and simple auto-responses are generated. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int tcpsock; +static struct sockaddr_in server_sin; +static u_char bind_req[64]; +static unsigned bind_req_len; +static char system_id[16], password[9]; +static u_char rx_hdr[16]; +static unsigned rx_pkt_len, rx_command_id; + +static void +construct_bind_req() +{ + u_char *dp; + unsigned slen; + + dp = bind_req + 4; /* length will be filled last */ + /* command_id */ + *dp++ = 0; + *dp++ = 0; + *dp++ = 0; + *dp++ = 0x09; /* bind_transceiver */ + /* empty command_status */ + *dp++ = 0; + *dp++ = 0; + *dp++ = 0; + *dp++ = 0; + /* sequence_number */ + *dp++ = 0; + *dp++ = 0; + *dp++ = 0; + *dp++ = 1; + /* system_id */ + slen = strlen(system_id) + 1; + bcopy(system_id, dp, slen); + dp += slen; + /* password */ + slen = strlen(password) + 1; + bcopy(password, dp, slen); + dp += slen; + /* system_type */ + strcpy(dp, "SMPP"); + dp += 5; + /* interface_version */ + *dp++ = 0x34; + /* addr_ton */ + *dp++ = 0; + /* addr_npi */ + *dp++ = 0; + /* address_range */ + *dp++ = 0; + bind_req_len = dp - bind_req; + bind_req[0] = bind_req_len >> 24; + bind_req[1] = bind_req_len >> 16; + bind_req[2] = bind_req_len >> 8; + bind_req[3] = bind_req_len; +} + +static void +print_bind_req() +{ + unsigned off, chunk; + int i, c; + + printf("Constructed bind request of %u bytes\n", bind_req_len); + for (off = 0; off < bind_req_len; off += chunk) { + chunk = bind_req_len - off; + if (chunk > 16) + chunk = 16; + printf("%02X: ", off); + for (i = 0; i < 16; i++) { + if (i < chunk) + printf("%02X ", bind_req[off + i]); + else + fputs(" ", stdout); + if (i == 7 || i == 15) + putchar(' '); + } + for (i = 0; i < chunk; i++) { + c = bind_req[off + i]; + if (c < ' ' || c > '~') + c = '.'; + putchar(c); + } + putchar('\n'); + } +} + +static void +init_stage() +{ + int rc; + + rc = connect(tcpsock, (struct sockaddr *) &server_sin, + sizeof(struct sockaddr_in)); + if (rc < 0) { + perror("connect"); + exit(1); + } + rc = write(tcpsock, bind_req, bind_req_len); + if (rc != bind_req_len) { + perror("write"); + exit(1); + } +} + +static void +rx_bytes(buf, need_len) + u_char *buf; + unsigned need_len; +{ + int cc; + unsigned remain; + + for (remain = need_len; remain; remain -= cc) { + cc = read(tcpsock, buf, remain); + if (cc <= 0) { + perror("read"); + exit(1); + } + } +} + +static void +print_hdr() +{ + int i, j, pos; + + fputs("Got header:", stdout); + pos = 0; + for (i = 0; i < 4; i++) { + putchar(' '); + for (j = 0; j < 4; j++) + printf("%02X", rx_hdr[pos++]); + } + putchar('\n'); +} + +static void +preen_rx_hdr() +{ + rx_pkt_len = (rx_hdr[0] << 24) | (rx_hdr[1] << 16) | (rx_hdr[2] << 8) | + rx_hdr[3]; + printf("Rx packet length: %u bytes\n", rx_pkt_len); + if (rx_pkt_len < 16) { + printf("Error: packet length is too short\n"); + exit(1); + } + rx_command_id = (rx_hdr[4] << 24) | (rx_hdr[5] << 16) | + (rx_hdr[6] << 8) | rx_hdr[7]; +} + +static void +read_and_dump_body() +{ + u_char buf[16]; + unsigned offset, chunk; + int i, c; + + for (offset = 16; offset < rx_pkt_len; offset += chunk) { + chunk = rx_pkt_len - offset; + if (chunk > 16) + chunk = 16; + rx_bytes(buf, chunk); + printf("%08X: ", offset); + for (i = 0; i < 16; i++) { + if (i < chunk) + printf("%02X ", buf[i]); + else + fputs(" ", stdout); + if (i == 7 || i == 15) + putchar(' '); + } + for (i = 0; i < chunk; i++) { + c = buf[i]; + if (c < ' ' || c > '~') + c = '.'; + putchar(c); + } + putchar('\n'); + } +} + +static void +resp_hdr_only() +{ + u_char resp[16]; + int rc; + + /* command_length */ + resp[0] = 0; + resp[1] = 0; + resp[2] = 0; + resp[3] = 16; + /* command_id */ + resp[4] = rx_hdr[4] | 0x80; + resp[5] = rx_hdr[5]; + resp[6] = rx_hdr[6]; + resp[7] = rx_hdr[7]; + /* command_status */ + resp[8] = 0; + resp[9] = 0; + resp[10] = 0; + resp[11] = 0; + /* sequence_number */ + resp[12] = rx_hdr[12]; + resp[13] = rx_hdr[13]; + resp[14] = rx_hdr[14]; + resp[15] = rx_hdr[15]; + /* good to go */ + rc = write(tcpsock, resp, 16); + if (rc != 16) { + perror("write"); + exit(1); + } +} + +static void +resp_dummy_msgid() +{ + u_char resp[17]; + int rc; + + /* command_length */ + resp[0] = 0; + resp[1] = 0; + resp[2] = 0; + resp[3] = 17; + /* command_id */ + resp[4] = rx_hdr[4] | 0x80; + resp[5] = rx_hdr[5]; + resp[6] = rx_hdr[6]; + resp[7] = rx_hdr[7]; + /* command_status */ + resp[8] = 0; + resp[9] = 0; + resp[10] = 0; + resp[11] = 0; + /* sequence_number */ + resp[12] = rx_hdr[12]; + resp[13] = rx_hdr[13]; + resp[14] = rx_hdr[14]; + resp[15] = rx_hdr[15]; + /* empty message_id */ + resp[16] = 0; + /* good to go */ + rc = write(tcpsock, resp, 17); + if (rc != 17) { + perror("write"); + exit(1); + } +} + +static void +auto_resp_logic() +{ + switch (rx_command_id) { + case 0x005: + printf("Got deliver_sm, responding with deliver_sm_resp\n"); + resp_dummy_msgid(); + return; + case 0x103: + printf("Got data_sm, responding with data_sm_resp\n"); + resp_dummy_msgid(); + return; + case 0x015: + printf("Got enquire_link, responding with enquire_link_resp\n"); + resp_hdr_only(); + return; + } +} + +main(argc, argv) + char **argv; +{ + if (argc < 3 || argc > 4) { + fprintf(stderr, "usage: %s server-ip system-id [password]\n", + argv[0]); + exit(1); + } + server_sin.sin_family = AF_INET; + server_sin.sin_addr.s_addr = inet_addr(argv[1]); + if (server_sin.sin_addr.s_addr == INADDR_NONE) { + fprintf(stderr, "error: invalid IP address argument \"%s\"\n", + argv[1]); + exit(1); + } + server_sin.sin_port = htons(2775); + if (strlen(argv[2]) > 15) { + fprintf(stderr, "error: system-id string is too long\n"); + exit(1); + } + strcpy(system_id, argv[2]); + if (argv[3]) { + if (strlen(argv[3]) > 8) { + fprintf(stderr, "error: password string is too long\n"); + exit(1); + } + strcpy(password, argv[3]); + } + construct_bind_req(); + setlinebuf(stdout); + print_bind_req(); + tcpsock = socket(AF_INET, SOCK_STREAM, 0); + if (tcpsock < 0) { + perror("socket"); + exit(1); + } + init_stage(); + for (;;) { + rx_bytes(rx_hdr, 16); + print_hdr(); + preen_rx_hdr(); + read_and_dump_body(); + auto_resp_logic(); + } +}