changeset 222:9d6e8d99d2b1

smpp-trx-sa: new program
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 03 Aug 2023 21:13:41 -0800
parents e1d7db9d734c
children f11c3e40c87a
files .hgignore Makefile smpp-trx-sa/Makefile smpp-trx-sa/localsock.c smpp-trx-sa/log.c smpp-trx-sa/main.c smpp-trx-sa/pdu_out.c smpp-trx-sa/tcpconn.c
diffstat 8 files changed, 525 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Thu Aug 03 10:00:33 2023 -0800
+++ b/.hgignore	Thu Aug 03 21:13:41 2023 -0800
@@ -16,6 +16,8 @@
 
 ^sip-out/themwi-sip-out$
 
+^smpp-trx-sa/smpp-trx-sa$
+
 ^utils/rtp-alloc-test$
 ^utils/sip-out-test$
 ^utils/sip-rx-test$
--- a/Makefile	Thu Aug 03 10:00:33 2023 -0800
+++ b/Makefile	Thu Aug 03 21:13:41 2023 -0800
@@ -1,7 +1,7 @@
 CC=	gcc
 CFLAGS=	-O2
 
-PROGDIR=mgw mncc mtctest rtp-mgr sip-in sip-manual-out sip-out utils
+PROGDIR=mgw mncc mtctest rtp-mgr sip-in sip-manual-out sip-out smpp-trx-sa utils
 LIBDIR=	libnumdb liboutrt librtpalloc libsip libutil
 SUBDIR=	${PROGDIR} ${LIBDIR}
 
@@ -14,6 +14,7 @@
 sip-in:		libnumdb libsip libutil
 sip-manual-out:	librtpalloc libsip libutil
 sip-out:	liboutrt libsip libutil
+smpp-trx-sa:	libutil
 utils:		libnumdb librtpalloc libsip libutil
 
 ${SUBDIR}: FRC
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/smpp-trx-sa/Makefile	Thu Aug 03 21:13:41 2023 -0800
@@ -0,0 +1,17 @@
+CC=	gcc
+CFLAGS=	-O2
+PROG=	smpp-trx-sa
+OBJS=	localsock.o log.o main.o pdu_out.o tcpconn.o
+LIBS=	../libutil/libutil.a
+INSTBIN=/usr/local/bin
+
+all:	${PROG}
+
+${PROG}: ${OBJS} ${LIBS}
+	${CC} ${CFLAGS} -o $@ ${OBJS} ${LIBS}
+
+install:
+	install -c -o bin -g bin -m 755 ${PROG} ${INSTBIN}
+
+clean:
+	rm -f *.o ${PROG} errs
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/smpp-trx-sa/localsock.c	Thu Aug 03 21:13:41 2023 -0800
@@ -0,0 +1,60 @@
+/*
+ * This module implements the local socket part of smpp-trx-sa.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int localsock;
+
+void
+create_local_socket(pathname)
+	char *pathname;
+{
+	struct sockaddr_un sa;
+	unsigned sa_len;
+	int rc;
+
+	localsock = socket(AF_UNIX, SOCK_DGRAM, 0);
+	if (localsock < 0) {
+		perror("socket(AF_UNIX, SOCK_DGRAM, 0)");
+		exit(1);
+	}
+	unlink(pathname);
+	fill_sockaddr_un(pathname, &sa, &sa_len);
+	rc = bind(localsock, (struct sockaddr *) &sa, sa_len);
+	if (rc < 0) {
+		fprintf(stderr, "bind error on %s\n", pathname);
+		perror("bind");
+		exit(1);
+	}
+}
+
+void
+localsock_select_handler()
+{
+	u_char buf[0x10000];
+	int cc;
+	unsigned pdu_len;
+
+	cc = recv(localsock, buf, sizeof buf, 0);
+	if (cc <= 0) {
+		perror("read from local socket");
+		log_fatal_error("error reading from local socket");
+		exit(1);
+	}
+	if (cc < 16) {
+inv_pdu:	log_fatal_error("Received invalid PDU on local socket");
+		return;
+	}
+	if (buf[0] || buf[1])
+		goto inv_pdu;
+	pdu_len = (buf[2] << 8) | buf[3];
+	if (pdu_len != cc)
+		goto inv_pdu;
+	send_pdu_from_localsock(buf, pdu_len);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/smpp-trx-sa/log.c	Thu Aug 03 21:13:41 2023 -0800
@@ -0,0 +1,88 @@
+/*
+ * This module implements smpp-trx-sa log file output.
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <time.h>
+
+extern FILE *logF;
+extern time_t curtime;
+extern int init_done;
+
+static char fmt_time[32];
+
+static void
+format_time()
+{
+	struct tm *tm;
+
+	tm = gmtime(&curtime);
+	sprintf(fmt_time, "%d-%02d-%02dT%02d:%02d:%02dZ",
+		tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
+		tm->tm_hour, tm->tm_min, tm->tm_sec);
+}
+
+void
+log_fatal_error(cause)
+	char *cause;
+{
+	if (!init_done)
+		return;
+	format_time();
+	fprintf(logF, "\n%s %s\n", fmt_time, cause);
+}
+
+static void
+pdu_hexdump(pdu, pdulen)
+	u_char *pdu;
+	unsigned pdulen;
+{
+	unsigned off, chunk;
+	int i, c;
+
+	for (off = 0; off < pdulen; off += chunk) {
+		fprintf(logF, "%04X:  ", off);
+		chunk = pdulen - off;
+		if (chunk > 16)
+			chunk = 16;
+		for (i = 0; i < 16; i++) {
+			if (i < chunk)
+				fprintf(logF, "%02X ", pdu[off + i]);
+			else
+				fputs("   ", logF);
+			if (i == 7 || i == 15)
+				putc(' ', logF);
+		}
+		for (i = 0; i < chunk; i++) {
+			c = pdu[off + i];
+			if (c < ' ' || c > '~')
+				c = '.';
+			putc(c, logF);
+		}
+		putc('\n', logF);
+	}
+}
+
+void
+log_rx_pdu(pdu, pdulen)
+	u_char *pdu;
+	unsigned pdulen;
+{
+	format_time();
+	fprintf(logF, "\n%s Received PDU:\n", fmt_time);
+	pdu_hexdump(pdu, pdulen);
+}
+
+void
+log_sent_pdu(pdu, pdulen)
+	u_char *pdu;
+	unsigned pdulen;
+{
+	format_time();
+	fprintf(logF, "\n%s Sent PDU:\n", fmt_time);
+	pdu_hexdump(pdu, pdulen);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/smpp-trx-sa/main.c	Thu Aug 03 21:13:41 2023 -0800
@@ -0,0 +1,88 @@
+/*
+ * This C file is the main module for smpp-trx-sa - a standalone bind_trx
+ * client (ESME role) that writes all incoming messages into a log file
+ * and also allows outgoing messages to be sent via a UNIX domain local
+ * socket (datagram).
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <time.h>
+#include <unistd.h>
+
+extern int tcpsock, localsock;
+
+FILE *logF;
+time_t curtime;
+int init_done;
+
+main(argc, argv)
+	char **argv;
+{
+	struct sockaddr_in server_sin;
+	fd_set fds;
+	int max_fd, rc;
+
+	if (argc != 6) {
+		fprintf(stderr,
+	"usage: %s server-ip system-id password log-file socket-pathname\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);
+	}
+	if (strlen(argv[3]) > 8) {
+		fprintf(stderr, "error: password string is too long\n");
+		exit(1);
+	}
+	logF = fopen(argv[4], "a");
+	if (!logF) {
+		perror(argv[4]);
+		exit(1);
+	}
+	create_local_socket(argv[5]);
+	max_fd = localsock;
+	open_tcp_conn(&server_sin);
+	if (tcpsock > max_fd)
+		max_fd = tcpsock;
+	time(&curtime);
+	send_bind_req(argv[2], argv[3]);
+	init_done = 1;
+	/* main select loop */
+	for (;;) {
+		FD_ZERO(&fds);
+		FD_SET(tcpsock, &fds);
+		FD_SET(localsock, &fds);
+		rc = select(max_fd+1, &fds, 0, 0, 0);
+		if (rc < 0) {
+			if (errno == EINTR)
+				continue;
+			perror("select");
+			log_fatal_error("select syscall error");
+			exit(1);
+		}
+		time(&curtime);
+		if (FD_ISSET(tcpsock, &fds))
+			tcpsock_select_handler();
+		if (FD_ISSET(localsock, &fds))
+			localsock_select_handler();
+		fflush(logF);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/smpp-trx-sa/pdu_out.c	Thu Aug 03 21:13:41 2023 -0800
@@ -0,0 +1,162 @@
+/*
+ * This module implements all functions related to sending outgoing PDUs
+ * to the SMPP server.
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+
+extern int tcpsock;
+
+static unsigned req_out_seq = 1;
+
+static void
+pdu_to_tcp(pdu, pdulen)
+	u_char *pdu;
+	unsigned pdulen;
+{
+	int cc;
+
+	cc = write(tcpsock, pdu, pdulen);
+	if (cc != pdulen) {
+		perror("write to TCP socket");
+		log_fatal_error("error writing to TCP socket");
+		exit(1);
+	}
+}
+
+void
+send_bind_req(system_id, password)
+	char *system_id, *password;
+{
+	u_char bind_req[64], *dp;
+	unsigned bind_req_len, 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;
+	pdu_to_tcp(bind_req, bind_req_len);
+	log_sent_pdu(bind_req, bind_req_len);
+}
+
+void
+send_enq_link_resp(rx_hdr)
+	u_char *rx_hdr;
+{
+	u_char resp[16];
+
+	/* 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 */
+	pdu_to_tcp(resp, 16);
+}
+
+void
+send_message_resp(rx_hdr)
+	u_char *rx_hdr;
+{
+	u_char resp[17];
+
+	/* 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 */
+	pdu_to_tcp(resp, 17);
+	log_sent_pdu(resp, 17);
+}
+
+void
+send_pdu_from_localsock(pdu, pdulen)
+	u_char *pdu;
+	unsigned pdulen;
+{
+	/* assign incrementing sequence number */
+	req_out_seq++;
+	if (req_out_seq > 0x7FFFFFFF)
+		req_out_seq = 1;
+	pdu[12] = req_out_seq >> 24;
+	pdu[13] = req_out_seq >> 16;
+	pdu[14] = req_out_seq >> 8;
+	pdu[15] = req_out_seq;
+	/* good to go */
+	pdu_to_tcp(pdu, pdulen);
+	log_sent_pdu(pdu, pdulen);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/smpp-trx-sa/tcpconn.c	Thu Aug 03 21:13:41 2023 -0800
@@ -0,0 +1,106 @@
+/*
+ * This module implements the part of smpp-trx-sa that handles
+ * the TCP connection to the SMPP server.
+ */
+
+#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>
+
+extern FILE *logF;
+
+int tcpsock;
+
+static u_char rx_buf[0x10000];
+static unsigned rx_accum, rx_pdu_len;
+static int rx_body;
+
+void
+open_tcp_conn(server_sin)
+	struct sockaddr_in *server_sin;
+{
+	int rc;
+
+	tcpsock = socket(AF_INET, SOCK_STREAM, 0);
+	if (tcpsock < 0) {
+		perror("socket(AF_INET, SOCK_STREAM, 0)");
+		exit(1);
+	}
+	rc = connect(tcpsock, (struct sockaddr *) server_sin,
+		     sizeof(struct sockaddr_in));
+	if (rc < 0) {
+		perror("TCP connect");
+		exit(1);
+	}
+}
+
+static void
+got_full_pdu()
+{
+	unsigned command_id;
+
+	/* prepare for next PDU Rx */
+	rx_body = 0;
+	rx_accum = 0;
+	/* back to the one we just got */
+	command_id = (rx_buf[4] << 24) | (rx_buf[5] << 16) | (rx_buf[6] << 8) |
+		     rx_buf[7];
+	if (command_id == 0x15 && rx_pdu_len == 16) {
+		send_enq_link_resp(rx_buf);
+		return;
+	}
+	log_rx_pdu(rx_buf, rx_pdu_len);
+	if (command_id == 0x05 || command_id == 0x103)
+		send_message_resp(rx_buf);
+}
+
+void
+tcpsock_select_handler()
+{
+	unsigned goal;
+	int cc;
+
+	if (rx_body)
+		goal = rx_pdu_len;
+	else
+		goal = 16;
+	cc = read(tcpsock, rx_buf + rx_accum, goal - rx_accum);
+	if (cc < 0) {
+		perror("read from TCP socket");
+		log_fatal_error("error reading from TCP socket");
+		exit(1);
+	}
+	if (cc == 0) {
+		log_fatal_error("Server closed TCP connection");
+		exit(1);
+	}
+	rx_accum += cc;
+	if (rx_accum < goal)
+		return;
+	if (rx_body) {
+		got_full_pdu();
+		return;
+	}
+	if (rx_buf[0] || rx_buf[1]) {
+		log_rx_pdu(rx_buf, 16);
+		fprintf(logF, "Fatal error: length exceeds limit\n");
+		exit(1);
+	}
+	rx_pdu_len = (rx_buf[2] << 8) | rx_buf[3];
+	if (rx_pdu_len < 16) {
+		log_rx_pdu(rx_buf, 16);
+		fprintf(logF, "Fatal error: length below 16\n");
+		exit(1);
+	}
+	if (rx_pdu_len == 16) {
+		got_full_pdu();
+		return;
+	}
+	rx_body = 1;
+}