/*------------------------------------------------------------------------------ * 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; }