FreeCalypso > hg > themwi-system-sw
view mgw/crcx.c @ 97:9aed16c30622
mgw p2g: set M bit when restarting forwarding after no-forward
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sun, 25 Sep 2022 20:05:02 -0800 |
parents | 020ba624bdd8 |
children | 738be11ac432 |
line wrap: on
line source
/* * 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 <stdint.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_PARAM; 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); }