예제 #1
0
Boolean socketJoinGroupSSM(UsageEnvironment& env, int socket,
			   netAddressBits groupAddress,
			   netAddressBits sourceFilterAddr) {
  if (!IsMulticastAddress(groupAddress)) return True; // ignore this case

  struct ip_mreq_source imr;
#ifdef __ANDROID__
    imr.imr_multiaddr = groupAddress;
    imr.imr_sourceaddr = sourceFilterAddr;
    imr.imr_interface = ReceivingInterfaceAddr;
#else
    imr.imr_multiaddr.s_addr = groupAddress;
    imr.imr_sourceaddr.s_addr = sourceFilterAddr;
    imr.imr_interface.s_addr = ReceivingInterfaceAddr;
#endif
  if (setsockopt(socket, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP,
		 (const char*)&imr, sizeof (struct ip_mreq_source)) < 0) {
    socketErr(env, "setsockopt(IP_ADD_SOURCE_MEMBERSHIP) error: ");
    return False;
  }

  clearMulticastAllSocketOption(socket);

  return True;
}
예제 #2
0
Boolean socketJoinGroup(UsageEnvironment& env, int socket,
			netAddressBits groupAddress){
  if (!IsMulticastAddress(groupAddress)) return True; // ignore this case

  struct ip_mreq imr;
  imr.imr_multiaddr.s_addr = groupAddress;
  imr.imr_interface.s_addr = ReceivingInterfaceAddr;
  if (setsockopt(socket, IPPROTO_IP, IP_ADD_MEMBERSHIP,
		 (const char*)&imr, sizeof (struct ip_mreq)) < 0) {
#if defined(__WIN32__) || defined(_WIN32)
    if (env.getErrno() != 0) {
      // That piece-of-shit toy operating system (Windows) sometimes lies
      // about setsockopt() failing!
#endif
      socketErr(env, "setsockopt(IP_ADD_MEMBERSHIP) error: ");
      return False;
#if defined(__WIN32__) || defined(_WIN32)
    }
#endif
  }

  clearMulticastAllSocketOption(socket);

  return True;
}
예제 #3
0
void
Groupsock::changeDestinationParameters(struct in_addr const& newDestAddr,
				       Port newDestPort, int newDestTTL, unsigned sessionId) {
  destRecord* dest;
  for (dest = fDests; dest != NULL && dest->fSessionId != sessionId; dest = dest->fNext) {}

  if (dest == NULL) { // There's no existing 'destRecord' for this "sessionId"; add a new one:
    fDests = createNewDestRecord(newDestAddr, newDestPort, newDestTTL, sessionId, fDests);
    return;
  }

  // "dest" is an existing 'destRecord' for this "sessionId"; change its values to the new ones:
  struct in_addr destAddr = dest->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 = dest->fGroupEId.portNum();
  if (newDestPort.num() != 0) {
    if (newDestPort.num() != destPortNum
	&& IsMulticastAddress(destAddr.s_addr)) {
      // Also bind to the new port number:
      changePort(newDestPort);
      // And rejoin the multicast group:
      socketJoinGroup(env(), socketNum(), destAddr.s_addr);
    }
    destPortNum = newDestPort.num();
  }

  u_int8_t destTTL = ttl();
  if (newDestTTL != ~0) destTTL = (u_int8_t)newDestTTL;

  dest->fGroupEId = GroupEId(destAddr, destPortNum, destTTL);

  // Finally, remove any other 'destRecord's that might also have this "sessionId":
  removeDestinationFrom(dest->fNext, sessionId);
}
예제 #4
0
Boolean socketLeaveGroup(UsageEnvironment&, int socket, netAddressBits groupAddress) {
  if (!IsMulticastAddress(groupAddress)) return True; // ignore this case

  struct ip_mreq imr;
  imr.imr_multiaddr.s_addr = groupAddress;
  imr.imr_interface.s_addr = ReceivingInterfaceAddr;
  if (setsockopt(socket, IPPROTO_IP, IP_DROP_MEMBERSHIP,
		 (const char*)&imr, sizeof (struct ip_mreq)) < 0) {
    return False;
  }

  return True;
}
void StreamState
::startPlaying(Destinations* dests,
				 TaskFunc* rtcpRRHandler, void* rtcpRRHandlerClientData) {
	if (dests == NULL) return;
	
	//skip play action if it's already being played
	if (!fAreCurrentlyPlaying && fMediaSource != NULL) {
		if (fRTPSink != NULL) {
			fRTPSink->startPlaying(*fMediaSource, afterPlayingStreamState, this);
			fAreCurrentlyPlaying = True;
		} else if (fUDPSink != NULL) {
			fUDPSink->startPlaying(*fMediaSource, afterPlayingStreamState, this);
			fAreCurrentlyPlaying = True;
		}
		createWorkingThread();
	}

	if (fRTCPInstance == NULL && fRTPSink != NULL) {
		// Create (and start) a 'RTCP instance' for this RTP sink:
		fRTCPInstance
	//		= RTCPInstance::createNew(fRTPSink->envir(), fRTCPgs,
			= RTCPInstance::createNew(fRtcpEnv, fRTCPgs,
			fTotalBW, (unsigned char*)fMaster.fCNAME,
			fRTPSink, NULL /* we're a server */);
		// Note: This starts RTCP running automatically
	}

	if (dests->isTCP) {
		// Change RTP and RTCP to use the TCP socket instead of UDP:
		if (fRTPSink != NULL) {
			fRTPSink->addStreamSocket(dests->tcpSocketNum, dests->rtpChannelId);
		}
		if (fRTCPInstance != NULL) {
			fRTCPInstance->addStreamSocket(dests->tcpSocketNum, dests->rtcpChannelId);
			fRTCPInstance->setSpecificRRHandler(dests->tcpSocketNum, dests->rtcpChannelId,
				rtcpRRHandler, rtcpRRHandlerClientData);
		}
	} else {
		// Tell the RTP and RTCP 'groupsocks' about this destination
		// (in case they don't already have it):
		//	printf("addDestination %s\n", inet_ntoa(dests->addr));	//jay
		if (fRTPgs != NULL) fRTPgs->addDestination(dests->addr, dests->rtpPort);
		if (fRTCPgs != NULL) fRTCPgs->addDestination(dests->addr, dests->rtcpPort);
		if (fRTCPInstance != NULL) {
			if (!IsMulticastAddress(dests->addr.s_addr)) {
				fRTCPInstance->setSpecificRRHandler(dests->addr.s_addr, dests->rtcpPort,
				rtcpRRHandler, rtcpRRHandlerClientData);
			}
		}
	}
}
예제 #6
0
void
Groupsock::changeDestinationParameters(struct in_addr const& newDestAddr,
							 Port newDestPort, int newDestTTL) {
  if (fDests == NULL) return;
	printf("changeDestinationParameters: %s:%d\n", inet_ntoa(newDestAddr), ntohs(newDestPort.num()));	//jay

  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) {
	  if (newDestPort.num() != destPortNum
	&& IsMulticastAddress(destAddr.s_addr)) {
			// Also bind to the new port number:
		  changePort(newDestPort);
			// And rejoin the multicast group:
		  socketJoinGroup(env(), socketNum(), destAddr.s_addr);
		}
	  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);
}
예제 #7
0
Boolean socketLeaveGroupSSM(UsageEnvironment& /*env*/, int socket,
			    netAddressBits groupAddress,
			    netAddressBits sourceFilterAddr) {
  if (!IsMulticastAddress(groupAddress)) return True; // ignore this case

  struct ip_mreq_source imr;
#ifdef __ANDROID__
    imr.imr_multiaddr = groupAddress;
    imr.imr_sourceaddr = sourceFilterAddr;
    imr.imr_interface = ReceivingInterfaceAddr;
#else
    imr.imr_multiaddr.s_addr = groupAddress;
    imr.imr_sourceaddr.s_addr = sourceFilterAddr;
    imr.imr_interface.s_addr = ReceivingInterfaceAddr;
#endif
  if (setsockopt(socket, IPPROTO_IP, IP_DROP_SOURCE_MEMBERSHIP,
		 (const char*)&imr, sizeof (struct ip_mreq_source)) < 0) {
    return False;
  }

  return True;
}
예제 #8
0
Boolean socketLeaveGroupSSM(UsageEnvironment& /*env*/, int socket,
			    netAddressBits groupAddress,
			    netAddressBits sourceFilterAddr) {
  if (!IsMulticastAddress(groupAddress)) return True; // ignore this case

  struct ip_mreq_source imr;
  //imr.imr_multiaddr.s_addr = groupAddress;
  //imr.imr_sourceaddr.s_addr = sourceFilterAddr;
  //imr.imr_interface.s_addr = ReceivingInterfaceAddr;
  /* I wish I understood a little more about preprocessing as I am unable
     * to understand why the above lines do not compile, as a matter of time
     * I have commented those lines out and inserted the 3 below which I believe
     * will achieve the same thing. */
  imr.imr_multiaddr = groupAddress;
  imr.imr_sourceaddr = sourceFilterAddr;
  imr.imr_interface = ReceivingInterfaceAddr;
  if (setsockopt(socket, IPPROTO_IP, IP_DROP_SOURCE_MEMBERSHIP,
		 (const char*)&imr, sizeof (struct ip_mreq_source)) < 0) {
    return False;
  }

  return True;
}
예제 #9
0
Boolean MediaSubsession::initiate(int useSpecialRTPoffset) {
  if (fReadSource != NULL) return True; // has already been initiated

  do {
    if (fCodecName == NULL) {
      env().setResultMsg("Codec is unspecified");
      break;
    }

    // Create RTP and RTCP 'Groupsocks' on which to receive incoming data.
    // (Groupsocks will work even for unicast addresses)
    struct in_addr tempAddr;
    tempAddr.s_addr = connectionEndpointAddress();
        // This could get changed later, as a result of a RTSP "SETUP"

    if (fClientPortNum != 0  && IsMulticastAddress(tempAddr.s_addr)) {
      // This is a multicast stream, and the sockets' port numbers were specified for us.  Use these:
      Boolean const protocolIsRTP = strcmp(fProtocolName, "RTP") == 0;
      if (protocolIsRTP) {
	fClientPortNum = fClientPortNum&~1; // use an even-numbered port for RTP, and the next (odd-numbered) port for RTCP
      }
      if (isSSM()) {
	fRTPSocket = new Groupsock(env(), tempAddr, fSourceFilterAddr, fClientPortNum);
      } else {
	fRTPSocket = new Groupsock(env(), tempAddr, fClientPortNum, 255);
      }
      if (fRTPSocket == NULL) {
	env().setResultMsg("Failed to create RTP socket");
	break;
      }
      
      if (protocolIsRTP) {
	// Set our RTCP port to be the RTP port +1
	portNumBits const rtcpPortNum = fClientPortNum|1;
	if (isSSM()) {
	  fRTCPSocket = new Groupsock(env(), tempAddr, fSourceFilterAddr, rtcpPortNum);
	} else {
	  fRTCPSocket = new Groupsock(env(), tempAddr, rtcpPortNum, 255);
	}
      }
    } else {
      // Port numbers were not specified in advance, so we use ephemeral port numbers.
      // Create sockets until we get a port-number pair (even: RTP; even+1: RTCP).
      // We need to make sure that we don't keep trying to use the same bad port numbers over and over again.
      // so we store bad sockets in a table, and delete them all when we're done.
      HashTable* socketHashTable = HashTable::create(ONE_WORD_HASH_KEYS);
      if (socketHashTable == NULL) break;
      Boolean success = False;
      NoReuse dummy(env()); // ensures that our new ephemeral port number won't be one that's already in use

      while (1) {
	// Create a new socket:
	if (isSSM()) {
	  fRTPSocket = new Groupsock(env(), tempAddr, fSourceFilterAddr, 0);
	} else {
	  fRTPSocket = new Groupsock(env(), tempAddr, 0, 255);
	}
	if (fRTPSocket == NULL) {
	  env().setResultMsg("MediaSession::initiate(): unable to create RTP and RTCP sockets");
	  break;
	}

	// Get the client port number, and check whether it's even (for RTP):
	Port clientPort(0);
	if (!getSourcePort(env(), fRTPSocket->socketNum(), clientPort)) {
	  break;
	}
	fClientPortNum = ntohs(clientPort.num()); 
	if ((fClientPortNum&1) != 0) { // it's odd
	  // Record this socket in our table, and keep trying:
	  unsigned key = (unsigned)fClientPortNum;
	  Groupsock* existing = (Groupsock*)socketHashTable->Add((char const*)key, fRTPSocket);
	  delete existing; // in case it wasn't NULL
	  continue;
	}

	// Make sure we can use the next (i.e., odd) port number, for RTCP:
	portNumBits rtcpPortNum = fClientPortNum|1;
	if (isSSM()) {
	  fRTCPSocket = new Groupsock(env(), tempAddr, fSourceFilterAddr, rtcpPortNum);
	} else {
	  fRTCPSocket = new Groupsock(env(), tempAddr, rtcpPortNum, 255);
	}
	if (fRTCPSocket != NULL && fRTCPSocket->socketNum() >= 0) {
	  // Success! Use these two sockets.
	  success = True;
	  break;
	} else {
	  // We couldn't create the RTCP socket (perhaps that port number's already in use elsewhere?).
	  delete fRTCPSocket;

	  // Record the first socket in our table, and keep trying:
	  unsigned key = (unsigned)fClientPortNum;
	  Groupsock* existing = (Groupsock*)socketHashTable->Add((char const*)key, fRTPSocket);
	  delete existing; // in case it wasn't NULL
	  continue;
	}
      }

      // Clean up the socket hash table (and contents):
      Groupsock* oldGS;
      while ((oldGS = (Groupsock*)socketHashTable->RemoveNext()) != NULL) {
	delete oldGS;
      }
      delete socketHashTable;

      if (!success) break; // a fatal error occurred trying to create the RTP and RTCP sockets; we can't continue
    }

    // Try to use a big receive buffer for RTP - at least 0.1 second of
    // specified bandwidth and at least 50 KB
    unsigned rtpBufSize = fBandwidth * 25 / 2; // 1 kbps * 0.1 s = 12.5 bytes
    if (rtpBufSize < 50 * 1024)
      rtpBufSize = 50 * 1024;
    increaseReceiveBufferTo(env(), fRTPSocket->socketNum(), rtpBufSize);

    if (isSSM() && fRTCPSocket != NULL) {
      // Special case for RTCP SSM: Send RTCP packets back to the source via unicast:
      fRTCPSocket->changeDestinationParameters(fSourceFilterAddr,0,~0);
    }

    // Create "fRTPSource" and "fReadSource":
    if (!createSourceObjects(useSpecialRTPoffset)) break;

    if (fReadSource == NULL) {
      env().setResultMsg("Failed to create read source");
      break;
    }

    // Finally, create our RTCP instance. (It starts running automatically)
    if (fRTPSource != NULL && fRTCPSocket != NULL) {
      // If bandwidth is specified, use it and add 5% for RTCP overhead.
      // Otherwise make a guess at 500 kbps.
      unsigned totSessionBandwidth
	= fBandwidth ? fBandwidth + fBandwidth / 20 : 500;
      fRTCPInstance = RTCPInstance::createNew(env(), fRTCPSocket,
					      totSessionBandwidth,
					      (unsigned char const*)
					      fParent.CNAME(),
					      NULL /* we're a client */,
					      fRTPSource);
      if (fRTCPInstance == NULL) {
	env().setResultMsg("Failed to create RTCP instance");
	break;
      }
    }

    return True;
  } while (0);

  delete fRTPSocket; fRTPSocket = NULL;
  delete fRTCPSocket; fRTCPSocket = NULL;
  Medium::close(fRTCPInstance); fRTCPInstance = NULL;
  Medium::close(fReadSource); fReadSource = fRTPSource = NULL;
  fClientPortNum = 0;
  return False;
}