rtperror RTPSessionRemoveSendAddr(context cid, char *addr, u_int16 port, u_int8 ttl) {
  address_holder_t *holder;
  struct in_addr translation;
  hl_context *uc;
  rtperror err;

  err = RTPSessionGetHighLevelInfo(cid, (void**)&uc);
  if (err != RTP_OK)
    /* The cid is bogus */
    return err;

  holder = uc->send_addr_list;

  /* If the port is odd, assume it's the RTCP port */

  if((port & 1) == 1)
    port--;

  translation = host2ip(addr);
  if(translation.s_addr == (u_int32) -1) {
    return errordebug(RTP_BAD_ADDR, "RTPSessionRemoveSendAddr",
		      "Could not resolve address");
  }


  /* TTL matching is only done for multicast. For unicast, all TTL's
     are set to zero */

  if(!IsMulticast(translation)) ttl = 0;

  while(holder != NULL) {
    if(!(holder->deleteflag) &&
       (holder->address.s_addr == translation.s_addr) &&
       (holder->port == htons(port)) &&
       (holder->ttl == ttl)) 
      break;

    holder = holder->next;
  }

  /* Now holder is either NULL if there was no match, else it points
     to the address which matched */

  if(holder == NULL) {
    return errordebug(RTP_BAD_ADDR, "RTPSessionRemoveSendAddr",
		      "No such address");
  } else {
    holder->deleteflag = TRUE;
    return RTP_OK;
  }
}
void KnxTelegram::InfoVerbose(String& str) const
{
  byte payloadLength = GetPayloadLength();
  str+= "Repeat="; str+= IsRepeated() ? "YES" : "NO";
  str+="\nPrio=";
  switch(GetPriority())
  {
    case KNX_PRIORITY_SYSTEM_VALUE : str+="SYSTEM"; break;
    case KNX_PRIORITY_ALARM_VALUE : str+="ALARM"; break;
    case KNX_PRIORITY_HIGH_VALUE : str+="HIGH"; break;
    case KNX_PRIORITY_NORMAL_VALUE : str+="NORMAL"; break;
    default : str+="ERR_VAL!"; break;
  }
  str+="\nSrcAddr=" + String(GetSourceAddress(),HEX);
  str+="\nTargetAddr=" + String(GetTargetAddress(),HEX);
  str+="\nGroupAddr="; if (IsMulticast()) str+= "YES"; else str+="NO";
  str+="\nRout.Counter=" + String(GetRoutingCounter(),DEC);
  str+="\nPayloadLgth=" + String(payloadLength,DEC);
  str+="\nTelegramLength=" + String(GetTelegramLength(),DEC);
  str+="\nCommand=";
  switch(GetCommand())
  {
    case KNX_COMMAND_VALUE_READ : str+="VAL_READ"; break;
    case KNX_COMMAND_VALUE_RESPONSE : str+="VAL_RESP"; break;
    case KNX_COMMAND_VALUE_WRITE : str+="VAL_WRITE"; break;
    case KNX_COMMAND_MEMORY_WRITE : str+="MEM_WRITE"; break;
    default : str+="ERR_VAL!"; break;
  }
  str+="\nPayload=" + String(GetFirstPayloadByte(),HEX)+' ';
  for (byte i = 0; i < payloadLength-1; i++) str+=String(_payloadChecksum[i], HEX)+' ';
  str+="\nValidity=";
   switch(GetValidity())
  {
    case KNX_TELEGRAM_VALID : str+="VALID"; break;
    case KNX_TELEGRAM_INVALID_CONTROL_FIELD : str+="INVALID_CTRL_FIELD"; break;
    case KNX_TELEGRAM_UNSUPPORTED_FRAME_FORMAT : str+="UNSUPPORTED_FRAME_FORMAT"; break;
    case KNX_TELEGRAM_INCORRECT_PAYLOAD_LENGTH : str+="INCORRECT_PAYLOAD_LGTH"; break;
    case KNX_TELEGRAM_INVALID_COMMAND_FIELD : str+="INVALID_CMD_FIELD"; break;
    case KNX_TELEGRAM_UNKNOWN_COMMAND : str+="UNKNOWN_CMD"; break;
    case KNX_TELEGRAM_INCORRECT_CHECKSUM : str+="INCORRECT_CHKSUM"; break;
    default : str+="ERR_VAL!"; break;
  }
  str+='\n';
}
Exemple #3
0
/* -------------------------------------------------------------------------
 * Function   : BmfTunPacketCaptured
 * Description: Handle an IP packet, captured outgoing on the tuntap interface
 * Input      : encapsulationUdpData - space for the encapsulation header, followed by
 *                the captured outgoing IP packet
 * Output     : none
 * Return     : none
 * Data Used  : none
 * Notes      : The packet is assumed to be captured on a socket of family
 *              PF_PACKET and type SOCK_DGRAM (cooked).
 * ------------------------------------------------------------------------- */
static void BmfTunPacketCaptured(unsigned char* encapsulationUdpData)
{
  union olsr_ip_addr srcIp;
  union olsr_ip_addr dstIp;
  union olsr_ip_addr broadAddr;
  struct TBmfInterface* walker;
  unsigned char* ipPacket;
  u_int16_t ipPacketLen;
  struct ip* ipHeader;
  u_int32_t crc32;
  struct TEncapHeader* encapHdr;
#ifndef NODEBUG
  struct ipaddr_str srcIpBuf, dstIpBuf;
#endif
  ipPacket = GetIpPacket(encapsulationUdpData);
  ipPacketLen = GetIpTotalLength(ipPacket);
  ipHeader = GetIpHeader(encapsulationUdpData);

  dstIp.v4 = ipHeader->ip_dst;
  broadAddr.v4.s_addr = htonl(EtherTunTapIpBroadcast);

  /* Only forward multicast packets. If configured, also forward local broadcast packets */
  if (IsMulticast(&dstIp) ||
      (EnableLocalBroadcast != 0 && ipequal(&dstIp, &broadAddr)))
  {
    /* continue */
  }
  else
  {
    return;
  }

  srcIp.v4 = ipHeader->ip_src;

  OLSR_PRINTF(
    8,
    "%s: outgoing pkt of %ld bytes captured on tuntap interface \"%s\": %s->%s\n",
    PLUGIN_NAME_SHORT,
    (long)ipPacketLen,
    EtherTunTapIfName,
    olsr_ip_to_string(&srcIpBuf, &srcIp),
    olsr_ip_to_string(&dstIpBuf, &dstIp));

  /* Calculate packet fingerprint */
  crc32 = PacketCrc32(ipPacket, ipPacketLen);

  /* Check if this packet was seen recently */
  if (CheckAndMarkRecentPacket(crc32))
  {
    OLSR_PRINTF(
      8,
      "%s: --> discarding: packet is duplicate\n",
      PLUGIN_NAME_SHORT);
    return;
  }

  /* Compose encapsulation header */
  encapHdr = (struct TEncapHeader*) encapsulationUdpData;
  memset (encapHdr, 0, ENCAP_HDR_LEN);
  encapHdr->type = BMF_ENCAP_TYPE;
  encapHdr->len = BMF_ENCAP_LEN;
  encapHdr->reserved = 0;
  encapHdr->crc32 = htonl(crc32);

  /* Check with each network interface what needs to be done on it */
  for (walker = BmfInterfaces; walker != NULL; walker = walker->next)
  {
    /* Is the forwarding interface OLSR-enabled? */
    if (walker->olsrIntf != NULL)
    {
      /* On an OLSR interface: encapsulate and forward packet. */
      EncapsulateAndForwardPacket(walker, encapsulationUdpData, NULL, NULL, NULL);
    }
    else
    {
      /* On a non-OLSR interface: what to do?
       * Answer 1: nothing. Multicast routing between non-OLSR interfaces
       * is to be done by other protocols (e.g. PIM, DVMRP).
       * Answer 2 (better): Forward it. */
      ForwardPacket (walker, ipPacket, ipPacketLen, "forwarded from non-OLSR to non-OLSR interface");
    } /* if */
  } /* for */
} /* BmfTunPacketCaptured */
Exemple #4
0
/* -------------------------------------------------------------------------
 * Function   : BmfPacketCaptured
 * Description: Handle a captured IP packet
 * Input      : intf - the network interface on which the packet was captured
 *              sllPkttype - the type of packet. Either PACKET_OUTGOING,
 *                PACKET_BROADCAST or PACKET_MULTICAST.
 *              encapsulationUdpData - space for the encapsulation header, followed by
 *                the captured IP packet
 * Output     : none
 * Return     : none
 * Data Used  : BmfInterfaces
 * Notes      : The IP packet is assumed to be captured on a socket of family
 *              PF_PACKET and type SOCK_DGRAM (cooked).
 * ------------------------------------------------------------------------- */
static void BmfPacketCaptured(
  struct TBmfInterface* intf,
  unsigned char sllPkttype,
  unsigned char* encapsulationUdpData)
{
  union olsr_ip_addr src; /* Source IP address in captured packet */
  union olsr_ip_addr dst; /* Destination IP address in captured packet */
  union olsr_ip_addr* origIp; /* Main OLSR address of source of captured packet */
  struct TBmfInterface* walker;
  int isFromOlsrIntf;
  int isFromOlsrNeighbor;
  int iAmMpr;
  unsigned char* ipPacket; /* The captured IP packet... */
  u_int16_t ipPacketLen; /* ...and its length */
  struct ip* ipHeader; /* The IP header inside the captured IP packet */
  u_int32_t crc32;
  struct TEncapHeader* encapHdr;
#ifndef NODEBUG
  struct ipaddr_str srcBuf, dstBuf;
#endif
  ipHeader = GetIpHeader(encapsulationUdpData);

  dst.v4 = ipHeader->ip_dst;

  /* Only forward multicast packets. If configured, also forward local broadcast packets */
  if (IsMulticast(&dst) ||
      (EnableLocalBroadcast != 0 && ipequal(&dst, &intf->broadAddr)))
  {
    /* continue */
  }
  else
  {
    return;
  }

  ipPacket = GetIpPacket(encapsulationUdpData);

  /* Don't forward fragments of IP packets: there is no way to distinguish fragments
   * of BMF encapsulation packets from other fragments.
   * Well yes, there is the IP-ID, which can be kept in a list to relate a fragment
   * to earlier sent BMF packets, but... sometimes the second fragment comes in earlier
   * than the first fragment, so that the list is not yet up to date and the second
   * fragment is not recognized as a BMF packet.
   * Also, don't forward OLSR packets (UDP port 698) and BMF encapsulated packets */
  if (IsIpFragment(ipPacket) || IsOlsrOrBmfPacket(ipPacket))
  {
    return;
  }

  /* Increase counter */
  intf->nBmfPacketsRx++;

  /* Check if the frame is captured on an OLSR-enabled interface */
  isFromOlsrIntf = (intf->olsrIntf != NULL);

  /* Retrieve the length of the captured packet */
  ipPacketLen = GetIpTotalLength(ipPacket);

  src.v4 = ipHeader->ip_src;

  OLSR_PRINTF(
    8,
    "%s: %s pkt of %ld bytes captured on %s interface \"%s\": %s->%s\n",
    PLUGIN_NAME_SHORT,
    sllPkttype == PACKET_OUTGOING ? "outgoing" : "incoming",
    (long)ipPacketLen,
    isFromOlsrIntf ? "OLSR" : "non-OLSR",
    intf->ifName,
    olsr_ip_to_string(&srcBuf, &src),
    olsr_ip_to_string(&dstBuf, &dst));

  /* Lookup main address of source in the MID table of OLSR */
  origIp = MainAddressOf(&src);

  /* Calculate packet fingerprint */
  crc32 = PacketCrc32(ipPacket, ipPacketLen);

  /* Check if this packet was seen recently */
  if (CheckAndMarkRecentPacket(crc32))
  {
    /* Increase counter */
    intf->nBmfPacketsRxDup++;

    OLSR_PRINTF(
      8,
      "%s: --> discarding: packet is duplicate\n",
      PLUGIN_NAME_SHORT);
    return;
  }

  /* Compose encapsulation header */
  encapHdr = (struct TEncapHeader*) encapsulationUdpData;
  memset (encapHdr, 0, ENCAP_HDR_LEN);
  encapHdr->type = BMF_ENCAP_TYPE;
  encapHdr->len = BMF_ENCAP_LEN;
  encapHdr->reserved = 0;
  encapHdr->crc32 = htonl(crc32);

  /* Check if the frame is captured on an OLSR interface from an OLSR neighbor.
   * TODO: get_best_link_to_neighbor() may be very CPU-expensive, a simpler call
   * would do here (something like 'get_any_link_to_neighbor()'). */
  isFromOlsrNeighbor =
    (isFromOlsrIntf /* The frame is captured on an OLSR interface... */
    && get_best_link_to_neighbor(origIp) != NULL); /* ...from an OLSR neighbor */ 

  /* Check with OLSR if I am MPR for that neighbor */
  iAmMpr = olsr_lookup_mprs_set(origIp) != NULL;

  /* Check with each network interface what needs to be done on it */
  for (walker = BmfInterfaces; walker != NULL; walker = walker->next)
  {
    /* Is the forwarding interface OLSR-enabled? */
    int isToOlsrIntf = (walker->olsrIntf != NULL);

    /* Depending on certain conditions, we decide whether or not to forward
     * the packet, and if it is forwarded, in which form (encapsulated
     * or not, TTL decreased or not). These conditions are:
     * - is the packet is coming in on an OLSR interface or not? (isFromOlsrIntf)
     * - is the packet going out on an OLSR interface or not? (isToOlsrIntf)
     * - if the packet if coming in on an OLSR interface:
     *   - is the node that forwarded the packet my OLSR-neighbor? (isFromOlsrNeighbor)
     *   - has the node that forwarded the packet selected me as MPR? (iAmMpr)
     *
     * Based on these conditions, the following cases can be distinguished:
     *
     * - Case 1: Packet coming in on an OLSR interface. What to
     *   do with it on an OLSR interface?
     *   Answer:
     *   - Case 1.1: If the forwarding node is an OLSR neighbor that has *not*
     *     selected me as MPR: don't forward the packet.
     *   - Case 1.2: If the forwarding node is an OLSR neighbor that has selected
     *     me as MPR: encapsulate and forward the packet.
     *   - Case 1.3: If the forwarding node is not an OLSR neighbor: encapsulate
     *     and forward the packet.
     *     NOTE: Case 1.3 is a special case. In the perfect world, we expect to
     *     see only OLSR-neighbors on OLSR-enabled interfaces. Sometimes, however,
     *     ignorant users will connect a host not running OLSR, to a LAN in
     *     which there are hosts running OLSR. Of course these ignorant users,
     *     expecting magic, want to see their multicast packets being forwarded
     *     through the network.
     *
     * - Case 2: Packet coming in on an OLSR interface. What to do with it on a
     *   non-OLSR interface?
     *   Answer: Forward it.
     *
     * - Case 3: Packet coming in on a non-OLSR interface. What to
     *   do with it on an OLSR interface?
     *   Answer: Encapsulate and forward it.
     *
     * - Case 4: Packet coming in on non-OLSR interface. What to do with it on a
     *   non-OLSR interface?
     *   Answer 1: nothing. Multicast routing between non-OLSR interfaces
     *   is to be done by other protocols (e.g. PIM, DVMRP).
     *   Answer 2 (better): Forward it.
     */

    if (isFromOlsrIntf && isToOlsrIntf)
    {
      /* Case 1: Forward from an OLSR interface to an OLSR interface */

      if (isFromOlsrNeighbor && !iAmMpr)
      {
        /* Case 1.1 */
        {
#ifndef NODEBUG
          struct ipaddr_str buf;
#endif
          OLSR_PRINTF(
            8,
            "%s: --> not encap-forwarding on \"%s\": I am not selected as MPR by neighbor %s\n",
            PLUGIN_NAME_SHORT,
            walker->ifName,
            olsr_ip_to_string(&buf, &src));
        }    
      }
      else if (sllPkttype == PACKET_OUTGOING && intf == walker)
      {
        OLSR_PRINTF(
          8,
          "%s: --> not encap-forwarding on \"%s\": pkt was captured on that interface\n",
          PLUGIN_NAME_SHORT,
          walker->ifName);
      }
      else
      {
        /* Case 1.2 and 1.3 */
        EncapsulateAndForwardPacket(walker, encapsulationUdpData, NULL, NULL, NULL);
      }
    } /* if (isFromOlsrIntf && isToOlsrIntf) */

    else if (isFromOlsrIntf && !isToOlsrIntf)
    {
      /* Case 2: Forward from OLSR interface to non-OLSR interface */
      ForwardPacket (walker, ipPacket, ipPacketLen, "forwarded to non-OLSR interface");
    } /* else if (isFromOlsrIntf && !isToOlsrIntf) */

    else if (!isFromOlsrIntf && isToOlsrIntf)
    {
      /* Case 3: Forward from a non-OLSR interface to an OLSR interface.
       * Encapsulate and forward packet. */
      EncapsulateAndForwardPacket(walker, encapsulationUdpData, NULL, NULL, NULL);
    } /* else if (!isFromOlsrIntf && isToOlsrIntf) */

    else
    {
      /* Case 4: Forward from non-OLSR interface to non-OLSR interface. */

      /* Don't forward on interface on which packet was received */
      if (intf == walker)
      {
        OLSR_PRINTF(
          8,
          "%s: --> not forwarding on \"%s\": pkt was captured on that interface\n",
          PLUGIN_NAME_SHORT,
          walker->ifName);
      }

      else
      {
        ForwardPacket (walker, ipPacket, ipPacketLen, "forwarded from non-OLSR to non-OLSR interface");
      } /* if (intf == walker) */
    } /* if */
  } /* for */
} /* BmfPacketCaptured */
rtperror RTPOpenConnection(context cid){
  struct sockaddr_in saddr;
  int dynamic_ports,bind_count,problem, nRet;
  socktype rtpskt, rtcpskt;
  hl_context *uc;
  rtperror err;

  err = RTPSessionGetHighLevelInfo(cid, (void**)&uc);
  if (err != RTP_OK)
    /* The cid is bogus */
    return err;

  if (uc->connection_opened){
    RTPCloseConnection(cid,NULL);
  }

  /* First check if the user has set the local address */
  if(uc->recv_addr_list == NULL) {
    return errordebug(RTP_BAD_ADDR, "RTPOpenConnection",
		      "Address not yet set");
  }

  /* Set a flag for dynamic ports */

  if(uc->recv_addr_list->port == 0) 
    dynamic_ports = 1;
  else
    dynamic_ports = 0;

  /* For dynamic ports, we choose a port randomly, and try
     and bind to it, plus the one one higher for RTCP. If either
     fail, we iterate _BIND_COUNTER times, and then give up */

  bind_count = 0;
  while(bind_count < _BIND_COUNTER) {
    bind_count++;

    /* We only use ports in the dynamic range - 49152 - 65535 */

    if(dynamic_ports == 1) 
      uc->recv_addr_list->port =
	htons(_UDP_PORT_BASE + 2 * ((u_int16) (drand48() * _UDP_PORT_RANGE)));


    /* Create the RTP and RTCP sockets */
    uc->recv_addr_list->rtpsocket = _sys_create_socket(SOCK_DGRAM);
    rtpskt = uc->recv_addr_list->rtpsocket;
    if (uc->recv_addr_list->rtpsocket == _SYS_INVALID_SOCKET){
      return errordebug(RTP_CANT_GET_SOCKET, "RTPOpenConnection",
			"couldn't get RTP socket for context %d",  (int)cid);
    }
    uc->recv_addr_list->rtcpsocket = _sys_create_socket(SOCK_DGRAM);
    rtcpskt = uc->recv_addr_list->rtcpsocket;
    if (uc->recv_addr_list->rtcpsocket == _SYS_INVALID_SOCKET){
      _sys_close_socket(rtpskt);
      return errordebug(RTP_CANT_GET_SOCKET, "RTPOpenConnection",
			"couldn't get RTCP socket for context %d",  (int)cid);
    }


	if(_sys_set_reuseaddr(rtpskt) == _SYS_SOCKET_ERROR) {
      _sys_close_socket (rtpskt);
      _sys_close_socket (rtcpskt);
      return errordebug(RTP_CANT_SET_SOCKOPT, "RTPOpenConnection",
			"couldn't reuse RTP address for context %d", (int)cid);
    }
	if(_sys_set_reuseaddr(rtcpskt) == _SYS_SOCKET_ERROR) {
      _sys_close_socket(rtpskt);
      _sys_close_socket(rtcpskt);
      return errordebug(RTP_CANT_SET_SOCKOPT, "RTPOpenConnection",
			"couldn't reuse RTCP address for context %d", (int)cid);
    } 

	if(_sys_set_reuseport(rtpskt) == _SYS_SOCKET_ERROR) {
      _sys_close_socket(rtpskt);
      _sys_close_socket(rtcpskt);
      return errordebug(RTP_CANT_SET_SOCKOPT, "RTPOpenConnection",
			"couldn't reuse RTP port for context %d",  (int)cid);
    }
    if (_sys_set_reuseport(rtcpskt) == _SYS_SOCKET_ERROR) {
      _sys_close_socket(rtpskt);
      _sys_close_socket(rtcpskt);
      return errordebug(RTP_CANT_SET_SOCKOPT, "RTPOpenConnection",
			"couldn't reuse RTCP port for context %d",  (int)cid);
    } 

    /* bind sockets */
    
    memset(&saddr, 0, sizeof(saddr));
    saddr.sin_family = AF_INET;
    saddr.sin_addr = uc->recv_addr_list->address;
    saddr.sin_port = uc->recv_addr_list->port;

    /* If the address is multicast or null, bind to INADDR_ANY */

    if((uc->recv_addr_list->address.s_addr == 0) ||
       IsMulticast(saddr.sin_addr))
      saddr.sin_addr.s_addr = INADDR_ANY;

    /* RTP port bind */
    problem = 0;
    if((problem = _sys_bind(rtpskt, &saddr)) == _SYS_SOCKET_ADDRNOTAVAIL) {
		saddr.sin_addr.s_addr = INADDR_ANY;
		problem = _sys_bind(rtpskt, &saddr);
    }

    /* Address in use, try another port if we're doing dynamic ports */

    if((problem == _SYS_SOCKET_ADDRINUSE) &&
       (dynamic_ports == 1)) {
      _sys_close_socket(rtpskt);
      _sys_close_socket(rtcpskt);
      continue;
    } else if(problem != 0) {
      return errordebug(RTP_CANT_BIND_SOCKET, "RTPOpenConnection",
			"couldn't bind RTP address for context %d",  (int)cid);
    }

    /* No error! */

    saddr.sin_port = htons(ntohs(uc->recv_addr_list->port) + 1);

    /* Bind to RTCP port */

    problem = 0;
    if((problem = _sys_bind(rtcpskt, &saddr)) == _SYS_SOCKET_ADDRNOTAVAIL) {


      /* The user specified a nonlocal address - probably they want to
	 send to this as a unicast address, so try INADDR_ANY */
		saddr.sin_addr.s_addr = INADDR_ANY;
		problem = _sys_bind(rtpskt, &saddr);

    }

    /* Address in use, try another port if we're doing dynamic ports */

    if((problem == _SYS_SOCKET_ADDRINUSE) &&
       (dynamic_ports == 1)) {
      _sys_close_socket(rtpskt);
      _sys_close_socket(rtcpskt);
      continue;
    } else if(problem != 0) {
      return errordebug(RTP_CANT_BIND_SOCKET, "RTPOpenConnection",
			"couldn't bind RTCP address for context %d", (int)cid);
    }

    break;

  }

  /* Now we are here either because of success, or looping
     too much */

  if(bind_count == _BIND_COUNTER) {
    return errordebug(RTP_CANT_BIND_SOCKET, "RTPOpenConnection",
		      "couldn't bind dynamic address for context %d", (int)cid);
  }


  /* Allow reuse of the address and port  */

  if (IsMulticast(uc->recv_addr_list->address)){ /* Multicast */
  
    /* Every member of the session is a member of the multicast session */
	  memset(&saddr, 0, sizeof(saddr));
	  saddr.sin_family = AF_INET;
	  saddr.sin_addr = uc->recv_addr_list->address;
	  saddr.sin_port = uc->recv_addr_list->port;
	  nRet = _sys_join_mcast_group(rtpskt, &saddr);
	  if(nRet == _SYS_SOCKET_ERROR) {
		  _sys_close_socket(rtpskt);
		  _sys_close_socket(rtcpskt);
		  return errordebug(RTP_CANT_SET_SOCKOPT, "RTPOpenConnection",
			  "couldn't join RTP multicast group for context %d",  (int)cid);
	  }
	  nRet = _sys_join_mcast_group(rtcpskt, &saddr);
	  if(nRet == _SYS_SOCKET_ERROR) {
		  _sys_close_socket(rtpskt);
		  _sys_close_socket(rtcpskt);
		  return errordebug(RTP_CANT_SET_SOCKOPT, "RTPOpenConnection",
			  "couldn't join RTCP multicast group for context %d",  (int)cid);
	  }

  }

  /* Schedule the first rtcp packet, and initialize some data structures */
  err = RTPStartSession(cid);
  if (err != RTP_OK)
    return err;

  uc->connection_opened = TRUE;

  return RTP_OK;
}
rtperror RTPSessionAddSendAddr(context cid, char *addr, u_int16 port, u_int8 ttl){
  address_holder_t *holder;
  struct sockaddr_in saddr;
  int len, nRet;
  struct in_addr translation;
  hl_context *uc;
  rtperror err;

  err = RTPSessionGetHighLevelInfo(cid, (void**)&uc);
  if (err != RTP_OK)
    /* The cid is bogus */
    return err;

  if (port == 0) {
    return errordebug(RTP_BAD_PORT, "RTPSessionAddSendAddr",
		      "Port number zero not allowed");
  }
  /* If the port is odd, assume it's the RTCP port */

  if((port & 1) == 1)
    port--;

  if((holder = (address_holder_t *) malloc(sizeof(address_holder_t))) == 0) {
    return errordebug(RTP_CANT_ALLOC_MEM, "RTPSessionAddSendAddr",
		      "Cannot allocate memory");
  }


  /* Translate address */
  translation = host2ip(addr);
  if(translation.s_addr == (u_int32) -1) {
    free(holder);
    return errordebug(RTP_BAD_ADDR, "RTPSessionAddSendAddr",
		      "Could not resolve address");
  }


  /* Write values of address, port to context */
  holder->address = translation;
  holder->port = htons(port);
  holder->deleteflag = FALSE;
  holder->ttl = 0;
  if(IsMulticast(translation)) holder->ttl = ttl;


  /* Create the RTP and RTCP sockets for this sender */

  holder->rtpsocket = _sys_create_socket(SOCK_DGRAM);

  if (holder->rtpsocket == _SYS_INVALID_SOCKET){
    free(holder);
    return errordebug(RTP_CANT_GET_SOCKET, "RTPSessionAddSendAddr",
		      "couldn't get RTP socket for context %d",  (int)cid);
  }

  holder->rtcpsocket = _sys_create_socket(SOCK_DGRAM);
  if (holder->rtcpsocket == _SYS_INVALID_SOCKET){
    _sys_close_socket(holder->rtpsocket);
    free(holder);
    return errordebug(RTP_CANT_GET_SOCKET, "RTPSessionAddSendAddr",
		      "couldn't get RTCP socket for context %d",  (int)cid);
  }

  /* Connect them, first RTP socket */

  memset(&saddr, 0, sizeof(saddr));
  saddr.sin_family = AF_INET;
  saddr.sin_addr = holder->address;
  saddr.sin_port = htons(port);

  if(_sys_connect_socket(holder->rtpsocket, &saddr) == _SYS_SOCKET_ERROR) {
    err = errordebug(RTP_CANT_GET_SOCKET, "RTPSessionAddSendAddr", 
		     "couldn't connect RTP socket for context %d",  (int)cid);
    goto bailout;
  }

  /* Now RTCP socket */
  saddr.sin_port = htons(port+1);

  if(_sys_connect_socket(holder->rtcpsocket, &saddr) == _SYS_SOCKET_ERROR) {
    err = errordebug(RTP_CANT_GET_SOCKET, "RTPSessionAddSendAddr", 
		      "couldn't connect RTCP socket for context %d",  (int)cid);
    goto bailout;
  }
  
  if(IsMulticast(holder->address)) {
    /* Set multicast TTL if needed */
	  nRet = _sys_set_ttl(holder->rtpsocket, ttl);
	  if(nRet == _SYS_SOCKET_ERROR) {
		  err = errordebug(RTP_CANT_SET_SOCKOPT, "RTPSessionAddSendAddr",
			  "couldn't set RTP TTL for context %d",  (int)cid);
		  goto bailout;
	  }
	  nRet = _sys_set_ttl(holder->rtcpsocket, ttl);
	  
	  if(nRet == _SYS_SOCKET_ERROR) {
		  err = errordebug(RTP_CANT_SET_SOCKOPT, "RTPSessionAddSendAddr",
			  "couldn't set RTCP TTL for context %d",  (int)cid);
		  goto bailout;
	  }



	  /* Determine source addresses, for loopback detection */
	  /* XXX: multiple multicast destinations might have different sources */

	  len = sizeof(struct sockaddr_in);

	  if(_sys_get_socket_name(holder->rtpsocket, &uc->rtp_sourceaddr) == _SYS_SOCKET_ERROR) {
		  err = errordebug(RTP_CANT_GET_SOCKET, "RTPSessionAddSendAddr",
			  "Couldn't get RTP source address for context %d", (int)cid);
		  goto bailout;
	  }
	  if(_sys_get_socket_name(holder->rtcpsocket, &uc->rtcp_sourceaddr) == _SYS_SOCKET_ERROR) {
		  err = errordebug(RTP_CANT_GET_SOCKET, "RTPSessionAddSendAddr",
			  "Couldn't get RTCP source address for context %d", (int)cid);
		  goto bailout;
	  }
  }
   
  /* Add address to list */

  holder->next = uc->send_addr_list;
  uc->send_addr_list = holder;

  return RTP_OK;

  bailout:

  _sys_close_socket(holder->rtpsocket);
  _sys_close_socket(holder->rtcpsocket);
  free(holder);

  return err;
}