📄 udp.c
字号:
/* The udp plugin is a GPL plugin for partysip. Copyright (C) 2002,2003 WellX Telecom - <partysip@wellx.com> Copyright (C) 2002,2003 Aymeric MOIZARD - <jack@atosc.org> The udp plugin is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The udp plugin is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Foobar; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/#include <partysip/partysip.h>#include <ppl/ppl_dns.h>#include <ppl/ppl_socket.h>#include "udp.h"#include <fcntl.h>/* to avoid warnings on WIN32 setsockopt calls */#ifdef WIN32#define OPTVALCAST (const char*)#else#define OPTVALCAST #endiflocal_ctx_t *ctx = NULL;static int ipv6_enable = 0;intlocal_ctx_init (int in_port, int out_port){#ifdef MULTICAST_SUPPORT char *multicast;#endif int option; int atry; int i; struct sockaddr_in6 raddr6; struct sockaddr_in raddr; ctx = (local_ctx_t *) osip_malloc (sizeof (local_ctx_t)); if (ctx == NULL) return -1; ctx->mcast_socket = -1; /* if unused */ ctx->in_port = in_port; /* not used by now */ ctx->out_port = out_port; { char *atmp = psp_config_get_element ("ipv6_enable"); if (atmp!=NULL && 0==osip_strncasecmp(atmp, "on", 2)) ipv6_enable = 1; } if (ipv6_enable==1) ctx->in_socket = ppl_socket (PF_INET6, SOCK_DGRAM, IPPROTO_UDP); else ctx->in_socket = ppl_socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP); if (ctx->in_socket == -1) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "udp plugin: cannot create descriptor for port %i!\n", ctx->in_port)); goto lci_error1; } option = 1; i = setsockopt (ctx->in_socket, SOL_SOCKET, SO_REUSEADDR, OPTVALCAST &option, sizeof option); if (i!=0) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_WARNING, NULL, "upd plugin; UDP listener SO_REUSE_ADDR failed %i (%i)!\n", ctx->in_port, i)); } if (out_port == in_port) ctx->out_socket = ctx->in_socket; else { if (ipv6_enable==1) ctx->out_socket = ppl_socket (PF_INET6, SOCK_DGRAM, IPPROTO_UDP); else ctx->out_socket = ppl_socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP); if (ctx->out_socket == -1) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "udp plugin: cannot create descriptor for port %i!\n", ctx->out_port)); goto lci_error2; } i = (-1); atry = 0; while (i < 0 && atry < 40) { atry++; if (ipv6_enable==1) { raddr6.sin6_addr = in6addr_any; raddr6.sin6_port = htons ((short) ctx->out_port); raddr6.sin6_family = AF_INET6; i = ppl_socket_bind (ctx->out_socket, (struct sockaddr *) &raddr6, sizeof (raddr6)); } else { raddr.sin_addr.s_addr = htons (INADDR_ANY); raddr.sin_port = htons ((short) ctx->out_port); raddr.sin_family = AF_INET; i = ppl_socket_bind (ctx->out_socket, (struct sockaddr *) &raddr, sizeof (raddr)); } if (i < 0) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_WARNING, NULL, "udp plugin: cannot bind on port %i!\n", ctx->out_port)); ctx->out_port++; } } if (i != 0) goto lci_error3; } if (ipv6_enable==1) { raddr6.sin6_addr = in6addr_any; raddr6.sin6_port = htons ((short) ctx->in_port); raddr6.sin6_family = AF_INET6; i = ppl_socket_bind (ctx->in_socket, (struct sockaddr *) &raddr6, sizeof (raddr6)); } else { raddr.sin_addr.s_addr = htons (INADDR_ANY); raddr.sin_port = htons ((short) ctx->in_port); raddr.sin_family = AF_INET; i = ppl_socket_bind (ctx->in_socket, (struct sockaddr *) &raddr, sizeof (raddr)); } if (i < 0) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_WARNING, NULL, "udp plugin: cannot bind on port %i!\n", ctx->in_port)); return -1; }#ifdef MULTICAST_SUPPORT multicast = psp_config_get_element ("multicast"); if (multicast == NULL) { ctx->mcast_socket = -1; /* disabled */ } else if (0 == osip_strncasecmp (multicast, "on", 2)) { struct ip_mreq mreq; struct ipv6_mreq mreq6; OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO1, NULL, "udp plugin: Multicast is enabled!\n"));#ifdef __linux /* linux has support for listening on specific interface. */ { char *if_mcast = psp_config_get_element ("if_mcast"); char *if_ipmcast = psp_config_get_element ("if_ipmcast"); if (if_mcast==NULL&&if_ipmcast==NULL) { if (ipv6_enable==1) memcpy ((void *)mreq6.ipv6mr_multiaddr.s6_addr, (void const *)&in6_addr_any, 16); else mreq.imr_interface.s_addr = htonl(INADDR_ANY); } else if (if_mcast!=NULL) { char *tmp_name; char *tmp_ip; char *tmp_mask; if (ipv6_enable==1) { if (0 != ppl_dns_get_local_fqdn (&tmp_name, &tmp_ip, &tmp_mask,if_mcast, 0, AF_INET6)) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "udp plugin: error while looking for %s interface!\n", if_mcast)); goto lci_error5; } } else { if (0 != ppl_dns_get_local_fqdn (&tmp_name, &tmp_ip, &tmp_mask,if_mcast, 0, AF_INET)) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "udp plugin: error while looking for %s interface!\n", if_mcast)); goto lci_error5; } } if (ipv6_enable==1) ppl_inet_pton ((const char *)tmp_ip, (void *)&mreq6.ipv6mr_multiaddr.s6_addr); else mreq.imr_interface.s_addr = inet_addr(tmp_ip); OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO1, NULL, "udp plugin: Enabling multicast on %s interface!\n", if_mcast)); OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO1, NULL, "udp plugin: %s %s %s!\n", tmp_name, tmp_ip, tmp_mask)); osip_free(tmp_name); osip_free(tmp_ip); osip_free(tmp_mask); } else if (if_ipmcast!=NULL) { if (ipv6_enable==1) ppl_inet_pton ((const char *)if_ipmcast, (void *)&mreq6.ipv6mr_multiaddr.s6_addr); else mreq.imr_interface.s_addr = inet_addr(if_ipmcast); } }#else /* non __linux */ { char *if_ipmcast = psp_config_get_element ("if_ipmcast"); if (if_ipmcast==NULL) { if (ipv6_enable==1) memcpy ((void *)mreq6.ipv6mr_multiaddr.s6_addr, (void const *)&in6_addr_any, 16); else mreq.imr_interface.s_addr = htonl(INADDR_ANY); } else { if (ipv6_enable==1) ppl_inet_pton ((const char *)if_ipmcast, (void *)&mreq6.ipv6mr_multiaddr.s6_addr); else mreq.imr_interface.s_addr = inet_addr(if_ipmcast); } }#endif /* __linux */ if (ipv6_enable==0) { /* For IPv4, sip.mcast.org is the well-known IPv4 multicast IP address*/ /* 224.0.1.75 is the multicast IP address of sip.mcast.org */ mreq.imr_multiaddr.s_addr = inet_addr("224.0.1.75"); if (ctx->in_port==5060) ctx->mcast_socket = ctx->in_socket; /* reuse the same socket */ else { /* open a new socket on 5060 for multicast */ raddr.sin_addr.s_addr = htons (INADDR_ANY); raddr.sin_port = htons ((short) 5060); /* always 5060 */ raddr.sin_family = AF_INET; ctx->mcast_socket = ppl_socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP); if (ctx->mcast_socket<0) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_WARNING, NULL, "upd plugin; Cannot create socket for multicast!\n")); ctx->mcast_socket = -1; goto skip_multicast; } option = 1; i = setsockopt (ctx->mcast_socket, SOL_SOCKET, SO_REUSEADDR, OPTVALCAST &option, sizeof option); if (i!=0) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_WARNING, NULL, "upd plugin; UDP listener SO_REUSE_ADDR failed %i (%i)!\n", 5060, i)); ppl_socket_close(ctx->mcast_socket); ctx->mcast_socket = -1; goto skip_multicast; } i = ppl_socket_bind (ctx->mcast_socket, (struct sockaddr *) &raddr, sizeof (raddr)); if (i < 0) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_WARNING, NULL, "udp plugin: disabling multicast support %i (%s)!\n", 5060, strerror (errno))); ppl_socket_close(ctx->mcast_socket); ctx->mcast_socket = -1; goto skip_multicast; } } option=0; if(0 != setsockopt(ctx->mcast_socket, IPPROTO_IP, IP_MULTICAST_LOOP, OPTVALCAST &option, sizeof(option))) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_WARNING, NULL, "udp plugin; cannot disable loopback for multicast socket. (%i)!\n", 5060)); if (ctx->in_port!=5060) ppl_socket_close(ctx->mcast_socket); ctx->mcast_socket = -1; goto skip_multicast; } /* Enable Multicast support */ option=1; if (0 != setsockopt(ctx->mcast_socket, IPPROTO_IP, IP_MULTICAST_TTL, OPTVALCAST &option, sizeof(option))) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_WARNING, NULL, "udp plugin: cannot set multicast ttl value. (%i)!\n", 5060)); if (ctx->in_port!=5060) ppl_socket_close(ctx->mcast_socket); ctx->mcast_socket = -1; goto skip_multicast; } if (0 != setsockopt (ctx->mcast_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, OPTVALCAST &mreq, sizeof(mreq))) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_WARNING, NULL, "udp plugin; cannot set multicast ttl value. (%i)!\n", 5060)); if (ctx->in_port!=5060) ppl_socket_close(ctx->mcast_socket); ctx->mcast_socket = -1; goto skip_multicast; } } skip_multicast: }#endif /* !MULTICAST_SUPPORT */ /* set the socket to never block on recv() calls */#ifndef WIN32 if (0 != fcntl (ctx->in_socket, F_SETFL, O_NONBLOCK)) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "udp plugin; cannot set O_NONBLOCK to the file desciptor (%i)!\n", ctx->in_port)); goto lci_error5; } if (0 != fcntl (ctx->out_socket, F_SETFL, O_NONBLOCK)) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "udp plugin; cannot set O_NONBLOCK to the file desciptor (%i)!\n", ctx->out_port)); goto lci_error5; }#else { int timeout = 0; int err; err = setsockopt (ctx->in_socket, SOL_SOCKET, SO_RCVTIMEO, OPTVALCAST &timeout, sizeof (timeout)); if (err != NO_ERROR) { /* failed for some reason... */ OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "udp plugin; cannot set O_NONBLOCK to the file desciptor (%i)!\n", ctx->in_port)); goto lci_error5; } err = setsockopt (ctx->out_socket, SOL_SOCKET, SO_RCVTIMEO, OPTVALCAST &timeout, sizeof (timeout)); if (err != NO_ERROR) { /* failed for some reason... */ OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "udp plugin; cannot set O_NONBLOCK to the file desciptor (%i)!\n", ctx->out_port)); goto lci_error5; } }#endif return 0;lci_error5:lci_error3: ppl_socket_close (ctx->out_socket);lci_error2: ppl_socket_close (ctx->in_socket);lci_error1: osip_free (ctx); ctx = NULL; return -1;}voidlocal_ctx_free (){ if (ctx == NULL) return; if (ctx->in_socket != -1) { ppl_socket_close (ctx->in_socket); ctx->in_socket = -1; } if (ctx->in_port == ctx->out_port) ctx->out_socket = (-1); else if (ctx->out_socket != -1) ppl_socket_close (ctx->out_socket); osip_free (ctx); ctx = NULL;}#ifdef MULTICAST_SUPPORT#ifndef IN_MULTICAST# define IN_MULTICAST(a) IN_CLASSD(a)#endif#endif/* max_analysed = maximum number of message when this method can parse messages whithout returning. This method returns: -1 on error 0 on no message available 1 on max_analysed reached*/intcb_rcv_udp_message (int max){ fd_set memo_fdset; fd_set osip_fdset; int max_fd; struct sockaddr_in6 sa6; struct sockaddr_in sa4; struct sockaddr *sa; char *buf; int i; struct timeval tv;#ifdef __linux socklen_t slen;#else int slen;#endif if (ctx == NULL) return -1; tv.tv_sec = 0; tv.tv_usec = 0; FD_ZERO (&memo_fdset); FD_SET (ctx->in_socket, &memo_fdset); if (ctx->out_socket>0 &&ctx->out_socket!=ctx->in_socket)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -