📄 groupsockhelper.cpp.save
字号:
/**********This library is free software; you can redistribute it and/or modify it underthe terms of the GNU Lesser General Public License as published by theFree Software Foundation; either version 2.1 of the License, or (at youroption) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)This library is distributed in the hope that it will be useful, but WITHOUTANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESSFOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License formore details.You should have received a copy of the GNU Lesser General Public Licensealong with this library; if not, write to the Free Software Foundation, Inc.,59 Temple Place, Suite 330, Boston, MA 02111-1307 USA**********/// "mTunnel" multicast access service// Copyright (c) 1996-2004 Live Networks, Inc. All rights reserved.// Helper routines to implement 'group sockets'// Implementation#include "GroupsockHelper.hh"#if defined(__WIN32__) || defined(_WIN32)#ifdef _WIN32_WCE#include <afxwin.h>#include <wcealt.h>#define ctime wce_ctime#endif#include <time.h>extern "C" int initializeWinsockIfNecessary();#else#include <stdarg.h>#include <time.h>#include <fcntl.h>#define initializeWinsockIfNecessary() 1#endif#include <stdio.h>// By default, use INADDR_ANY for the sending and receiving interfaces:netAddressBits SendingInterfaceAddr = INADDR_ANY;netAddressBits ReceivingInterfaceAddr = INADDR_ANY;static void socketErr(UsageEnvironment& env, char* errorMsg) { env.setResultErrMsg(errorMsg);}int setupDatagramSocket(UsageEnvironment& env, Port port,#ifdef IP_MULTICAST_LOOP Boolean setLoopback#else Boolean#endif) { if (!initializeWinsockIfNecessary()) { socketErr(env, "Failed to initialize 'winsock': "); return -1; } int newSocket = socket(AF_INET, SOCK_DGRAM, 0); if (newSocket < 0) { socketErr(env, "unable to create datagram socket: "); return newSocket; } const int reuseFlag = 1; if (setsockopt(newSocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuseFlag, sizeof reuseFlag) < 0) { socketErr(env, "setsockopt(SO_REUSEADDR) error: "); closeSocket(newSocket); return -1; } #if defined(__WIN32__) || defined(_WIN32) // Windoze doesn't handle SO_REUSEPORT or IP_MULTICAST_LOOP#else#ifdef SO_REUSEPORT if (setsockopt(newSocket, SOL_SOCKET, SO_REUSEPORT, (const char*)&reuseFlag, sizeof reuseFlag) < 0) { socketErr(env, "setsockopt(SO_REUSEPORT) error: "); closeSocket(newSocket); return -1; }#endif #ifdef IP_MULTICAST_LOOP const u_int8_t loop = (u_int8_t)setLoopback; if (setsockopt(newSocket, IPPROTO_IP, IP_MULTICAST_LOOP, (const char*)&loop, sizeof loop) < 0) { socketErr(env, "setsockopt(IP_MULTICAST_LOOP) error: "); closeSocket(newSocket); return -1; }#endif#endif // Note: Windoze requires binding, even if the port number is 0#if defined(__WIN32__) || defined(_WIN32)#else if (port.num() != 0 || ReceivingInterfaceAddr != INADDR_ANY) {#endif struct sockaddr_in name; name.sin_family = AF_INET; name.sin_port = port.num(); name.sin_addr.s_addr = ReceivingInterfaceAddr; if (bind(newSocket, (struct sockaddr*)&name, sizeof name) != 0) { char tmpBuffer[100]; sprintf(tmpBuffer, "bind() error (port number: %d): ", ntohs(port.num())); socketErr(env, tmpBuffer); closeSocket(newSocket); return -1; }#if defined(__WIN32__) || defined(_WIN32)#else }#endif // Set the sending interface for multicasts, if it's not the default: if (SendingInterfaceAddr != INADDR_ANY) { struct in_addr addr; addr.s_addr = SendingInterfaceAddr; if (setsockopt(newSocket, IPPROTO_IP, IP_MULTICAST_IF, (const char*)&addr, sizeof addr) < 0) { socketErr(env, "error setting outgoing multicast interface: "); closeSocket(newSocket); return -1; } } return newSocket;}int setupStreamSocket(UsageEnvironment& env, Port port, Boolean makeNonBlocking) { if (!initializeWinsockIfNecessary()) { socketErr(env, "Failed to initialize 'winsock': "); return -1; } int newSocket = socket(AF_INET, SOCK_STREAM, 0); if (newSocket < 0) { socketErr(env, "unable to create stream socket: "); return newSocket; } const int reuseFlag = 1; if (setsockopt(newSocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuseFlag, sizeof reuseFlag) < 0) { socketErr(env, "setsockopt(SO_REUSEADDR) error: "); closeSocket(newSocket); return -1; } // SO_REUSEPORT doesn't really make sense for TCP sockets, so we // normally don't set them. However, if you really want to do this // #define REUSE_FOR_TCP#ifdef REUSE_FOR_TCP#if defined(__WIN32__) || defined(_WIN32) // Windoze doesn't handle SO_REUSEPORT#else#ifdef SO_REUSEPORT if (setsockopt(newSocket, SOL_SOCKET, SO_REUSEPORT, (const char*)&reuseFlag, sizeof reuseFlag) < 0) { socketErr(env, "setsockopt(SO_REUSEPORT) error: "); closeSocket(newSocket); return -1; }#endif#endif#endif // Note: Windoze requires binding, even if the port number is 0#if defined(__WIN32__) || defined(_WIN32)#else if (port.num() != 0 || ReceivingInterfaceAddr != INADDR_ANY) {#endif struct sockaddr_in name; name.sin_family = AF_INET; name.sin_port = port.num(); name.sin_addr.s_addr = ReceivingInterfaceAddr; if (bind(newSocket, (struct sockaddr*)&name, sizeof name) != 0) { char tmpBuffer[100]; sprintf(tmpBuffer, "bind() error (port number: %d): ", ntohs(port.num())); socketErr(env, tmpBuffer); closeSocket(newSocket); return -1; }#if defined(__WIN32__) || defined(_WIN32)#else }#endif if (makeNonBlocking) { // Make the socket non-blocking:#if defined(__WIN32__) || defined(_WIN32) || defined(IMN_PIM) unsigned long arg = 1; if (ioctlsocket(newSocket, FIONBIO, &arg) != 0) {#elif defined(VXWORKS) int arg = 1; if (ioctl(newSocket, FIONBIO, (int)&arg) != 0) {#else int curFlags = fcntl(newSocket, F_GETFL, 0); if (fcntl(newSocket, F_SETFL, curFlags|O_NONBLOCK) < 0) {#endif socketErr(env, "failed to make non-blocking: "); closeSocket(newSocket); return -1; } } return newSocket;}#ifndef IMN_PIMstatic int blockUntilReadable(UsageEnvironment& env, int socket, struct timeval* timeout) { int result = -1; do { fd_set rd_set; FD_ZERO(&rd_set); if (socket < 0) break; FD_SET((unsigned) socket, &rd_set); const unsigned numFds = socket+1; result = select(numFds, &rd_set, NULL, NULL, timeout); if (timeout != NULL && result == 0) { break; // this is OK - timeout occurred } else if (result <= 0) { socketErr(env, "select() error: "); break; } if (!FD_ISSET(socket, &rd_set)) { socketErr(env, "select() error - !FD_ISSET"); break; } } while (0); return result;}#elseextern int blockUntilReadable(UsageEnvironment& env, int socket, struct timeval* timeout);#endifint readSocket(UsageEnvironment& env, int socket, unsigned char* buffer, unsigned bufferSize, struct sockaddr_in& fromAddress, struct timeval* timeout) { int bytesRead = -1; do { int result = blockUntilReadable(env, socket, timeout); if (timeout != NULL && result == 0) { bytesRead = 0; break; } else if (result <= 0) { break; } SOCKLEN_T addressSize = sizeof fromAddress; bytesRead = recvfrom(socket, (char*)buffer, bufferSize, 0, (struct sockaddr*)&fromAddress, &addressSize); if (bytesRead < 0) { //##### HACK to work around bugs in Linux and Windows: int err = env.getErrno(); if (err == 111 /*ECONNREFUSED (Linux)*/#if defined(__WIN32__) || defined(_WIN32) // What a piece of crap Windows is. Sometimes // recvfrom() returns -1, but with an 'errno' of 0. // This appears not to be a real error; just treat // it as if it were a read of zero bytes, and hope // we don't have to do anything else to 'reset' // this alleged error: || err == 0#else || err == EAGAIN#endif || err == 113 /*EHOSTUNREACH (Linux)*/) { //Why does Linux return this for datagram sock? fromAddress.sin_addr.s_addr = 0; return 0; } //##### END HACK socketErr(env, "recvfrom() error: "); break; } } while (0); return bytesRead;}int readSocketExact(UsageEnvironment& env, int socket, unsigned char* buffer, unsigned bufferSize, struct sockaddr_in& fromAddress, struct timeval* timeout) { /* read EXACTLY bufferSize bytes from the socket into the buffer. fromaddress is address of last read. return the number of bytes acually read when an error occurs */ int bsize = bufferSize; int bytesRead = 0; int totBytesRead =0; do { bytesRead = readSocket (env, socket, buffer + totBytesRead, bsize, fromAddress, timeout); if (bytesRead <= 0) break; totBytesRead += bytesRead; bsize -= bytesRead; } while (bsize != 0); return totBytesRead;}Boolean writeSocket(UsageEnvironment& env, int socket, struct in_addr address, Port port, u_int8_t ttlArg, unsigned char* buffer, unsigned bufferSize) { do { if (ttlArg != 0) { // Before sending, set the socket's TTL:#if defined(__WIN32__) || defined(_WIN32)#define TTL_TYPE int#else#define TTL_TYPE u_int8_t#endif TTL_TYPE ttl = (TTL_TYPE)ttlArg; if (setsockopt(socket, IPPROTO_IP, IP_MULTICAST_TTL, (const char*)&ttl, sizeof ttl) < 0) { socketErr(env, "setsockopt(IP_MULTICAST_TTL) error: "); break; } } struct sockaddr_in dest; dest.sin_family = AF_INET; dest.sin_port = port.num(); dest.sin_addr = address; int bytesSent = sendto(socket, (char*)buffer, bufferSize, 0, (struct sockaddr*)&dest, sizeof dest); if (bytesSent != (int)bufferSize) { char tmpBuf[100]; sprintf(tmpBuf, "writeSocket(%d), sendTo() error: wrote %d bytes instead of %u: ", socket, bytesSent, bufferSize); socketErr(env, tmpBuf); break; } return True; } while (0); return False;}static unsigned getBufferSize(UsageEnvironment& env, int bufOptName, int socket) { unsigned curSize; SOCKLEN_T sizeSize = sizeof curSize; if (getsockopt(socket, SOL_SOCKET, bufOptName, (char*)&curSize, &sizeSize) < 0) { socketErr(env, "getBufferSize() error: "); return 0; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -