changeset 221:e1d7db9d734c

smpp-test2 program written
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 03 Aug 2023 10:00:33 -0800
parents c798a1762c7c
children 9d6e8d99d2b1
files .hgignore utils/Makefile utils/smpp-test2.c
diffstat 3 files changed, 338 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- 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$
--- 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
 
--- /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 <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+
+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();
+	}
+}