//-----CFileTransferManager::ConnectToFileServer----------------------------- bool CFileTransferManager::ConnectToFileServer(unsigned short nPort) { ICQUser *u = gUserManager.FetchUser(m_nUin, LOCK_R); if (u == NULL) return false; bool bTryDirect = u->Version() <= 6 || u->Mode() == MODE_DIRECT; bool bSendIntIp = u->SendIntIp(); gUserManager.DropUser(u); bool bSuccess = false; if (bTryDirect) { gLog.Info("%sFile Transfer: Connecting to server.\n", L_TCPxSTR); bSuccess = licqDaemon->OpenConnectionToUser(m_nUin, &ftSock, nPort); } bool bResult = false; if (!bSuccess) { ICQOwner *o = gUserManager.FetchOwner(LOCK_R); unsigned long nIp = bSendIntIp ? o->IntIp() : o->Ip(); gUserManager.DropOwner(); // try reverse connect int nId = licqDaemon->RequestReverseConnection(m_nUin, 0, nIp, LocalPort(), nPort); if (nId != -1) { struct SFileReverseConnectInfo *r = new struct SFileReverseConnectInfo; r->nId = nId; r->m = this; r->bTryDirect = !bTryDirect; pthread_mutex_lock(&thread_cancel_mutex); pthread_create(&m_tThread, NULL, FileWaitForSignal_tep, r); m_bThreadRunning = true; pthread_mutex_unlock(&thread_cancel_mutex); bResult = true; } } else bResult = SendFileHandshake(); return bResult; }
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; }