Beispiel #1
0
void *ProcessRunningEvent_Client_tep(void *p)
{
  pthread_detach(pthread_self());

  pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
  /* want to be cancelled immediately so we don't try to derefence the event
     after it has been deleted */
  pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);

  DEBUG_THREADS("[ProcessRunningEvent_Client_tep] Caught event.\n");

  ICQEvent *e = (ICQEvent *)p;

  pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
  pthread_testcancel();

  CICQDaemon *d = e->m_pDaemon;

  // Check if the socket is connected
  if (e->m_nSocketDesc == -1)
  {
    unsigned long nDestinationUin = e->m_nDestinationUin;
    unsigned char nChannel = e->Channel();
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
   
    ICQUser *u = gUserManager.FetchUser(nDestinationUin, LOCK_R);
    if (u == NULL)
    {
      if (d->DoneEvent(e, EVENT_ERROR) != NULL)
        d->ProcessDoneEvent(e);
      else
      {
        pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
        pthread_testcancel();
        delete e;
      }
      pthread_exit(NULL);
    }

    unsigned long nVersion = u->Version();
    unsigned char nMode = u->Mode();
    unsigned short nRemotePort = u->Port();
    bool bSendIntIp = u->SendIntIp();
    gUserManager.DropUser(u);

    ICQOwner *o = gUserManager.FetchOwner(LOCK_R);
    unsigned long nIP = bSendIntIp ? o->IntIp() : o->Ip();
    unsigned short nLocalPort = o->Port();
    gUserManager.DropOwner();

    int socket = -1;
    if (!bSendIntIp && nVersion > 6 && nMode != MODE_DIRECT)
    {
      int nId = d->RequestReverseConnection(nDestinationUin, nChannel, nIP,
                                            nLocalPort, nRemotePort);
      if (nId != -1)
      {
        d->WaitForReverseConnection(nId, nDestinationUin);
        u = gUserManager.FetchUser(nDestinationUin, LOCK_R);
        if (u == NULL)
        {
          if (d->DoneEvent(e, EVENT_ERROR) != NULL)
            d->ProcessDoneEvent(e);
          else
          {
            pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
            pthread_testcancel();
            delete e;
          }
          pthread_exit(NULL);
        }
        socket = u->SocketDesc(nChannel);
        gUserManager.DropUser(u);
      }
      
      // if we failed, try direct anyway
      if (socket == -1)
      {
        pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
        pthread_testcancel();
        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);

        socket = d->ConnectToUser(nDestinationUin, nChannel);
      }
    }
    else
    {
      socket = d->ConnectToUser(nDestinationUin, nChannel);

      // if we failed, try through server
      if (socket == -1)
      {
        pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
        pthread_testcancel();
        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);

        int nId = d->RequestReverseConnection(nDestinationUin, nChannel, nIP,
                                              nLocalPort, nRemotePort);
        if (nId != -1)
        {
          d->WaitForReverseConnection(nId, nDestinationUin);
          u = gUserManager.FetchUser(nDestinationUin, LOCK_R);
          if (u == NULL)
          {
            if (d->DoneEvent(e, EVENT_ERROR) != NULL)
              d->ProcessDoneEvent(e);
            else
            {
              pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
              pthread_testcancel();
              delete e;
            }
            pthread_exit(NULL);
          }
          socket = u->SocketDesc(nChannel);
          gUserManager.DropUser(u);
        }
      }
    }

    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    pthread_testcancel();
    e->m_nSocketDesc = socket;
    // Check again, if still -1, fail the event
    if (e->m_nSocketDesc == -1)
    {
      pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
      if (d->DoneEvent(e, EVENT_ERROR) != NULL)
        d->ProcessDoneEvent(e);
      else
      {
        pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
        pthread_testcancel();
        delete e;
      }
      pthread_exit(NULL);
    }
  }

  int socket = e->m_nSocketDesc;
  pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
  INetSocket *s = gSocketManager.FetchSocket(socket);
  if (s == NULL)
  {
    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    pthread_testcancel();
    unsigned short nSequence = e->m_nSequence;
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);

    gLog.Warn(tr("%sSocket %d does not exist (#%hu).\n"), L_WARNxSTR, socket,
       nSequence);
    if (d->DoneEvent(e, EVENT_ERROR) != NULL)
      d->ProcessDoneEvent(e);
    else
    {
      pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
      pthread_testcancel();
      delete e;
    }
    pthread_exit(NULL);
  }

  CBuffer *buf;
  bool sent;
  char szErrorBuf[128];
  pthread_cleanup_push(cleanup_socket, s);

    pthread_mutex_lock(&d->mutex_cancelthread);

    // check to make sure we were not cancelled already
    pthread_cleanup_push(cleanup_mutex, &d->mutex_cancelthread);
      pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
      pthread_testcancel();
      pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);

      //if we get here  then we haven't been cancelled and we won't be
      //as long as we hold mutex_cancelthread

      buf = e->m_pPacket->Finalize(s);

      pthread_mutex_unlock(&d->mutex_cancelthread);
    pthread_cleanup_pop(0);

    sent = s->Send(buf);

    if (!sent)
      s->ErrorStr(szErrorBuf, 128);

    gSocketManager.DropSocket(s);
  pthread_cleanup_pop(0);

  if (!sent)
  {
    // Close the socket, alert the socket thread
    gSocketManager.CloseSocket(socket);
    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    pthread_testcancel();
    unsigned short nSequence = e->m_nSequence;
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);

    gLog.Warn(tr("%sError sending event (#%hu):\n%s%s.\n"), L_WARNxSTR,
     -nSequence, L_BLANKxSTR, szErrorBuf);
    write(d->pipe_newsocket[PIPE_WRITE], "S", 1);
    // Kill the event, do after the above as ProcessDoneEvent erase the event
    if (d->DoneEvent(e, EVENT_ERROR) != NULL)
      d->ProcessDoneEvent(e);
    else
    {
      pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
      pthread_testcancel();
      delete e;
    }
    pthread_exit(NULL);
  }
  pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
  pthread_testcancel();

  e->thread_running = false;

  // pthread_exit is not async cancel safe???
  pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
  pthread_exit(NULL);
  // Avoid compiler warnings
  return NULL;
}