📄 udp.c
字号:
#endif/** * IP-agnostic multicast join, * with fallback to old APIs, and fallback from SSM to ASM. */static intnet_SourceSubscribe (vlc_object_t *obj, int fd, const struct sockaddr *src, socklen_t srclen, const struct sockaddr *grp, socklen_t grplen){ int level, iid = 0; char *iface = var_CreateGetNonEmptyString (obj, "miface"); if (iface != NULL) { iid = if_nametoindex (iface); if (iid == 0) { msg_Err (obj, "invalid multicast interface: %s", iface); free (iface); return -1; } free (iface); } switch (grp->sa_family) {#ifdef AF_INET6 case AF_INET6: level = SOL_IPV6; if (((const struct sockaddr_in6 *)grp)->sin6_scope_id) iid = ((const struct sockaddr_in6 *)grp)->sin6_scope_id; break;#endif case AF_INET: level = SOL_IP; break; default: errno = EAFNOSUPPORT; return -1; } if (src != NULL) switch (src->sa_family) {#ifdef AF_INET6 case AF_INET6: if (memcmp (&((const struct sockaddr_in6 *)src)->sin6_addr, &in6addr_any, sizeof (in6addr_any)) == 0) src = NULL; break;#endif case AF_INET: if (((const struct sockaddr_in *)src)->sin_addr.s_addr == INADDR_ANY) src = NULL; break; } /* Agnostic ASM/SSM multicast join */#ifdef MCAST_JOIN_SOURCE_GROUP union { struct group_req gr; struct group_source_req gsr; } opt; socklen_t optlen; memset (&opt, 0, sizeof (opt)); if (src != NULL) { if ((grplen > sizeof (opt.gsr.gsr_group)) || (srclen > sizeof (opt.gsr.gsr_source))) return -1; opt.gsr.gsr_interface = iid; memcpy (&opt.gsr.gsr_source, src, srclen); memcpy (&opt.gsr.gsr_group, grp, grplen); optlen = sizeof (opt.gsr); } else { if (grplen > sizeof (opt.gr.gr_group)) return -1; opt.gr.gr_interface = iid; memcpy (&opt.gr.gr_group, grp, grplen); optlen = sizeof (opt.gr); } msg_Dbg (obj, "Multicast %sgroup join request", src ? "source " : ""); if (setsockopt (fd, level, src ? MCAST_JOIN_SOURCE_GROUP : MCAST_JOIN_GROUP, (void *)&opt, optlen) == 0) return 0;#endif /* Fallback to IPv-specific APIs */ if ((src != NULL) && (src->sa_family != grp->sa_family)) return -1; switch (grp->sa_family) { case AF_INET: if ((grplen < sizeof (struct sockaddr_in)) || ((src != NULL) && (srclen < sizeof (struct sockaddr_in)))) return -1; if (net_IPv4Join (obj, fd, (const struct sockaddr_in *)src, (const struct sockaddr_in *)grp) == 0) return 0; break;#ifdef AF_INET6 case AF_INET6: if ((grplen < sizeof (struct sockaddr_in6)) || ((src != NULL) && (srclen < sizeof (struct sockaddr_in6)))) return -1; /* IPv6-specific SSM API does not exist. So if we're here * it means IPv6 SSM is not supported on this OS and we * directly fallback to ASM */ if (net_IPv6Join (obj, fd, (const struct sockaddr_in6 *)grp) == 0) return 0; break;#endif } msg_Err (obj, "Multicast group join error (%m)"); if (src != NULL) { msg_Warn (obj, "Trying ASM instead of SSM..."); return net_Subscribe (obj, fd, grp, grplen); } msg_Err (obj, "Multicast not supported"); return -1;}int net_Subscribe (vlc_object_t *obj, int fd, const struct sockaddr *addr, socklen_t addrlen){ return net_SourceSubscribe (obj, fd, NULL, 0, addr, addrlen);}static int net_SetDSCP( int fd, uint8_t dscp ){ struct sockaddr_storage addr; if( getsockname( fd, (struct sockaddr *)&addr, &(socklen_t){ sizeof (addr) }) ) return -1; int level, cmd; switch( addr.ss_family ) {#ifdef IPV6_TCLASS case AF_INET6: level = SOL_IPV6; cmd = IPV6_TCLASS; break;#endif case AF_INET: level = SOL_IP; cmd = IP_TOS; break; default:#ifdef ENOPROTOOPT errno = ENOPROTOOPT;#endif return -1; } return setsockopt( fd, level, cmd, &(int){ dscp }, sizeof (int));}/***************************************************************************** * __net_ConnectDgram: ***************************************************************************** * Open a datagram socket to send data to a defined destination, with an * optional hop limit. *****************************************************************************/int __net_ConnectDgram( vlc_object_t *p_this, const char *psz_host, int i_port, int i_hlim, int proto ){ struct addrinfo hints, *res, *ptr; int i_val, i_handle = -1; bool b_unreach = false; if( i_hlim < 1 ) i_hlim = var_CreateGetInteger( p_this, "ttl" ); memset( &hints, 0, sizeof( hints ) ); hints.ai_socktype = SOCK_DGRAM; msg_Dbg( p_this, "net: connecting to [%s]:%d", psz_host, i_port ); i_val = vlc_getaddrinfo( p_this, psz_host, i_port, &hints, &res ); if( i_val ) { msg_Err( p_this, "cannot resolve [%s]:%d : %s", psz_host, i_port, vlc_gai_strerror( i_val ) ); return -1; } for( ptr = res; ptr != NULL; ptr = ptr->ai_next ) { char *str; int fd = net_Socket (p_this, ptr->ai_family, ptr->ai_socktype, proto ?: ptr->ai_protocol); if (fd == -1) continue;#if !defined( SYS_BEOS ) /* Increase the receive buffer size to 1/2MB (8Mb/s during 1/2s) * to avoid packet loss caused by scheduling problems */ setsockopt (fd, SOL_SOCKET, SO_RCVBUF, &(int){ 0x80000 }, sizeof (int)); setsockopt (fd, SOL_SOCKET, SO_SNDBUF, &(int){ 0x80000 }, sizeof (int)); /* Allow broadcast sending */ setsockopt (fd, SOL_SOCKET, SO_BROADCAST, &(int){ 1 }, sizeof (int));#endif if( i_hlim > 0 ) net_SetMcastHopLimit( p_this, fd, ptr->ai_family, i_hlim ); str = var_CreateGetNonEmptyString (p_this, "miface"); if (str != NULL) { net_SetMcastOut (p_this, fd, ptr->ai_family, str, NULL); free (str); } str = var_CreateGetNonEmptyString (p_this, "miface-addr"); if (str != NULL) { net_SetMcastOut (p_this, fd, ptr->ai_family, NULL, str); free (str); } net_SetDSCP (fd, var_CreateGetInteger (p_this, "dscp")); if( connect( fd, ptr->ai_addr, ptr->ai_addrlen ) == 0 ) { /* success */ i_handle = fd; break; }#if defined( WIN32 ) || defined( UNDER_CE ) if( WSAGetLastError () == WSAENETUNREACH )#else if( errno == ENETUNREACH )#endif b_unreach = true; else { msg_Warn( p_this, "%s port %d : %m", psz_host, i_port); net_Close( fd ); continue; } } vlc_freeaddrinfo( res ); if( i_handle == -1 ) { if( b_unreach ) msg_Err( p_this, "Host %s port %d is unreachable", psz_host, i_port ); return -1; } return i_handle;}/***************************************************************************** * __net_OpenDgram: ***************************************************************************** * OpenDgram a datagram socket and return a handle *****************************************************************************/int __net_OpenDgram( vlc_object_t *obj, const char *psz_bind, int i_bind, const char *psz_server, int i_server, int family, int protocol ){ if ((psz_server == NULL) || (psz_server[0] == '\0')) return net_ListenSingle (obj, psz_bind, i_bind, family, protocol); msg_Dbg (obj, "net: connecting to [%s]:%d from [%s]:%d", psz_server, i_server, psz_bind, i_bind); struct addrinfo hints, *loc, *rem; int val; memset (&hints, 0, sizeof (hints)); hints.ai_family = family; hints.ai_socktype = SOCK_DGRAM; val = vlc_getaddrinfo (obj, psz_server, i_server, &hints, &rem); if (val) { msg_Err (obj, "cannot resolve %s port %d : %s", psz_bind, i_bind, vlc_gai_strerror (val)); return -1; } hints.ai_flags = AI_PASSIVE; val = vlc_getaddrinfo (obj, psz_bind, i_bind, &hints, &loc); if (val) { msg_Err (obj, "cannot resolve %s port %d : %s", psz_bind, i_bind, vlc_gai_strerror (val)); vlc_freeaddrinfo (rem); return -1; } for (struct addrinfo *ptr = loc; ptr != NULL; ptr = ptr->ai_next) { int fd = net_Socket (obj, ptr->ai_family, ptr->ai_socktype, protocol ?: ptr->ai_protocol); if (fd == -1) continue; // usually, address family not supported fd = net_SetupDgramSocket( obj, fd, ptr ); if( fd == -1 ) continue; val = -1; for (struct addrinfo *ptr2 = rem; ptr2 != NULL; ptr2 = ptr2->ai_next) { if ((ptr2->ai_family != ptr->ai_family) || (ptr2->ai_socktype != ptr->ai_socktype) || (ptr2->ai_protocol != ptr->ai_protocol)) continue; if (net_SockAddrIsMulticast (ptr->ai_addr, ptr->ai_addrlen) ? net_SourceSubscribe (obj, fd, ptr2->ai_addr, ptr2->ai_addrlen, ptr->ai_addr, ptr->ai_addrlen) : connect (fd, ptr2->ai_addr, ptr2->ai_addrlen)) { msg_Err (obj, "cannot connect to %s port %d: %m", psz_server, i_server); continue; } val = fd; break; } if (val != -1) break; net_Close (fd); } vlc_freeaddrinfo (rem); vlc_freeaddrinfo (loc); return val;}/** * net_SetCSCov: * Sets the send and receive checksum coverage of a socket: * @param fd socket * @param sendcov payload coverage of sent packets (bytes), -1 for full * @param recvcov minimum payload coverage of received packets, -1 for full */int net_SetCSCov (int fd, int sendcov, int recvcov){ int type; if (getsockopt (fd, SOL_SOCKET, SO_TYPE, &type, &(socklen_t){ sizeof (type) })) return VLC_EGENERIC; switch (type) {#ifdef UDPLITE_RECV_CSCOV case SOCK_DGRAM: /* UDP-Lite */ if (sendcov == -1) sendcov = 0; else sendcov += 8; /* partial */ if (setsockopt (fd, SOL_UDPLITE, UDPLITE_SEND_CSCOV, &sendcov, sizeof (sendcov))) return VLC_EGENERIC; if (recvcov == -1) recvcov = 0; else recvcov += 8; if (setsockopt (fd, SOL_UDPLITE, UDPLITE_RECV_CSCOV, &recvcov, sizeof (recvcov))) return VLC_EGENERIC; return VLC_SUCCESS;#endif#ifdef DCCP_SOCKOPT_SEND_CSCOV case SOCK_DCCP: /* DCCP and its ill-named socket type */ if ((sendcov == -1) || (sendcov > 56)) sendcov = 0; else sendcov = (sendcov + 3) / 4; if (setsockopt (fd, SOL_DCCP, DCCP_SOCKOPT_SEND_CSCOV, &sendcov, sizeof (sendcov))) return VLC_EGENERIC; if ((recvcov == -1) || (recvcov > 56)) recvcov = 0; else recvcov = (recvcov + 3) / 4; if (setsockopt (fd, SOL_DCCP, DCCP_SOCKOPT_RECV_CSCOV, &recvcov, sizeof (recvcov))) return VLC_EGENERIC; return VLC_SUCCESS;#endif }#if !defined( UDPLITE_RECV_CSCOV ) && !defined( DCCP_SOCKOPT_SEND_CSCOV ) VLC_UNUSED(sendcov); VLC_UNUSED(recvcov);#endif return VLC_EGENERIC;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -