📄 rtpsession_inet.c
字号:
/* The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack. Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/#include "ortp/ortp.h"#include "utils.h"#include "ortp/rtpsession.h"#include "rtpsession_priv.h"#if defined(WIN32) || defined(_WIN32_WCE)#include "ortp-config-win32.h"#else#include "ortp-config.h" /*needed for HAVE_SYS_UIO_H */#endif#ifdef HAVE_SYS_UIO_H#include <sys/uio.h>#define USE_SENDMSG 1#endif#define can_connect(s) ( (s)->use_connect && !(s)->symmetric_rtp)static bool_t try_connect(int fd, const struct sockaddr *dest, socklen_t addrlen){ if (connect(fd,dest,addrlen)<0){ ortp_warning("Could not connect() socket: %s",getSocketError()); return FALSE; } return TRUE;}static ortp_socket_t create_and_bind(const char *addr, int port, int *sock_family, bool_t reuse_addr){ int err; int optval = 1; ortp_socket_t sock=-1;#ifdef ORTP_INET6 char num[8]; struct addrinfo hints, *res0, *res;#else struct sockaddr_in saddr;#endif #ifdef ORTP_INET6 memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; snprintf(num, sizeof(num), "%d",port); err = getaddrinfo(addr,num, &hints, &res0); if (err!=0) { ortp_warning ("Error in getaddrinfo on (addr=%s port=%i): %s", addr, port, gai_strerror(err)); return -1; } for (res = res0; res; res = res->ai_next) { sock = socket(res->ai_family, res->ai_socktype, 0); if (sock==-1) continue; if (reuse_addr){ err = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (SOCKET_OPTION_VALUE)&optval, sizeof (optval)); if (err < 0) { ortp_warning ("Fail to set rtp address reusable: %s.", getSocketError()); } } *sock_family=res->ai_family; err = bind (sock, res->ai_addr, res->ai_addrlen); if (err != 0){ ortp_warning ("Fail to bind rtp socket to (addr=%s port=%i) : %s.", addr,port, getSocketError()); close_socket (sock); sock=-1; continue; }#ifndef __hpux switch (res->ai_family) { case AF_INET: if (IN_MULTICAST(ntohl(((struct sockaddr_in *) res->ai_addr)->sin_addr.s_addr))) { struct ip_mreq mreq; mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *) res->ai_addr)->sin_addr.s_addr; mreq.imr_interface.s_addr = INADDR_ANY; err = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (SOCKET_OPTION_VALUE) &mreq, sizeof(mreq)); if (err < 0){ ortp_warning ("Fail to join address group: %s.", getSocketError()); close_socket (sock); sock=-1; continue; } } break; case AF_INET6: if (IN6_IS_ADDR_MULTICAST(&(((struct sockaddr_in6 *) res->ai_addr)->sin6_addr))) { struct ipv6_mreq mreq; mreq.ipv6mr_multiaddr = ((struct sockaddr_in6 *) res->ai_addr)->sin6_addr; mreq.ipv6mr_interface = 0; err = setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (SOCKET_OPTION_VALUE)&mreq, sizeof(mreq)); if (err < 0) { ortp_warning ("Fail to join address group: %s.", getSocketError()); close_socket (sock); sock=-1; continue; } } break; }#endif /*hpux*/ break; } freeaddrinfo(res0);#else saddr.sin_family = AF_INET; *sock_family=AF_INET; err = inet_aton (addr, &saddr.sin_addr); if (err < 0) { ortp_warning ("Error in socket address:%s.", getSocketError()); return -1; } saddr.sin_port = htons (port); sock = socket (PF_INET, SOCK_DGRAM, 0); if (sock==-1) return -1; if (reuse_addr){ err = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (SOCKET_OPTION_VALUE)&optval, sizeof (optval)); if (err < 0) { ortp_warning ("Fail to set rtp address reusable: %s.",getSocketError()); } } err = bind (sock, (struct sockaddr *) &saddr, sizeof (saddr)); if (err != 0) { ortp_warning ("Fail to bind rtp socket to port %i: %s.", port, getSocketError()); close_socket (sock); return -1; }#endif if (sock!=-1){ set_non_blocking_socket (sock); } return sock;}static void set_socket_sizes(int sock, unsigned int sndbufsz, unsigned int rcvbufsz){ int err; bool_t done=FALSE; if (sndbufsz>0){#ifdef SO_SNDBUFFORCE err = setsockopt(sock, SOL_SOCKET, SO_SNDBUFFORCE, (void *)&sndbufsz, sizeof(sndbufsz)); if (err == -1) { ortp_error("Fail to increase socket's send buffer size with SO_SNDBUFFORCE: %s.", getSocketError()); }else done=TRUE;#endif if (!done){ err = setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void *)&sndbufsz, sizeof(sndbufsz)); if (err == -1) { ortp_error("Fail to increase socket's send buffer size with SO_SNDBUF: %s.", getSocketError()); } } } done=FALSE; if (rcvbufsz>0){#ifdef SO_RCVBUFFORCE err = setsockopt(sock, SOL_SOCKET, SO_RCVBUFFORCE, (void *)&rcvbufsz, sizeof(rcvbufsz)); if (err == -1) { ortp_error("Fail to increase socket's recv buffer size with SO_RCVBUFFORCE: %s.", getSocketError()); }#endif if (!done){ err = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (void *)&rcvbufsz, sizeof(rcvbufsz)); if (err == -1) { ortp_error("Fail to increase socket's recv buffer size with SO_RCVBUF: %s.", getSocketError()); } } }}static ortp_socket_t create_and_bind_random(const char *localip, int *sock_family, int *port){ int retry; ortp_socket_t sock = -1; for (retry=0;retry<100;retry++) { int localport; do { localport = (rand () + 5000) & 0xfffe; } while ((localport < 5000) || (localport > 0xffff)); /*do not set REUSEADDR in case of random allocation */ sock = create_and_bind(localip, localport, sock_family,FALSE); if (sock!=-1) { *port=localport; return sock; } } ortp_warning("create_and_bind_random: Could not find a random port for %s !",localip); return -1;}/** *rtp_session_set_local_addr: *@session: a rtp session freshly created. *@addr: a local IP address in the xxx.xxx.xxx.xxx form. *@port: a local port or -1 to let oRTP choose the port randomly * * Specify the local addr to be use to listen for rtp packets or to send rtp packet from. * In case where the rtp session is send-only, then it is not required to call this function: * when calling rtp_session_set_remote_addr(), if no local address has been set, then the * default INADRR_ANY (0.0.0.0) IP address with a random port will be used. Calling * rtp_sesession_set_local_addr() is mandatory when the session is recv-only or duplex. * * Returns: 0 on success.**/intrtp_session_set_local_addr (RtpSession * session, const char * addr, int port){ ortp_socket_t sock; int sockfamily; if (session->rtp.socket>=0){ /* don't rebind, but close before*/ rtp_session_release_sockets(session); } /* try to bind the rtp port */ if (port>0) sock=create_and_bind(addr,port,&sockfamily,TRUE); else sock=create_and_bind_random(addr,&sockfamily,&port); if (sock!=-1){ set_socket_sizes(sock,session->rtp.snd_socket_size,session->rtp.rcv_socket_size); session->rtp.sockfamily=sockfamily; session->rtp.socket=sock; session->rtp.loc_port=port; /*try to bind rtcp port */ sock=create_and_bind(addr,port+1,&sockfamily,TRUE); if (sock!=-1){ session->rtcp.sockfamily=sockfamily; session->rtcp.socket=sock; }else{ ortp_warning("Could not create and bind rtcp socket."); } /* set socket options (but don't change chosen states) */ rtp_session_set_dscp( session, -1 ); rtp_session_set_multicast_ttl( session, -1 ); rtp_session_set_multicast_loopback( session, -1 ); return 0; } return -1;}/** *rtp_session_set_multicast_ttl: *@session: a rtp session *@ttl: desired Multicast Time-To-Live * * Sets the TTL (Time-To-Live) for outgoing multicast packets. * * Returns: 0 on success. ***/int rtp_session_set_multicast_ttl(RtpSession *session, int ttl){ int retval; // Store new TTL if one is specified if (ttl>0) session->multicast_ttl = ttl; // Don't do anything if socket hasn't been created yet if (session->rtp.socket < 0) return 0; switch (session->rtp.sockfamily) { case AF_INET: { retval= setsockopt(session->rtp.socket, IPPROTO_IP, IP_MULTICAST_TTL, (SOCKET_OPTION_VALUE) &session->multicast_ttl, sizeof(session->multicast_ttl)); if (retval<0) break; retval= setsockopt(session->rtcp.socket, IPPROTO_IP, IP_MULTICAST_TTL, (SOCKET_OPTION_VALUE) &session->multicast_ttl, sizeof(session->multicast_ttl)); } break; case AF_INET6: { retval= setsockopt(session->rtp.socket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (SOCKET_OPTION_VALUE)&session->multicast_ttl, sizeof(session->multicast_ttl)); if (retval<0) break; retval= setsockopt(session->rtcp.socket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (SOCKET_OPTION_VALUE) &session->multicast_ttl, sizeof(session->multicast_ttl)); } break; default: retval=-1; } if (retval<0) ortp_warning("Failed to set multicast TTL on socket."); return retval;}/** *rtp_session_get_multicast_ttl: *@session: a rtp session * * Returns the TTL (Time-To-Live) for outgoing multicast packets. ***/int rtp_session_get_multicast_ttl(RtpSession *session){ return session->multicast_ttl;}/** *rtp_session_set_multicast_loopback: *@session: a rtp session *@ttl: desired Multicast Time-To-Live * * Sets the TTL (Time-To-Live) for outgoing multicast packets. * * Returns: 0 on success. ***/int rtp_session_set_multicast_loopback(RtpSession *session, int yesno){ int retval; // Store new loopback state if one is specified if (yesno==0) { // Don't loop back session->multicast_loopback = 0; } else if (yesno>0) { // Do loop back session->multicast_loopback = 1; } // Don't do anything if socket hasn't been created yet if (session->rtp.socket < 0) return 0; switch (session->rtp.sockfamily) { case AF_INET: { retval= setsockopt(session->rtp.socket, IPPROTO_IP, IP_MULTICAST_LOOP, (SOCKET_OPTION_VALUE) &session->multicast_loopback, sizeof(session->multicast_loopback)); if (retval<0) break; retval= setsockopt(session->rtcp.socket, IPPROTO_IP, IP_MULTICAST_LOOP, (SOCKET_OPTION_VALUE) &session->multicast_loopback, sizeof(session->multicast_loopback)); } break; case AF_INET6: { retval= setsockopt(session->rtp.socket, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (SOCKET_OPTION_VALUE) &session->multicast_loopback, sizeof(session->multicast_loopback)); if (retval<0) break; retval= setsockopt(session->rtcp.socket, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (SOCKET_OPTION_VALUE) &session->multicast_loopback, sizeof(session->multicast_loopback)); } break; default: retval=-1; } if (retval<0) ortp_warning("Failed to set multicast loopback on socket."); return retval;}/** *rtp_session_get_multicast_loopback: *@session: a rtp session * * Returns the multicast loopback state of rtp session (true or false). ***/int rtp_session_get_multicast_loopback(RtpSession *session){ return session->multicast_loopback;}/** *rtp_session_set_dscp: *@session: a rtp session *@dscp: desired DSCP PHB value * * Sets the DSCP (Differentiated Services Code Point) for outgoing RTP packets. * * Returns: 0 on success. ***/int rtp_session_set_dscp(RtpSession *session, int dscp){ int retval=0; int tos; // Store new DSCP value if one is specified if (dscp>=0) session->dscp = dscp; // Don't do anything if socket hasn't been created yet if (session->rtp.socket < 0) return 0; // DSCP value is in the upper six bits of the TOS field tos = (session->dscp << 2) & 0xFC; switch (session->rtp.sockfamily) { case AF_INET: retval = setsockopt(session->rtp.socket, IPPROTO_IP, IP_TOS, (SOCKET_OPTION_VALUE)&tos, sizeof(tos)); break;#ifdef ORTP_INET6 case AF_INET6:# ifdef IPV6_TCLASS /*seems not defined by my libc*/ retval = setsockopt(session->rtp.socket, IPPROTO_IPV6, IPV6_TCLASS, (SOCKET_OPTION_VALUE)&tos, sizeof(tos));# else /*in case that works:*/ retval = setsockopt(session->rtp.socket, IPPROTO_IPV6, IP_TOS, (SOCKET_OPTION_VALUE)&tos, sizeof(tos));#endif break;#endif default: retval=-1; } if (retval<0) ortp_warning("Failed to set DSCP value on socket."); return retval;}/** *rtp_session_get_dscp: *@session: a rtp session * * Returns the DSCP (Differentiated Services Code Point) for outgoing RTP packets. ***/int rtp_session_get_dscp(const RtpSession *session){ return session->dscp;}/** *rtp_session_get_local_port: *@session: a rtp session for which rtp_session_set_local_addr() or rtp_session_set_remote_addr() has been called * * This function can be useful to retrieve the local port that was randomly choosen by * rtp_session_set_remote_addr() when rtp_session_set_local_addr() was not called. * * Returns: the local port used to listen for rtp packets, -1 if not set.**/int rtp_session_get_local_port(const RtpSession *session){ return (session->rtp.loc_port>0) ? session->rtp.loc_port : -1;}static char * ortp_inet_ntoa(struct sockaddr *addr, int addrlen, char *dest, int destlen){#ifdef ORTP_INET6 int err; dest[0]=0; err=getnameinfo(addr,addrlen,dest,destlen,NULL,0,NI_NUMERICHOST); if (err!=0){ ortp_warning("getnameinfo error: %s",gai_strerror(err)); }#else char *tmp=inet_ntoa(((struct sockaddr_in*)addr)->sin_addr); strncpy(dest,tmp,destlen); dest[destlen-1]='\0';
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -