📄 groupsock.cpp
字号:
/**********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**********/// LIVE.COM Streaming Media Libraries// Copyright (c) 1996-1999 Live Networks, Inc. All rights reserved.// 'Group sockets'// Implementation#include "Groupsock.hh"#include "GroupsockHelper.hh"//##### Eventually fix the following #include; we shouldn't know about tunnels#include "TunnelEncaps.hh"#ifndef NO_STRSTREAM#if (defined(__WIN32__) || defined(_WIN32)) && !defined(__MINGW32__)#include <strstrea.h>#else#if defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ > 0)#include <strstream>#else#include <strstream.h>#endif#endif#endif#include <stdio.h>///////// OutputSocket //////////OutputSocket::OutputSocket(UsageEnvironment& env) : Socket(env, 0 /* let kernel choose port */), fSourcePort(0), fLastSentTTL(0) {}OutputSocket::OutputSocket(UsageEnvironment& env, Port port) : Socket(env, port), fSourcePort(0), fLastSentTTL(0) {}OutputSocket::~OutputSocket() {}Boolean OutputSocket::write(netAddressBits address, Port port, u_int8_t ttl, unsigned char* buffer, unsigned bufferSize) { if (ttl == fLastSentTTL) { // Optimization: So we don't do a 'set TTL' system call again ttl = 0; } else { fLastSentTTL = ttl; } struct in_addr destAddr; destAddr.s_addr = address; if (!writeSocket(env(), socketNum(), destAddr, port, ttl, buffer, bufferSize)) return False; if (sourcePortNum() == 0) { // Now that we've sent a packet, we can find out what the // kernel chose as our ephemeral source port number: if (!getSourcePort(env(), socketNum(), fSourcePort)) { if (DebugLevel >= 1) env() << *this << ": failed to get source port: " << env().getResultMsg() << "\n"; return False; } } return True;}// By default, we don't do reads:Boolean OutputSocket::handleRead(unsigned char* /*buffer*/, unsigned /*bufferMaxSize*/, unsigned& /*bytesRead*/, struct sockaddr_in& /*fromAddress*/) { return True;}///////// destRecord //////////destRecord::destRecord(struct in_addr const& addr, Port const& port, u_int8_t ttl, destRecord* next) : fNext(next), fGroupEId(addr, port.num(), ttl), fPort(port) {}destRecord::~destRecord() { delete fNext;}///////// Groupsock //////////NetInterfaceTrafficStats Groupsock::statsIncoming;NetInterfaceTrafficStats Groupsock::statsOutgoing;NetInterfaceTrafficStats Groupsock::statsRelayedIncoming;NetInterfaceTrafficStats Groupsock::statsRelayedOutgoing;// Constructor for a source-independent multicast groupGroupsock::Groupsock(UsageEnvironment& env, struct in_addr const& groupAddr, Port port, u_int8_t ttl) : OutputSocket(env, port), deleteIfNoMembers(False), isSlave(False), fIncomingGroupEId(groupAddr, port.num(), ttl), fDests(NULL), fTTL(ttl) { addDestination(groupAddr, port); if (!socketJoinGroup(env, socketNum(), groupAddr.s_addr)) { if (DebugLevel >= 1) { env << *this << ": failed to join group: " << env.getResultMsg() << "\n"; } } // Make sure we can get our source address: if (ourSourceAddressForMulticast(env) == 0) { if (DebugLevel >= 0) { // this is a fatal error env << "Unable to determine our source address: " << env.getResultMsg() << "\n"; } } if (DebugLevel >= 2) env << *this << ": created\n";}// Constructor for a source-specific multicast groupGroupsock::Groupsock(UsageEnvironment& env, struct in_addr const& groupAddr, struct in_addr const& sourceFilterAddr, Port port) : OutputSocket(env, port), deleteIfNoMembers(False), isSlave(False), fIncomingGroupEId(groupAddr, sourceFilterAddr, port.num()), fDests(NULL), fTTL(255) { addDestination(groupAddr, port); // First try a SSM join. If that fails, try a regular join: if (!socketJoinGroupSSM(env, socketNum(), groupAddr.s_addr, sourceFilterAddr.s_addr)) { if (DebugLevel >= 3) { env << *this << ": SSM join failed: " << env.getResultMsg(); env << " - trying regular join instead\n"; } if (!socketJoinGroup(env, socketNum(), groupAddr.s_addr)) { if (DebugLevel >= 1) { env << *this << ": failed to join group: " << env.getResultMsg() << "\n"; } } } if (DebugLevel >= 2) env << *this << ": created\n";}Groupsock::~Groupsock() { if (isSSM()) { if (!socketLeaveGroupSSM(env(), socketNum(), groupAddress().s_addr, sourceFilterAddress().s_addr)) { socketLeaveGroup(env(), socketNum(), groupAddress().s_addr); } } else { socketLeaveGroup(env(), socketNum(), groupAddress().s_addr); } delete fDests; if (DebugLevel >= 2) env() << *this << ": deleting\n";}voidGroupsock::changeDestinationParameters(struct in_addr const& newDestAddr, Port newDestPort, int newDestTTL) { if (fDests == NULL) return; struct in_addr destAddr = fDests->fGroupEId.groupAddress(); if (newDestAddr.s_addr != 0) { if (newDestAddr.s_addr != destAddr.s_addr && IsMulticastAddress(newDestAddr.s_addr)) { // If the new destination is a multicast address, then we assume that // we want to join it also. (If this is not in fact the case, then // call "multicastSendOnly()" afterwards.) socketLeaveGroup(env(), socketNum(), destAddr.s_addr); socketJoinGroup(env(), socketNum(), newDestAddr.s_addr); } destAddr.s_addr = newDestAddr.s_addr; } portNumBits destPortNum = fDests->fGroupEId.portNum(); if (newDestPort.num() != 0) { destPortNum = newDestPort.num(); fDests->fPort = newDestPort; } u_int8_t destTTL = ttl(); if (newDestTTL != ~0) destTTL = (u_int8_t)newDestTTL; fDests->fGroupEId = GroupEId(destAddr, destPortNum, destTTL);}void Groupsock::addDestination(struct in_addr const& addr, Port const& port) { // Check whether this destination is already known: for (destRecord* dests = fDests; dests != NULL; dests = dests->fNext) { if (addr.s_addr == dests->fGroupEId.groupAddress().s_addr && port.num() == dests->fPort.num()) { return; } } fDests = new destRecord(addr, port, ttl(), fDests);}void Groupsock::removeDestination(struct in_addr const& addr, Port const& port) { for (destRecord** destsPtr = &fDests; *destsPtr != NULL; destsPtr = &((*destsPtr)->fNext)) { if (addr.s_addr == (*destsPtr)->fGroupEId.groupAddress().s_addr && port.num() == (*destsPtr)->fPort.num()) { // Remove the record pointed to by *destsPtr : destRecord* next = (*destsPtr)->fNext; (*destsPtr)->fNext = NULL; delete (*destsPtr); *destsPtr = next; return; } }}void Groupsock::removeAllDestinations() { delete fDests; fDests = NULL;}void Groupsock::multicastSendOnly() { socketLeaveGroup(env(), socketNum(), fIncomingGroupEId.groupAddress().s_addr); for (destRecord* dests = fDests; dests != NULL; dests = dests->fNext) { socketLeaveGroup(env(), socketNum(), dests->fGroupEId.groupAddress().s_addr); }}Boolean Groupsock::output(UsageEnvironment& env, u_int8_t ttlToSend, unsigned char* buffer, unsigned bufferSize, DirectedNetInterface* interfaceNotToFwdBackTo) { do { // First, do the datagram send, to each destination: Boolean writeSuccess = True; for (destRecord* dests = fDests; dests != NULL; dests = dests->fNext) { if (!write(dests->fGroupEId.groupAddress().s_addr, dests->fPort, ttlToSend, buffer, bufferSize)) { writeSuccess = False; break; } } if (!writeSuccess) break; statsOutgoing.countPacket(bufferSize); statsGroupOutgoing.countPacket(bufferSize); // Then, forward to our members: int numMembers = outputToAllMembersExcept(interfaceNotToFwdBackTo, ttlToSend, buffer, bufferSize, ourSourceAddressForMulticast(env)); if (numMembers < 0) break; if (DebugLevel >= 3) { env << *this << ": wrote " << bufferSize << " bytes, ttl " << (unsigned)ttlToSend; if (numMembers > 0) { env << "; relayed to " << numMembers << " members"; } env << "\n"; } return True; } while (0); if (DebugLevel >= 0) { // this is a fatal error env.setResultMsg("Groupsock write failed: ", env.getResultMsg()); } return False;}Boolean Groupsock::handleRead(unsigned char* buffer, unsigned bufferMaxSize, unsigned& bytesRead, struct sockaddr_in& fromAddress) { // Read data from the socket, and relay it across any attached tunnels //##### later make this code more general - independent of tunnels bytesRead = 0; int maxBytesToRead = bufferMaxSize - TunnelEncapsulationTrailerMaxSize; int numBytes = readSocket(env(), socketNum(), buffer, maxBytesToRead, fromAddress); if (numBytes < 0) { if (DebugLevel >= 0) { // this is a fatal error env().setResultMsg("Groupsock read failed: ", env().getResultMsg()); } return False; } // If we're a SSM group, make sure the source address matches: if (isSSM() && fromAddress.sin_addr.s_addr != sourceFilterAddress().s_addr) { return True; } // We'll handle this data. // Also write it (with the encapsulation trailer) to each member, // unless the packet was originally sent by us to begin with. bytesRead = numBytes; int numMembers = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -