Exemple #1
0
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;
}
Exemple #3
0
/**
 * 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);
}