# HG changeset patch # User Mychaela Falconia # Date 1657435904 28800 # Node ID b3f74df7b8089d624e73aa4de027ad4e7a8485ea # Parent 08d7794cdd0a664e742cc4ce7edf89fe16d1e6d4 beginning of themwi-mgw diff -r 08d7794cdd0a -r b3f74df7b808 .hgignore --- a/.hgignore Wed Jul 06 22:38:44 2022 -0800 +++ b/.hgignore Sat Jul 09 22:51:44 2022 -0800 @@ -2,6 +2,8 @@ \.[oa]$ +^mgw/themwi-mgw$ + ^mncc/themwi-mncc$ ^mtctest/themwi-test-mtc$ diff -r 08d7794cdd0a -r b3f74df7b808 mgw/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mgw/Makefile Sat Jul 09 22:51:44 2022 -0800 @@ -0,0 +1,17 @@ +CC= gcc +CFLAGS= -O2 +PROG= themwi-mgw +OBJS= crcx.o ctrl_prot.o ctrl_sock.o dlcx.o main.o mdcx.o readconf.o udpsink.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 diff -r 08d7794cdd0a -r b3f74df7b808 mgw/crcx.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mgw/crcx.c Sat Jul 09 22:51:44 2022 -0800 @@ -0,0 +1,164 @@ +/* + * In this module we implement our CRCX operation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../include/tmgw_ctrl.h" +#include "../include/tmgw_const.h" +#include "struct.h" +#include "select.h" + +extern struct endpoint *find_ep_by_id(); +extern void udp_sink_rcvr(); + +extern struct bind_range_cfg bind_range_gsm, bind_range_pstn; + +static unsigned +get_new_ep_id(conn) + struct ctrl_conn *conn; +{ + unsigned id; + + for (;;) { + id = conn->next_ep_id++; + if (!find_ep_by_id(conn, id)) + return id; + } +} + +static int +get_local_port_pair(ep, roe, brc) + struct endpoint *ep; + struct rtp_one_end *roe; + struct bind_range_cfg *brc; +{ + struct sockaddr_in sin; + unsigned tries, rtp_port; + int rc; + + sin.sin_family = AF_INET; + sin.sin_addr = brc->bind_ip; + for (tries = brc->port_tries; tries; tries--) { + rtp_port = brc->port_next; + brc->port_next += 2; + if (brc->port_next >= brc->port_range_end) + brc->port_next = brc->port_range_start; + sin.sin_port = htons(rtp_port); + roe->rtp_fd = socket(AF_INET, SOCK_DGRAM, 0); + if (roe->rtp_fd < 0) { + syslog(LOG_CRIT, "socket(AF_INET, SOCK_DGRAM, 0): %m"); + return(-1); + } + rc = bind(roe->rtp_fd, (struct sockaddr *) &sin, sizeof sin); + if (rc < 0) { + close(roe->rtp_fd); + continue; + } + bcopy(&sin, &roe->bound_addr, sizeof(struct sockaddr_in)); + sin.sin_port = htons(rtp_port+1); + roe->rtcp_fd = socket(AF_INET, SOCK_DGRAM, 0); + if (roe->rtcp_fd < 0) { + syslog(LOG_CRIT, "socket(AF_INET, SOCK_DGRAM, 0): %m"); + close(roe->rtp_fd); + return(-1); + } + rc = bind(roe->rtcp_fd, (struct sockaddr *) &sin, sizeof sin); + if (rc < 0) { + close(roe->rtp_fd); + close(roe->rtcp_fd); + continue; + } + /* all good - make the file descriptors live for select */ + update_max_fd(roe->rtp_fd); + FD_SET(roe->rtp_fd, &select_for_read); + select_handlers[roe->rtp_fd] = udp_sink_rcvr; + select_data[roe->rtp_fd] = (void *) ep; + update_max_fd(roe->rtcp_fd); + FD_SET(roe->rtcp_fd, &select_for_read); + select_handlers[roe->rtcp_fd] = udp_sink_rcvr; + select_data[roe->rtcp_fd] = (void *) ep; + return(0); + } + /* couldn't find a free port pair */ + return(-1); +} + +void +process_crcx(conn, req, resp) + struct ctrl_conn *conn; + struct tmgw_ctrl_req *req; + struct tmgw_ctrl_resp *resp; +{ + struct endpoint *ep; + int rc; + + /* ep_id in request encodes ep_type */ + switch (req->ep_id) { + case TMGW_EP_TYPE_DUMMY_GSM: + case TMGW_EP_TYPE_DUMMY_PSTN: + case TMGW_EP_TYPE_GATEWAY: + break; + default: + resp->res = TMGW_RESP_ERR_PROT; + return; + } + ep = malloc(sizeof(struct endpoint)); + if (!ep) { + syslog(LOG_CRIT, "malloc for endpoint: %m"); + resp->res = TMGW_RESP_ERR_RSRC; + return; + } + bzero(ep, sizeof(struct endpoint)); + ep->ep_type = req->ep_id; + ep->ep_id = get_new_ep_id(conn); + if (ep->ep_type & TMGW_EP_HAS_GSM_SOCK) { + rc = get_local_port_pair(ep, &ep->rtp_gsm, &bind_range_gsm); + if (rc < 0) { + syslog(LOG_ERR, + "unable to get local port pair on GSM side"); + free(ep); + resp->res = TMGW_RESP_ERR_RSRC; + return; + } + } + if (ep->ep_type & TMGW_EP_HAS_PSTN_SOCK) { + rc = get_local_port_pair(ep, &ep->rtp_pstn, &bind_range_pstn); + if (rc < 0) { + syslog(LOG_ERR, + "unable to get local port pair on PSTN side"); + if (ep->ep_type & TMGW_EP_HAS_GSM_SOCK) + free_rtp_end(&ep->rtp_gsm); + free(ep); + resp->res = TMGW_RESP_ERR_RSRC; + return; + } + } + rc = mdcx_operation(ep, req, resp); + if (rc < 0) { + if (ep->ep_type & TMGW_EP_HAS_GSM_SOCK) + free_rtp_end(&ep->rtp_gsm); + if (ep->ep_type & TMGW_EP_HAS_PSTN_SOCK) + free_rtp_end(&ep->rtp_pstn); + free(ep); + return; + } + /* all good - accept the new endpoint and return OK */ + ep->next = conn->endp_list; + conn->endp_list = ep; + resp->res = TMGW_RESP_OK; + resp->ep_id = ep->ep_id; + bcopy(&ep->rtp_gsm.bound_addr, &resp->gsm_addr, + sizeof(struct sockaddr_in)); + bcopy(&ep->rtp_pstn.bound_addr, &resp->pstn_addr, + sizeof(struct sockaddr_in)); + syslog(LOG_INFO, "CRCX endpoint type %u id %u", ep->ep_type, ep->ep_id); +} diff -r 08d7794cdd0a -r b3f74df7b808 mgw/ctrl_prot.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mgw/ctrl_prot.c Sat Jul 09 22:51:44 2022 -0800 @@ -0,0 +1,65 @@ +/* + * In this module we implement our control socket protocol. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../include/tmgw_ctrl.h" +#include "struct.h" +#include "select.h" + +struct endpoint * +find_ep_by_id(conn, id) + struct ctrl_conn *conn; + unsigned id; +{ + struct endpoint *ep; + + for (ep = conn->endp_list; ep; ep = ep->next) + if (ep->ep_id == id) + return ep; + return 0; +} + +void +ctrl_message_handler(fd, conn) + struct ctrl_conn *conn; +{ + struct tmgw_ctrl_req req; + struct tmgw_ctrl_resp resp; + int rc; + + rc = recv(fd, &req, sizeof req, 0); + if (rc < sizeof req) { + syslog(LOG_INFO, "ctrl connection closing %s active endpoints", + conn->endp_list ? "with" : "without"); + close(fd); + FD_CLR(fd, &select_for_read); + dlcx_all_on_conn(conn); + free(conn); + return; + } + bzero(&resp, sizeof resp); + resp.transact_ref = req.transact_ref; + switch (req.opcode) { + case TMGW_CTRL_OP_CRCX: + process_crcx(conn, &req, &resp); + break; + case TMGW_CTRL_OP_MDCX: + process_mdcx(conn, &req, &resp); + break; + case TMGW_CTRL_OP_DLCX: + process_dlcx(conn, &req, &resp); + break; + default: + resp.res = TMGW_RESP_ERR_PROT; + } + send(fd, &resp, sizeof resp, 0); +} diff -r 08d7794cdd0a -r b3f74df7b808 mgw/ctrl_sock.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mgw/ctrl_sock.c Sat Jul 09 22:51:44 2022 -0800 @@ -0,0 +1,78 @@ +/* + * In this module we implement the logic of listening on the + * TMGW control socket and accepting control connections. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "struct.h" +#include "select.h" + +static char ctrl_socket_pathname[] = "/var/gsm/tmgw_socket"; + +extern void ctrl_message_handler(); + +void +ctrlsock_accept_handler(listener_fd) +{ + struct sockaddr_un sa; + socklen_t sa_len; + int conn_fd; + struct ctrl_conn *conn; + + sa_len = sizeof sa; + conn_fd = accept(listener_fd, (struct sockaddr *) &sa, &sa_len); + if (conn_fd < 0) { + syslog(LOG_CRIT, "accept on UNIX socket: %m"); + exit(1); + } + conn = malloc(sizeof(struct ctrl_conn)); + if (!conn) { + syslog(LOG_CRIT, "malloc for ctrl socket conn: %m"); + close(conn_fd); + return; + } + bzero(conn, sizeof(struct ctrl_conn)); + update_max_fd(conn_fd); + FD_SET(conn_fd, &select_for_read); + select_handlers[conn_fd] = ctrl_message_handler; + select_data[conn_fd] = (void *) conn; + syslog(LOG_INFO, "accepted ctrl connection"); +} + +create_ctrl_socket() +{ + struct sockaddr_un sa; + unsigned sa_len; + int fd, rc; + + fd = socket(AF_UNIX, SOCK_SEQPACKET, 0); + if (fd < 0) { + syslog(LOG_CRIT, "socket(AF_UNIX, SOCK_SEQPACKET, 0): %m"); + return(-1); + } + unlink(ctrl_socket_pathname); + fill_sockaddr_un(ctrl_socket_pathname, &sa, &sa_len); + rc = bind(fd, (struct sockaddr *) &sa, sa_len); + if (rc < 0) { + syslog(LOG_ERR, "bind to %s: %m", ctrl_socket_pathname); + return(-1); + } + rc = listen(fd, 3); + if (rc < 0) { + syslog(LOG_CRIT, "listen on UNIX socket: %m"); + return(-1); + } + update_max_fd(fd); + FD_SET(fd, &select_for_read); + select_handlers[fd] = ctrlsock_accept_handler; + return(0); +} diff -r 08d7794cdd0a -r b3f74df7b808 mgw/dlcx.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mgw/dlcx.c Sat Jul 09 22:51:44 2022 -0800 @@ -0,0 +1,88 @@ +/* + * In this module we implement our DLCX operation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../include/tmgw_ctrl.h" +#include "../include/tmgw_const.h" +#include "struct.h" +#include "select.h" + +extern struct endpoint *find_ep_by_id(); + +static struct endpoint *delq; + +static void +put_on_delq(ep) + struct endpoint *ep; +{ + ep->next = delq; + delq = ep; +} + +void +process_dlcx(conn, req, resp) + struct ctrl_conn *conn; + struct tmgw_ctrl_req *req; + struct tmgw_ctrl_resp *resp; +{ + struct endpoint *ep, **epp; + + for (epp = &conn->endp_list; ep = *epp; epp = &ep->next) + if (ep->ep_id == req->ep_id) + break; + if (!ep) { + resp->res = TMGW_RESP_ERR_PROT; + return; + } + syslog(LOG_INFO, "DLCX endpoint id %u", ep->ep_id); + *epp = ep->next; + put_on_delq(ep); + resp->res = TMGW_RESP_OK; +} + +void +dlcx_all_on_conn(conn) + struct ctrl_conn *conn; +{ + struct endpoint *ep, *np; + + for (ep = conn->endp_list; ep; ep = np) { + np = ep->next; + put_on_delq(ep); + } +} + +void +free_rtp_end(roe) + struct rtp_one_end *roe; +{ + close(roe->rtp_fd); + close(roe->rtcp_fd); + FD_CLR(roe->rtp_fd, &select_for_read); + FD_CLR(roe->rtcp_fd, &select_for_read); +} + +void +free_deleted_endpoints() +{ + struct endpoint *ep, *np; + + for (ep = delq; ep; ep = np) { + np = ep->next; + if (ep->ep_type & TMGW_EP_HAS_GSM_SOCK) + free_rtp_end(&ep->rtp_gsm); + if (ep->ep_type & TMGW_EP_HAS_PSTN_SOCK) + free_rtp_end(&ep->rtp_pstn); + free(ep); + } + delq = 0; +} diff -r 08d7794cdd0a -r b3f74df7b808 mgw/main.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mgw/main.c Sat Jul 09 22:51:44 2022 -0800 @@ -0,0 +1,63 @@ +/* + * Main module for themwi-mgw. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +fd_set select_for_read; +void (*select_handlers[FD_SETSIZE])(); +void *select_data[FD_SETSIZE]; + +static int max_fd; + +update_max_fd(newfd) +{ + if (newfd >= FD_SETSIZE) { + syslog(LOG_CRIT, "FATAL: file descriptor %d >= FD_SETSIZE", + newfd); + exit(1); + } + if (newfd > max_fd) + max_fd = newfd; +} + +main(argc, argv) + char **argv; +{ + fd_set fds; + int cc, i; + + openlog("themwi-mgw", 0, LOG_LOCAL5); + read_config_file(); + if (create_ctrl_socket() < 0) { + fprintf(stderr, "error creating TMGW control socket\n"); + exit(1); + } + signal(SIGPIPE, SIG_IGN); + /* main select loop */ + for (;;) { + bcopy(&select_for_read, &fds, sizeof(fd_set)); + cc = select(max_fd+1, &fds, 0, 0, 0); + if (cc < 0) { + if (errno == EINTR) + continue; + syslog(LOG_CRIT, "select: %m"); + exit(1); + } + for (i = 0; cc && i <= max_fd; i++) { + if (FD_ISSET(i, &fds)) { + select_handlers[i](i, select_data[i]); + cc--; + } + } + free_deleted_endpoints(); + } +} diff -r 08d7794cdd0a -r b3f74df7b808 mgw/mdcx.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mgw/mdcx.c Sat Jul 09 22:51:44 2022 -0800 @@ -0,0 +1,72 @@ +/* + * In this module we implement our MDCX operation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "../include/tmgw_ctrl.h" +#include "../include/tmgw_const.h" +#include "struct.h" + +extern struct endpoint *find_ep_by_id(); + +mdcx_operation(ep, req, resp) + struct endpoint *ep; + struct tmgw_ctrl_req *req; + struct tmgw_ctrl_resp *resp; +{ + if (req->setup_mask & TMGW_CTRL_MASK_GSM_CONN) { + if (ep->ep_type != TMGW_EP_TYPE_GATEWAY) { + resp->res = TMGW_RESP_ERR_PROT; + return(-1); + } + bcopy(&req->gsm_addr, &ep->rtp_gsm.remote_addr, + sizeof(struct sockaddr_in)); + ep->gsm_payload_type = req->gsm_payload_type; + ep->gsm_payload_msg_type = req->gsm_payload_msg_type; + } + if (req->setup_mask & TMGW_CTRL_MASK_PSTN_CONN) { + if (ep->ep_type != TMGW_EP_TYPE_GATEWAY) { + resp->res = TMGW_RESP_ERR_PROT; + return(-1); + } + bcopy(&req->pstn_addr, &ep->rtp_pstn.remote_addr, + sizeof(struct sockaddr_in)); + ep->pstn_payload_type = req->pstn_payload_type; + } + if (req->setup_mask & TMGW_CTRL_MASK_FWD_MODE) { + if (ep->ep_type != TMGW_EP_TYPE_GATEWAY || + ep->rtp_gsm.remote_addr.sin_family != AF_INET || + ep->rtp_pstn.remote_addr.sin_family != AF_INET) { + resp->res = TMGW_RESP_ERR_PROT; + return(-1); + } + ep->fwd_mode = req->fwd_mode; + } + return(0); +} + +void +process_mdcx(conn, req, resp) + struct ctrl_conn *conn; + struct tmgw_ctrl_req *req; + struct tmgw_ctrl_resp *resp; +{ + struct endpoint *ep; + int rc; + + ep = find_ep_by_id(conn, req->ep_id); + if (!ep) { + resp->res = TMGW_RESP_ERR_PROT; + return; + } + rc = mdcx_operation(ep, req, resp); + if (rc == 0) + resp->res = TMGW_RESP_OK; +} diff -r 08d7794cdd0a -r b3f74df7b808 mgw/readconf.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mgw/readconf.c Sat Jul 09 22:51:44 2022 -0800 @@ -0,0 +1,187 @@ +/* + * In this module we implement the reading of /var/gsm/themwi-mgw.cfg: + * we parse and save the configured IP address and port range for each + * of our two sides, GSM and PSTN. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "struct.h" + +struct bind_range_cfg bind_range_gsm, bind_range_pstn; + +static char config_file_pathname[] = "/var/gsm/themwi-mgw.cfg"; + +struct parse_state { + int lineno; + int set_mask; +}; + +static void +handle_bind_ip(st, kw, brc, line) + struct parse_state *st; + char *kw, *line; + struct bind_range_cfg *brc; +{ + char *cp, *np; + + for (cp = line; 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, kw); + exit(1); + } + for (np = cp; *cp && !isspace(*cp); cp++) + ; + if (*cp) + *cp++ = '\0'; + while (isspace(*cp)) + cp++; + if (*cp != '\0' && *cp != '#') + goto inv_syntax; + brc->bind_ip.s_addr = inet_addr(np); + if (brc->bind_ip.s_addr == INADDR_NONE) { + fprintf(stderr, + "%s line %d: invalid IP address argument \"%s\"\n", + config_file_pathname, st->lineno, np); + exit(1); + } +} + +static void +handle_port_range(st, kw, brc, line) + struct parse_state *st; + char *kw, *line; + struct bind_range_cfg *brc; +{ + char *cp, *np1, *np2; + + for (cp = line; isspace(*cp); cp++) + ; + if (!isdigit(*cp)) { +inv_syntax: fprintf(stderr, + "%s line %d: %s setting requires two numeric arguments\n", + config_file_pathname, st->lineno, kw); + exit(1); + } + for (np1 = cp; isdigit(*cp); cp++) + ; + if (!isspace(*cp)) + goto inv_syntax; + while (isspace(*cp)) + cp++; + if (!isdigit(*cp)) + goto inv_syntax; + for (np2 = cp; isdigit(*cp); cp++) + ; + if (*cp && !isspace(*cp)) + goto inv_syntax; + while (isspace(*cp)) + cp++; + if (*cp != '\0' && *cp != '#') + goto inv_syntax; + brc->port_range_start = atoi(np1); + brc->port_range_end = atoi(np2); + if (brc->port_range_start & 1) { + fprintf(stderr, "%s line %d: start port must be even\n", + config_file_pathname, st->lineno); + exit(1); + } + if (!(brc->port_range_end & 1)) { + fprintf(stderr, "%s line %d: end port must be odd\n", + config_file_pathname, st->lineno); + exit(1); + } + if (brc->port_range_end <= brc->port_range_start) { + fprintf(stderr, + "%s line %d: end port must be greater than start port\n", + config_file_pathname, st->lineno); + exit(1); + } + brc->port_next = brc->port_range_start; + brc->port_tries = (brc->port_range_end - brc->port_range_start + 1) / 2; +} + +static void +process_line(st, line) + struct parse_state *st; + char *line; +{ + char *cp, *np; + void (*handler)(); + struct bind_range_cfg *ipside; + 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, "gsm-ip-addr")) { + handler = handle_bind_ip; + ipside = &bind_range_gsm; + set_id = 1; + } else if (!strcmp(np, "gsm-port-range")) { + handler = handle_port_range; + ipside = &bind_range_gsm; + set_id = 2; + } else if (!strcmp(np, "pstn-ip-addr")) { + handler = handle_bind_ip; + ipside = &bind_range_pstn; + set_id = 4; + } else if (!strcmp(np, "pstn-port-range")) { + handler = handle_port_range; + ipside = &bind_range_pstn; + set_id = 8; + } 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); + } + handler(st, np, ipside, cp); + 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 != 15) { + fprintf(stderr, "error: %s did not set all required settings\n", + config_file_pathname); + exit(1); + } +} diff -r 08d7794cdd0a -r b3f74df7b808 mgw/select.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mgw/select.h Sat Jul 09 22:51:44 2022 -0800 @@ -0,0 +1,5 @@ +/* extern declarations for select loop global variables */ + +extern fd_set select_for_read; +extern void (*select_handlers[])(); +extern void *select_data[]; diff -r 08d7794cdd0a -r b3f74df7b808 mgw/struct.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mgw/struct.h Sat Jul 09 22:51:44 2022 -0800 @@ -0,0 +1,36 @@ +/* + * This header file defines internal data structures for themwi-mgw. + */ + +struct bind_range_cfg { + struct in_addr bind_ip; + unsigned port_range_start; + unsigned port_range_end; + unsigned port_next; + unsigned port_tries; +}; + +struct rtp_one_end { + int rtp_fd; + int rtcp_fd; + struct sockaddr_in bound_addr; + struct sockaddr_in remote_addr; +}; + +struct endpoint { + unsigned ep_type; + struct rtp_one_end rtp_gsm; + struct rtp_one_end rtp_pstn; + unsigned gsm_payload_type; + unsigned gsm_payload_msg_type; + unsigned pstn_payload_type; + unsigned fwd_mode; + /* linked list management */ + unsigned ep_id; + struct endpoint *next; +}; + +struct ctrl_conn { + struct endpoint *endp_list; + unsigned next_ep_id; +}; diff -r 08d7794cdd0a -r b3f74df7b808 mgw/udpsink.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mgw/udpsink.c Sat Jul 09 22:51:44 2022 -0800 @@ -0,0 +1,23 @@ +/* + * There are times when we hold open some UDP sockets, but can't do + * anything with incoming packets other than discard them. This + * situation holds for dummy one-sided endpoints, for gateway + * endpoints that haven't been fully connected yet, and for all RTCP + * packets at the moment. + * + * In this module we implement the generic UDP "black hole" sink. + */ + +#include +#include +#include +#include +#include + +void +udp_sink_rcvr(fd) +{ + u_char buf[512]; + + recv(fd, buf, sizeof buf, 0); +}