FreeCalypso > hg > themwi-system-sw
diff mgw/crcx.c @ 32:b3f74df7b808
beginning of themwi-mgw
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sat, 09 Jul 2022 22:51:44 -0800 |
parents | |
children | 7dae2bae56a1 |
line wrap: on
line diff
--- /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 <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 <syslog.h> +#include <unistd.h> +#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); +}