int route_get(route_t *route, struct route_entry *entry) { MIB_IPFORWARDROW ipfrow; DWORD mask; if (entry->route_dst.addr_type != ADDR_TYPE_IP || GetBestRoute(entry->route_dst.addr_ip, IP_ADDR_ANY, &ipfrow) != NO_ERROR) return (-1); if (ipfrow.dwForwardProto == 2 && /* XXX - MIB_IPPROTO_LOCAL */ (ipfrow.dwForwardNextHop|IP_CLASSA_NET) != (IP_ADDR_LOOPBACK|IP_CLASSA_NET) && !IP_LOCAL_GROUP(ipfrow.dwForwardNextHop)) { errno = ENXIO; SetLastError(ERROR_NO_DATA); return (-1); } addr_btom(entry->route_dst.addr_bits, &mask, IP_ADDR_LEN); entry->route_gw.addr_type = ADDR_TYPE_IP; entry->route_gw.addr_bits = IP_ADDR_BITS; entry->route_gw.addr_ip = ipfrow.dwForwardNextHop; return (0); }
static int scamper_rtsock_getroute4(scamper_route_t *route) { struct in_addr *in = route->dst->addr; MIB_IPFORWARDROW fw; DWORD dw; if((dw = GetBestRoute(in->s_addr, 0, &fw)) != NO_ERROR) { route->error = dw; return -1; } route->ifindex = fw.dwForwardIfIndex; /* determine the gateway address to use, if one is specified */ if((dw = fw.dwForwardNextHop) != 0) { if((route->gw = scamper_addrcache_get_ipv4(addrcache, &dw)) == NULL) { route->error = errno; return -1; } } return 0; }
int getdefaultgateway(in_addr_t *addr) { MIB_IPFORWARDROW ip_forward = {0}; if(GetBestRoute(inet_addr("0.0.0.0"), 0, &ip_forward) != NO_ERROR) return -1; *addr = ip_forward.dwForwardNextHop; return 0; }
static void win32_log_interface_type(struct rtmp_stream *stream) { RTMP *rtmp = &stream->rtmp; MIB_IPFORWARDROW route; uint32_t dest_addr, source_addr; char hostname[256]; HOSTENT *h; if (rtmp->Link.hostname.av_len >= sizeof(hostname) - 1) return; strncpy(hostname, rtmp->Link.hostname.av_val, sizeof(hostname)); hostname[rtmp->Link.hostname.av_len] = 0; h = gethostbyname(hostname); if (!h) return; dest_addr = *(uint32_t*)h->h_addr_list[0]; if (rtmp->m_bindIP.addrLen == 0) source_addr = 0; else if (rtmp->m_bindIP.addr.ss_family = AF_INET) source_addr = (*(struct sockaddr_in*)&rtmp->m_bindIP) .sin_addr.S_un.S_addr; else return; if (!GetBestRoute(dest_addr, source_addr, &route)) { MIB_IFROW row; memset(&row, 0, sizeof(row)); row.dwIndex = route.dwForwardIfIndex; if (!GetIfEntry(&row)) { uint32_t speed =row.dwSpeed / 1000000; char *type; struct dstr other = {0}; if (row.dwType == IF_TYPE_ETHERNET_CSMACD) { type = "ethernet"; } else if (row.dwType == IF_TYPE_IEEE80211) { type = "802.11"; } else { dstr_printf(&other, "type %lu", row.dwType); type = other.array; } info("Interface: %s (%s, %lu mbps)", row.bDescr, type, speed); dstr_free(&other); } } }
// for a given destination address - return the local endpoint address and the gateway address that // will be used for a connection to the destination. // if the local address and the gateway address are the same then the destination is on a local network. void getRouteInfo (net::InetAddress destination, net::InetAddress& localAddr, net::InetAddress& gatewayAddr) { MIB_IPFORWARDROW routeInfo; DWORD res = GetBestRoute(htonl(destination.getIPAddress()), 0, &routeInfo); if (res != NO_ERROR) throw PacketException ("getRouteInfo: Error"); gatewayAddr.set(ntohl(routeInfo.dwForwardNextHop), 0); destination.setPortNumber(123); net::Socket s(SOCK_DGRAM); s.connect(destination); localAddr = s.getLocalAddress(); }
static Boolean ssh_ip_route_lookup_ipv4( SshIpAddr destination, DWORD *ifindex, SshIpAddr nexthop, DWORD *mtu) { DWORD d, error; MIB_IPFORWARDROW ifr; SSH_IP4_ENCODE(destination, &d); error = GetBestRoute(d, 0, &ifr); if (error != NO_ERROR) { if (error == ERROR_CAN_NOT_COMPLETE) { SSH_DEBUG(SSH_D_LOWOK, ("No route found")); return FALSE; } else { SSH_DEBUG(SSH_D_FAIL, ("GetBestRoute: error 0x%08X", (unsigned)error)); return FALSE; } } /* Do not consider local routes via loopback interfaces. */ if (ifr.dwForwardProto == MIB_IPPROTO_LOCAL && (ifr.dwForwardDest & ifr.dwForwardMask) != (ifr.dwForwardNextHop & ifr.dwForwardMask)) { SSH_DEBUG(SSH_D_LOWOK, ("Ignoring loopback route")); return FALSE; } *ifindex = ifr.dwForwardIfIndex; /* For directly connected destinatinations report the destination as the next hop. */ if (ifr.dwForwardType == MIB_IPROUTE_TYPE_DIRECT) SSH_IP4_DECODE(nexthop, &d); else SSH_IP4_DECODE(nexthop, &ifr.dwForwardNextHop); /* No route MTU; use link MTU. */ *mtu = 0; return TRUE; }
int SSDP_sendRequest(int s, uint32 ip, uint16 port, const CString& request) { char buffer[10240]; const CStringA sa(request); int length = sa.GetLength(); strcpy(buffer, (const char*)sa); struct sockaddr_in sockaddr; memset(&sockaddr, 0, sizeof(sockaddr)); sockaddr.sin_family = AF_INET; sockaddr.sin_port = htons(port); MIB_IPFORWARDROW ip_forward; if ( GetBestRoute(inet_addr("223.255.255.255"), 0, &ip_forward) != NO_ERROR) return 0; sockaddr.sin_addr.S_un.S_addr = ip_forward.dwForwardNextHop; return sendto(s, buffer, length, 0, (struct sockaddr *)&sockaddr, sizeof(sockaddr)); }
void LogInterfaceType (RTMP *rtmp) { MIB_IPFORWARDROW route; DWORD destAddr; CHAR hostname[256]; if (rtmp->Link.hostname.av_len >= sizeof(hostname)-1) return; strncpy (hostname, rtmp->Link.hostname.av_val, sizeof(hostname)-1); hostname[rtmp->Link.hostname.av_len] = 0; HOSTENT *h = gethostbyname(hostname); if (!h) return; destAddr = *(DWORD *)h->h_addr_list[0]; if (!GetBestRoute (destAddr, rtmp->m_bindIP.addr.sin_addr.S_un.S_addr, &route)) { MIB_IFROW row; zero (&row, sizeof(row)); row.dwIndex = route.dwForwardIfIndex; if (!GetIfEntry (&row)) { DWORD speed = row.dwSpeed / 1000000; TCHAR *type; String otherType; if (row.dwType == IF_TYPE_ETHERNET_CSMACD) type = TEXT("ethernet"); else if (row.dwType == IF_TYPE_IEEE80211) type = TEXT("802.11"); else { otherType = FormattedString (TEXT("type %d"), row.dwType); type = otherType.Array(); } Log (TEXT(" Interface: %S (%s, %d mbps)"), row.bDescr, type, speed); } } }
int route_delete(route_t *route, const struct route_entry *entry) { MIB_IPFORWARDROW ipfrow; DWORD mask; if (entry->route_dst.addr_type != ADDR_TYPE_IP || GetBestRoute(entry->route_dst.addr_ip, IP_ADDR_ANY, &ipfrow) != NO_ERROR) return (-1); addr_btom(entry->route_dst.addr_bits, &mask, IP_ADDR_LEN); if (ipfrow.dwForwardDest != entry->route_dst.addr_ip || ipfrow.dwForwardMask != mask) { errno = ENXIO; SetLastError(ERROR_NO_DATA); return (-1); } if (DeleteIpForwardEntry(&ipfrow) != NO_ERROR) return (-1); return (0); }
/* ssdpDiscoverDevices() : * return a chained list of all devices found or NULL if * no devices was found. * It is up to the caller to free the chained list * delay is in millisecond (poll). * UDA v1.1 says : * The TTL for the IP packet SHOULD default to 2 and * SHOULD be configurable. */ struct UPNPDev * ssdpDiscoverDevices(const char * const deviceTypes[], int delay, const char * multicastif, int localport, int ipv6, unsigned char ttl, int * error, int searchalltypes) { struct UPNPDev * tmp; struct UPNPDev * devlist = 0; unsigned int scope_id = 0; int opt = 1; static const char MSearchMsgFmt[] = "M-SEARCH * HTTP/1.1\r\n" "HOST: %s:" XSTR(SSDP_PORT) "\r\n" "ST: %s\r\n" "MAN: \"ssdp:discover\"\r\n" "MX: %u\r\n" "\r\n"; int deviceIndex; char bufr[1536]; /* reception and emission buffer */ int sudp; int n; struct sockaddr_storage sockudp_r; unsigned int mx; #ifdef NO_GETADDRINFO struct sockaddr_storage sockudp_w; #else int rv; struct addrinfo hints, *servinfo, *p; #endif #ifdef _WIN32 MIB_IPFORWARDROW ip_forward; unsigned long _ttl = (unsigned long)ttl; #endif int linklocal = 1; if(error) *error = MINISSDPC_UNKNOWN_ERROR; if(localport==UPNP_LOCAL_PORT_SAME) localport = SSDP_PORT; #ifdef _WIN32 sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, IPPROTO_UDP); #else sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0); #endif if(sudp < 0) { if(error) *error = MINISSDPC_SOCKET_ERROR; return NULL; } /* reception */ memset(&sockudp_r, 0, sizeof(struct sockaddr_storage)); if(ipv6) { struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_r; p->sin6_family = AF_INET6; if(localport > 0 && localport < 65536) p->sin6_port = htons((unsigned short)localport); p->sin6_addr = in6addr_any; /* in6addr_any is not available with MinGW32 3.4.2 */ } else { struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_r; p->sin_family = AF_INET; if(localport > 0 && localport < 65536) p->sin_port = htons((unsigned short)localport); p->sin_addr.s_addr = INADDR_ANY; } #ifdef _WIN32 /* This code could help us to use the right Network interface for * SSDP multicast traffic */ /* Get IP associated with the index given in the ip_forward struct * in order to give this ip to setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF) */ if(!ipv6 && (GetBestRoute(inet_addr("223.255.255.255"), 0, &ip_forward) == NO_ERROR)) { DWORD dwRetVal = 0; PMIB_IPADDRTABLE pIPAddrTable; DWORD dwSize = 0; #ifdef DEBUG IN_ADDR IPAddr; #endif int i; #ifdef DEBUG printf("ifIndex=%lu nextHop=%lx \n", ip_forward.dwForwardIfIndex, ip_forward.dwForwardNextHop); #endif pIPAddrTable = (MIB_IPADDRTABLE *) malloc(sizeof (MIB_IPADDRTABLE)); if(pIPAddrTable) { if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) { free(pIPAddrTable); pIPAddrTable = (MIB_IPADDRTABLE *) malloc(dwSize); } } if(pIPAddrTable) { dwRetVal = GetIpAddrTable( pIPAddrTable, &dwSize, 0 ); if (dwRetVal == NO_ERROR) { #ifdef DEBUG printf("\tNum Entries: %ld\n", pIPAddrTable->dwNumEntries); #endif for (i=0; i < (int) pIPAddrTable->dwNumEntries; i++) { #ifdef DEBUG printf("\n\tInterface Index[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwIndex); IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwAddr; printf("\tIP Address[%d]: \t%s\n", i, inet_ntoa(IPAddr) ); IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwMask; printf("\tSubnet Mask[%d]: \t%s\n", i, inet_ntoa(IPAddr) ); IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwBCastAddr; printf("\tBroadCast[%d]: \t%s (%ld)\n", i, inet_ntoa(IPAddr), pIPAddrTable->table[i].dwBCastAddr); printf("\tReassembly size[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwReasmSize); printf("\tType and State[%d]:", i); printf("\n"); #endif if (pIPAddrTable->table[i].dwIndex == ip_forward.dwForwardIfIndex) { /* Set the address of this interface to be used */ struct in_addr mc_if; memset(&mc_if, 0, sizeof(mc_if)); mc_if.s_addr = pIPAddrTable->table[i].dwAddr; setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)); ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = pIPAddrTable->table[i].dwAddr; #ifndef DEBUG break; #endif } } } free(pIPAddrTable); pIPAddrTable = NULL; } } #endif /* _WIN32 */ #ifdef _WIN32 if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof (opt)) < 0) #else if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)) < 0) #endif { if(error) *error = MINISSDPC_SOCKET_ERROR; closesocket(sudp); return NULL; } #ifdef _WIN32 if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_TTL, (const char *)&_ttl, sizeof(_ttl)) < 0) #else /* _WIN32 */ if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) #endif /* _WIN32 */ { /* not a fatal error */ } if(multicastif) { if(ipv6) { #if !defined(_WIN32) /* according to MSDN, if_nametoindex() is supported since * MS Windows Vista and MS Windows Server 2008. * http://msdn.microsoft.com/en-us/library/bb408409%28v=vs.85%29.aspx */ unsigned int ifindex = if_nametoindex(multicastif); /* eth0, etc. */ if(setsockopt(sudp, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex)) < 0) { } #else #ifdef DEBUG printf("Setting of multicast interface not supported in IPv6 under Windows.\n"); #endif #endif } else { struct in_addr mc_if; mc_if.s_addr = inet_addr(multicastif); /* ex: 192.168.x.x */ if(mc_if.s_addr != INADDR_NONE) { ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = mc_if.s_addr; if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) { } } else { #ifdef HAS_IP_MREQN /* was not an ip address, try with an interface name */ struct ip_mreqn reqn; /* only defined with -D_BSD_SOURCE or -D_GNU_SOURCE */ memset(&reqn, 0, sizeof(struct ip_mreqn)); reqn.imr_ifindex = if_nametoindex(multicastif); if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&reqn, sizeof(reqn)) < 0) { } #elif !defined(_WIN32) struct ifreq ifr; int ifrlen = sizeof(ifr); strncpy(ifr.ifr_name, multicastif, IFNAMSIZ); ifr.ifr_name[IFNAMSIZ-1] = '\0'; if(ioctl(sudp, SIOCGIFADDR, &ifr, &ifrlen) < 0) { } mc_if.s_addr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr; if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) { } #else /* _WIN32 */ #ifdef DEBUG printf("Setting of multicast interface not supported with interface name.\n"); #endif #endif /* #ifdef HAS_IP_MREQN / !defined(_WIN32) */ } } } /* Before sending the packed, we first "bind" in order to be able * to receive the response */ if (bind(sudp, (const struct sockaddr *)&sockudp_r, ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) != 0) { if(error) *error = MINISSDPC_SOCKET_ERROR; closesocket(sudp); return NULL; } if(error) *error = MINISSDPC_SUCCESS; /* Calculating maximum response time in seconds */ mx = ((unsigned int)delay) / 1000u; if(mx == 0) { mx = 1; delay = 1000; } /* receiving SSDP response packet */ for(deviceIndex = 0; deviceTypes[deviceIndex]; deviceIndex++) { /* sending the SSDP M-SEARCH packet */ n = snprintf(bufr, sizeof(bufr), MSearchMsgFmt, ipv6 ? (linklocal ? "[" UPNP_MCAST_LL_ADDR "]" : "[" UPNP_MCAST_SL_ADDR "]") : UPNP_MCAST_ADDR, deviceTypes[deviceIndex], mx); if ((unsigned int)n >= sizeof(bufr)) { if(error) *error = MINISSDPC_MEMORY_ERROR; goto error; } #ifdef DEBUG /*printf("Sending %s", bufr);*/ printf("Sending M-SEARCH request to %s with ST: %s\n", ipv6 ? (linklocal ? "[" UPNP_MCAST_LL_ADDR "]" : "[" UPNP_MCAST_SL_ADDR "]") : UPNP_MCAST_ADDR, deviceTypes[deviceIndex]); #endif #ifdef NO_GETADDRINFO /* the following code is not using getaddrinfo */ /* emission */ memset(&sockudp_w, 0, sizeof(struct sockaddr_storage)); if(ipv6) { struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_w; p->sin6_family = AF_INET6; p->sin6_port = htons(SSDP_PORT); inet_pton(AF_INET6, linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR, &(p->sin6_addr)); } else { struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_w; p->sin_family = AF_INET; p->sin_port = htons(SSDP_PORT); p->sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR); } n = sendto(sudp, bufr, n, 0, &sockudp_w, ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)); if (n < 0) { if(error) *error = MINISSDPC_SOCKET_ERROR; break; } #else /* #ifdef NO_GETADDRINFO */ memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; /* AF_INET6 or AF_INET */ hints.ai_socktype = SOCK_DGRAM; /*hints.ai_flags = */ if ((rv = getaddrinfo_retro(ipv6 ? (linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR) : UPNP_MCAST_ADDR, XSTR(SSDP_PORT), &hints, &servinfo)) != 0) { if(error) *error = MINISSDPC_SOCKET_ERROR; #ifdef _WIN32 fprintf(stderr, "getaddrinfo() failed: %d\n", rv); #else fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); #endif break; } for(p = servinfo; p; p = p->ai_next) { n = (int)sendto(sudp, bufr, n, 0, p->ai_addr, p->ai_addrlen); if (n < 0) { #ifdef DEBUG char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; if (getnameinfo(p->ai_addr, p->ai_addrlen, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV) == 0) { fprintf(stderr, "host:%s port:%s\n", hbuf, sbuf); } #endif continue; } } freeaddrinfo(servinfo); if(n < 0) { if(error) *error = MINISSDPC_SOCKET_ERROR; break; } #endif /* #ifdef NO_GETADDRINFO */ /* Waiting for SSDP REPLY packet to M-SEARCH * if searchalltypes is set, enter the loop only * when the last deviceType is reached */ if(!searchalltypes || !deviceTypes[deviceIndex + 1]) do { n = receivedata(sudp, bufr, sizeof(bufr), delay, &scope_id); if (n < 0) { /* error */ if(error) *error = MINISSDPC_SOCKET_ERROR; goto error; } else if (n == 0) { /* no data or Time Out */ #ifdef DEBUG printf("NODATA or TIMEOUT\n"); #endif /* DEBUG */ if (devlist && !searchalltypes) { /* found some devices, stop now*/ if(error) *error = MINISSDPC_SUCCESS; goto error; } } else { const char * descURL=NULL; int urlsize=0; const char * st=NULL; int stsize=0; const char * usn=NULL; int usnsize=0; parseMSEARCHReply(bufr, n, &descURL, &urlsize, &st, &stsize, &usn, &usnsize); if(st&&descURL) { #ifdef DEBUG printf("M-SEARCH Reply:\n ST: %.*s\n USN: %.*s\n Location: %.*s\n", stsize, st, usnsize, (usn?usn:""), urlsize, descURL); #endif /* DEBUG */ for(tmp=devlist; tmp; tmp = tmp->pNext) { if(memcmp(tmp->descURL, descURL, urlsize) == 0 && tmp->descURL[urlsize] == '\0' && memcmp(tmp->st, st, stsize) == 0 && tmp->st[stsize] == '\0' && (usnsize == 0 || memcmp(tmp->usn, usn, usnsize) == 0) && tmp->usn[usnsize] == '\0') break; } /* at the exit of the loop above, tmp is null if * no duplicate device was found */ if(tmp) continue; tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize+usnsize); if(!tmp) { /* memory allocation error */ if(error) *error = MINISSDPC_MEMORY_ERROR; goto error; } tmp->pNext = devlist; tmp->descURL = tmp->buffer; tmp->st = tmp->buffer + 1 + urlsize; tmp->usn = tmp->st + 1 + stsize; memcpy(tmp->buffer, descURL, urlsize); tmp->buffer[urlsize] = '\0'; memcpy(tmp->st, st, stsize); tmp->buffer[urlsize+1+stsize] = '\0'; if(usn != NULL) memcpy(tmp->usn, usn, usnsize); tmp->buffer[urlsize+1+stsize+1+usnsize] = '\0'; tmp->scope_id = scope_id; devlist = tmp; } } } while(n > 0); if(ipv6) { /* switch linklocal flag */ if(linklocal) { linklocal = 0; --deviceIndex; } else { linklocal = 1; } } } error: closesocket(sudp); return devlist; }
/* upnpDiscover() : * return a chained list of all devices found or NULL if * no devices was found. * It is up to the caller to free the chained list * delay is in millisecond (poll) */ LIBSPEC struct UPNPDev * upnpDiscover(int delay, const char * multicastif, const char * minissdpdsock, int sameport, int ipv6, int * error) { struct UPNPDev * tmp; struct UPNPDev * devlist = 0; unsigned int scope_id = 0; int opt = 1; static const char MSearchMsgFmt[] = "M-SEARCH * HTTP/1.1\r\n" "HOST: %s:" XSTR(PORT) "\r\n" "ST: %s\r\n" "MAN: \"ssdp:discover\"\r\n" "MX: %u\r\n" "\r\n"; static const char * const deviceList[] = { #if 0 "urn:schemas-upnp-org:device:InternetGatewayDevice:2", "urn:schemas-upnp-org:service:WANIPConnection:2", #endif "urn:schemas-upnp-org:device:InternetGatewayDevice:1", "urn:schemas-upnp-org:service:WANIPConnection:1", "urn:schemas-upnp-org:service:WANPPPConnection:1", "upnp:rootdevice", 0 }; int deviceIndex = 0; char bufr[1536]; /* reception and emission buffer */ int sudp; int n; struct sockaddr_storage sockudp_r; unsigned int mx; #ifdef NO_GETADDRINFO struct sockaddr_storage sockudp_w; #else int rv; struct addrinfo hints, *servinfo, *p; #endif #ifdef _WIN32 MIB_IPFORWARDROW ip_forward; #endif int linklocal = 1; if(error) *error = UPNPDISCOVER_UNKNOWN_ERROR; /* fallback to direct discovery */ #ifdef _WIN32 sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, IPPROTO_UDP); #else sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0); #endif if(sudp < 0) { if(error) *error = UPNPDISCOVER_SOCKET_ERROR; PRINT_SOCKET_ERROR("socket"); return NULL; } /* reception */ memset(&sockudp_r, 0, sizeof(struct sockaddr_storage)); if(ipv6) { struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_r; p->sin6_family = AF_INET6; if(sameport) p->sin6_port = htons(PORT); p->sin6_addr = in6addr_any; /* in6addr_any is not available with MinGW32 3.4.2 */ } else { struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_r; p->sin_family = AF_INET; if(sameport) p->sin_port = htons(PORT); p->sin_addr.s_addr = INADDR_ANY; } #ifdef _WIN32 /* This code could help us to use the right Network interface for * SSDP multicast traffic */ /* Get IP associated with the index given in the ip_forward struct * in order to give this ip to setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF) */ if(!ipv6 && (GetBestRoute(inet_addr("223.255.255.255"), 0, &ip_forward) == NO_ERROR)) { DWORD dwRetVal = 0; PMIB_IPADDRTABLE pIPAddrTable; DWORD dwSize = 0; #ifdef DEBUG IN_ADDR IPAddr; #endif int i; #ifdef DEBUG printf("ifIndex=%lu nextHop=%lx \n", ip_forward.dwForwardIfIndex, ip_forward.dwForwardNextHop); #endif pIPAddrTable = (MIB_IPADDRTABLE *) malloc(sizeof (MIB_IPADDRTABLE)); if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) { free(pIPAddrTable); pIPAddrTable = (MIB_IPADDRTABLE *) malloc(dwSize); } if(pIPAddrTable) { dwRetVal = GetIpAddrTable( pIPAddrTable, &dwSize, 0 ); #ifdef DEBUG printf("\tNum Entries: %ld\n", pIPAddrTable->dwNumEntries); #endif for (i=0; i < (int) pIPAddrTable->dwNumEntries; i++) { #ifdef DEBUG printf("\n\tInterface Index[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwIndex); IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwAddr; printf("\tIP Address[%d]: \t%s\n", i, inet_ntoa(IPAddr) ); IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwMask; printf("\tSubnet Mask[%d]: \t%s\n", i, inet_ntoa(IPAddr) ); IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwBCastAddr; printf("\tBroadCast[%d]: \t%s (%ld)\n", i, inet_ntoa(IPAddr), pIPAddrTable->table[i].dwBCastAddr); printf("\tReassembly size[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwReasmSize); printf("\tType and State[%d]:", i); printf("\n"); #endif if (pIPAddrTable->table[i].dwIndex == ip_forward.dwForwardIfIndex) { /* Set the address of this interface to be used */ struct in_addr mc_if; memset(&mc_if, 0, sizeof(mc_if)); mc_if.s_addr = pIPAddrTable->table[i].dwAddr; if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) { PRINT_SOCKET_ERROR("setsockopt"); } ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = pIPAddrTable->table[i].dwAddr; #ifndef DEBUG break; #endif } } free(pIPAddrTable); pIPAddrTable = NULL; } } #endif #ifdef _WIN32 if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof (opt)) < 0) #else if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)) < 0) #endif { if(error) *error = UPNPDISCOVER_SOCKET_ERROR; PRINT_SOCKET_ERROR("setsockopt"); return NULL; } if(multicastif) { if(ipv6) { #if !defined(_WIN32) /* according to MSDN, if_nametoindex() is supported since * MS Windows Vista and MS Windows Server 2008. * http://msdn.microsoft.com/en-us/library/bb408409%28v=vs.85%29.aspx */ unsigned int ifindex = if_nametoindex(multicastif); /* eth0, etc. */ if(setsockopt(sudp, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(&ifindex)) < 0) { PRINT_SOCKET_ERROR("setsockopt"); } #else #ifdef DEBUG printf("Setting of multicast interface not supported in IPv6 under Windows.\n"); #endif #endif } else { struct in_addr mc_if; mc_if.s_addr = inet_addr(multicastif); /* ex: 192.168.x.x */ if(mc_if.s_addr != INADDR_NONE) { ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = mc_if.s_addr; if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) { PRINT_SOCKET_ERROR("setsockopt"); } } else { #ifdef HAS_IP_MREQN /* was not an ip address, try with an interface name */ struct ip_mreqn reqn; /* only defined with -D_BSD_SOURCE or -D_GNU_SOURCE */ memset(&reqn, 0, sizeof(struct ip_mreqn)); reqn.imr_ifindex = if_nametoindex(multicastif); if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&reqn, sizeof(reqn)) < 0) { PRINT_SOCKET_ERROR("setsockopt"); } #else #ifdef DEBUG printf("Setting of multicast interface not supported with interface name.\n"); #endif #endif } } } /* Avant d'envoyer le paquet on bind pour recevoir la reponse */ if (bind(sudp, (const struct sockaddr *)&sockudp_r, ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) != 0) { if(error) *error = UPNPDISCOVER_SOCKET_ERROR; PRINT_SOCKET_ERROR("bind"); closesocket(sudp); return NULL; } if(error) *error = UPNPDISCOVER_SUCCESS; /* Calculating maximum response time in seconds */ mx = ((unsigned int)delay) / 1000u; /* receiving SSDP response packet */ for(n = 0; deviceList[deviceIndex]; deviceIndex++) { if(n == 0) { /* sending the SSDP M-SEARCH packet */ n = snprintf(bufr, sizeof(bufr), MSearchMsgFmt, ipv6 ? (linklocal ? "[" UPNP_MCAST_LL_ADDR "]" : "[" UPNP_MCAST_SL_ADDR "]") : UPNP_MCAST_ADDR, deviceList[deviceIndex], mx); #ifdef DEBUG printf("Sending %s", bufr); #endif #ifdef NO_GETADDRINFO /* the following code is not using getaddrinfo */ /* emission */ memset(&sockudp_w, 0, sizeof(struct sockaddr_storage)); if(ipv6) { struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_w; p->sin6_family = AF_INET6; p->sin6_port = htons(PORT); inet_pton(AF_INET6, linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR, &(p->sin6_addr)); } else { struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_w; p->sin_family = AF_INET; p->sin_port = htons(PORT); p->sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR); } n = sendto(sudp, bufr, n, 0, &sockudp_w, ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)); if (n < 0) { if(error) *error = UPNPDISCOVER_SOCKET_ERROR; PRINT_SOCKET_ERROR("sendto"); break; } #else /* #ifdef NO_GETADDRINFO */ memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; /* AF_INET6 or AF_INET */ hints.ai_socktype = SOCK_DGRAM; /*hints.ai_flags = */ if ((rv = getaddrinfo(ipv6 ? (linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR) : UPNP_MCAST_ADDR, XSTR(PORT), &hints, &servinfo)) != 0) { if(error) *error = UPNPDISCOVER_SOCKET_ERROR; #ifdef _WIN32 fprintf(stderr, "getaddrinfo() failed: %d\n", rv); #else fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); #endif break; } for(p = servinfo; p; p = p->ai_next) { n = sendto(sudp, bufr, n, 0, p->ai_addr, p->ai_addrlen); if (n < 0) { #ifdef DEBUG char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; if (getnameinfo(p->ai_addr, p->ai_addrlen, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV) == 0) { fprintf(stderr, "host:%s port:%s\n", hbuf, sbuf); } #endif PRINT_SOCKET_ERROR("sendto"); continue; } } freeaddrinfo(servinfo); if(n < 0) { if(error) *error = UPNPDISCOVER_SOCKET_ERROR; break; } #endif /* #ifdef NO_GETADDRINFO */ } /* Waiting for SSDP REPLY packet to M-SEARCH */ n = receivedata(sudp, bufr, sizeof(bufr), delay, &scope_id); if (n < 0) { /* error */ if(error) *error = UPNPDISCOVER_SOCKET_ERROR; break; } else if (n == 0) { /* no data or Time Out */ if (devlist) { /* no more device type to look for... */ if(error) *error = UPNPDISCOVER_SUCCESS; break; } if(ipv6) { if(linklocal) { linklocal = 0; --deviceIndex; } else { linklocal = 1; } } } else { const char * descURL=NULL; int urlsize=0; const char * st=NULL; int stsize=0; /*printf("%d byte(s) :\n%s\n", n, bufr);*/ /* affichage du message */ parseMSEARCHReply(bufr, n, &descURL, &urlsize, &st, &stsize); if(st&&descURL) { #ifdef DEBUG printf("M-SEARCH Reply:\nST: %.*s\nLocation: %.*s\n", stsize, st, urlsize, descURL); #endif for(tmp=devlist; tmp; tmp = tmp->pNext) { if(memcmp(tmp->descURL, descURL, urlsize) == 0 && tmp->descURL[urlsize] == '\0' && memcmp(tmp->st, st, stsize) == 0 && tmp->st[stsize] == '\0') break; } /* at the exit of the loop above, tmp is null if * no duplicate device was found */ if(tmp) continue; tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize); if(!tmp) { /* memory allocation error */ if(error) *error = UPNPDISCOVER_MEMORY_ERROR; break; } tmp->pNext = devlist; tmp->descURL = tmp->buffer; tmp->st = tmp->buffer + 1 + urlsize; memcpy(tmp->buffer, descURL, urlsize); tmp->buffer[urlsize] = '\0'; memcpy(tmp->buffer + urlsize + 1, st, stsize); tmp->buffer[urlsize+1+stsize] = '\0'; tmp->scope_id = scope_id; devlist = tmp; } } } closesocket(sudp); return devlist; }
/* upnpDiscover() : * return a chained list of all devices found or NULL if * no devices was found. * It is up to the caller to free the chained list * delay is in millisecond (poll) */ LIBSPEC struct UPNPDev * upnpDiscover(int delay, const char * multicastif, const char * minissdpdsock, int sameport) { struct UPNPDev * tmp; struct UPNPDev * devlist = 0; int opt = 1; static const char MSearchMsgFmt[] = "M-SEARCH * HTTP/1.1\r\n" "HOST: " UPNP_MCAST_ADDR ":" XSTR(PORT) "\r\n" "ST: %s\r\n" "MAN: \"ssdp:discover\"\r\n" "MX: %u\r\n" "\r\n"; static const char * const deviceList[] = { "urn:schemas-upnp-org:device:InternetGatewayDevice:1", "urn:schemas-upnp-org:service:WANIPConnection:1", "urn:schemas-upnp-org:service:WANPPPConnection:1", "upnp:rootdevice", 0 }; int deviceIndex = 0; char bufr[1536]; /* reception and emission buffer */ int sudp; int n; struct sockaddr sockudp_r; unsigned int mx; int rv; struct addrinfo hints, *servinfo, *p; #ifdef WIN32 MIB_IPFORWARDROW ip_forward; #endif #if !defined(WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) /* first try to get infos from minissdpd ! */ if(!minissdpdsock) minissdpdsock = "/var/run/minissdpd.sock"; while(!devlist && deviceList[deviceIndex]) { devlist = getDevicesFromMiniSSDPD(deviceList[deviceIndex], minissdpdsock); /* We return what we have found if it was not only a rootdevice */ if(devlist && !strstr(deviceList[deviceIndex], "rootdevice")) return devlist; deviceIndex++; } deviceIndex = 0; #endif /* fallback to direct discovery */ #ifdef WIN32 sudp = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); #else sudp = socket(PF_INET, SOCK_DGRAM, 0); #endif if(sudp < 0) { PRINT_SOCKET_ERROR("socket"); return NULL; } /* reception */ memset(&sockudp_r, 0, sizeof(struct sockaddr)); if(0/*ipv6*/) { struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_r; p->sin6_family = AF_INET6; if(sameport) p->sin6_port = htons(PORT); p->sin6_addr = in6addr_any;//IN6ADDR_ANY_INIT;/*INADDR_ANY;*/ } else { struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_r; p->sin_family = AF_INET; if(sameport) p->sin_port = htons(PORT); p->sin_addr.s_addr = INADDR_ANY; } #if 0 /* emission */ memset(&sockudp_w, 0, sizeof(struct sockaddr_in)); sockudp_w.sin_family = AF_INET; sockudp_w.sin_port = htons(PORT); sockudp_w.sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR); #endif #ifdef WIN32 /* This code could help us to use the right Network interface for * SSDP multicast traffic */ /* Get IP associated with the index given in the ip_forward struct * in order to give this ip to setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF) */ if(GetBestRoute(inet_addr("223.255.255.255"), 0, &ip_forward) == NO_ERROR) { DWORD dwRetVal = 0; PMIB_IPADDRTABLE pIPAddrTable; DWORD dwSize = 0; #ifdef DEBUG IN_ADDR IPAddr; #endif int i; #ifdef DEBUG printf("ifIndex=%lu nextHop=%lx \n", ip_forward.dwForwardIfIndex, ip_forward.dwForwardNextHop); #endif pIPAddrTable = (MIB_IPADDRTABLE *) malloc(sizeof (MIB_IPADDRTABLE)); if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) { free(pIPAddrTable); pIPAddrTable = (MIB_IPADDRTABLE *) malloc(dwSize); } if(pIPAddrTable) { dwRetVal = GetIpAddrTable( pIPAddrTable, &dwSize, 0 ); #ifdef DEBUG printf("\tNum Entries: %ld\n", pIPAddrTable->dwNumEntries); #endif for (i=0; i < (int) pIPAddrTable->dwNumEntries; i++) { #ifdef DEBUG printf("\n\tInterface Index[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwIndex); IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwAddr; printf("\tIP Address[%d]: \t%s\n", i, inet_ntoa(IPAddr) ); IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwMask; printf("\tSubnet Mask[%d]: \t%s\n", i, inet_ntoa(IPAddr) ); IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwBCastAddr; printf("\tBroadCast[%d]: \t%s (%ld)\n", i, inet_ntoa(IPAddr), pIPAddrTable->table[i].dwBCastAddr); printf("\tReassembly size[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwReasmSize); printf("\tType and State[%d]:", i); printf("\n"); #endif if (pIPAddrTable->table[i].dwIndex == ip_forward.dwForwardIfIndex) { /* Set the address of this interface to be used */ struct in_addr mc_if; memset(&mc_if, 0, sizeof(mc_if)); mc_if.s_addr = pIPAddrTable->table[i].dwAddr; if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) { PRINT_SOCKET_ERROR("setsockopt"); } ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = pIPAddrTable->table[i].dwAddr; #ifndef DEBUG break; #endif } } free(pIPAddrTable); pIPAddrTable = NULL; } } #endif #ifdef WIN32 if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof (opt)) < 0) #else if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)) < 0) #endif { PRINT_SOCKET_ERROR("setsockopt"); return NULL; } if(multicastif) { struct in_addr mc_if; mc_if.s_addr = inet_addr(multicastif); if(0/*ipv6*/) { } else { ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = mc_if.s_addr; } if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) { PRINT_SOCKET_ERROR("setsockopt"); } } /* Avant d'envoyer le paquet on bind pour recevoir la reponse */ if (bind(sudp, &sockudp_r, 0/*ipv6*/?sizeof(struct sockaddr_in6):sizeof(struct sockaddr_in)) != 0) { PRINT_SOCKET_ERROR("bind"); closesocket(sudp); return NULL; } /* Calculating maximum response time in seconds */ mx = ((unsigned int)delay) / 1000u; /* receiving SSDP response packet */ for(n = 0;;) { if(n == 0) { /* sending the SSDP M-SEARCH packet */ n = snprintf(bufr, sizeof(bufr), MSearchMsgFmt, deviceList[deviceIndex++], mx); /*printf("Sending %s", bufr);*/ #if 0 n = sendto(sudp, bufr, n, 0, (struct sockaddr *)&sockudp_w, sizeof(struct sockaddr_in)); if (n < 0) { PRINT_SOCKET_ERROR("sendto"); closesocket(sudp); return devlist; } #endif memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; // AF_INET6 or AF_INET hints.ai_socktype = SOCK_DGRAM; /*hints.ai_flags = */ if ((rv = getaddrinfo(UPNP_MCAST_ADDR, XSTR(PORT), &hints, &servinfo)) != 0) { #ifdef WIN32 fprintf(stderr, "getaddrinfo() failed: %d\n", rv); #else fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); #endif return devlist; } for(p = servinfo; p; p = p->ai_next) { n = sendto(sudp, bufr, n, 0, p->ai_addr, p->ai_addrlen); if (n < 0) { PRINT_SOCKET_ERROR("sendto"); continue; } } freeaddrinfo(servinfo); if(n < 0) { closesocket(sudp); return devlist; } } /* Waiting for SSDP REPLY packet to M-SEARCH */ n = ReceiveData(sudp, bufr, sizeof(bufr), delay); if (n < 0) { /* error */ closesocket(sudp); return devlist; } else if (n == 0) { /* no data or Time Out */ if (devlist || (deviceList[deviceIndex] == 0)) { /* no more device type to look for... */ closesocket(sudp); return devlist; } } else { const char * descURL=NULL; int urlsize=0; const char * st=NULL; int stsize=0; /*printf("%d byte(s) :\n%s\n", n, bufr);*/ /* affichage du message */ parseMSEARCHReply(bufr, n, &descURL, &urlsize, &st, &stsize); if(st&&descURL) { #ifdef DEBUG printf("M-SEARCH Reply:\nST: %.*s\nLocation: %.*s\n", stsize, st, urlsize, descURL); #endif for(tmp=devlist; tmp; tmp = tmp->pNext) { if(memcmp(tmp->descURL, descURL, urlsize) == 0 && tmp->descURL[urlsize] == '\0' && memcmp(tmp->st, st, stsize) == 0 && tmp->st[stsize] == '\0') break; } /* at the exit of the loop above, tmp is null if * no duplicate device was found */ if(tmp) continue; tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize); tmp->pNext = devlist; tmp->descURL = tmp->buffer; tmp->st = tmp->buffer + 1 + urlsize; memcpy(tmp->buffer, descURL, urlsize); tmp->buffer[urlsize] = '\0'; memcpy(tmp->buffer + urlsize + 1, st, stsize); tmp->buffer[urlsize+1+stsize] = '\0'; devlist = tmp; } } } }
static int init_send(struct rtmp_stream *stream) { int ret; size_t idx = 0; bool next = true; #if defined(_WIN32) adjust_sndbuf_size(stream, MIN_SENDBUF_SIZE); #endif reset_semaphore(stream); ret = pthread_create(&stream->send_thread, NULL, send_thread, stream); if (ret != 0) { RTMP_Close(&stream->rtmp); warn("Failed to create send thread"); return OBS_OUTPUT_ERROR; } if (stream->new_socket_loop) { int one = 1; #ifdef _WIN32 if (ioctlsocket(stream->rtmp.m_sb.sb_socket, FIONBIO, &one)) { stream->rtmp.last_error_code = WSAGetLastError(); #else if (ioctl(stream->rtmp.m_sb.sb_socket, FIONBIO, &one)) { stream->rtmp.last_error_code = errno; #endif warn("Failed to set non-blocking socket"); return OBS_OUTPUT_ERROR; } os_event_reset(stream->send_thread_signaled_exit); info("New socket loop enabled by user"); if (stream->low_latency_mode) info("Low latency mode enabled by user"); if (stream->write_buf) bfree(stream->write_buf); int total_bitrate = 0; obs_output_t *context = stream->output; obs_encoder_t *vencoder = obs_output_get_video_encoder(context); if (vencoder) { obs_data_t *params = obs_encoder_get_settings(vencoder); if (params) { int bitrate = obs_data_get_int(params, "bitrate"); total_bitrate += bitrate; obs_data_release(params); } } obs_encoder_t *aencoder = obs_output_get_audio_encoder(context, 0); if (aencoder) { obs_data_t *params = obs_encoder_get_settings(aencoder); if (params) { int bitrate = obs_data_get_int(params, "bitrate"); total_bitrate += bitrate; obs_data_release(params); } } // to bytes/sec int ideal_buffer_size = total_bitrate * 128; if (ideal_buffer_size < 131072) ideal_buffer_size = 131072; stream->write_buf_size = ideal_buffer_size; stream->write_buf = bmalloc(ideal_buffer_size); #ifdef _WIN32 ret = pthread_create(&stream->socket_thread, NULL, socket_thread_windows, stream); #else warn("New socket loop not supported on this platform"); return OBS_OUTPUT_ERROR; #endif if (ret != 0) { RTMP_Close(&stream->rtmp); warn("Failed to create socket thread"); return OBS_OUTPUT_ERROR; } stream->socket_thread_active = true; stream->rtmp.m_bCustomSend = true; stream->rtmp.m_customSendFunc = socket_queue_data; stream->rtmp.m_customSendParam = stream; } os_atomic_set_bool(&stream->active, true); while (next) { if (!send_meta_data(stream, idx++, &next)) { warn("Disconnected while attempting to connect to " "server."); set_output_error(stream); return OBS_OUTPUT_DISCONNECTED; } } obs_output_begin_data_capture(stream->output, 0); return OBS_OUTPUT_SUCCESS; } #ifdef _WIN32 static void win32_log_interface_type(struct rtmp_stream *stream) { RTMP *rtmp = &stream->rtmp; MIB_IPFORWARDROW route; uint32_t dest_addr, source_addr; char hostname[256]; HOSTENT *h; if (rtmp->Link.hostname.av_len >= sizeof(hostname) - 1) return; strncpy(hostname, rtmp->Link.hostname.av_val, sizeof(hostname)); hostname[rtmp->Link.hostname.av_len] = 0; h = gethostbyname(hostname); if (!h) return; dest_addr = *(uint32_t*)h->h_addr_list[0]; if (rtmp->m_bindIP.addrLen == 0) source_addr = 0; else if (rtmp->m_bindIP.addr.ss_family == AF_INET) source_addr = (*(struct sockaddr_in*)&rtmp->m_bindIP) .sin_addr.S_un.S_addr; else return; if (!GetBestRoute(dest_addr, source_addr, &route)) { MIB_IFROW row; memset(&row, 0, sizeof(row)); row.dwIndex = route.dwForwardIfIndex; if (!GetIfEntry(&row)) { uint32_t speed =row.dwSpeed / 1000000; char *type; struct dstr other = {0}; if (row.dwType == IF_TYPE_ETHERNET_CSMACD) { type = "ethernet"; } else if (row.dwType == IF_TYPE_IEEE80211) { type = "802.11"; } else { dstr_printf(&other, "type %lu", row.dwType); type = other.array; } info("Interface: %s (%s, %lu mbps)", row.bDescr, type, speed); dstr_free(&other); } } }
/* * Add a route to RTMv2 based on a routing socket message. * XXX: We should report errors in more detail, e.g. if the * route could not be added because it already existed, etc. */ int rtm_add_route(struct rt_msghdr *rtm, int msgsize) { static const proper_msgsize = (sizeof(struct rt_msghdr) + (sizeof(sockunion_t) * 3)); sockunion_t *sa; #ifdef IPV6_DLL struct in6_addr in6_dest; struct in6_addr in6_mask; struct in6_addr in6_nexthop; #else struct in_addr in_dest; struct in_addr in_mask; struct in_addr in_nexthop; MIB_IPFORWARDROW ro; #endif int retval; int prefix; DWORD result; RTM_NET_ADDRESS dest; RTM_NET_ADDRESS nexthop; RTM_NEXTHOP_HANDLE nhh; RTM_NEXTHOP_INFO nhi; RTM_ROUTE_HANDLE nrh; RTM_ROUTE_INFO ri; RTM_ROUTE_CHANGE_FLAGS changeFlags; /* * Sanity check message size, fields etc. */ if (!rtm) return -1; if (msgsize < proper_msgsize || (rtm->rtm_msglen < proper_msgsize)) return -1; if (rtm->rtm_type != RTM_ADD) return -1; if ((rtm->rtm_addrs & (RTA_DST|RTA_GATEWAY|RTA_NETMASK)) != (RTA_DST|RTA_GATEWAY|RTA_NETMASK)) return -1; nhh = NULL; nrh = NULL; /* * Extract destination, netmask and next-hop from routing * socket message. */ #ifdef IPV6_DLL sa = (sockunion_t *)(rtm + 1); in6_dest = sa->sin6.sin6_addr; if (sa->sa.sa_family != AF_INET6) return -1; ++sa; in6_nexthop = sa->sin6.sin6_addr; if (sa->sa.sa_family != AF_INET6) return -1; ++sa; in6_mask = sa->sin6.sin6_addr; if (sa->sa.sa_family != AF_INET6) return -1; #else sa = (sockunion_t *)(rtm + 1); if (sa->sa.sa_family != AF_INET) return -1; in_dest = sa->sin.sin_addr; ++sa; if (sa->sa.sa_family != AF_INET) return -1; in_nexthop = sa->sin.sin_addr; ++sa; if (sa->sa.sa_family != AF_INET) return -1; in_mask = sa->sin.sin_addr; #endif #ifndef IPV6_DLL /* * Look up the next-hop in the system routing table via * IP Helper. If there is no directly connected route we * can use to reach the next-hop, then we reject this attempt * to add a route, as we need to know the interface index * of this route in order to add the new route. * XXX This is not good for multihop. * XXX IPv6! */ result = GetBestRoute(in_nexthop.s_addr, INADDR_ANY, &ro); if (result != NO_ERROR) { TRACE1(NETWORK, "error: GetBestRoute() returned %d", result); return -1; } #endif /* * Convert netmask to a prefix length. * Convert destination to an RTM_NET_ADDRESS. * Convert next-hop to an RTM_NET_ADDRESS. * XXX: IPv6 path needs 'get length from mask' macro. * XXX: IPv6 path needs interface index. */ #ifdef IPV6_DLL RTM_IPV6_LEN_FROM_MASK(prefix, in6_mask.s_addr); RTM_IPV6_MAKE_NET_ADDRESS(&dest, in6_dest.s_addr, prefix); RTM_IPV6_MAKE_NET_ADDRESS(&nexthop, in6_nexthop.s_addr, 128); #else RTM_IPV4_LEN_FROM_MASK(prefix, in_mask.s_addr); RTM_IPV4_MAKE_NET_ADDRESS(&dest, in_dest.s_addr, prefix); RTM_IPV4_MAKE_NET_ADDRESS(&nexthop, in_nexthop.s_addr, 32); /* * Fill out the next-hop info structure. * Create the next-hop in the RTMv2 table. */ ZeroMemory(&nhi, sizeof(nhi)); nhi.InterfaceIndex = ro.dwForwardIfIndex; nhi.NextHopAddress = nexthop; #endif /* IPV6_DLL */ result = RtmAddNextHop(g_ce.hRtmHandle, &nhi, &nhh, &changeFlags); if (result != NO_ERROR) { TRACE1(NETWORK, "error %u adding nexthop", result); retval = -1; goto out; } /* * Fill out the RTM_ROUTE_INFO structure. * Attempt to add the route. */ ZeroMemory(&ri, sizeof(ri)); ri.PrefInfo.Metric = XORPRTM_RI_METRIC; ri.PrefInfo.Preference = XORPRTM_RI_PREF; ri.BelongsToViews = RTM_VIEW_MASK_UCAST; ri.NextHopsList.NumNextHops = 1; ri.NextHopsList.NextHops[0] = nhh; changeFlags = 0; result = RtmAddRouteToDest(g_ce.hRtmHandle, &nrh, &dest, &ri, INFINITE, NULL, 0, NULL, &changeFlags); if (result != NO_ERROR) { TRACE1(NETWORK, "error %u adding route", result); retval = -1; goto out; } retval = 0; out: if (nrh != NULL) RtmReleaseRoutes(g_ce.hRtmHandle, 1, &nrh); if (nhh != NULL) RtmReleaseNextHops(g_ce.hRtmHandle, 1, &nhh); return (retval); }