FreeCalypso > hg > themwi-system-sw
changeset 47:62f39c7cee15
themwi-sip-in skeleton started
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Tue, 06 Sep 2022 20:33:56 -0800 |
parents | 5427b26525cd |
children | 8117d8ee44a5 |
files | .hgignore Makefile sip-in/Makefile sip-in/main.c sip-in/mgw_sock.c sip-in/readconf.c sip-in/sip_log.c sip-in/sip_uas.c sip-in/sip_udp.c |
diffstat | 9 files changed, 542 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgignore Tue Sep 06 20:29:44 2022 -0800 +++ b/.hgignore Tue Sep 06 20:33:56 2022 -0800 @@ -8,6 +8,8 @@ ^mtctest/themwi-test-mtc$ +^sip-in/themwi-sip-in$ + ^utils/sip-rx-test$ ^utils/sip-udp-dump$ ^utils/themwi-check-own$
--- a/Makefile Tue Sep 06 20:29:44 2022 -0800 +++ b/Makefile Tue Sep 06 20:33:56 2022 -0800 @@ -1,7 +1,7 @@ CC= gcc CFLAGS= -O2 -PROGDIR=mgw mncc mtctest utils +PROGDIR=mgw mncc mtctest sip-in utils LIBDIR= libnumdb libsip libutil SUBDIR= ${PROGDIR} ${LIBDIR} @@ -10,6 +10,7 @@ mgw: libutil mncc: libnumdb libutil mtctest: libnumdb libutil +sip-in: libnumdb libsip libutil utils: libnumdb libsip libutil ${SUBDIR}: FRC
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sip-in/Makefile Tue Sep 06 20:33:56 2022 -0800 @@ -0,0 +1,17 @@ +CC= gcc +CFLAGS= -O2 +PROG= themwi-sip-in +OBJS= main.o mgw_sock.o readconf.o sip_log.o sip_uas.o sip_udp.o +LIBS= ../libnumdb/libnumdb.a ../libsip/libsip.a ../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/sip-in/main.c Tue Sep 06 20:33:56 2022 -0800 @@ -0,0 +1,72 @@ +/* + * Main module for themwi-sip-in. + */ + +#include <sys/types.h> +#include <sys/time.h> +#include <sys/errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <signal.h> +#include <syslog.h> +#include <unistd.h> + +extern int mgw_socket, sip_socket; + +static int max_fd; + +struct timeval cur_event_time; + +update_max_fd(newfd) +{ + if (newfd > max_fd) + max_fd = newfd; +} + +main(argc, argv) + char **argv; +{ + fd_set fds; + int rc; + + openlog("themwi-sip-in", 0, LOG_LOCAL5); + read_config_file(); + if (read_number_db() < 0) { + fprintf(stderr, "error reading number database\n"); + exit(1); + } + if (open_tmgw_socket() < 0) { + fprintf(stderr, "error connecting to themwi-mgw socket\n"); + exit(1); + } + if (open_sip_udp_socket() < 0) { + fprintf(stderr, "error opening SIP UDP socket\n"); + exit(1); + } + if (argv[1]) { + rc = open_sip_log_file(argv[1]); + if (rc < 0) + exit(1); /* error msg already printed */ + } + signal(SIGPIPE, SIG_IGN); + /* main select loop */ + for (;;) { + FD_ZERO(&fds); + FD_SET(mgw_socket, &fds); + FD_SET(sip_socket, &fds); + rc = select(max_fd+1, &fds, 0, 0, 0); + if (rc < 0) { + if (errno == EINTR) + continue; + syslog(LOG_CRIT, "select: %m"); + exit(1); + } + gettimeofday(&cur_event_time, 0); + if (FD_ISSET(mgw_socket, &fds)) + mgw_socket_select(); + if (FD_ISSET(sip_socket, &fds)) + sip_socket_select(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sip-in/mgw_sock.c Tue Sep 06 20:33:56 2022 -0800 @@ -0,0 +1,57 @@ +/* + * In this module we implement our local socket interface to themwi-mgw. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <syslog.h> +#include "../include/tmgw_ctrl.h" + +static char tmgw_socket_pathname[] = "/var/gsm/tmgw_socket"; + +int mgw_socket; + +open_tmgw_socket() +{ + struct sockaddr_un sa; + unsigned sa_len; + int rc; + + mgw_socket = socket(AF_UNIX, SOCK_SEQPACKET, 0); + if (mgw_socket < 0) { + syslog(LOG_CRIT, "socket(AF_UNIX, SOCK_SEQPACKET, 0): %m"); + return(-1); + } + fill_sockaddr_un(tmgw_socket_pathname, &sa, &sa_len); + rc = connect(mgw_socket, (struct sockaddr *) &sa, sa_len); + if (rc < 0) { + syslog(LOG_ERR, "connect to %s: %m", tmgw_socket_pathname); + return(-1); + } + update_max_fd(mgw_socket); + return(0); +} + +void +mgw_socket_select() +{ + struct tmgw_ctrl_resp msg; + int rc; + + rc = recv(mgw_socket, &msg, sizeof msg, 0); + if (rc < 0) { + syslog(LOG_CRIT, "error reading from TMGW socket: %m"); + exit(1); + } + if (rc != sizeof(struct tmgw_ctrl_resp)) { + syslog(LOG_CRIT, + "response packet from TMGW has wrong length: %d bytes", + rc); + exit(1); + } + /* processing to be implemented */ +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sip-in/readconf.c Tue Sep 06 20:33:56 2022 -0800 @@ -0,0 +1,164 @@ +/* + * In this module we implement the reading of /var/gsm/themwi-sip-in.cfg: + * the main settings are bind-ip and bind-port, but we also have some + * optional config settings. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> + +struct in_addr sip_bind_ip; +unsigned sip_bind_port; +int cfg_use_100rel; + +static char config_file_pathname[] = "/var/gsm/themwi-sip-in.cfg"; + +struct parse_state { + int lineno; + int set_mask; +}; + +static void +handle_ip(st, kw, var, arg) + struct parse_state *st; + char *kw, *arg; + struct in_addr *var; +{ + var->s_addr = inet_addr(arg); + if (var->s_addr == INADDR_NONE) { + fprintf(stderr, + "%s line %d: invalid IP address argument \"%s\"\n", + config_file_pathname, st->lineno, arg); + exit(1); + } +} + +static void +handle_num(st, kw, var, arg) + struct parse_state *st; + char *kw, *arg; + unsigned *var; +{ + char *endp; + + *var = strtoul(arg, &endp, 10); + if (*endp) { + fprintf(stderr, "%s line %d: invalid numeric argument \"%s\"\n", + config_file_pathname, st->lineno, arg); + exit(1); + } +} + +static void +handle_bool(st, kw, var, arg) + struct parse_state *st; + char *kw, *arg; + int *var; +{ + if (!strcmp(arg, "true") || !strcmp(arg, "on") || !strcmp(arg, "yes") + || !strcmp(arg, "1")) { + *var = 1; + return; + } + if (!strcmp(arg, "false") || !strcmp(arg, "off") || !strcmp(arg, "no") + || !strcmp(arg, "0")) { + *var = 0; + return; + } + fprintf(stderr, "%s line %d: invalid boolean argument \"%s\"\n", + config_file_pathname, st->lineno, arg); + exit(1); +} + +static void +process_line(st, line) + struct parse_state *st; + char *line; +{ + char *cp, *np, *arg; + void (*handler)(), *var; + int set_id; + + if (!index(line, '\n')) { + fprintf(stderr, "%s line %d: too long or missing newline\n", + config_file_pathname, st->lineno); + exit(1); + } + for (cp = line; isspace(*cp); cp++) + ; + if (*cp == '\0' || *cp == '#') + return; + for (np = cp; *cp && !isspace(*cp); cp++) + ; + if (*cp) + *cp++ = '\0'; + if (!strcmp(np, "bind-ip")) { + handler = handle_ip; + var = &sip_bind_ip; + set_id = 1; + } else if (!strcmp(np, "bind-port")) { + handler = handle_num; + var = &sip_bind_port; + set_id = 2; + } else if (!strcmp(np, "use-100rel")) { + handler = handle_bool; + var = &cfg_use_100rel; + set_id = 0; + } else { + fprintf(stderr, "%s line %d: non-understood keyword \"%s\"\n", + config_file_pathname, st->lineno, np); + exit(1); + } + if (st->set_mask & set_id) { + fprintf(stderr, "%s line %d: duplicate %s setting\n", + config_file_pathname, st->lineno, np); + exit(1); + } + while (isspace(*cp)) + cp++; + if (*cp == '\0' || *cp == '#') { +inv_syntax: fprintf(stderr, + "%s line %d: %s setting requires one argument\n", + config_file_pathname, st->lineno, np); + exit(1); + } + for (arg = cp; *cp && !isspace(*cp); cp++) + ; + if (*cp) + *cp++ = '\0'; + while (isspace(*cp)) + cp++; + if (*cp != '\0' && *cp != '#') + goto inv_syntax; + handler(st, np, var, arg); + st->set_mask |= set_id; +} + +read_config_file() +{ + FILE *inf; + struct parse_state pst; + char linebuf[256]; + + inf = fopen(config_file_pathname, "r"); + if (!inf) { + perror(config_file_pathname); + exit(1); + } + pst.set_mask = 0; + for (pst.lineno = 1; fgets(linebuf, sizeof linebuf, inf); pst.lineno++) + process_line(&pst, linebuf); + fclose(inf); + if (pst.set_mask != 3) { + fprintf(stderr, "error: %s did not set all required settings\n", + config_file_pathname); + exit(1); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sip-in/sip_log.c Tue Sep 06 20:33:56 2022 -0800 @@ -0,0 +1,68 @@ +/* + * In this module we implement debug logging of SIP Rx & Tx messages. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> + +struct timeval cur_event_time; + +static FILE *logfile; + +open_sip_log_file(filename) + char *filename; +{ + logfile = fopen(filename, "a"); + if (!logfile) { + perror(filename); + return(-1); + } + return(0); +} + +static void +log_common(msg, msglen, sin, dir) + char *msg, *dir; + unsigned msglen; + struct sockaddr_in *sin; +{ + unsigned sec, ms; + + sec = cur_event_time.tv_sec % 86400; + ms = cur_event_time.tv_usec / 1000; + fprintf(logfile, "Msg %s %s:%u %u bytes %02u:%02u:%02u.%03u\n", dir, + inet_ntoa(sin->sin_addr), ntohs(sin->sin_port), msglen, + sec / 3600, (sec / 60) % 60, sec % 60, ms); + fwrite(msg, 1, msglen, logfile); + putc('\n', logfile); + fflush(logfile); +} + +void +log_sip_msg_rx(msg, msglen, sin) + char *msg; + unsigned msglen; + struct sockaddr_in *sin; +{ + if (!logfile) + return; + log_common(msg, msglen, sin, "from"); +} + +void +log_sip_msg_tx(msg, msglen, sin) + char *msg; + unsigned msglen; + struct sockaddr_in *sin; +{ + if (!logfile) + return; + log_common(msg, msglen, sin, "to"); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sip-in/sip_uas.c Tue Sep 06 20:33:56 2022 -0800 @@ -0,0 +1,75 @@ +/* + * Basic UAS functions for themwi-sip-in. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <syslog.h> +#include <unistd.h> +#include "../libsip/parse.h" +#include "../libsip/uas_basic.h" +#include "../libsip/out_msg.h" + +static void +method_tbi(req, ess, sin) + struct sip_pkt_rx *req; + struct uas_parse_hdrs *ess; + struct sockaddr_in *sin; +{ + syslog(LOG_ERR, "SIP method %s remains to be implemented", + req->req_method); +} + +static void +unsupported_method(req, ess, sin) + struct sip_pkt_rx *req; + struct uas_parse_hdrs *ess; + struct sockaddr_in *sin; +{ + struct sip_msg_out resp; + int rc; + + start_response_out_msg(&resp, "405 Method not supported"); + rc = add_resp_basic_headers(&resp, ess, req->req_method); + if (rc < 0) { +too_long: syslog(LOG_ERR, "sending 405 error: response length exceeded"); + return; + } + rc = out_msg_add_header(&resp, "Allow", "INVITE,ACK,CANCEL,BYE"); + if (rc < 0) + goto too_long; + out_msg_finish(&resp); + sip_tx_packet(&resp, sin); +} + +void +process_sip_request(msg, sin) + struct sip_pkt_rx *msg; + struct sockaddr_in *sin; +{ + struct uas_parse_hdrs ess; + int rc; + + rc = uas_get_basic_headers(msg, &ess); + if (rc < 0) { + syslog(LOG_ERR, "SIP %.16s request: bad or missing %s header", + msg->req_method, ess.error_field); + return; + } + /* dispatch by method */ + if (!strcmp(msg->req_method, "INVITE")) + method_tbi(msg, &ess, sin); + else if (!strcmp(msg->req_method, "ACK")) + method_tbi(msg, &ess, sin); + else if (!strcmp(msg->req_method, "CANCEL")) + method_tbi(msg, &ess, sin); + else if (!strcmp(msg->req_method, "BYE")) + method_tbi(msg, &ess, sin); + else + unsupported_method(msg, &ess, sin); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sip-in/sip_udp.c Tue Sep 06 20:33:56 2022 -0800 @@ -0,0 +1,85 @@ +/* + * In this module we implement our UDP socket for SIP, + * and the associated lowest-level protocol handling. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <syslog.h> +#include <unistd.h> +#include "../libsip/parse.h" +#include "../libsip/out_msg.h" + +extern struct in_addr sip_bind_ip; +extern unsigned sip_bind_port; + +int sip_socket; + +open_sip_udp_socket() +{ + struct sockaddr_in sin; + int rc; + + sip_socket = socket(AF_INET, SOCK_DGRAM, 0); + if (sip_socket < 0) { + syslog(LOG_CRIT, "socket(AF_INET, SOCK_DGRAM, 0): %m"); + return(-1); + } + sin.sin_family = AF_INET; + sin.sin_addr = sip_bind_ip; + sin.sin_port = htons(sip_bind_port); + rc = bind(sip_socket, (struct sockaddr *) &sin, sizeof sin); + if (rc < 0) { + syslog(LOG_CRIT, "bind of SIP UDP socket: %m"); + return(-1); + } + update_max_fd(sip_socket); + return(0); +} + +void +sip_socket_select() +{ + struct sip_pkt_rx pkt; + struct sockaddr_in sin; + socklen_t addrlen; + int rc; + + addrlen = sizeof sin; + rc = recvfrom(sip_socket, pkt.pkt_buffer, MAX_SIP_RX_PACKET, 0, + (struct sockaddr *) &sin, &addrlen); + if (rc <= 0) + return; + pkt.pkt_length = rc; + log_sip_msg_rx(pkt.pkt_buffer, pkt.pkt_length, &sin); + rc = parse_incoming_sip_msg(&pkt); + if (rc < 0) { + /* parse errors */ + if (rc == -2 && pkt.parse_msgtype == SIP_MSG_TYPE_REQ) + syslog(LOG_ERR, + "SIP %.16s msg exceeds MAX_HEADER_FIELDS", + pkt.req_method); + else if (rc == -2 && pkt.parse_msgtype == SIP_MSG_TYPE_RESP) + syslog(LOG_ERR, + "SIP response msg exceeds MAX_HEADER_FIELDS"); + /* in any case, silently discard */ + return; + } + /* dispatch good-so-far SIP message */ + if (pkt.parse_msgtype == SIP_MSG_TYPE_REQ) + process_sip_request(&pkt, &sin); +} + +void +sip_tx_packet(msg, sin) + struct sip_msg_out *msg; + struct sockaddr_in *sin; +{ + log_sip_msg_tx(msg->buf, msg->msg_len, sin); + /* actual UDP send to BulkVS omitted at this development stage */ +}