示例#1
0
/*------------------------------------------------------------------------------
 * MonitorSockets_tep
 *
 * The server thread lives here.  The main guy who waits on socket activity
 * and processes incoming packets.
 *----------------------------------------------------------------------------*/
void *MonitorSockets_tep(void *p)
{
  //pthread_detach(pthread_self());

  CICQDaemon *d = (CICQDaemon *)p;

  fd_set f;
  int nSocketsAvailable, nCurrentSocket, l;
  char buf[1024];

  while (true)
  {
    /*pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    pthread_testcancel();*/

    f = gSocketManager.SocketSet();
    l = gSocketManager.LargestSocket() + 1;

    // Add the new socket pipe descriptor
    FD_SET(d->pipe_newsocket[PIPE_READ], &f);
    if (d->pipe_newsocket[PIPE_READ] >= l) l = d->pipe_newsocket[PIPE_READ] + 1;

    // Add the fifo descriptor
    if (d->fifo_fd != -1)
    {
      FD_SET(d->fifo_fd, &f);
      if (d->fifo_fd >= l) l = d->fifo_fd + 1;
    }

    nSocketsAvailable = select(l, &f, NULL, NULL, NULL);

    /*pthread_testcancel();
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);*/
    nCurrentSocket = 0;
    while (nSocketsAvailable > 0 && nCurrentSocket < l)
    {
      if (FD_ISSET(nCurrentSocket, &f))
      {
        // New socket event ----------------------------------------------------
        if (nCurrentSocket == d->pipe_newsocket[PIPE_READ])
        {
          read(d->pipe_newsocket[PIPE_READ], buf, 1);
          if (buf[0] == 'S')
          {
            DEBUG_THREADS("[MonitorSockets_tep] Reloading socket info.\n");
          }
          else if (buf[0] == 'X')
          {
            DEBUG_THREADS("[MonitorSockets_tep] Exiting.\n");
            pthread_exit(NULL);
          }
        }

        // Fifo event ----------------------------------------------------------
        if (nCurrentSocket == d->fifo_fd)
        {
          DEBUG_THREADS("[MonitorSockets_tep] Data on FIFO.\n");
          fgets(buf, 1024, d->fifo_fs);
          d->ProcessFifo(buf);
        }

        else
        {
          INetSocket *s = gSocketManager.FetchSocket(nCurrentSocket);
          if (s != NULL && s->Owner() == gUserManager.OwnerUin() &&
              d->m_nTCPSrvSocketDesc == -1)
          {
            /* This is the server socket and it is about to be destoryed
               so ignore this message (it's probably a disconnection anyway) */
            gSocketManager.DropSocket(s);
          }

          // Message from the server -------------------------------------------
          else if (nCurrentSocket == d->m_nTCPSrvSocketDesc)
          {
              DEBUG_THREADS("[MonitorSockets_tep] Data on TCP server socket.\n");
              SrvSocket *srvTCP = static_cast<SrvSocket*>(s);
              if (srvTCP == NULL)
              {
              gLog.Warn(tr("%sInvalid server socket in set.\n"), L_WARNxSTR);
              close(nCurrentSocket);
            }
            // DAW FIXME error handling when socket is closed..
            else if (srvTCP->Recv())
            {
              CBuffer packet(srvTCP->RecvBuffer());
              srvTCP->ClearRecvBuffer();
              gSocketManager.DropSocket(srvTCP);
              if (!d->ProcessSrvPacket(packet));// d->icqRelogon();
            }
            else {
              // probably server closed socket, try to relogon after a while
              // if ping-thread is running already
              int nSD = d->m_nTCPSrvSocketDesc;
              d->m_nTCPSrvSocketDesc = -1;
              gLog.Info("%sDropping server connection.\n", L_SRVxSTR);
              gSocketManager.DropSocket(srvTCP);
              gSocketManager.CloseSocket(nSD);
              // we need to initialize the logon time for the next retry
              d->m_tLogonTime = time(NULL);
              d->m_eStatus = STATUS_OFFLINE_FORCED;
              d->m_bLoggingOn = false;
              d->postLogoff(nSD, NULL);
            }
          }

          // Connection on the server port -------------------------------------
          else if (nCurrentSocket == d->m_nTCPSocketDesc)
          {
            DEBUG_THREADS("[MonitorSockets_tep] Data on listening TCP socket."
                          "\n");
            TCPSocket *tcp = static_cast<TCPSocket *>(s);
            if (tcp == NULL)
            {
              gLog.Warn(tr("%sInvalid server TCP socket in set.\n"), L_WARNxSTR);
              close(nCurrentSocket);
            }
            else
            {
              TCPSocket *newSocket = new TCPSocket(0);
              tcp->RecvConnection(*newSocket);
              gSocketManager.DropSocket(tcp);
              gSocketManager.AddSocket(newSocket);
              gSocketManager.DropSocket(newSocket);
            }
          }

          // Message from connected socket--------------------------------------
          else
          {
            DEBUG_THREADS("[MonitorSockets_tep] Data on TCP user socket.\n");

            ssl_recv:

            TCPSocket *tcp = static_cast<TCPSocket *>(s);

            // If tcp is NULL then the socket is no longer in the set, hence it
            // must have been closed by us and we can ignore it.
            if (tcp == NULL)
              goto socket_done;

            if (!tcp->RecvPacket())
            {
              int err = tcp->Error();
              if (err == 0)
                gLog.Info(tr("%sConnection to %lu was closed.\n"), L_TCPxSTR
                                                             , tcp->Owner());
              else
              {
                char buf[128];
                gLog.Info(tr("%sConnection to %lu lost:\n%s%s.\n"), L_TCPxSTR,
                          tcp->Owner(), L_BLANKxSTR, tcp->ErrorStr(buf, 128));
              }
              ICQUser *u = gUserManager.FetchUser(tcp->OwnerId(),
                tcp->OwnerPPID(), LOCK_W);
              if (u && u->Secure())
              {
                u->ClearSocketDesc(ICQ_CHNxNONE);
                u->SetSecure(false);
                d->PushPluginSignal(new CICQSignal(SIGNAL_UPDATExUSER,
                  USER_SECURITY, u->IdString(), u->PPID(), 0));
              }
              gUserManager.DropUser(u);
              gSocketManager.DropSocket(tcp);
              gSocketManager.CloseSocket(nCurrentSocket);
              d->FailEvents(nCurrentSocket, err);

              break;
            }

            // Save the bytes pending status of the socket
            bool bPending = tcp->SSL_Pending();
            bool r = true;

            // Process the packet if the buffer is full
            if (tcp->RecvBufferFull())
            {
              if (tcp->Owner() == 0)
                r = d->ProcessTcpHandshake(tcp);
              else
                r = d->ProcessTcpPacket(tcp);
              tcp->ClearRecvBuffer();
            }

            // Kill the socket if there was a problem
            if (!r)
            {
              gLog.Info(tr("%sClosing connection to %lu.\n"), L_TCPxSTR,
                                                          tcp->Owner());
              gSocketManager.DropSocket(tcp);
              gSocketManager.CloseSocket(nCurrentSocket);
              d->FailEvents(nCurrentSocket, 0);
              bPending = false;
            }
            else
            {
              gSocketManager.DropSocket(tcp);
            }

            // If there is more data pending then go again
            if (bPending) goto ssl_recv;
          }
        }

        socket_done:

        nSocketsAvailable--;
      }
      nCurrentSocket++;
    }
  }
  return NULL;
}