FreeCalypso > hg > themwi-system-sw
changeset 71:d74b545a3c2a
sip-manual-out: new test program
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Tue, 20 Sep 2022 10:14:18 -0800 |
parents | 47976db01894 |
children | 9ca6f0708237 |
files | .hgignore Makefile sip-manual-out/Makefile sip-manual-out/dummy_rtp.c sip-manual-out/main.c sip-manual-out/readconf.c sip-manual-out/sip_log.c sip-manual-out/sip_udp.c sip-manual-out/uac.c sip-manual-out/uas.c |
diffstat | 10 files changed, 740 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgignore Mon Sep 19 21:30:33 2022 -0800 +++ b/.hgignore Tue Sep 20 10:14:18 2022 -0800 @@ -10,6 +10,8 @@ ^sip-in/themwi-sip-in$ +^sip-manual-out/sip-manual-out$ + ^utils/sip-out-test$ ^utils/sip-rx-test$ ^utils/sip-udp-dump$
--- a/Makefile Mon Sep 19 21:30:33 2022 -0800 +++ b/Makefile Tue Sep 20 10:14:18 2022 -0800 @@ -1,7 +1,7 @@ CC= gcc CFLAGS= -O2 -PROGDIR=mgw mncc mtctest sip-in utils +PROGDIR=mgw mncc mtctest sip-in sip-manual-out utils LIBDIR= libnumdb libsip libutil SUBDIR= ${PROGDIR} ${LIBDIR} @@ -11,6 +11,7 @@ mncc: libnumdb libutil mtctest: libnumdb libutil sip-in: libnumdb libsip libutil +sip-manual-out: libsip libutil utils: libnumdb libsip libutil ${SUBDIR}: FRC
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sip-manual-out/Makefile Tue Sep 20 10:14:18 2022 -0800 @@ -0,0 +1,17 @@ +CC= gcc +CFLAGS= -O2 +PROG= sip-manual-out +OBJS= dummy_rtp.o main.o readconf.o sip_log.o sip_udp.o uac.o uas.o +LIBS= ../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-manual-out/dummy_rtp.c Tue Sep 20 10:14:18 2022 -0800 @@ -0,0 +1,66 @@ +/* + * In this module we implement the code that connects to themwi-mgw + * and obtains a dummy PSTN-side RTP endpoint. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <netinet/in.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include "../include/tmgw_ctrl.h" +#include "../include/tmgw_const.h" + +struct sockaddr_in dummy_rtp_endp; + +static char tmgw_socket_pathname[] = "/var/gsm/tmgw_socket"; + +obtain_dummy_rtp() +{ + struct sockaddr_un sa; + unsigned sa_len; + int fd, rc; + struct tmgw_ctrl_req req; + struct tmgw_ctrl_resp resp; + + fd = socket(AF_UNIX, SOCK_SEQPACKET, 0); + if (fd < 0) { + perror("socket(AF_UNIX, SOCK_SEQPACKET, 0)"); + exit(1); + } + fill_sockaddr_un(tmgw_socket_pathname, &sa, &sa_len); + rc = connect(fd, (struct sockaddr *) &sa, sa_len); + if (rc < 0) { + perror(tmgw_socket_pathname); + exit(1); + } + bzero(&req, sizeof req); + req.opcode = TMGW_CTRL_OP_CRCX; + req.ep_id = TMGW_EP_TYPE_DUMMY_PSTN; + rc = send(fd, &req, sizeof req, 0); + if (rc < 0) { + perror("send to TMGW socket"); + exit(1); + } + rc = recv(fd, &resp, sizeof resp, 0); + if (rc < 0) { + perror("recv from TMGW socket"); + exit(1); + } + if (rc != sizeof resp) { + fprintf(stderr, + "error: response packet from TMGW has wrong length (%d bytes)\n", + rc); + exit(1); + } + if (resp.res != TMGW_RESP_OK) { + fprintf(stderr, "TMGW CRCX returned error %u\n", resp.res); + exit(1); + } + bcopy(&resp.pstn_addr, &dummy_rtp_endp, sizeof(struct sockaddr_in)); + return(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sip-manual-out/main.c Tue Sep 20 10:14:18 2022 -0800 @@ -0,0 +1,106 @@ +/* + * This is the main module for sip-manual-out test program. + */ + +#include <sys/types.h> +#include <sys/time.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 <unistd.h> +#include "../libsip/out_msg.h" +#include "../libsip/sdp.h" + +extern int sip_socket; +extern struct in_addr sip_bind_ip, sip_dest_ip; +extern unsigned sip_bind_port, sip_dest_port; +extern char sip_dest_domain[]; +extern struct sockaddr_in dummy_rtp_endp; + +struct sockaddr_in sip_dest_sin; +char from_uri[128], to_uri[128], call_id[128]; +struct timeval cur_event_time; + +send_invite_req() +{ + struct sip_msg_out msg; + struct sdp_gen sdp; + int rc; + + rc = start_request_out_msg(&msg, "INVITE", to_uri); + if (rc < 0) { +msg_size_err: fprintf(stderr, "composing INVITE req: msg size error\n"); + exit(1); + } + rc = add_req_boilerplate(&msg, "1 INVITE"); + if (rc < 0) + goto msg_size_err; + rc = add_contact_header(&msg); + if (rc < 0) + goto msg_size_err; + rc = out_msg_add_header(&msg, "Content-Type", "application/sdp"); + if (rc < 0) + goto msg_size_err; + bzero(&sdp, sizeof sdp); + sdp.conn_ip = dummy_rtp_endp.sin_addr; + sdp.conn_port = ntohs(dummy_rtp_endp.sin_port); + sdp.codec_mask = SDP_CODEC_MASK_BOTH; + sdp.session_id = sdp.conn_port << 16; + sdp.owner_ip = sip_bind_ip; + rc = out_msg_finish_sdp(&msg, &sdp); + if (rc < 0) + goto msg_size_err; + sip_tx_packet(&msg, &sip_dest_sin); +} + +main(argc, argv) + char **argv; +{ + fd_set fds; + int rc; + + if (argc < 4 || argc > 5) { + fprintf(stderr, + "usage: %s dest-conf from-num to-num [logfile]\n", + argv[0]); + exit(1); + } + read_config_file(argv[1]); + open_sip_udp_socket(); + obtain_dummy_rtp(); + sip_dest_sin.sin_family = AF_INET; + sip_dest_sin.sin_addr = sip_dest_ip; + sip_dest_sin.sin_port = htons(sip_dest_port); + sprintf(from_uri, "sip:%s@%s", argv[2], inet_ntoa(sip_bind_ip)); + sprintf(to_uri, "sip:%s@%s", argv[3], sip_dest_domain); + if (argv[4]) { + rc = open_sip_log_file(argv[4]); + if (rc < 0) + exit(1); /* error msg already printed */ + } + gettimeofday(&cur_event_time, 0); + sprintf(call_id, "%08u_%u@%s", + (unsigned)(cur_event_time.tv_sec % 100000000), + ntohs(dummy_rtp_endp.sin_port), inet_ntoa(sip_bind_ip)); + send_invite_req(); + /* main select loop */ + for (;;) { + FD_ZERO(&fds); + FD_SET(sip_socket, &fds); + rc = select(sip_socket+1, &fds, 0, 0, 0); + if (rc < 0) { + if (errno == EINTR) + continue; + perror("select"); + exit(1); + } + gettimeofday(&cur_event_time, 0); + if (FD_ISSET(sip_socket, &fds)) + sip_socket_select(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sip-manual-out/readconf.c Tue Sep 20 10:14:18 2022 -0800 @@ -0,0 +1,159 @@ +/* + * In this module we implement the reading of destination configuration + * for sip-manual-out. + */ + +#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, sip_dest_ip; +unsigned sip_bind_port, sip_dest_port = 5060; +char sip_dest_domain[64]; + +struct parse_state { + char *filename; + 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", + st->filename, 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", + st->filename, st->lineno, arg); + exit(1); + } +} + +static void +handle_str(st, kw, var, arg) + struct parse_state *st; + char *kw, *arg, *var; +{ + strcpy(var, arg); +} + +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", + st->filename, 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, "dest-ip")) { + handler = handle_ip; + var = &sip_dest_ip; + set_id = 4; + } else if (!strcmp(np, "dest-port")) { + handler = handle_num; + var = &sip_dest_port; + set_id = 0; + } else if (!strcmp(np, "dest-domain")) { + handler = handle_str; + var = sip_dest_domain; + set_id = 8; + } else { + fprintf(stderr, "%s line %d: non-understood keyword \"%s\"\n", + st->filename, st->lineno, np); + exit(1); + } + if (st->set_mask & set_id) { + fprintf(stderr, "%s line %d: duplicate %s setting\n", + st->filename, 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", + st->filename, 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(filename) + char *filename; +{ + FILE *inf; + struct parse_state pst; + char linebuf[256]; + + inf = fopen(filename, "r"); + if (!inf) { + perror(filename); + exit(1); + } + pst.set_mask = 0; + pst.filename = filename; + for (pst.lineno = 1; fgets(linebuf, sizeof linebuf, inf); pst.lineno++) + process_line(&pst, linebuf); + fclose(inf); + if (pst.set_mask != 15) { + fprintf(stderr, "error: %s did not set all required settings\n", + filename); + exit(1); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sip-manual-out/sip_log.c Tue Sep 20 10:14:18 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> + +extern 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-manual-out/sip_udp.c Tue Sep 20 10:14:18 2022 -0800 @@ -0,0 +1,83 @@ +/* + * 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 <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) { + perror("socket(AF_INET, SOCK_DGRAM, 0)"); + exit(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) { + perror("bind of SIP UDP socket"); + exit(1); + } + 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) { + perror("recvfrom"); + 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) { + printf("Incoming SIP UDP message parse error %d\n", rc); + return; + } + /* dispatch good-so-far SIP message */ + if (pkt.parse_msgtype == SIP_MSG_TYPE_REQ) + process_sip_request(&pkt, &sin); + else if (pkt.parse_msgtype == SIP_MSG_TYPE_RESP) + process_sip_response(&pkt, &sin); +} + +void +sip_tx_packet(msg, sin) + struct sip_msg_out *msg; + struct sockaddr_in *sin; +{ + socklen_t addrlen; + + addrlen = sizeof(struct sockaddr_in); + sendto(sip_socket, msg->buf, msg->msg_len, 0, (struct sockaddr *) sin, + addrlen); + log_sip_msg_tx(msg->buf, msg->msg_len, sin); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sip-manual-out/uac.c Tue Sep 20 10:14:18 2022 -0800 @@ -0,0 +1,124 @@ +/* + * Here we implement processing of SIP responses to the requests we sent out. + */ + +#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 "../libsip/parse.h" +#include "../libsip/out_msg.h" + +#define MAX_TO_TAG 63 + +extern char *get_single_header(); + +extern struct in_addr sip_bind_ip; +extern unsigned sip_bind_port; +extern char call_id[], from_uri[], to_uri[]; + +char to_tag[MAX_TO_TAG+1]; + +add_req_boilerplate(msg, cseq) + struct sip_msg_out *msg; + char *cseq; +{ + char strbuf[256]; + int rc; + + sprintf(strbuf, "SIP/2.0/UDP %s:%u", + inet_ntoa(sip_bind_ip), sip_bind_port); + rc = out_msg_add_header(msg, "Via", strbuf); + if (rc < 0) + return rc; + rc = out_msg_add_header(msg, "From", from_uri); + if (rc < 0) + return rc; + if (to_tag[0]) { + sprintf(strbuf, "<%s>;tag=%s", to_uri, to_tag); + rc = out_msg_add_header(msg, "To", strbuf); + } else + rc = out_msg_add_header(msg, "To", to_uri); + if (rc < 0) + return rc; + rc = out_msg_add_header(msg, "Call-ID", call_id); + if (rc < 0) + return rc; + rc = out_msg_add_header(msg, "CSeq", cseq); + if (rc < 0) + return rc; + return out_msg_add_header(msg, "Max-Forwards", "70"); +} + +add_contact_header(msg) + struct sip_msg_out *msg; +{ + char strbuf[80]; + + sprintf(strbuf, "<sip:%s:%u;transport=udp>", + inet_ntoa(sip_bind_ip), sip_bind_port); + return out_msg_add_header(msg, "Contact", strbuf); +} + +static void +send_ack(sin) + struct sockaddr_in *sin; +{ + struct sip_msg_out msg; + int rc; + + rc = start_request_out_msg(&msg, "ACK", to_uri); + if (rc < 0) { +msg_size_err: fprintf(stderr, "composing ACK message: size error\n"); + return; + } + rc = add_req_boilerplate(&msg, "1 ACK"); + if (rc < 0) + goto msg_size_err; + out_msg_finish(&msg); + sip_tx_packet(&msg, sin); +} + +static void +handle_invite_response(msg, sin) + struct sip_pkt_rx *msg; + struct sockaddr_in *sin; +{ + printf("Response to INVITE: %s\n", msg->status_str); + if (msg->status_code >= 200) { + printf("Sending ACK\n"); + send_ack(sin); + } +} + +void +process_sip_response(msg, sin) + struct sip_pkt_rx *msg; + struct sockaddr_in *sin; +{ + char *call_id_hdr, *cseq_hdr; + + call_id_hdr = get_single_header(msg, "Call-ID", "i", (int *) 0); + if (!call_id_hdr) { + printf("Got SIP response w/o Call-ID header\n"); + return; + } + if (strcmp(call_id_hdr, call_id)) { + printf("Got SIP response with wrong Call-ID\n"); + return; + } + cseq_hdr = get_single_header(msg, "CSeq", (char *) 0, (int *) 0); + if (!cseq_hdr) { + printf("Got SIP response w/o CSeq header\n"); + return; + } + if (!strcmp(cseq_hdr, "1 INVITE")) + handle_invite_response(msg, sin); + else + printf("Got SIP resp for our Call-ID with unknown CSeq %s\n", + cseq_hdr); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sip-manual-out/uas.c Tue Sep 20 10:14:18 2022 -0800 @@ -0,0 +1,113 @@ +/* + * UAS for sip-manual-out. + */ + +#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 "../libsip/parse.h" +#include "../libsip/uas_basic.h" +#include "../libsip/out_msg.h" + +extern char call_id[]; + +static void +bye_correct_call(req, ess, sin) + struct sip_pkt_rx *req; + struct uas_parse_hdrs *ess; + struct sockaddr_in *sin; +{ + struct sip_msg_out resp; + int rc; + + printf("Received BYE for our call, responding with 200\n"); + start_response_out_msg(&resp, "200 OK"); + rc = add_resp_basic_headers(&resp, ess, req->req_method); + if (rc < 0) { + fprintf(stderr, "sending 200 response: msg length exceeded\n"); + return; + } + out_msg_finish(&resp); + sip_tx_packet(&resp, sin); +} + +static void +bye_unknown_call(req, ess, sin) + struct sip_pkt_rx *req; + struct uas_parse_hdrs *ess; + struct sockaddr_in *sin; +{ + struct sip_msg_out resp; + int rc; + + printf("Received BYE for unknown call, responding with 481\n"); + start_response_out_msg(&resp, "481 Call-ID not found"); + rc = add_resp_basic_headers(&resp, ess, req->req_method); + if (rc < 0) { + fprintf(stderr, "sending 481 response: msg length exceeded\n"); + return; + } + out_msg_finish(&resp); + sip_tx_packet(&resp, sin); +} + +static void +handle_bye(req, ess, sin) + struct sip_pkt_rx *req; + struct uas_parse_hdrs *ess; + struct sockaddr_in *sin; +{ + if (!strcmp(ess->call_id, call_id)) + bye_correct_call(req, ess, sin); + else + bye_unknown_call(req, ess, sin); +} + +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; + + printf("SIP %.16s request: unsupported method\n", req->req_method); + start_response_out_msg(&resp, "501 Method not supported"); + rc = add_resp_basic_headers(&resp, ess, req->req_method); + if (rc < 0) { +too_long: fprintf(stderr, + "sending 501 error: response length exceeded\n"); + return; + } + rc = out_msg_add_header(&resp, "Allow", "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) { + printf("SIP %.16s request: bad or missing %s header\n", + msg->req_method, ess.error_field); + return; + } + /* dispatch by method */ + if (!strcmp(msg->req_method, "BYE")) + handle_bye(msg, &ess, sin); + else + unsupported_method(msg, &ess, sin); +}