예제 #1
0
static void
SetNextState(STUN_TRANSACTION_DATA* trans,
             STUN_STATE             NextState)
{
  STUN_CLIENT_DATA* client = trans->client;

  if  (NextState >= NoOfStates)
  {
    StunPrint(client->logUserData,
              client->Log_cb,
              StunInfoCategory_Error,
              "<STUNCLIENT:%02d> SetNextState, Illegal State %d",
              trans->inst,
              NextState);
    return;
  }

  if (trans->state != NextState)
  {
    StunPrint(client->logUserData, client->Log_cb, StunInfoCategory_Trace,
              "<STUNCLIENT:%02d> State (%s -> %s)", trans->inst,
              StateTable[trans->state].StateStr,
              StateTable[NextState].StateStr);
    trans->state = NextState;
  }

  /* always free instance on return to idle */
  if (NextState == STUN_STATE_Idle)
  {
    trans->inUse = false;
  }
}
예제 #2
0
void
StunClient_HandleIncResp(STUN_CLIENT_DATA*      clientData,
                         const StunMessage*     msg,
                         const struct sockaddr* srcAddr)
{
  if (clientData == NULL)
  {
    return;
  }

  for (int i = 0; i < MAX_STUN_TRANSACTIONS; i++)
  {
    STUN_TRANSACTION_DATA* trans = &clientData->data[i];
    if ( trans->inUse &&
         TransIdIsEqual(&msg->msgHdr.id, &trans->stunBindReq.transactionId) )
    {
      StunRespStruct m;
      gettimeofday(&trans->stop[trans->retransmits], NULL);
      memcpy( &m.stunRespMessage, msg, sizeof(m.stunRespMessage) );
      sockaddr_copy( (struct sockaddr*)&m.srcAddr, srcAddr );
      StunClientMain(clientData, i, StunMsgToInternalStunSig(msg), (void*)&m);
      return;
    }
  }
  StunPrint(clientData->logUserData,
            clientData->Log_cb,
            StunInfoCategory_Trace,
            "<STUNCLIENT> no instance with transId, discarding, msgType %d\n ",
            msg->msgHdr.msgType);
}
예제 #3
0
static bool
StoreBindResp(STUN_TRANSACTION_DATA* trans,
              StunMessage*           resp)
{
  STUN_CLIENT_DATA* client = trans->client;

  if (resp->hasXorMappedAddress)
  {
    if (resp->xorMappedAddress.familyType == STUN_ADDR_IPv4Family)
    {
      sockaddr_initFromIPv4Int( (struct sockaddr_in*)&trans->rflxAddr,
                                htonl(resp->xorMappedAddress.addr.v4.addr),
                                htons(resp->xorMappedAddress.addr.v4.port) );
    }
    else if (resp->xorMappedAddress.familyType == STUN_ADDR_IPv6Family)
    {
      sockaddr_initFromIPv6Int( (struct sockaddr_in6*)&trans->rflxAddr,
                                resp->xorMappedAddress.addr.v6.addr,
                                htons(resp->xorMappedAddress.addr.v6.port) );
    }

    return true;
  }
  else
  {
    StunPrint(client->logUserData, client->Log_cb, StunInfoCategory_Error,
              "<STUNCLIENT:%02d> Missing XorMappedAddress BindResp",
              trans->inst);
    return false;
  }
}
예제 #4
0
static void
ICMPRespCallback(STUN_TRANSACTION_DATA* trans,
                 const struct sockaddr* srcAddr)
{
  STUN_CLIENT_DATA*  client = trans->client;
  char               ip_str [SOCKADDR_MAX_STRLEN];
  StunCallBackData_T res;

  memset( &res, 0, sizeof (StunCallBackData_T) );

  memcpy( &res.msgId, &trans->stunBindReq.transactionId, sizeof(StunMsgId) );

  res.stunResult = StunResult_ICMPResp;
  res.ICMPtype   = trans->ICMPtype;
  res.ttl        = trans->ttl;

  res.rtt         = getRTTvalue(trans);
  res.retransmits = trans->retransmits;
  sockaddr_copy( (struct sockaddr*)&res.srcAddr,
                 srcAddr );

  StunPrint( client->logUserData, client->Log_cb, StunInfoCategory_Info,
             "<STUNCLIENT:%02d> ICMPResp from src: %s",
             trans->inst,
             sockaddr_toString( (struct sockaddr*) &res.srcAddr, ip_str,
                                SOCKADDR_MAX_STRLEN,
                                true ) );


  if (trans->stunBindReq.stunCbFunc)
  {
    (trans->stunBindReq.stunCbFunc)(trans->stunBindReq.userCtx, &res);
  }
}
예제 #5
0
static void
CancelRetryTimeoutHandler(STUN_TRANSACTION_DATA* trans)
{
  STUN_CLIENT_DATA* client = trans->client;
  uint32_t max;

  if (trans->stunBindReq.stuntrace)
  {
    max = STUNTRACE_MAX_RETRANSMITS;
  }
  else
  {
    max = STUNCLIENT_MAX_RETRANSMITS;
  }


  if ( (trans->retransmits < max)
       && (stunTimeoutList[trans->retransmits] != 0) ) /* can be 0 terminated if
                                                        * using fewer
                                                        * retransmits
                                                        **/
  {
    StartNextRetransmitTimer(trans);
    trans->retransmits++;
  }
  else
  {
    StunPrint(client->logUserData, client->Log_cb, StunInfoCategory_Trace,
              "<STUNCLIENT:%02d> Cancel complete", trans->inst);
    CallBack(trans, StunResult_CancelComplete);
    SetNextState(trans, STUN_STATE_Idle);
  }
}
예제 #6
0
void
StunClient_HandleICMP(STUN_CLIENT_DATA*      clientData,
                      const struct sockaddr* srcAddr,
                      uint32_t               ICMPtype)
{
  if (clientData == NULL)
  {
    return;
  }
  /* Todo: Test if this is for me.. */
  StunPrint(clientData->logUserData,
            clientData->Log_cb,
            StunInfoCategory_Trace,
            "<STUNTRACE> StunClient_HandleICMP: Got ICMP type: %i\n ",
            ICMPtype);

  if ( isTimeExceeded(ICMPtype, srcAddr->sa_family) ||
       isDstUnreachable(ICMPtype,srcAddr->sa_family) )
  {
    for (int i = 0; i < MAX_STUN_TRANSACTIONS; i++)
    {
      STUN_TRANSACTION_DATA* trans = &clientData->data[i];
      if ( trans->inUse &&
           TransIdIsEqual(&clientData->traceResult.currStunMsgId,
                          &trans->stunBindReq.transactionId) )
      {
        StunRespStruct m;
        gettimeofday(&trans->stop[trans->retransmits], NULL);
        /* memcpy(&m.stunRespMessage, msg, sizeof(m.stunRespMessage)); */
        sockaddr_copy( (struct sockaddr*)&m.srcAddr, srcAddr );
        m.ICMPtype = ICMPtype;
        m.ttl      = clientData->traceResult.currentTTL;
        StunClientMain(clientData, i, STUN_SIGNAL_ICMPResp, (void*)&m);
        return;

      }
    }
  }
  else
  {
    StunPrint(clientData->logUserData,
              clientData->Log_cb,
              StunInfoCategory_Trace,
              "<STUNTRACE> StunClient_HandleICMP: Ignoring ICMP Type, nothing to do\n ",
              ICMPtype);
  }
}
예제 #7
0
/* Common signal handling for all states */
static void
StunAllState(STUN_TRANSACTION_DATA* trans,
             STUN_SIGNAL            sig)
{
  STUN_CLIENT_DATA* client = trans->client;

  StunPrint(client->logUserData, client->Log_cb, StunInfoCategory_Error,
            "<STUNCLIENT:%02d> undefined signal %s in state %d",
            trans->inst, StunsigToStr(sig), trans->state);
}
예제 #8
0
static void
StunClientMain(STUN_CLIENT_DATA* clientData,
               int               ctx,
               STUN_SIGNAL       sig,
               uint8_t*          payload)
{
  /* if  context is already known, just call the  fsm */
  if (ctx != STUNCLIENT_CTX_UNKNOWN)
  {
    if (ctx < MAX_STUN_TRANSACTIONS)
    {
      StunClientFsm(&clientData->data[ctx], sig, payload);
    }
    else
    {
      StunPrint(clientData->logUserData,
                clientData->Log_cb,
                StunInfoCategory_Error,
                "<STUNCLIENT> sig: %s illegal context %d exceeds %d\n ",
                StunsigToStr(sig),
                ctx,
                MAX_STUN_TRANSACTIONS);
    }
  }
  else if (sig == STUN_SIGNAL_BindReq)
  {
    ctx = AllocFreeInst(clientData,&sig, payload);
    if (ctx >= 0)
    {
      StunClientFsm(&clientData->data[ctx], sig, payload);
    }
    else
    {
      StunPrint( clientData->logUserData, clientData->Log_cb,
                 StunInfoCategory_Error,
                 "<STUNCLIENT> No free instances, sig: %s", StunsigToStr(sig) );
    }
  }
}
예제 #9
0
/* check if timer has expired and return the timer signal */
static void
StopTimer(STUN_TRANSACTION_DATA* trans,
          STUN_SIGNAL            sig)
{
  STUN_CLIENT_DATA* client = trans->client;

    StunPrint( client->logUserData, client->Log_cb, StunInfoCategory_Trace,
             "<STUNCLIENT:%02d> StopTimer(%s)", trans->inst,
             StunsigToStr(sig) );

  switch (sig)
  {
  case STUN_SIGNAL_TimerRetransmit:
    trans->TimerRetransmit = 0;
    break;

  default:
    StunPrint(client->logUserData, client->Log_cb, StunInfoCategory_Error,
              "<STUNCLIENT:%02d> illegal StopTimer %d", trans->inst,  sig);
    break;
  }
}
예제 #10
0
static void
StunClientFsm(STUN_TRANSACTION_DATA* trans,
              STUN_SIGNAL            sig,
              uint8_t*               payload)
{
  STUN_CLIENT_DATA* client = trans->client;

  if (trans->state < STUN_STATE_End)
  {
    StunPrint(client->logUserData, client->Log_cb, StunInfoCategory_Trace,
              "<STUNCLIENT:%02d> IN <-- %s (state %s)",
              trans->inst, StunsigToStr(sig),
              StateTable[trans->state].StateStr);
    (StateTable[trans->state].Statefunc)(trans, sig, payload);
  }
  else
  {
    StunPrint( client->logUserData, client->Log_cb, StunInfoCategory_Error,
               "<STUNCLIENT:%02d> undefned state %d, sig %s",
               trans->inst, trans->state, StunsigToStr(sig) );
  }
}
예제 #11
0
static bool
SendConnectivityBindResponse(STUN_CLIENT_DATA*      clientData,
                             int32_t                globalSocketId,
                             StunMessage*           stunRespMsg,
                             const char*            password,
                             const struct sockaddr* dstAddr,
                             void*                  userData,
                             STUN_SENDFUNC          sendFunc,
                             int                    proto,
                             bool                   useRelay)
{
  uint8_t stunBuff[STUN_MAX_PACKET_SIZE];
  int     stunLen;

  (void) userData;
  /* encode bind Response */
  stunLen = stunlib_encodeMessage(stunRespMsg,
                                  (uint8_t*)stunBuff,
                                  STUN_MAX_PACKET_SIZE,
                                  (unsigned char*)password,           /* md5key
                                                                      **/
                                  password ? strlen(password) : 0,    /* keyLen
                                                                      **/
                                  NULL);
  if (!stunLen)
  {
    StunPrint(clientData->logUserData,
              clientData->Log_cb,
              StunInfoCategory_Error,
              "<STUNCLIENT>  Failed to encode Binding request response\n");
    return false;
  }

  /* send */
  /* sendFunc(globalSocketId, stunBuff, stunLen, dstAddr, useRelay, 0); */
  sendFunc(clientData->userCtx,
           globalSocketId,
           stunBuff,
           stunLen,
           dstAddr,
           proto,
           useRelay,
           0);
  clientData->stats.BindRespSent++;
  return true;
}
예제 #12
0
static void
CommonRetryTimeoutHandler(STUN_TRANSACTION_DATA* trans,
                          StunResult_T           stunResult,
                          const char*            errStr,
                          STUN_STATE             FailedState)
{
  STUN_CLIENT_DATA* client = trans->client;

  uint32_t max;

  if (trans->stunBindReq.stuntrace)
  {
    max = STUNTRACE_MAX_RETRANSMITS;
  }
  else
  {
    max = STUNCLIENT_MAX_RETRANSMITS;
  }

  if ( (trans->retransmits < max)
       && (stunTimeoutList[trans->retransmits] != 0) ) /* can be 0 terminated if
                                                        * using fewer
                                                        * retransmits
                                                        **/
  {
    char peer [SOCKADDR_MAX_STRLEN] = {0,};
    sockaddr_toString( (struct sockaddr*) &trans->stunBindReq.serverAddr, peer,
                       sizeof (peer), true );

    StunPrint(client->logUserData, client->Log_cb, StunInfoCategory_Trace,
              "<STUNCLIENT:%02d> Retrans %s Retry: %d to %s",
              trans->inst, errStr, trans->retransmits + 1, peer);
    RetransmitLastReq(trans, &trans->stunBindReq.serverAddr);
    StartNextRetransmitTimer(trans);
    trans->retransmits++;
    trans->stats.Retransmits++;
  }
  else
  {
    CallBack(trans, stunResult);
    SetNextState(trans, FailedState);
    trans->stats.Failures++;
  }
}
예제 #13
0
static void
BindRespCallback(STUN_TRANSACTION_DATA* trans,
                 const struct sockaddr* srcAddr)
{
  STUN_CLIENT_DATA*  client = trans->client;
  char               ip_str [SOCKADDR_MAX_STRLEN];
  StunCallBackData_T res;

  memset( &res, 0, sizeof (StunCallBackData_T) );

  memcpy( &res.msgId, &trans->stunBindReq.transactionId, sizeof(StunMsgId) );

  res.stunResult = StunResult_BindOk;

  sockaddr_copy( (struct sockaddr*)&res.rflxAddr,
                 (struct sockaddr*)&trans->rflxAddr );

  sockaddr_copy( (struct sockaddr*)&res.srcAddr,
                 srcAddr );

  sockaddr_copy( (struct sockaddr*)&res.dstBaseAddr,
                 (struct sockaddr*)&trans->stunBindReq.baseAddr );

  /* So did we loose a packet, or got an answer to the first response?*/

  res.rtt = getRTTvalue(trans);
  res.ttl = trans->stunBindReq.ttl;

  StunPrint( client->logUserData, client->Log_cb, StunInfoCategory_Info,
             "<STUNCLIENT:%02d> BindResp from src: %s",
             trans->inst,
             sockaddr_toString( (struct sockaddr*) &res.srcAddr, ip_str,
                                SOCKADDR_MAX_STRLEN,
                                true ) );

  if (trans->stunBindReq.stunCbFunc)
  {
    (trans->stunBindReq.stunCbFunc)(trans->stunBindReq.userCtx, &res);
  }
}
예제 #14
0
/********** Server handling of incoming STUN BIND REQ **********/
bool
StunServer_HandleStunIncomingBindReqMsg(STUN_CLIENT_DATA*       clientData,
                                        STUN_INCOMING_REQ_DATA* pReq,
                                        const StunMessage*      stunMsg,
                                        bool                    fromRelay)
{
  if (!clientData)
  {
    return false;
  }

  memcpy( &pReq->transactionId, &stunMsg->msgHdr.id, sizeof(StunMsgId) );

  pReq->fromRelay = fromRelay;

  if (stunMsg->hasUsername)
  {
    strncpy( pReq->ufrag, stunMsg->username.value,
             min(stunMsg->username.sizeValue, STUN_MAX_STRING) );
    if (stunMsg->username.sizeValue < STUN_MAX_STRING)
    {
      pReq->ufrag[stunMsg->username.sizeValue] = '\0';
    }
    else
    {
      pReq->ufrag[STUN_MAX_STRING - 1] = '\0';
    }
  }
  else
  {
    StunPrint(clientData->logUserData,
              clientData->Log_cb,
              StunInfoCategory_Error,
              "<STUNCLIENT> Missing Username in Binding Request\n");
    return false;
  }

  if (stunMsg->hasPriority)
  {
    pReq->peerPriority = stunMsg->priority.value;
  }
  else
  {
    StunPrint(clientData->logUserData,
              clientData->Log_cb,
              StunInfoCategory_Error,
              "<STUNCLIENT> Missing Priority in Binding Request\n");
    return false;
  }

  pReq->useCandidate = stunMsg->hasUseCandidate;

  if (stunMsg->hasControlling)
  {
    pReq->iceControlling = true;
    pReq->tieBreaker     = stunMsg->controlling.value;
  }
  else
  {
    pReq->iceControlling = false;
  }

  if (stunMsg->hasControlled)
  {
    pReq->iceControlled = true;
    pReq->tieBreaker    = stunMsg->controlled.value;
  }
  else
  {
    pReq->iceControlled = false;
  }

  if (fromRelay)
  {
    clientData->stats.BindReqReceived_ViaRelay++;
  }
  clientData->stats.BindReqReceived++;

  return true;
}
예제 #15
0
void
StunClient_dumpStats (STUN_CLIENT_DATA*  clientData,
                      STUN_INFO_FUNC_PTR logPtr,
                      void*              userData)
{
  struct StunClientStats  stats;
  struct StunClientStats* ptr     = &clientData->stats;
  int                     usedCnt = 0;

    memset(&stats, 0, sizeof stats);

  stats.InProgress                   += ptr->InProgress;
  stats.BindReqSent                  += ptr->BindReqSent;
  stats.BindReqSent_ViaRelay         += ptr->BindReqSent_ViaRelay;
  stats.BindRespReceived             += ptr->BindRespReceived;
  stats.BindRespReceived_AfterCancel += ptr->BindRespReceived_AfterCancel;
  stats.BindRespReceived_InIdle      += ptr->BindRespReceived_InIdle;
  stats.BindRespReceived_ViaRelay    += ptr->BindRespReceived_ViaRelay;
  stats.BindRespErrReceived          += ptr->BindRespErrReceived;
  stats.BindReqReceived              += ptr->BindReqReceived;
  stats.BindReqReceived_ViaRelay     += ptr->BindReqReceived_ViaRelay;
  stats.BindRespSent                 += ptr->BindRespSent;
  stats.BindRespSent_ViaRelay        += ptr->BindRespSent_ViaRelay;
  stats.Retransmits                  += ptr->Retransmits;
  stats.Failures                     += ptr->Failures;

  for (int i = 0; i < MAX_STUN_TRANSACTIONS; i++)
  {
    ptr = &clientData->data[i].stats;

    stats.InProgress                   += ptr->InProgress;
    stats.BindReqSent                  += ptr->BindReqSent;
    stats.BindReqSent_ViaRelay         += ptr->BindReqSent_ViaRelay;
    stats.BindRespReceived             += ptr->BindRespReceived;
    stats.BindRespReceived_AfterCancel += ptr->BindRespReceived_AfterCancel;
    stats.BindRespReceived_InIdle      += ptr->BindRespReceived_InIdle;
    stats.BindRespReceived_ViaRelay    += ptr->BindRespReceived_ViaRelay;
    stats.BindRespErrReceived          += ptr->BindRespErrReceived;
    stats.BindReqReceived              += ptr->BindReqReceived;
    stats.BindReqReceived_ViaRelay     += ptr->BindReqReceived_ViaRelay;
    stats.BindRespSent                 += ptr->BindRespSent;
    stats.BindRespSent_ViaRelay        += ptr->BindRespSent_ViaRelay;
    stats.Retransmits                  += ptr->Retransmits;
    stats.Failures                     += ptr->Failures;

    if (ptr->BindReqSent > 0)
    {
      usedCnt++;
    }
  }

  StunPrint(userData, logPtr, StunInfoCategory_Info,
            "<STUNCLIENTS used:%02d> Stats:"
            "\n\t InProgress %d,"
            "\n\t BindReqSent %d,"
            "\n\t BindRespReceived %d,"
            "\n\t BindRespErrReceived %d,"
            "\n\t BindReqReceived %d,"
            "\n\t BindRespSent %d,"
            "\n\t Retransmits %d,"
            "\n\t Failures %d",
            usedCnt,
            stats.InProgress,
            stats.BindReqSent,
            stats.BindRespReceived,
            stats.BindRespErrReceived,
            stats.BindReqReceived,
            stats.BindRespSent,
            stats.Retransmits,
            stats.Failures);
}
예제 #16
0
/* encode and send */
static bool
SendStunReq(STUN_TRANSACTION_DATA* trans,
            StunMessage*           stunReqMsg)
{
  STUN_CLIENT_DATA* client = trans->client;
  /* encode the BindReq */
  if (strlen(trans->stunBindReq.password) > 0)
  {
    trans->stunReqMsgBufLen = stunlib_encodeMessage(stunReqMsg,
                                                    (unsigned char*) (trans->
                                                                      stunReqMsgBuf),
                                                    STUN_MAX_PACKET_SIZE,
                                                    (unsigned char*)&trans->stunBindReq.password,
                                                    /* key */
                                                    strlen(trans->stunBindReq.
                                                           password),
                                                    /* keyLen
                                                     * */
                                                    NULL);
  }
  else
  {
    trans->stunReqMsgBufLen = stunlib_encodeMessage(stunReqMsg,
                                                    (unsigned char*) (trans->
                                                                      stunReqMsgBuf),
                                                    STUN_MAX_PACKET_SIZE,
                                                    NULL,
                                                    /* key */
                                                    0,
                                                    /* keyLen  */
                                                    NULL);

  }

  if (!trans->stunReqMsgBufLen)
  {
    StunPrint(client->logUserData,
              client->Log_cb,
              StunInfoCategory_Error,
              "<STUNCLIENT:%02d>  SendStunReq(BindReq), failed encode",
              trans->inst);
    return false;
  }

  /*Store Time so we can messure RTT */
  gettimeofday(&trans->start[trans->retransmits], NULL);
  if (trans->stunBindReq.sendFunc != NULL)
  {
    trans->stunBindReq.sendFunc(trans->client->userCtx,
                                trans->stunBindReq.sockhandle,
                                trans->stunReqMsgBuf,
                                trans->stunReqMsgBufLen,
                                (struct sockaddr*)&trans->stunBindReq.serverAddr,
                                trans->stunBindReq.proto,
                                trans->stunBindReq.useRelay,
                                trans->stunBindReq.ttl);
  }
  trans->stats.BindReqSent++;

  return true;
}