FreeCalypso > hg > themwi-system-sw
view utils/sip-out-test.c @ 124:7e04d28fae8b
sip-in: default use-100rel to no
BulkVS servers act badly when we send a reliable 180 Ringing response
to an incoming call, even though they advertise 100rel support in
the Supported header in the INVITE packet, and we probably won't be
implementing 100rel for outbound because doing per-the-spec PRACK
as a UAC is just too burdensome. Therefore, we need to consider
100rel extension as not-really-supported in themwi-system-sw.
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sat, 01 Oct 2022 15:54:50 -0800 |
parents | ffb563a17f23 |
children |
line wrap: on
line source
/* * This program is a contraption for testing manually constructed * outgoing SIP calls to BulkVS. */ #include <sys/types.h> #include <sys/socket.h> #include <sys/time.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> #define MAX_SIP_TX_PACKET 1472 static struct in_addr local_ip, remote_ip; static unsigned local_sip_port, local_rtp_port, remote_port; static char *invite_filename, *log_filename; static char invite_packet[MAX_SIP_TX_PACKET]; static unsigned invite_packet_len; static FILE *logF; static struct timeval curtime; static void read_invite_file() { FILE *inf; char linebuf[128], *cp, *dp; int lineno; unsigned size_accum, linelen; inf = fopen(invite_filename, "r"); if (!inf) { perror(invite_filename); exit(1); } size_accum = 0; dp = invite_packet; for (lineno = 1; fgets(linebuf, sizeof(linebuf), inf); lineno++) { cp = index(linebuf, '\n'); if (!cp) { fprintf(stderr, "%s line %d: too long or missing newline\n", invite_filename, lineno); exit(1); } *cp = '\0'; linelen = cp - linebuf; if (size_accum + linelen + 2 > MAX_SIP_TX_PACKET) { fprintf(stderr, "%s line %d: packet overflow\n", invite_filename, lineno); exit(1); } bcopy(linebuf, dp, linelen); dp += linelen; *dp++ = '\r'; *dp++ = '\n'; size_accum += linelen + 2; } fclose(inf); if (!size_accum) { fprintf(stderr, "error: %s is empty\n", invite_filename); exit(1); } invite_packet_len = size_accum; } static void log_common(msg, msglen, sin, dir, outf) char *msg, *dir; unsigned msglen; struct sockaddr_in *sin; FILE *outf; { unsigned sec, ms; sec = curtime.tv_sec % 86400; ms = curtime.tv_usec / 1000; fprintf(outf, "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, outf); putc('\n', outf); fflush(outf); } static void log_sip_msg_rx(msg, msglen, sin) char *msg; unsigned msglen; struct sockaddr_in *sin; { log_common(msg, msglen, sin, "from", stdout); if (logF) log_common(msg, msglen, sin, "from", logF); } static void log_sip_msg_tx(msg, msglen, sin) char *msg; unsigned msglen; struct sockaddr_in *sin; { log_common(msg, msglen, sin, "to", stdout); if (logF) log_common(msg, msglen, sin, "to", logF); } main(argc, argv) char **argv; { struct sockaddr_in sin_local, sin_rtp, sin_rtcp, sin_remote, sin_rx; int sock_sip, sock_rtp, sock_rtcp, max_fd; socklen_t addrlen; fd_set fds; char recv_buf[4096]; int rc; /* grok command line arguments */ if (argc < 7 || argc > 8) { fprintf(stderr, "usage: %s local-ip local-sip local-rtp remote-ip remote-sip inv-file [logfile]\n", argv[0]); exit(1); } local_ip.s_addr = inet_addr(argv[1]); if (local_ip.s_addr == INADDR_NONE) { fprintf(stderr, "error: invalid IP address \"%s\"\n", argv[1]); exit(1); } local_sip_port = atoi(argv[2]); local_rtp_port = atoi(argv[3]); remote_ip.s_addr = inet_addr(argv[4]); if (remote_ip.s_addr == INADDR_NONE) { fprintf(stderr, "error: invalid IP address \"%s\"\n", argv[4]); exit(1); } remote_port = atoi(argv[5]); invite_filename = argv[6]; log_filename = argv[7]; /* fill sin structures */ sin_local.sin_family = AF_INET; sin_local.sin_addr = local_ip; sin_local.sin_port = htons(local_sip_port); sin_rtp.sin_family = AF_INET; sin_rtp.sin_addr = local_ip; sin_rtp.sin_port = htons(local_rtp_port); sin_rtcp.sin_family = AF_INET; sin_rtcp.sin_addr = local_ip; sin_rtcp.sin_port = htons(local_rtp_port+1); sin_remote.sin_family = AF_INET; sin_remote.sin_addr = remote_ip; sin_remote.sin_port = htons(remote_port); /* create and bind sockets */ sock_sip = socket(AF_INET, SOCK_DGRAM, 0); if (sock_sip < 0) { perror("socket"); exit(1); } rc = bind(sock_sip, (struct sockaddr *) &sin_local, sizeof(struct sockaddr_in)); if (rc < 0) { perror("bind"); exit(1); } sock_rtp = socket(AF_INET, SOCK_DGRAM, 0); if (sock_rtp < 0) { perror("socket"); exit(1); } rc = bind(sock_rtp, (struct sockaddr *) &sin_rtp, sizeof(struct sockaddr_in)); if (rc < 0) { perror("bind"); exit(1); } sock_rtcp = socket(AF_INET, SOCK_DGRAM, 0); if (sock_rtcp < 0) { perror("socket"); exit(1); } rc = bind(sock_rtcp, (struct sockaddr *) &sin_rtcp, sizeof(struct sockaddr_in)); if (rc < 0) { perror("bind"); exit(1); } /* read the INVITE packet */ read_invite_file(); /* open the log file, if we have one */ if (log_filename) { logF = fopen(log_filename, "a"); if (!logF) { perror(log_filename); exit(1); } } /* now get down to business */ max_fd = sock_sip; if (sock_rtp > max_fd) max_fd = sock_rtp; if (sock_rtcp > max_fd) max_fd = sock_rtcp; addrlen = sizeof(struct sockaddr_in); rc = sendto(sock_sip, invite_packet, invite_packet_len, 0, (struct sockaddr *) &sin_remote, addrlen); if (rc < 0) { perror("sendto"); exit(1); } gettimeofday(&curtime, 0); log_sip_msg_tx(invite_packet, invite_packet_len, &sin_remote); /* main select loop */ for (;;) { FD_ZERO(&fds); FD_SET(sock_sip, &fds); FD_SET(sock_rtp, &fds); FD_SET(sock_rtcp, &fds); rc = select(max_fd+1, &fds, 0, 0, 0); if (rc < 0) { if (errno == EINTR) continue; perror("select"); exit(1); } gettimeofday(&curtime, 0); if (FD_ISSET(sock_sip, &fds)) { addrlen = sizeof(struct sockaddr_in); rc = recvfrom(sock_sip, recv_buf, sizeof recv_buf, 0, (struct sockaddr *) &sin_rx, &addrlen); if (rc < 0) { perror("recvfrom"); exit(1); } log_sip_msg_rx(recv_buf, rc, &sin_rx); } if (FD_ISSET(sock_rtp, &fds)) { addrlen = sizeof(struct sockaddr_in); rc = recvfrom(sock_rtp, recv_buf, sizeof recv_buf, 0, (struct sockaddr *) &sin_rx, &addrlen); if (rc < 0) { perror("recvfrom"); exit(1); } } if (FD_ISSET(sock_rtcp, &fds)) { addrlen = sizeof(struct sockaddr_in); rc = recvfrom(sock_rtp, recv_buf, sizeof recv_buf, 0, (struct sockaddr *) &sin_rx, &addrlen); if (rc < 0) { perror("recvfrom"); exit(1); } } } }