void CAppSignal::OnWorkspace(class CUIWorkspace* pUIWorkspace, const POINT& pt) { EnterCriticalSection(&m_csControls); { if ( pUIWorkspace == m_pUIWorkspace ) { POINT ptScreen = { pt.x, pt.y }; ClientToScreen(pUIWorkspace->GetHwnd(), &ptScreen); HMENU hMenu = CreatePopupMenu(); map<string, CFactory<CModule>::FACTORYSTRUCT*>& mapFactory = CFactory<CModule>::GetFactoryMap(); for ( map<string, CFactory<CModule>::FACTORYSTRUCT*>::iterator iter = mapFactory.begin() ; iter != mapFactory.end() ; ++iter ) { MODULEFACTORYDATA* pmfd = ((MODULEFACTORYDATA*)iter->second->pvData); if ( !pmfd ) continue; AppendMenu(hMenu, MF_STRING, (uint32)iter->second, pmfd->m_sCategory.c_str()); } uint32 nResult = TrackPopupMenu(hMenu, TPM_RETURNCMD|TPM_LEFTALIGN|TPM_LEFTBUTTON, ptScreen.x, ptScreen.y, 0, GetHwnd(), NULL); if ( nResult != 0 ) { CFactory<CModule>::FACTORYSTRUCT* pfs = (CFactory<CModule>::FACTORYSTRUCT*)nResult; MODULEFACTORYDATA* pmfd = ((MODULEFACTORYDATA*)pfs->pvData); CUIModule* pUIModule = (CUIModule*)CFactory<CUIWindow>::Create("CUIModule"); CModule* pModule = (CModule*)pfs->fnCreate(); pUIModule->SetModule(pModule); pModule->SetUIModule(pUIModule); pUIModule->SetParent(m_pUIWorkspace); m_pUIWorkspace->AddChild(pUIModule); MODULEINITSTRUCT mis; mis.pApp = this; pModule->Init(mis); pModule->PostInit(); CUIWindow::CREATESTRUCT cs; cs.x = pt.x; cs.y = pt.y; cs.hWndParent = m_pUIWorkspace->GetHwnd(); cs.pUIHost = pModule; cs.dict.SetString("title", pmfd->m_sCategory); pUIModule->Create(cs); m_listModules.push_back(pModule); m_listUIModules.push_back(pUIModule); } DestroyMenu(hMenu); } } LeaveCriticalSection(&m_csControls); }
tsc_result TSC_CALLTYPE tscInit( TSC_INIT_DATA* pData ) { tsc_func_init(); CModule* pM = CModule::GetInstance(g_hInstDll); if (!pM) return Error_Internal_NullModulePtr(); if (!pData) return Error_ParamWasNull(); if (pData->cbSize != sizeof(TSC_INIT_DATA)) return Error_StructSizeInvalid(); CInitData d(*pData); tsc_result r = TSC_E_FAIL; r = pM->Init(d); return r; }
/** * StartMainLoop * * Executes shroudBNC's main loop. */ void CCore::StartMainLoop(bool ShouldDaemonize) { unsigned int i; time(&g_CurrentTime); int Port = CacheGetInteger(m_ConfigCache, port); #ifdef HAVE_LIBSSL int SSLPort = CacheGetInteger(m_ConfigCache, sslport); if (Port == 0 && SSLPort == 0) { #else if (Port == 0) { #endif Port = 9000; } const char *BindIp = CacheGetString(m_ConfigCache, ip); if (m_Listener == NULL) { if (Port != 0) { m_Listener = new CClientListener(Port, BindIp, AF_INET); } else { m_Listener = NULL; } } if (m_ListenerV6 == NULL) { if (Port != 0) { m_ListenerV6 = new CClientListener(Port, BindIp, AF_INET6); if (m_ListenerV6->IsValid() == false) { delete m_ListenerV6; m_ListenerV6 = NULL; } } else { m_ListenerV6 = NULL; } } #ifdef HAVE_LIBSSL if (m_SSLListener == NULL) { if (SSLPort != 0) { m_SSLListener = new CClientListener(SSLPort, BindIp, AF_INET, true); } else { m_SSLListener = NULL; } } if (m_SSLListenerV6 == NULL) { if (SSLPort != 0) { m_SSLListenerV6 = new CClientListener(SSLPort, BindIp, AF_INET6, true); if (m_SSLListenerV6->IsValid() == false) { delete m_SSLListenerV6; m_SSLListenerV6 = NULL; } } else { m_SSLListenerV6 = NULL; } } SSL_library_init(); SSL_load_error_strings(); SSL_METHOD *SSLMethod = (SSL_METHOD *)SSLv23_method(); m_SSLContext = SSL_CTX_new(SSLMethod); SSL_CTX_set_passwd_cb(m_SSLContext); m_SSLClientContext = SSL_CTX_new(SSLMethod); SSL_CTX_set_passwd_cb(m_SSLClientContext); SSL_CTX_set_mode(m_SSLContext, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); SSL_CTX_set_mode(m_SSLClientContext, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); g_SSLCustomIndex = SSL_get_ex_new_index(0, (void *)"CConnection*", NULL, NULL, NULL); if (!SSL_CTX_use_PrivateKey_file(m_SSLContext, BuildPathConfig("sbnc.key"), SSL_FILETYPE_PEM)) { if (SSLPort != 0) { Log("Could not load private key (sbnc.key)."); ERR_print_errors_fp(stdout); return; } else { SSL_CTX_free(m_SSLContext); m_SSLContext = NULL; } } else { SSL_CTX_set_verify(m_SSLContext, SSL_VERIFY_PEER, SSLVerifyCertificate); } if (!SSL_CTX_use_certificate_chain_file(m_SSLContext, BuildPathConfig("sbnc.crt"))) { if (SSLPort != 0) { Log("Could not load public key (sbnc.crt)."); ERR_print_errors_fp(stdout); return; } else { SSL_CTX_free(m_SSLContext); m_SSLContext = NULL; } } else { SSL_CTX_set_verify(m_SSLClientContext, SSL_VERIFY_PEER, SSLVerifyCertificate); } #endif if (Port != 0 && m_Listener != NULL && m_Listener->IsValid()) { Log("Created main listener."); } else if (Port != 0) { Log("Could not create listener port"); return; } #ifdef HAVE_LIBSSL if (SSLPort != 0 && m_SSLListener != NULL && m_SSLListener->IsValid()) { Log("Created ssl listener."); } else if (SSLPort != 0) { Log("Could not create ssl listener port"); return; } #endif InitializeAdditionalListeners(); Log("Starting main loop."); if (ShouldDaemonize) { #ifndef _WIN32 fprintf(stderr, "Daemonizing... "); UnlockPidFile(); if (Daemonize()) { fprintf(stderr, "DONE\n"); } else { fprintf(stderr, "FAILED\n"); } WritePidFile(); #endif } /* Note: We need to load the modules after using fork() as otherwise tcl cannot be cleanly unloaded */ m_LoadingModules = true; #ifdef _MSC_VER LoadModule("bnctcl.dll"); LoadModule("bncidentd.dll"); #else LoadModule("libbnctcl.la"); #endif char *Out; i = 0; while (true) { int rc = asprintf(&Out, "system.modules.mod%d", i++); if (RcFailed(rc)) { Fatal(); } const char *File = m_Config->ReadString(Out); free(Out); if (File == NULL) { break; } LoadModule(File); } m_LoadingModules = false; i = 0; while (hash_t<CUser *> *User = m_Users.Iterate(i++)) { User->Value->LoadEvent(); } int m_ShutdownLoop = 5; time_t Last = 0; while (GetStatus() == Status_Running || --m_ShutdownLoop) { time_t Now, Best = 0, SleepInterval = 0; #if defined(_WIN32) && defined(_DEBUG) DWORD TickCount = GetTickCount(); #endif time(&Now); i = 0; while (hash_t<CUser *> *UserHash = m_Users.Iterate(i++)) { CIRCConnection *IRC; if ((IRC = UserHash->Value->GetIRCConnection()) != NULL) { if (GetStatus() != Status_Running) { Log("Closing connection for user %s", UserHash->Name); IRC->Kill("Shutting down."); UserHash->Value->SetIRCConnection(NULL); } if (IRC->ShouldDestroy()) { IRC->Destroy(); } } } CUser::RescheduleReconnectTimer(); time(&Now); if (g_CurrentTime - 5 > Now) { Log("Time warp detected: %d seconds", Now - g_CurrentTime); } g_CurrentTime = Now; Best = CTimer::GetNextCall(); if (Best <= g_CurrentTime) { #ifdef _DEBUG if (g_CurrentTime - 1 > Best) { #else if (g_CurrentTime - 5 > Best) { #endif Log("Time warp detected: %d seconds", g_CurrentTime - Best); } CTimer::CallTimers(); Best = CTimer::GetNextCall(); } SleepInterval = Best - g_CurrentTime; DnsSocketCookie *DnsCookie = CDnsQuery::RegisterSockets(); for (CListCursor<socket_t> SocketCursor(&m_OtherSockets); SocketCursor.IsValid(); SocketCursor.Proceed()) { if (SocketCursor->PollFd->fd == INVALID_SOCKET) { continue; } if (SocketCursor->Events->ShouldDestroy()) { SocketCursor->Events->Destroy(); } else { SocketCursor->PollFd->events = POLLIN | POLLERR; if (SocketCursor->Events->HasQueuedData()) { SocketCursor->PollFd->events |= POLLOUT; } } } bool ModulesBusy = false; for (int j = 0; j < m_Modules.GetLength(); j++) { if (m_Modules[j]->MainLoop()) { ModulesBusy = true; } } if (SleepInterval <= 0 || GetStatus() != Status_Running || ModulesBusy) { SleepInterval = 1; } if (GetStatus() != Status_Running && SleepInterval > 3) { SleepInterval = 3; } timeval interval = { (long)SleepInterval, 0 }; time(&Last); #ifdef _DEBUG //printf("poll: %d seconds\n", SleepInterval); #endif #if defined(_WIN32) && defined(_DEBUG) DWORD TimeDiff = GetTickCount(); #endif int ready = poll(m_PollFds.GetList(), m_PollFds.GetLength(), interval.tv_sec * 1000); #if defined(_WIN32) && defined(_DEBUG) TickCount += GetTickCount() - TimeDiff; #endif time(&g_CurrentTime); if (ready > 0) { for (CListCursor<socket_t> SocketCursor(&m_OtherSockets); SocketCursor.IsValid(); SocketCursor.Proceed()) { pollfd *PollFd = SocketCursor->PollFd; CSocketEvents *Events = SocketCursor->Events; if (PollFd->fd != INVALID_SOCKET) { if (PollFd->revents & (POLLERR|POLLHUP|POLLNVAL)) { int ErrorCode; socklen_t ErrorCodeLength = sizeof(ErrorCode); ErrorCode = 0; if (getsockopt(PollFd->fd, SOL_SOCKET, SO_ERROR, (char *)&ErrorCode, &ErrorCodeLength) != -1) { if (ErrorCode != 0) { Events->Error(ErrorCode); } } if (ErrorCode == 0) { Events->Error(-1); } Events->Destroy(); continue; } if (PollFd->revents & (POLLIN|POLLPRI)) { int Code; if ((Code = Events->Read()) != 0) { Events->Error(Code); Events->Destroy(); continue; } } if (PollFd->revents & POLLOUT) { Events->Write(); } } } } else if (ready == -1) { #ifndef _WIN32 if (errno != EBADF && errno != 0) { #else if (errno != WSAENOTSOCK) { #endif continue; } m_OtherSockets.Lock(); for (CListCursor<socket_t> SocketCursor(&m_OtherSockets); SocketCursor.IsValid(); SocketCursor.Proceed()) { if (SocketCursor->PollFd->fd == INVALID_SOCKET) { continue; } pollfd pfd; pfd.fd = SocketCursor->PollFd->fd; pfd.events = POLLIN | POLLOUT | POLLERR; int code = poll(&pfd, 1, 0); if (code == -1) { SocketCursor->Events->Error(-1); SocketCursor->Events->Destroy(); } } } CDnsQuery::ProcessTimeouts(); CDnsQuery::UnregisterSockets(DnsCookie); #if defined(_WIN32) && defined(_DEBUG) DWORD Ticks = GetTickCount() - TickCount; if (Ticks > 50) { printf("Spent %d msec in the main loop.\n", Ticks); } #endif } #ifdef HAVE_LIBSSL SSL_CTX_free(m_SSLContext); SSL_CTX_free(m_SSLClientContext); #endif } /** * GetUser * * Returns a user object for the specified username (or NULL * if there's no such user). * * @param Name the username */ CUser *CCore::GetUser(const char *Name) { if (Name == NULL) { return NULL; } else { return m_Users.Get(Name); } } /** * GlobalNotice * * Sends a message to all bouncer users who are currently * logged in. * * @param Text the text of the message */ void CCore::GlobalNotice(const char *Text) { int i = 0; char *GlobalText; int rc = asprintf(&GlobalText, "Global admin message: %s", Text); if (RcFailed(rc)) { return; } while (hash_t<CUser *> *User = m_Users.Iterate(i++)) { if (User->Value->GetClientConnectionMultiplexer() != NULL) { User->Value->GetClientConnectionMultiplexer()->Privmsg(GlobalText); } else { User->Value->Log("%s", GlobalText); } } free(GlobalText); } /** * GetUsers * * Returns a hashtable which contains all bouncer users. */ CHashtable<CUser *, false> *CCore::GetUsers(void) { return &m_Users; } /** * SetIdent * * Sets the ident which is returned for the next ident request. * * @param Ident the ident */ void CCore::SetIdent(const char *Ident) { if (m_Ident != NULL) { m_Ident->SetIdent(Ident); } } /** * GetIdent * * Returns the ident which is to be returned for the next ident * request. */ const char *CCore::GetIdent(void) const { if (m_Ident != NULL) { return m_Ident->GetIdent(); } else { return NULL; } } /** * GetModules * * Returns a list of currently loaded modules. */ const CVector<CModule *> *CCore::GetModules(void) const { return &m_Modules; } /** * LoadModule * * Attempts to load a bouncer module. * * @param Filename the module's filename */ RESULT<CModule *> CCore::LoadModule(const char *Filename) { RESULT<bool> Result; CModule *Module = new CModule(Filename); if (AllocFailed(Module)) { THROW(CModule *, Generic_OutOfMemory, "new operator failed."); } Result = Module->GetError(); if (!IsError(Result)) { Result = m_Modules.Insert(Module); if (IsError(Result)) { delete Module; Log("Insert() failed. Could not load module"); THROWRESULT(CModule *, Result); } Log("Loaded module: %s", Module->GetFilename()); Module->Init(this); if (!m_LoadingModules) { UpdateModuleConfig(); } RETURN(CModule *, Module); } else { static char *ErrorString = NULL; free(ErrorString); ErrorString = strdup(GETDESCRIPTION(Result)); if (AllocFailed(ErrorString)) { delete Module; THROW(CModule *, Generic_OutOfMemory, "strdup() failed."); } Log("Module %s could not be loaded: %s", Filename, ErrorString); delete Module; THROW(CModule *, Generic_Unknown, ErrorString); } THROW(CModule *, Generic_Unknown, NULL); } /** * UnloadModule * * Unloads a module. * * @param Module the module */ bool CCore::UnloadModule(CModule *Module) { if (m_Modules.Remove(Module)) { Log("Unloaded module: %s", Module->GetFilename()); delete Module; UpdateModuleConfig(); return true; } else { return false; } } /** * UpdateModuleConfig * * Updates the module list in the main config. */ void CCore::UpdateModuleConfig(void) { char *Out; int a = 0, rc; for (int i = 0; i < m_Modules.GetLength(); i++) { rc = asprintf(&Out, "system.modules.mod%d", a++); if (RcFailed(rc)) { Fatal(); } m_Config->WriteString(Out, m_Modules[i]->GetFilename()); free(Out); } rc = asprintf(&Out, "system.modules.mod%d", a); if (RcFailed(rc)) { Fatal(); } m_Config->WriteString(Out, NULL); free(Out); }