void frobkey(int press, int release, int scan, int key, int ascii) { INPUT_RECORD ckey; DWORD d; SHORT s; ckey.EventType=KEY_EVENT; ckey.Event.KeyEvent.dwControlKeyState=0; if(alt) ckey.Event.KeyEvent.dwControlKeyState |= LEFT_ALT_PRESSED; if(ctrl) ckey.Event.KeyEvent.dwControlKeyState |= LEFT_CTRL_PRESSED; if(shift) ckey.Event.KeyEvent.dwControlKeyState |= SHIFT_PRESSED; ckey.Event.KeyEvent.wRepeatCount=1; ckey.Event.KeyEvent.wVirtualKeyCode=key; /* ALT key */ ckey.Event.KeyEvent.wVirtualScanCode=scan; ckey.Event.KeyEvent.uChar.AsciiChar=ascii; if(press) { ckey.Event.KeyEvent.bKeyDown=TRUE; d=0; while(!d) { if(!WriteConsoleInput(console_input, &ckey, 1, &d)) d=0; } } if(release) { ckey.Event.KeyEvent.bKeyDown=FALSE; d=0; while(!d) { if(!WriteConsoleInput(console_input, &ckey, 1, &d)) d=0; } } }
void QConsolePrivate::sendConsoleText (const QString& s) { // Send the string in chunks of 512 characters. Each character is // translated into an equivalent keypress event. #define TEXT_CHUNK_SIZE 512 int len = s.length (); INPUT_RECORD events[TEXT_CHUNK_SIZE]; DWORD nEvents = 0, written; HANDLE hStdIn = GetStdHandle (STD_INPUT_HANDLE); ZeroMemory (events, sizeof (events)); for (int i = 0; i < len; i++) { QChar c = s.at (i); if (c == L'\r' || c == L'\n') { if (c == L'\r' && i < (len - 1) && s.at (i+1) == L'\n') i++; if (nEvents) { WriteConsoleInput (hStdIn, events, nEvents, &written); nEvents = 0; ZeroMemory (events, sizeof (events)); } PostMessage (m_consoleWindow, WM_KEYDOWN, VK_RETURN, 0x001C0001); PostMessage (m_consoleWindow, WM_KEYDOWN, VK_RETURN, 0xC01C0001); } else { events[nEvents].EventType = KEY_EVENT; events[nEvents].Event.KeyEvent.bKeyDown = TRUE; events[nEvents].Event.KeyEvent.wRepeatCount = 1; events[nEvents].Event.KeyEvent.wVirtualKeyCode = LOBYTE (VkKeyScan (c.unicode ())); events[nEvents].Event.KeyEvent.wVirtualScanCode = 0; events[nEvents].Event.KeyEvent.uChar.UnicodeChar = c.unicode (); events[nEvents].Event.KeyEvent.dwControlKeyState = 0; nEvents++; } if (nEvents == TEXT_CHUNK_SIZE || (nEvents > 0 && i == (len - 1))) { WriteConsoleInput (hStdIn, events, nEvents, &written); nEvents = 0; ZeroMemory (events, sizeof (events)); } } }
void LogonConsole::Kill() { _thread->kill=true; #if (defined( WIN32 ) || defined( WIN64 ) ) /* write the return keydown/keyup event */ DWORD dwTmp; INPUT_RECORD ir[2]; ir[0].EventType = KEY_EVENT; ir[0].Event.KeyEvent.bKeyDown = TRUE; ir[0].Event.KeyEvent.dwControlKeyState = 288; ir[0].Event.KeyEvent.uChar.AsciiChar = 13; ir[0].Event.KeyEvent.wRepeatCount = 1; ir[0].Event.KeyEvent.wVirtualKeyCode = 13; ir[0].Event.KeyEvent.wVirtualScanCode = 28; ir[1].EventType = KEY_EVENT; ir[1].Event.KeyEvent.bKeyDown = FALSE; ir[1].Event.KeyEvent.dwControlKeyState = 288; ir[1].Event.KeyEvent.uChar.AsciiChar = 13; ir[1].Event.KeyEvent.wRepeatCount = 1; ir[1].Event.KeyEvent.wVirtualKeyCode = 13; ir[1].Event.KeyEvent.wVirtualScanCode = 28; WriteConsoleInput (GetStdHandle(STD_INPUT_HANDLE), ir, 2, & dwTmp); #endif printf("Waiting for console thread to terminate....\n"); while(_thread != NULL) { Sleep(100); } printf("Console shut down.\n"); }
void ConsoleThread::terminate() { m_threadRunning = false; #ifdef WIN32 /* write the return keydown/keyup event */ DWORD dwTmp; INPUT_RECORD ir[2]; ir[0].EventType = KEY_EVENT; ir[0].Event.KeyEvent.bKeyDown = TRUE; ir[0].Event.KeyEvent.dwControlKeyState = 288; ir[0].Event.KeyEvent.uChar.AsciiChar = 13; ir[0].Event.KeyEvent.wRepeatCount = 1; ir[0].Event.KeyEvent.wVirtualKeyCode = 13; ir[0].Event.KeyEvent.wVirtualScanCode = 28; ir[1].EventType = KEY_EVENT; ir[1].Event.KeyEvent.bKeyDown = FALSE; ir[1].Event.KeyEvent.dwControlKeyState = 288; ir[1].Event.KeyEvent.uChar.AsciiChar = 13; ir[1].Event.KeyEvent.wRepeatCount = 1; ir[1].Event.KeyEvent.wVirtualKeyCode = 13; ir[1].Event.KeyEvent.wVirtualScanCode = 28; WriteConsoleInput( GetStdHandle( STD_INPUT_HANDLE ), ir, 2, & dwTmp ); #endif printf( "Waiting for console thread to terminate....\n" ); while( m_isRunning ) { Sleep( 100 ); } printf( "Console shut down.\n" ); }
WORD scrollkeys() { HANDLE hConsole = GetStdHandle(STD_INPUT_HANDLE); INPUT_RECORD InputRecord; BOOL done = FALSE; while (!done) { DWORD dwInput; WaitForSingleObject( hConsole, INFINITE ); if (!ReadConsoleInput(hConsole, &InputRecord, 1, &dwInput)){ done = TRUE; continue; } if (InputRecord.EventType == KEY_EVENT && InputRecord.Event.KeyEvent.bKeyDown ) { // Why not just return the key code? (Paul Brannan 12/5/98) return InputRecord.Event.KeyEvent.wVirtualKeyCode; } else if(InputRecord.EventType == MOUSE_EVENT) { if(!InputRecord.Event.MouseEvent.dwEventFlags) { // Put the mouse's X and Y coords back into the input buffer WriteConsoleInput(hConsole, &InputRecord, 1, &dwInput); return SC_MOUSE; } } } return SC_ESC; }
static void __write_console_input(LPCWSTR str, DWORD length) { if(!str || !length) return; INPUT_RECORD *p, *buf; DWORD i = 0; p = buf = new INPUT_RECORD[ length ]; for( ; i < length ; i++, p++) { p->EventType = KEY_EVENT; p->Event.KeyEvent.bKeyDown = TRUE; p->Event.KeyEvent.wRepeatCount = 1; p->Event.KeyEvent.wVirtualKeyCode = 0; p->Event.KeyEvent.wVirtualScanCode = 0; p->Event.KeyEvent.uChar.UnicodeChar = 0; p->Event.KeyEvent.dwControlKeyState = 0; if(*str == '\r') { str++; length--; } if(*str == '\n') { p->Event.KeyEvent.wVirtualKeyCode = VK_RETURN; str++; } else { p->Event.KeyEvent.uChar.UnicodeChar = *str++; } } WriteConsoleInput(gStdIn, buf, length, &length); delete [] buf; }
void LogonConsole::Kill() { _thread->kill.SetVal(true); #ifdef WIN32 /* write the return keydown/keyup event */ DWORD dwTmp; INPUT_RECORD ir[2]; ir[0].EventType = KEY_EVENT; ir[0].Event.KeyEvent.bKeyDown = TRUE; ir[0].Event.KeyEvent.dwControlKeyState = 288; ir[0].Event.KeyEvent.uChar.AsciiChar = 13; ir[0].Event.KeyEvent.wRepeatCount = 1; ir[0].Event.KeyEvent.wVirtualKeyCode = 13; ir[0].Event.KeyEvent.wVirtualScanCode = 28; ir[1].EventType = KEY_EVENT; ir[1].Event.KeyEvent.bKeyDown = FALSE; ir[1].Event.KeyEvent.dwControlKeyState = 288; ir[1].Event.KeyEvent.uChar.AsciiChar = 13; ir[1].Event.KeyEvent.wRepeatCount = 1; ir[1].Event.KeyEvent.wVirtualKeyCode = 13; ir[1].Event.KeyEvent.wVirtualScanCode = 28; WriteConsoleInput(GetStdHandle(STD_INPUT_HANDLE), ir, 2, & dwTmp); #endif LOG_BASIC("Waiting for console thread to terminate...."); while(_thread != NULL) { arcpro::Sleep(100); } LOG_BASIC("Console shut down."); }
static void __attribute__((destructor)) exit_console (void) { #if !defined(BUILDING_UTILS) if (!has_console) return; if (started_from_a_gui || !attached_to_console) { puts("\nPress any key to exit"); _getch(); } else { /* * The calling shell doesn't append a <CR> to the cmd-line when we exit a * GUI app. Get the prompt back by putting a <CR> in the console input queue. */ HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); if (!started_from_a_gui && hStdin != INVALID_HANDLE_VALUE) { INPUT_RECORD rec; DWORD written; memset (&rec, 0, sizeof(rec)); rec.EventType = KEY_EVENT; rec.Event.KeyEvent.bKeyDown = TRUE; rec.Event.KeyEvent.wRepeatCount = 1; rec.Event.KeyEvent.wVirtualKeyCode = 13; rec.Event.KeyEvent.uChar.AsciiChar = 13; WriteConsoleInput(hStdin, &rec, 1, &written); } } FreeConsole(); /* free allocated or attached console */ has_console = FALSE; #endif }
virtual unsigned ThreadHandlerProc(void) { CHAR boxName[50]; DWORD err, dwWritten; IPCMsg msg; wsprintf(boxName, "ExpectInjector_pid%d", GetCurrentProcessId()); // Create the shared memory IPC transfer mechanism by name // (a mailbox). ConsoleDebuggerIPC = new CMclMailbox(IPC_NUMSLOTS, IPC_SLOTSIZE, boxName); // Check status. err = ConsoleDebuggerIPC->Status(); if (err != NO_ERROR && err != ERROR_ALREADY_EXISTS) { OutputDebugString(GetSysMsg(err)); delete ConsoleDebuggerIPC; return 0x666; } OutputDebugString("Expect's injector DLL loaded and ready.\n"); // forever loop receiving messages over IPC. while (ConsoleDebuggerIPC->GetAlertable(&msg, interrupt)) { switch (msg.type) { case CTRL_EVENT: // Generate a Ctrl+C or Ctrl+Break to cause the equivalent // of a SIGINT into this process. GenerateConsoleCtrlEvent(msg.event, 0); break; case IRECORD: // Stuff it into this console as if it had been entered // by the user. #ifdef IPC_MAXRECORDS // If IPC_MAXRECORDS is defined, we have grouped key events. WriteConsoleInput(console, msg.irecord, msg.event, &dwWritten); #else WriteConsoleInput(console, &msg.irecord, 1, &dwWritten); #endif break; } } delete ConsoleDebuggerIPC; return 0; }
BOOL WriteText (LPCTSTR szText) { DWORD dwWritten; INPUT_RECORD rec; char upper, *sz; sz = (LPTSTR) szText; while (*sz) { // 13 is the code for a carriage return (\n) instead of 10. if (*sz == 10) *sz = 13; upper = toupper(*sz); rec.EventType = KEY_EVENT; rec.Event.KeyEvent.bKeyDown = TRUE; rec.Event.KeyEvent.wRepeatCount = 1; rec.Event.KeyEvent.wVirtualKeyCode = upper; rec.Event.KeyEvent.wVirtualScanCode = CharToCode (*sz); rec.Event.KeyEvent.uChar.AsciiChar = *sz; rec.Event.KeyEvent.uChar.UnicodeChar = *sz; rec.Event.KeyEvent.dwControlKeyState = isupper(*sz) ? 0x80 : 0x0; WriteConsoleInput( hStdin, &rec, 1, &dwWritten); rec.Event.KeyEvent.bKeyDown = FALSE; WriteConsoleInput( hStdin, &rec, 1, &dwWritten); sz++; } //ServerWindowProcCommandExecute (); return TRUE; }
virtual bool WriteInput(INPUT_RECORD* Buffer, size_t Length, size_t& NumberOfEventsWritten) const override { if(Global->Opt->WindowMode && Buffer->EventType==MOUSE_EVENT) { Buffer->Event.MouseEvent.dwMousePosition.Y+=GetDelta(); } DWORD dwNumberOfEventsWritten = 0; bool Result = WriteConsoleInput(GetInputHandle(), Buffer, static_cast<DWORD>(Length), &dwNumberOfEventsWritten)!=FALSE; NumberOfEventsWritten = dwNumberOfEventsWritten; return Result; }
/////////////////////////////////////////////////////////////////////// // GetAndSendInputThread // Thread procedure that monitors the console for input and sends input // to the child process through the input pipe. // This thread ends when the child application exits. /////////////////////////////////////////////////////////////////////// DWORD WINAPI GetAndSendInputThread(LPVOID lpvThreadParam) { CHAR read_buff[256]; DWORD nBytesWrote; HANDLE hPipeWrite = (HANDLE)lpvThreadParam; HANDLE hconin=CreateFile("CONIN$",GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ,0,OPEN_EXISTING,0,0); // Get input from our console and send it to child through the pipe. printf("Hmmm...\n"); while (bRunThread) { Sleep(1000); INPUT_RECORD inputRecords[4]; inputRecords[0].EventType = KEY_EVENT; inputRecords[0].Event.KeyEvent.bKeyDown = TRUE; inputRecords[0].Event.KeyEvent.uChar.UnicodeChar = '?'; inputRecords[1].EventType = KEY_EVENT; inputRecords[1].Event.KeyEvent.bKeyDown = FALSE; inputRecords[1].Event.KeyEvent.uChar.UnicodeChar = '?'; inputRecords[2].EventType = KEY_EVENT; inputRecords[2].Event.KeyEvent.bKeyDown = TRUE; inputRecords[2].Event.KeyEvent.dwControlKeyState = 0; inputRecords[2].Event.KeyEvent.uChar.UnicodeChar = '\r'; inputRecords[2].Event.KeyEvent.wRepeatCount = 1; inputRecords[2].Event.KeyEvent.wVirtualKeyCode = VK_RETURN; inputRecords[2].Event.KeyEvent.wVirtualScanCode = MapVirtualKey(VK_RETURN, MAPVK_VK_TO_VSC); inputRecords[3].EventType = KEY_EVENT; inputRecords[3].Event.KeyEvent.bKeyDown = FALSE; inputRecords[3].Event.KeyEvent.dwControlKeyState = 0; inputRecords[3].Event.KeyEvent.uChar.UnicodeChar = '\r'; inputRecords[3].Event.KeyEvent.wRepeatCount = 1; inputRecords[3].Event.KeyEvent.wVirtualKeyCode = VK_RETURN; inputRecords[3].Event.KeyEvent.wVirtualScanCode = MapVirtualKey(VK_RETURN, MAPVK_VK_TO_VSC); if (!WriteConsoleInput(hPipeWrite,inputRecords,sizeof(inputRecords) / sizeof(*inputRecords),&nBytesWrote)) { if (GetLastError() == ERROR_NO_DATA) { printf("NO ERROR\n"); break; // Pipe was closed (normal exit path). } else { DisplayError("WriteConsoleInput"); } } else { printf("Hmmm success...\n"); } } return 1; }
BOOL WINAPI co_console_widget_control_handler(DWORD T) { DWORD r; INPUT_RECORD c; if (!(T == CTRL_CLOSE_EVENT || T == CTRL_LOGOFF_EVENT)) return false; memset(&c, 0, sizeof(INPUT_RECORD)); c.EventType = KEY_EVENT; WriteConsoleInput(GetStdHandle(STD_INPUT_HANDLE), &c, 1, &r); return ctrl_exit = true; }
JNIEXPORT void JNICALL Java_com_yifanlu_Josh_Josh_WRITECONSOLEINPUT (JNIEnv *env, jclass jcls, jlong pointer, jint eventType, jintArray data, jint length) { HANDLE hIn = pointerToHandle(pointer); INPUT_RECORD InRec; DWORD NumWrote; jint *body = env->GetIntArrayElements(data, 0); InRec.EventType = eventType; switch(InRec.EventType){ case FOCUS_EVENT: { InRec.Event.FocusEvent.bSetFocus = (body[1] == 1 ? TRUE : FALSE); break; } case KEY_EVENT: { InRec.Event.KeyEvent.bKeyDown = (body[1] == 1 ? TRUE : FALSE); InRec.Event.KeyEvent.wRepeatCount = body[2]; InRec.Event.KeyEvent.wVirtualKeyCode = body[3]; InRec.Event.KeyEvent.wVirtualScanCode = body[4]; InRec.Event.KeyEvent.uChar.UnicodeChar = (char)body[5]; InRec.Event.KeyEvent.dwControlKeyState = body[6]; break; } case MENU_EVENT: { InRec.Event.MenuEvent.dwCommandId = body[1]; break; } case MOUSE_EVENT: { InRec.Event.MouseEvent.dwMousePosition.X = body[1]; InRec.Event.MouseEvent.dwMousePosition.Y = body[2]; InRec.Event.MouseEvent.dwButtonState = body[3]; InRec.Event.MouseEvent.dwControlKeyState = body[4]; InRec.Event.MouseEvent.dwEventFlags = body[5]; break; } case WINDOW_BUFFER_SIZE_EVENT: { InRec.Event.WindowBufferSizeEvent.dwSize.X = body[1]; InRec.Event.WindowBufferSizeEvent.dwSize.Y = body[2]; break; } } WriteConsoleInput(hIn, &InRec, length, &NumWrote); }
void SendSequence(LPTSTR seq) { DWORD out; INPUT_RECORD in; HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE); in.EventType = KEY_EVENT; in.Event.KeyEvent.bKeyDown = TRUE; in.Event.KeyEvent.wRepeatCount = 1; in.Event.KeyEvent.wVirtualKeyCode = 0; in.Event.KeyEvent.wVirtualScanCode = 0; in.Event.KeyEvent.dwControlKeyState = 0; for (; *seq; ++seq) { in.Event.KeyEvent.uChar.UnicodeChar = *seq; WriteConsoleInput(hStdIn, &in, 1, &out); } }
void writeConsoleReturn() { DWORD num_events_written; INPUT_RECORD inprec[2]; DWORD vk = VK_RETURN; inprec[0].EventType = KEY_EVENT; inprec[0].Event.KeyEvent.bKeyDown = TRUE; inprec[0].Event.KeyEvent.wRepeatCount = 1; inprec[0].Event.KeyEvent.wVirtualKeyCode = vk; inprec[0].Event.KeyEvent.wVirtualScanCode = MapVirtualKey(vk, MAPVK_VK_TO_VSC); inprec[0].Event.KeyEvent.uChar.UnicodeChar = MapVirtualKey(vk, MAPVK_VK_TO_CHAR); inprec[0].Event.KeyEvent.dwControlKeyState = 0; inprec[1] = inprec[0]; inprec[1].Event.KeyEvent.bKeyDown = FALSE; WriteConsoleInput(gStdIn, inprec, sizeof inprec / sizeof inprec[0], &num_events_written); }
/*--------------------------------------------------------------------------*/ static void simulateCarriageReturn(void) { INPUT_RECORD rec; DWORD written; memset (&rec, 0, sizeof(rec)); rec.EventType = KEY_EVENT; rec.Event.KeyEvent.bKeyDown = TRUE; rec.Event.KeyEvent.wRepeatCount = 13; rec.Event.KeyEvent.uChar.AsciiChar = 13; if (!Win32InputStream) { Win32InputStream = GetStdHandle(STD_INPUT_HANDLE); } WriteConsoleInput(Win32InputStream, &rec, 1, &written); }
static void win_trigger_event(struct win32_signal *ws) { if (ws->mode == WSO_MODE_SERVICE && HANDLE_DEFINED(ws->in.read)) SetEvent (ws->in.read); else /* generate a key-press event */ { DWORD tmp; INPUT_RECORD ir; HANDLE stdin_handle = GetStdHandle(STD_INPUT_HANDLE); CLEAR(ir); ir.EventType = KEY_EVENT; ir.Event.KeyEvent.bKeyDown = true; if (!stdin_handle || !WriteConsoleInput(stdin_handle, &ir, 1, &tmp)) msg(M_WARN|M_ERRNO, "WARN: win_trigger_event: WriteConsoleInput"); } }
void CHIDCmd::FlushPreCommand() { bool bSysCmd = false; while ( m_nPreCommands > 0 ) { bool bCmd = OnCommand(m_ppPreCommands[0], &bSysCmd, true); qDebug() << m_nPreCommands << " : " << m_ppPreCommands[0]; m_nPreCommands--; delete [] m_ppPreCommands[0]; if ( m_nPreCommands == 0 ) { delete [] m_ppPreCommands; m_ppPreCommands = NULL; } else { char ** ppPreCommands = new char *[m_nPreCommands]; memcpy(ppPreCommands, m_ppPreCommands + 1, m_nPreCommands * sizeof(char *)); delete [] m_ppPreCommands; m_ppPreCommands = ppPreCommands; } if ( !bCmd ) { #ifdef Q_OS_WIN HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE); INPUT_RECORD ir; ir.EventType = KEY_EVENT; ir.Event.KeyEvent.bKeyDown = 1; ir.Event.KeyEvent.wRepeatCount = 1; ir.Event.KeyEvent.wVirtualKeyCode = VK_SPACE; ir.Event.KeyEvent.wVirtualScanCode = 0x39; ir.Event.KeyEvent.uChar.AsciiChar = ' '; ir.Event.KeyEvent.dwControlKeyState = 0x0; DWORD dwWrite; WriteConsoleInput(hIn, &ir, 1, &dwWrite); #endif return; } if ( !bSysCmd ) break; } }
void FlushMouseEvents() { if (ghConWnd) { HANDLE h = GetStdHandle(STD_INPUT_HANDLE); DWORD nTotal = 0; if (GetNumberOfConsoleInputEvents(h, &nTotal) && nTotal) { INPUT_RECORD *pr = (INPUT_RECORD*)calloc(nTotal, sizeof(*pr)); if (pr && PeekConsoleInput(h, pr, nTotal, &nTotal) && nTotal) { bool bHasMouse = false; DWORD j = 0; for (DWORD i = 0; i < nTotal; i++) { if (pr[i].EventType == MOUSE_EVENT) { bHasMouse = true; continue; } else { if (i > j) pr[j] = pr[i]; j++; } } // Если были мышиные события - сбросить их if (bHasMouse) { if (FlushConsoleInputBuffer(h)) { // Но если были НЕ мышиные - вернуть их в буфер if (j > 0) { WriteConsoleInput(h, pr, j, &nTotal); } } } } } } }
bool console::WriteInput(INPUT_RECORD* Buffer, size_t Length, size_t& NumberOfEventsWritten) const { if (sWindowMode) { const auto Delta = GetDelta(); for (auto& i : span(Buffer, Length)) { if (i.EventType == MOUSE_EVENT) { i.Event.MouseEvent.dwMousePosition.Y += Delta; } } } DWORD dwNumberOfEventsWritten = 0; bool Result = WriteConsoleInput(GetInputHandle(), Buffer, static_cast<DWORD>(Length), &dwNumberOfEventsWritten) != FALSE; NumberOfEventsWritten = dwNumberOfEventsWritten; return Result; }
BOOL consoleEnterCancelEvent ( ) { INPUT_RECORD Record; DWORD dw; Record.EventType = KEY_EVENT; Record.Event.KeyEvent.bKeyDown = TRUE; Record.Event.KeyEvent.wRepeatCount = 0; Record.Event.KeyEvent.wVirtualKeyCode = VK_CANCEL; Record.Event.KeyEvent.wVirtualScanCode = 0; Record.Event.KeyEvent.uChar.AsciiChar = 0; Record.Event.KeyEvent.dwControlKeyState = 0; PutEvent( &Record ); Record.Event.KeyEvent.bKeyDown = TRUE; WriteConsoleInput( hInput, &Record, 1, &dw ); return TRUE; }
static void stop_stdin_thread(void) { if (input_thread) { CONSOLE_SCREEN_BUFFER_INFO sb; INPUT_RECORD ir = {0}; DWORD written; // This is not enough because the background thread may be blocked in ReadFile input_run = false; SetEvent(input_processed); /* We'll soon push VK_RETURN to the console input, which will result in a newline, so move the cursor up one line to avoid showing it. */ GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &sb); if (sb.dwCursorPosition.Y > 0) { sb.dwCursorPosition.Y--; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), sb.dwCursorPosition); } ir.EventType = KEY_EVENT; ir.Event.KeyEvent.bKeyDown = TRUE; ir.Event.KeyEvent.dwControlKeyState = 0; ir.Event.KeyEvent.uChar.AsciiChar = '\r'; ir.Event.KeyEvent.wRepeatCount = 1; // Write a newline to snap the background thread out of the blocking ReadFile call WriteConsoleInput(GetStdHandle(STD_INPUT_HANDLE), &ir, 1, &written); WaitForSingleObject(input_thread, INFINITE); CloseHandle(input_thread); } if (input_processed) CloseHandle(input_processed); if (input_available) CloseHandle(input_available); }
/// Main function int Master::Run() { /// worldd PID file creation std::string pidfile = sConfig.GetStringDefault("PidFile", ""); if(!pidfile.empty()) { uint32 pid = CreatePIDFile(pidfile); if( !pid ) { sLog.outError( "Cannot create PID file %s.\n", pidfile.c_str() ); Log::WaitBeforeContinueIfNeed(); return 1; } sLog.outString( "Daemon PID: %u\n", pid ); } ///- Start the databases if (!_StartDB()) { Log::WaitBeforeContinueIfNeed(); return 1; } ///- Initialize the World sWorld.SetInitialWorldSettings(); #ifndef WIN32 detachDaemon(); #endif //server loaded successfully => enable async DB requests //this is done to forbid any async transactions during server startup! CharacterDatabase.AllowAsyncTransactions(); WorldDatabase.AllowAsyncTransactions(); LoginDatabase.AllowAsyncTransactions(); ///- Catch termination signals _HookSignals(); ///- Launch WorldRunnable thread ACE_Based::Thread world_thread(new WorldRunnable); world_thread.setPriority(ACE_Based::Highest); // set realmbuilds depend on mangosd expected builds, and set server online { std::string builds = AcceptableClientBuildsListStr(); LoginDatabase.escape_string(builds); LoginDatabase.DirectPExecute("UPDATE realmlist SET realmflags = realmflags & ~(%u), population = 0, realmbuilds = '%s' WHERE id = '%u'", REALM_FLAG_OFFLINE, builds.c_str(), realmID); } ACE_Based::Thread* cliThread = NULL; #ifdef WIN32 if (sConfig.GetBoolDefault("Console.Enable", true) && (m_ServiceStatus == -1)/* need disable console in service mode*/) #else if (sConfig.GetBoolDefault("Console.Enable", true)) #endif { ///- Launch CliRunnable thread cliThread = new ACE_Based::Thread(new CliRunnable); } ACE_Based::Thread* rar_thread = NULL; if(sConfig.GetBoolDefault ("Ra.Enable", false)) { rar_thread = new ACE_Based::Thread(new RARunnable); } ///- Handle affinity for multiple processors and process priority on Windows #ifdef WIN32 { HANDLE hProcess = GetCurrentProcess(); uint32 Aff = sConfig.GetIntDefault("UseProcessors", 0); if(Aff > 0) { ULONG_PTR appAff; ULONG_PTR sysAff; if(GetProcessAffinityMask(hProcess,&appAff,&sysAff)) { ULONG_PTR curAff = Aff & appAff; // remove non accessible processors if(!curAff ) { sLog.outError("Processors marked in UseProcessors bitmask (hex) %x not accessible for mangosd. Accessible processors bitmask (hex): %x",Aff,appAff); } else { if(SetProcessAffinityMask(hProcess,curAff)) sLog.outString("Using processors (bitmask, hex): %x", curAff); else sLog.outError("Can't set used processors (hex): %x",curAff); } } sLog.outString(); } bool Prio = sConfig.GetBoolDefault("ProcessPriority", false); // if(Prio && (m_ServiceStatus == -1)/* need set to default process priority class in service mode*/) if(Prio) { if(SetPriorityClass(hProcess,HIGH_PRIORITY_CLASS)) sLog.outString("mangosd process priority class set to HIGH"); else sLog.outError("Can't set mangosd process priority class."); sLog.outString(); } } #endif ///- Start soap serving thread ACE_Based::Thread* soap_thread = NULL; if(sConfig.GetBoolDefault("SOAP.Enabled", false)) { MaNGOSsoapRunnable *runnable = new MaNGOSsoapRunnable(); runnable->setListenArguments(sConfig.GetStringDefault("SOAP.IP", "127.0.0.1"), sConfig.GetIntDefault("SOAP.Port", 7878)); soap_thread = new ACE_Based::Thread(runnable); } ///- Start up freeze catcher thread ACE_Based::Thread* freeze_thread = NULL; if(uint32 freeze_delay = sConfig.GetIntDefault("MaxCoreStuckTime", 0)) { FreezeDetectorRunnable *fdr = new FreezeDetectorRunnable(); fdr->SetDelayTime(freeze_delay*1000); freeze_thread = new ACE_Based::Thread(fdr); freeze_thread->setPriority(ACE_Based::Highest); } ///- Launch the world listener socket uint16 wsport = sWorld.getConfig (CONFIG_UINT32_PORT_WORLD); std::string bind_ip = sConfig.GetStringDefault ("BindIP", "0.0.0.0"); if (sWorldSocketMgr->StartNetwork (wsport, bind_ip) == -1) { sLog.outError ("Failed to start network"); Log::WaitBeforeContinueIfNeed(); World::StopNow(ERROR_EXIT_CODE); // go down and shutdown the server } sWorldSocketMgr->Wait (); ///- Stop freeze protection before shutdown tasks if (freeze_thread) { freeze_thread->destroy(); delete freeze_thread; } ///- Stop soap thread if(soap_thread) { soap_thread->wait(); soap_thread->destroy(); delete soap_thread; } ///- Set server offline in realmlist LoginDatabase.DirectPExecute("UPDATE realmlist SET realmflags = realmflags | %u WHERE id = '%u'", REALM_FLAG_OFFLINE, realmID); ///- Remove signal handling before leaving _UnhookSignals(); // when the main thread closes the singletons get unloaded // since worldrunnable uses them, it will crash if unloaded after master world_thread.wait(); if(rar_thread) { rar_thread->wait(); rar_thread->destroy(); delete rar_thread; } ///- Clean account database before leaving clearOnlineAccounts(); // send all still queued mass mails (before DB connections shutdown) sMassMailMgr.Update(true); ///- Wait for DB delay threads to end CharacterDatabase.HaltDelayThread(); WorldDatabase.HaltDelayThread(); LoginDatabase.HaltDelayThread(); sLog.outString( "Halting process..." ); if (cliThread) { #ifdef WIN32 // this only way to terminate CLI thread exist at Win32 (alt. way exist only in Windows Vista API) //_exit(1); // send keyboard input to safely unblock the CLI thread INPUT_RECORD b[5]; HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE); b[0].EventType = KEY_EVENT; b[0].Event.KeyEvent.bKeyDown = TRUE; b[0].Event.KeyEvent.uChar.AsciiChar = 'X'; b[0].Event.KeyEvent.wVirtualKeyCode = 'X'; b[0].Event.KeyEvent.wRepeatCount = 1; b[1].EventType = KEY_EVENT; b[1].Event.KeyEvent.bKeyDown = FALSE; b[1].Event.KeyEvent.uChar.AsciiChar = 'X'; b[1].Event.KeyEvent.wVirtualKeyCode = 'X'; b[1].Event.KeyEvent.wRepeatCount = 1; b[2].EventType = KEY_EVENT; b[2].Event.KeyEvent.bKeyDown = TRUE; b[2].Event.KeyEvent.dwControlKeyState = 0; b[2].Event.KeyEvent.uChar.AsciiChar = '\r'; b[2].Event.KeyEvent.wVirtualKeyCode = VK_RETURN; b[2].Event.KeyEvent.wRepeatCount = 1; b[2].Event.KeyEvent.wVirtualScanCode = 0x1c; b[3].EventType = KEY_EVENT; b[3].Event.KeyEvent.bKeyDown = FALSE; b[3].Event.KeyEvent.dwControlKeyState = 0; b[3].Event.KeyEvent.uChar.AsciiChar = '\r'; b[3].Event.KeyEvent.wVirtualKeyCode = VK_RETURN; b[3].Event.KeyEvent.wVirtualScanCode = 0x1c; b[3].Event.KeyEvent.wRepeatCount = 1; DWORD numb; BOOL ret = WriteConsoleInput(hStdIn, b, 4, &numb); cliThread->wait(); #else cliThread->destroy(); #endif delete cliThread; } ///- Exit the process with specified return value uint8 worldExitCode = World::GetExitCode(); FILE* exitFile = fopen("mangos-exit.log","w"); fprintf(exitFile,"%d\n",worldExitCode); sLog.outString( "\nWorld exit code = %d\n",worldExitCode ); //fprintf(exitFile,"%d",worldExitCode); fflush(exitFile); fclose(exitFile); return worldExitCode; }
/// Main function int Master::Run() { BigNumber seed1; seed1.SetRand(16 * 8); sLog->outString("%s (worldserver-daemon)", _FULLVERSION); sLog->outString("<Ctrl-C> to stop.\n"); sLog->outString(" ______ __"); sLog->outString("/\\__ _\\ __ __/\\ \\__"); sLog->outString("\\/_/\\ \\/ _ __ /\\_\\ ___ /\\_\\ \\, _\\ __ __"); sLog->outString(" \\ \\ \\/\\`'__\\/\\ \\ /' _ `\\/\\ \\ \\ \\/ /\\ \\/\\ \\"); sLog->outString(" \\ \\ \\ \\ \\/ \\ \\ \\/\\ \\/\\ \\ \\ \\ \\ \\_\\ \\ \\_\\ \\"); sLog->outString(" \\ \\_\\ \\_\\ \\ \\_\\ \\_\\ \\_\\ \\_\\ \\__\\\\/`____ \\"); sLog->outString(" \\/_/\\/_/ \\/_/\\/_/\\/_/\\/_/\\/__/ `/___/> \\"); sLog->outString(" C O R E /\\___/"); sLog->outString("http://TrinityCore.org \\/__/\n"); /// worldserver PID file creation std::string pidfile = ConfigMgr::GetStringDefault("PidFile", ""); if (!pidfile.empty()) { uint32 pid = CreatePIDFile(pidfile); if (!pid) { sLog->outError("Cannot create PID file %s.\n", pidfile.c_str()); return 1; } sLog->outString("Daemon PID: %u\n", pid); } ///- Start the databases if (!_StartDB()) return 1; // set server offline (not connectable) LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = (flag & ~%u) | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, REALM_FLAG_INVALID, realmID); ///- Initialize the World sWorld->SetInitialWorldSettings(); // Initialise the signal handlers WorldServerSignalHandler SignalINT, SignalTERM; #ifdef _WIN32 WorldServerSignalHandler SignalBREAK; #endif /* _WIN32 */ // Register worldserver's signal handlers ACE_Sig_Handler Handler; Handler.register_handler(SIGINT, &SignalINT); Handler.register_handler(SIGTERM, &SignalTERM); #ifdef _WIN32 Handler.register_handler(SIGBREAK, &SignalBREAK); #endif /* _WIN32 */ ///- Launch WorldRunnable thread ACE_Based::Thread world_thread(new WorldRunnable); world_thread.setPriority(ACE_Based::Highest); ACE_Based::Thread* cliThread = NULL; #ifdef _WIN32 if (ConfigMgr::GetBoolDefault("Console.Enable", true) && (m_ServiceStatus == -1)/* need disable console in service mode*/) #else if (ConfigMgr::GetBoolDefault("Console.Enable", true)) #endif { ///- Launch CliRunnable thread cliThread = new ACE_Based::Thread(new CliRunnable); } ACE_Based::Thread rar_thread(new RARunnable); ///- Handle affinity for multiple processors and process priority on Windows #ifdef _WIN32 { HANDLE hProcess = GetCurrentProcess(); uint32 Aff = ConfigMgr::GetIntDefault("UseProcessors", 0); if (Aff > 0) { ULONG_PTR appAff; ULONG_PTR sysAff; if (GetProcessAffinityMask(hProcess, &appAff, &sysAff)) { ULONG_PTR curAff = Aff & appAff; // remove non accessible processors if (!curAff) { sLog->outError("Processors marked in UseProcessors bitmask (hex) %x are not accessible for the worldserver. Accessible processors bitmask (hex): %x", Aff, appAff); } else { if (SetProcessAffinityMask(hProcess, curAff)) sLog->outString("Using processors (bitmask, hex): %x", curAff); else sLog->outError("Can't set used processors (hex): %x", curAff); } } sLog->outString(""); } bool Prio = ConfigMgr::GetBoolDefault("ProcessPriority", false); //if (Prio && (m_ServiceStatus == -1) /* need set to default process priority class in service mode*/) if (Prio) { if (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS)) sLog->outString("worldserver process priority class set to HIGH"); else sLog->outError("Can't set worldserver process priority class."); sLog->outString(""); } } #endif //Start soap serving thread ACE_Based::Thread* soap_thread = NULL; if (ConfigMgr::GetBoolDefault("SOAP.Enabled", false)) { TCSoapRunnable* runnable = new TCSoapRunnable(); runnable->setListenArguments(ConfigMgr::GetStringDefault("SOAP.IP", "127.0.0.1"), ConfigMgr::GetIntDefault("SOAP.Port", 7878)); soap_thread = new ACE_Based::Thread(runnable); } ///- Start up freeze catcher thread if (uint32 freeze_delay = ConfigMgr::GetIntDefault("MaxCoreStuckTime", 0)) { FreezeDetectorRunnable* fdr = new FreezeDetectorRunnable(); fdr->SetDelayTime(freeze_delay*1000); ACE_Based::Thread freeze_thread(fdr); freeze_thread.setPriority(ACE_Based::Highest); } ///- Launch the world listener socket uint16 wsport = sWorld->getIntConfig(CONFIG_PORT_WORLD); std::string bind_ip = ConfigMgr::GetStringDefault("BindIP", "0.0.0.0"); if (sWorldSocketMgr->StartNetwork(wsport, bind_ip.c_str ()) == -1) { sLog->outError("Failed to start network"); World::StopNow(ERROR_EXIT_CODE); // go down and shutdown the server } // set server online (allow connecting now) LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag & ~%u, population = 0 WHERE id = '%u'", REALM_FLAG_INVALID, realmID); sLog->outString("%s (worldserver-daemon) ready...", _FULLVERSION); // when the main thread closes the singletons get unloaded // since worldrunnable uses them, it will crash if unloaded after master world_thread.wait(); rar_thread.wait(); if (soap_thread) { soap_thread->wait(); soap_thread->destroy(); delete soap_thread; } // set server offline LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, realmID); ///- Clean database before leaving ClearOnlineAccounts(); _StopDB(); sLog->outString("Halting process..."); if (cliThread) { #ifdef _WIN32 // this only way to terminate CLI thread exist at Win32 (alt. way exist only in Windows Vista API) //_exit(1); // send keyboard input to safely unblock the CLI thread INPUT_RECORD b[5]; HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE); b[0].EventType = KEY_EVENT; b[0].Event.KeyEvent.bKeyDown = TRUE; b[0].Event.KeyEvent.uChar.AsciiChar = 'X'; b[0].Event.KeyEvent.wVirtualKeyCode = 'X'; b[0].Event.KeyEvent.wRepeatCount = 1; b[1].EventType = KEY_EVENT; b[1].Event.KeyEvent.bKeyDown = FALSE; b[1].Event.KeyEvent.uChar.AsciiChar = 'X'; b[1].Event.KeyEvent.wVirtualKeyCode = 'X'; b[1].Event.KeyEvent.wRepeatCount = 1; b[2].EventType = KEY_EVENT; b[2].Event.KeyEvent.bKeyDown = TRUE; b[2].Event.KeyEvent.dwControlKeyState = 0; b[2].Event.KeyEvent.uChar.AsciiChar = '\r'; b[2].Event.KeyEvent.wVirtualKeyCode = VK_RETURN; b[2].Event.KeyEvent.wRepeatCount = 1; b[2].Event.KeyEvent.wVirtualScanCode = 0x1c; b[3].EventType = KEY_EVENT; b[3].Event.KeyEvent.bKeyDown = FALSE; b[3].Event.KeyEvent.dwControlKeyState = 0; b[3].Event.KeyEvent.uChar.AsciiChar = '\r'; b[3].Event.KeyEvent.wVirtualKeyCode = VK_RETURN; b[3].Event.KeyEvent.wVirtualScanCode = 0x1c; b[3].Event.KeyEvent.wRepeatCount = 1; DWORD numb; WriteConsoleInput(hStdIn, b, 4, &numb); cliThread->wait(); #else cliThread->destroy(); #endif delete cliThread; } // for some unknown reason, unloading scripts here and not in worldrunnable // fixes a memory leak related to detaching threads from the module //UnloadScriptingModule(); // Exit the process with specified return value return World::GetExitCode(); }
BOOL SendConsoleEvent(INPUT_RECORD* pr, UINT nCount) { if (!nCount || !pr) { _ASSERTE(nCount>0 && pr!=NULL); return FALSE; } BOOL fSuccess = FALSE; //// Если сейчас идет ресайз - нежелательно помещение в буфер событий //if (gpSrv->bInSyncResize) // WaitForSingleObject(gpSrv->hAllowInputEvent, MAX_SYNCSETSIZE_WAIT); //DWORD nCurInputCount = 0, cbWritten = 0; //INPUT_RECORD irDummy[2] = {{0},{0}}; //HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE); // тут был ghConIn // 02.04.2010 Maks - перенесено в WaitConsoleReady //// 27.06.2009 Maks - If input queue is not empty - wait for a while, to avoid conflicts with FAR reading queue //// 19.02.2010 Maks - замена на GetNumberOfConsoleInputEvents ////if (PeekConsoleInput(hIn, irDummy, 1, &(nCurInputCount = 0)) && nCurInputCount > 0) { //if (GetNumberOfConsoleInputEvents(hIn, &(nCurInputCount = 0)) && nCurInputCount > 0) { // DWORD dwStartTick = GetTickCount(); // WARNING("Do NOT wait, but place event in Cyclic queue"); // do { // Sleep(5); // //if (!PeekConsoleInput(hIn, irDummy, 1, &(nCurInputCount = 0))) // if (!GetNumberOfConsoleInputEvents(hIn, &(nCurInputCount = 0))) // nCurInputCount = 0; // } while ((nCurInputCount > 0) && ((GetTickCount() - dwStartTick) < MAX_INPUT_QUEUE_EMPTY_WAIT)); //} INPUT_RECORD* prNew = NULL; int nAllCount = 0; BOOL lbReqEmpty = FALSE; for (UINT n = 0; n < nCount; n++) { if (pr[n].EventType != KEY_EVENT) { nAllCount++; if (!lbReqEmpty && (pr[n].EventType == MOUSE_EVENT)) { // По всей видимости дурит консоль Windows. // Если в буфере сейчас еще есть мышиные события, то запись // в буфер возвращает ОК, но считывающее приложение получает 0-событий. // В итоге, получаем пропуск некоторых событий, что очень неприятно // при выделении кучи файлов правой кнопкой мыши (проводкой с зажатой кнопкой) if (pr[n].Event.MouseEvent.dwButtonState /*== RIGHTMOST_BUTTON_PRESSED*/) lbReqEmpty = TRUE; } } else { WORD vk = pr[n].Event.KeyEvent.wVirtualKeyCode; if (((vk == VK_RETURN) || (vk == VK_SPACE)) && gpSrv->pAppMap) { // github#19: don't post Enter/Space KeyUp events to the console input buffer // Also, type in PS prompt // get-help Get-ChildItem -full | out-host -paging // And press "Enter". You'll get one waste reaction for "Enter" KeyUp static DWORD nLastPID = 0; static WORD nLastVK = 0; bool bBypass = false; if (pr[n].Event.KeyEvent.bKeyDown) { // The application may use Read only for getting the event when it is ready // So the application is not waiting for and simple nReadConsoleInputPID // will be zero most of time... nLastPID = gpSrv->pAppMap->Ptr()->nLastReadInputPID; nLastVK = nLastPID ? vk : 0; bBypass = true; } else { if ((nLastPID != gpSrv->pAppMap->Ptr()->nLastReadInputPID) || (nLastVK != vk)) { // Skip this event pr[n].EventType = 0; nLastPID = 0; nLastVK = 0; continue; } else { bBypass = true; } } // Else - allow Enter/Space KeyUp UNREFERENCED_PARAMETER(bBypass); } if (!pr[n].Event.KeyEvent.wRepeatCount) { _ASSERTE(pr[n].Event.KeyEvent.wRepeatCount!=0); pr[n].Event.KeyEvent.wRepeatCount = 1; } nAllCount += pr[n].Event.KeyEvent.wRepeatCount; } } if (nAllCount > (int)nCount) { prNew = (INPUT_RECORD*)malloc(sizeof(INPUT_RECORD)*nAllCount); if (prNew) { INPUT_RECORD* ppr = prNew; INPUT_RECORD* pprMod = NULL; for (UINT n = 0; n < nCount; n++) { if (!pr[n].EventType) continue; *(ppr++) = pr[n]; if (pr[n].EventType == KEY_EVENT) { UINT nCurCount = pr[n].Event.KeyEvent.wRepeatCount; if (nCurCount > 1) { pprMod = (ppr-1); pprMod->Event.KeyEvent.wRepeatCount = 1; for (UINT i = 1; i < nCurCount; i++) { *(ppr++) = *pprMod; } } } else if (!lbReqEmpty && (pr[n].EventType == MOUSE_EVENT)) { // По всей видимости дурит консоль Windows. // Если в буфере сейчас еще есть мышиные события, то запись // в буфер возвращает ОК, но считывающее приложение получает 0-событий. // В итоге, получаем пропуск некоторых событий, что очень неприятно // при выделении кучи файлов правой кнопкой мыши (проводкой с зажатой кнопкой) if (pr[n].Event.MouseEvent.dwButtonState == RIGHTMOST_BUTTON_PRESSED) lbReqEmpty = TRUE; } } pr = prNew; _ASSERTE(nAllCount == (ppr-prNew)); nCount = (UINT)(ppr-prNew); } } // Если не готов - все равно запишем DEBUGTEST(BOOL bConReady = ) WaitConsoleReady(lbReqEmpty); DWORD cbWritten = 0; #ifdef _DEBUG wchar_t* pszDbgCurChars = NULL; wchar_t szDbg[255]; for (UINT i = 0; i < nCount; i++) { switch (pr[i].EventType) { case MOUSE_EVENT: _wsprintf(szDbg, SKIPLEN(countof(szDbg)) L"*** ConEmuC.MouseEvent(X=%i,Y=%i,Btns=0x%04x,Moved=%i)\n", pr[i].Event.MouseEvent.dwMousePosition.X, pr[i].Event.MouseEvent.dwMousePosition.Y, pr[i].Event.MouseEvent.dwButtonState, (pr[i].Event.MouseEvent.dwEventFlags & MOUSE_MOVED)); DEBUGSTRINPUTWRITE(szDbg); #ifdef _DEBUG { static int LastMsButton; if ((LastMsButton & 1) && (pr[i].Event.MouseEvent.dwButtonState == 0)) { // LButton was Down, now - Up LastMsButton = pr[i].Event.MouseEvent.dwButtonState; } else if (!LastMsButton && (pr[i].Event.MouseEvent.dwButtonState & 1)) { // LButton was Up, now - Down LastMsButton = pr[i].Event.MouseEvent.dwButtonState; } else { //-V523 LastMsButton = pr[i].Event.MouseEvent.dwButtonState; } } #endif break; case KEY_EVENT: { wchar_t szCh[3] = {pr[i].Event.KeyEvent.uChar.UnicodeChar}; switch (szCh[0]) { case 8: szCh[0] = L'\\'; szCh[1] = L'b'; break; case 9: szCh[0] = L'\\'; szCh[1] = L't'; break; case 10: szCh[0] = L'\\'; szCh[1] = L'r'; break; case 13: szCh[0] = L'\\'; szCh[1] = L'n'; break; case 27: szCh[0] = L'\\'; szCh[1] = L'e'; break; } _wsprintf(szDbg, SKIPLEN(countof(szDbg)) L"*** ConEmuC.KeybdEvent(%s, VK=%u, CH=%s)\n", pr[i].Event.KeyEvent.bKeyDown ? L"Dn" : L"Up", pr[i].Event.KeyEvent.wVirtualKeyCode, szCh); DEBUGSTRINPUTWRITE(szDbg); } break; } // Only for input_bug search purposes in Debug builds LONG idx = (InterlockedIncrement(&gn_LogWrittenChars) & (gn_LogWrittenCharsMax-1))*2; if (!pszDbgCurChars) pszDbgCurChars = gs_LogWrittenChars+idx; if (pr[i].EventType == KEY_EVENT) { gs_LogWrittenChars[idx++] = pr[i].Event.KeyEvent.bKeyDown ? L'\\' : L'/'; gs_LogWrittenChars[idx] = pr[i].Event.KeyEvent.uChar.UnicodeChar ? pr[i].Event.KeyEvent.uChar.UnicodeChar : L'.'; } else { gs_LogWrittenChars[idx++] = L'='; switch (pr[i].EventType) { case MOUSE_EVENT: gs_LogWrittenChars[idx] = L'm'; break; case WINDOW_BUFFER_SIZE_EVENT: gs_LogWrittenChars[idx] = L'w'; break; case MENU_EVENT: gs_LogWrittenChars[idx] = L'e'; break; case FOCUS_EVENT: gs_LogWrittenChars[idx] = L'f'; break; default: gs_LogWrittenChars[idx] = L'x'; break; } } gs_LogWrittenChars[++idx] = 0; } int nDbgSendLen = pszDbgCurChars ? lstrlen(pszDbgCurChars) : -1; SetLastError(0); #endif InputLogger::Log(InputLogger::Event::evt_WriteConInput, nCount); HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE); // тут был ghConIn // Strange VIM reaction on xterm-keypresses if ((nCount > 2) && (nCount <= 32) && (pr->EventType == KEY_EVENT) && (pr->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) { DWORD nWritten = 0; cbWritten = 0; for (UINT n = 0; n < nCount; n++) { if ((n + 1) == nCount) { DEBUGTEST(bConReady = ) WaitConsoleReady(TRUE); } fSuccess = WriteConsoleInput(hIn, pr+n, 1, &nWritten); if (fSuccess) cbWritten += nWritten; }
/// Main function int Master::Run() { /// worldd PID file creation std::string pidfile = sConfig.GetStringDefault("PidFile", ""); if(!pidfile.empty()) { uint32 pid = CreatePIDFile(pidfile); if( !pid ) { sLog.outError( "Cannot create PID file %s.\n", pidfile.c_str() ); return 1; } sLog.outString( "Daemon PID: %u\n", pid ); } ///- Start the databases if (!_StartDB()) return 1; ///- Initialize the World sWorld.SetInitialWorldSettings(); ///- Catch termination signals _HookSignals(); ///- Launch WorldRunnable thread ACE_Based::Thread world_thread(new WorldRunnable); world_thread.setPriority(ACE_Based::Highest); // set server online loginDatabase.PExecute("UPDATE realmlist SET color = 0, population = 0 WHERE id = '%d'",realmID); ACE_Based::Thread* cliThread = NULL; #ifdef WIN32 if (sConfig.GetBoolDefault("Console.Enable", true) && (m_ServiceStatus == -1)/* need disable console in service mode*/) #else if (sConfig.GetBoolDefault("Console.Enable", true)) #endif { ///- Launch CliRunnable thread cliThread = new ACE_Based::Thread(new CliRunnable); } ACE_Based::Thread rar_thread(new RARunnable); ///- Handle affinity for multiple processors and process priority on Windows #ifdef WIN32 { HANDLE hProcess = GetCurrentProcess(); uint32 Aff = sConfig.GetIntDefault("UseProcessors", 0); if(Aff > 0) { ULONG_PTR appAff; ULONG_PTR sysAff; if(GetProcessAffinityMask(hProcess,&appAff,&sysAff)) { ULONG_PTR curAff = Aff & appAff; // remove non accessible processors if(!curAff ) { sLog.outError("Processors marked in UseProcessors bitmask (hex) %x not accessible for mangosd. Accessible processors bitmask (hex): %x",Aff,appAff); } else { if(SetProcessAffinityMask(hProcess,curAff)) sLog.outString("Using processors (bitmask, hex): %x", curAff); else sLog.outError("Can't set used processors (hex): %x",curAff); } } sLog.outString(); } bool Prio = sConfig.GetBoolDefault("ProcessPriority", false); // if(Prio && (m_ServiceStatus == -1)/* need set to default process priority class in service mode*/) if(Prio) { if(SetPriorityClass(hProcess,HIGH_PRIORITY_CLASS)) sLog.outString("mangosd process priority class set to HIGH"); else sLog.outError("ERROR: Can't set mangosd process priority class."); sLog.outString(); } } #endif uint32 realCurrTime, realPrevTime; realCurrTime = realPrevTime = getMSTime(); uint32 socketSelecttime = sWorld.getConfig(CONFIG_SOCKET_SELECTTIME); ///- Start up freeze catcher thread if(uint32 freeze_delay = sConfig.GetIntDefault("MaxCoreStuckTime", 0)) { FreezeDetectorRunnable *fdr = new FreezeDetectorRunnable(); fdr->SetDelayTime(freeze_delay*1000); ACE_Based::Thread freeze_thread(fdr); freeze_thread.setPriority(ACE_Based::Highest); } ///- Launch the world listener socket port_t wsport = sWorld.getConfig (CONFIG_PORT_WORLD); std::string bind_ip = sConfig.GetStringDefault ("BindIP", "0.0.0.0"); if (sWorldSocketMgr->StartNetwork (wsport, bind_ip.c_str ()) == -1) { sLog.outError ("Failed to start network"); World::StopNow(ERROR_EXIT_CODE); // go down and shutdown the server } sWorldSocketMgr->Wait (); // set server offline loginDatabase.PExecute("UPDATE realmlist SET color = 2 WHERE id = '%d'",realmID); ///- Remove signal handling before leaving _UnhookSignals(); // when the main thread closes the singletons get unloaded // since worldrunnable uses them, it will crash if unloaded after master world_thread.wait(); rar_thread.wait (); ///- Clean database before leaving clearOnlineAccounts(); ///- Wait for delay threads to end CharacterDatabase.HaltDelayThread(); WorldDatabase.HaltDelayThread(); loginDatabase.HaltDelayThread(); sLog.outString( "Halting process..." ); if (cliThread) { #ifdef WIN32 // this only way to terminate CLI thread exist at Win32 (alt. way exist only in Windows Vista API) //_exit(1); // send keyboard input to safely unblock the CLI thread INPUT_RECORD b[5]; HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE); b[0].EventType = KEY_EVENT; b[0].Event.KeyEvent.bKeyDown = TRUE; b[0].Event.KeyEvent.uChar.AsciiChar = 'X'; b[0].Event.KeyEvent.wVirtualKeyCode = 'X'; b[0].Event.KeyEvent.wRepeatCount = 1; b[1].EventType = KEY_EVENT; b[1].Event.KeyEvent.bKeyDown = FALSE; b[1].Event.KeyEvent.uChar.AsciiChar = 'X'; b[1].Event.KeyEvent.wVirtualKeyCode = 'X'; b[1].Event.KeyEvent.wRepeatCount = 1; b[2].EventType = KEY_EVENT; b[2].Event.KeyEvent.bKeyDown = TRUE; b[2].Event.KeyEvent.dwControlKeyState = 0; b[2].Event.KeyEvent.uChar.AsciiChar = '\r'; b[2].Event.KeyEvent.wVirtualKeyCode = VK_RETURN; b[2].Event.KeyEvent.wRepeatCount = 1; b[2].Event.KeyEvent.wVirtualScanCode = 0x1c; b[3].EventType = KEY_EVENT; b[3].Event.KeyEvent.bKeyDown = FALSE; b[3].Event.KeyEvent.dwControlKeyState = 0; b[3].Event.KeyEvent.uChar.AsciiChar = '\r'; b[3].Event.KeyEvent.wVirtualKeyCode = VK_RETURN; b[3].Event.KeyEvent.wVirtualScanCode = 0x1c; b[3].Event.KeyEvent.wRepeatCount = 1; DWORD numb; BOOL ret = WriteConsoleInput(hStdIn, b, 4, &numb); cliThread->wait(); #else cliThread->destroy(); #endif delete cliThread; } // for some unknown reason, unloading scripts here and not in worldrunnable // fixes a memory leak related to detaching threads from the module UnloadScriptingModule(); // Exit the process with specified return value return World::GetExitCode(); }
BOOL SendConsoleEvent(INPUT_RECORD* pr, UINT nCount) { if (!nCount || !pr) { _ASSERTE(nCount>0 && pr!=NULL); return FALSE; } BOOL fSuccess = FALSE; //// Если сейчас идет ресайз - нежелательно помещение в буфер событий //if (gpSrv->bInSyncResize) // WaitForSingleObject(gpSrv->hAllowInputEvent, MAX_SYNCSETSIZE_WAIT); //DWORD nCurInputCount = 0, cbWritten = 0; //INPUT_RECORD irDummy[2] = {{0},{0}}; //HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE); // тут был ghConIn // 02.04.2010 Maks - перенесено в WaitConsoleReady //// 27.06.2009 Maks - If input queue is not empty - wait for a while, to avoid conflicts with FAR reading queue //// 19.02.2010 Maks - замена на GetNumberOfConsoleInputEvents ////if (PeekConsoleInput(hIn, irDummy, 1, &(nCurInputCount = 0)) && nCurInputCount > 0) { //if (GetNumberOfConsoleInputEvents(hIn, &(nCurInputCount = 0)) && nCurInputCount > 0) { // DWORD dwStartTick = GetTickCount(); // WARNING("Do NOT wait, but place event in Cyclic queue"); // do { // Sleep(5); // //if (!PeekConsoleInput(hIn, irDummy, 1, &(nCurInputCount = 0))) // if (!GetNumberOfConsoleInputEvents(hIn, &(nCurInputCount = 0))) // nCurInputCount = 0; // } while ((nCurInputCount > 0) && ((GetTickCount() - dwStartTick) < MAX_INPUT_QUEUE_EMPTY_WAIT)); //} INPUT_RECORD* prNew = NULL; int nAllCount = 0; BOOL lbReqEmpty = FALSE; for (UINT n = 0; n < nCount; n++) { if (pr[n].EventType != KEY_EVENT) { nAllCount++; if (!lbReqEmpty && (pr[n].EventType == MOUSE_EVENT)) { // По всей видимости дурит консоль Windows. // Если в буфере сейчас еще есть мышиные события, то запись // в буфер возвращает ОК, но считывающее приложение получает 0-событий. // В итоге, получаем пропуск некоторых событий, что очень неприятно // при выделении кучи файлов правой кнопкой мыши (проводкой с зажатой кнопкой) if (pr[n].Event.MouseEvent.dwButtonState /*== RIGHTMOST_BUTTON_PRESSED*/) lbReqEmpty = TRUE; } } else { if (!pr[n].Event.KeyEvent.wRepeatCount) { _ASSERTE(pr[n].Event.KeyEvent.wRepeatCount!=0); pr[n].Event.KeyEvent.wRepeatCount = 1; } nAllCount += pr[n].Event.KeyEvent.wRepeatCount; } } if (nAllCount > (int)nCount) { prNew = (INPUT_RECORD*)malloc(sizeof(INPUT_RECORD)*nAllCount); if (prNew) { INPUT_RECORD* ppr = prNew; INPUT_RECORD* pprMod = NULL; for(UINT n = 0; n < nCount; n++) { *(ppr++) = pr[n]; if (pr[n].EventType == KEY_EVENT) { UINT nCurCount = pr[n].Event.KeyEvent.wRepeatCount; if (nCurCount > 1) { pprMod = (ppr-1); pprMod->Event.KeyEvent.wRepeatCount = 1; for(UINT i = 1; i < nCurCount; i++) { *(ppr++) = *pprMod; } } } else if (!lbReqEmpty && (pr[n].EventType == MOUSE_EVENT)) { // По всей видимости дурит консоль Windows. // Если в буфере сейчас еще есть мышиные события, то запись // в буфер возвращает ОК, но считывающее приложение получает 0-событий. // В итоге, получаем пропуск некоторых событий, что очень неприятно // при выделении кучи файлов правой кнопкой мыши (проводкой с зажатой кнопкой) if (pr[n].Event.MouseEvent.dwButtonState == RIGHTMOST_BUTTON_PRESSED) lbReqEmpty = TRUE; } } pr = prNew; _ASSERTE(nAllCount == (ppr-prNew)); nCount = (UINT)(ppr-prNew); } } // Если не готов - все равно запишем DEBUGTEST(BOOL bConReady = ) WaitConsoleReady(lbReqEmpty); DWORD cbWritten = 0; #ifdef _DEBUG wchar_t* pszDbgCurChars = NULL; wchar_t szDbg[255]; for (UINT i = 0; i < nCount; i++) { if (pr[i].EventType == MOUSE_EVENT) { _wsprintf(szDbg, SKIPLEN(countof(szDbg)) L"*** ConEmuC.MouseEvent(X=%i,Y=%i,Btns=0x%04x,Moved=%i)\n", pr[i].Event.MouseEvent.dwMousePosition.X, pr[i].Event.MouseEvent.dwMousePosition.Y, pr[i].Event.MouseEvent.dwButtonState, (pr[i].Event.MouseEvent.dwEventFlags & MOUSE_MOVED)); DEBUGSTRINPUTWRITE(szDbg); #ifdef _DEBUG { static int LastMsButton; if ((LastMsButton & 1) && (pr[i].Event.MouseEvent.dwButtonState == 0)) { // LButton was Down, now - Up LastMsButton = pr[i].Event.MouseEvent.dwButtonState; } else if (!LastMsButton && (pr[i].Event.MouseEvent.dwButtonState & 1)) { // LButton was Up, now - Down LastMsButton = pr[i].Event.MouseEvent.dwButtonState; } else { //-V523 LastMsButton = pr[i].Event.MouseEvent.dwButtonState; } } #endif } // Only for input_bug search purposes in Debug builds LONG idx = (InterlockedIncrement(&gn_LogWrittenChars) & (gn_LogWrittenCharsMax-1))*2; if (!pszDbgCurChars) pszDbgCurChars = gs_LogWrittenChars+idx; if (pr[i].EventType == KEY_EVENT) { gs_LogWrittenChars[idx++] = pr[i].Event.KeyEvent.bKeyDown ? L'\\' : L'/'; gs_LogWrittenChars[idx] = pr[i].Event.KeyEvent.uChar.UnicodeChar ? pr[i].Event.KeyEvent.uChar.UnicodeChar : L'.'; } else { gs_LogWrittenChars[idx++] = L'='; switch (pr[i].EventType) { case MOUSE_EVENT: gs_LogWrittenChars[idx] = L'm'; break; case WINDOW_BUFFER_SIZE_EVENT: gs_LogWrittenChars[idx] = L'w'; break; case MENU_EVENT: gs_LogWrittenChars[idx] = L'e'; break; case FOCUS_EVENT: gs_LogWrittenChars[idx] = L'f'; break; default: gs_LogWrittenChars[idx] = L'x'; break; } } gs_LogWrittenChars[++idx] = 0; } int nDbgSendLen = pszDbgCurChars ? lstrlen(pszDbgCurChars) : -1; SetLastError(0); #endif HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE); // тут был ghConIn fSuccess = WriteConsoleInput(hIn, pr, nCount, &cbWritten); // Error ERROR_INVALID_HANDLE may occurs when ConEmu was Attached to some external console with redirected input. #ifdef _DEBUG DWORD dwErr = GetLastError(); if (!fSuccess || (nCount != cbWritten)) { _wsprintf(szDbg, SKIPLEN(countof(szDbg)) L"### WriteConsoleInput(Write=%i, Written=%i, Left=%i, Err=x%X)\n", nCount, cbWritten, gpSrv->InputQueue.GetNumberOfBufferEvents(), dwErr); DEBUGSTRINPUTWRITEFAIL(szDbg); } else { _wsprintf(szDbg, SKIPLEN(countof(szDbg)) L"*** WriteConsoleInput(Write=%i, Written=%i, Left=%i)\n", nCount, cbWritten, gpSrv->InputQueue.GetNumberOfBufferEvents()); DEBUGSTRINPUTWRITEALL(szDbg); } _ASSERTE((fSuccess && cbWritten==nCount) || (!fSuccess && dwErr==ERROR_INVALID_HANDLE && gbAttachMode)); #endif if (prNew) free(prNew); return fSuccess; }
/// Main function int Master::Run() { OpenSSLCrypto::threadsSetup(); BigNumber seed1; seed1.SetRand(16 * 8); TC_LOG_INFO("server.worldserver", "%s (worldserver-daemon)", _FULLVERSION); TC_LOG_INFO("server.worldserver", " "); TC_LOG_INFO("server.worldserver", " A World of Warcraft Cataclsym 4.3.4 Emulator "); TC_LOG_INFO("server.worldserver", " _/_/ _/ _/_/_/ _/_/ _/_/_/ _/_/_/_/ "); TC_LOG_INFO("server.worldserver", " _/ _/ _/ _/_/ _/ _/ _/ _/ _/ _/ _/ _/ "); TC_LOG_INFO("server.worldserver", " _/_/_/_/ _/_/ _/_/ _/ _/ _/ _/_/_/ _/_/_/ "); TC_LOG_INFO("server.worldserver", " _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ "); TC_LOG_INFO("server.worldserver", " _/ _/ _/ _/ _/ _/_/_/ _/_/ _/ _/ _/_/_/_/ NG "); TC_LOG_INFO("server.worldserver", " Arkania Community (c) 2017! <http://arkania.net/> "); TC_LOG_INFO("server.worldserver", " "); TC_LOG_INFO("server.worldserver", "<Ctrl-C> to stop.\n"); /// worldserver PID file creation std::string pidFile = sConfigMgr->GetStringDefault("PidFile", ""); if (!pidFile.empty()) { if (uint32 pid = CreatePIDFile(pidFile)) TC_LOG_INFO("server.worldserver", "Daemon PID: %u\n", pid); else { TC_LOG_ERROR("server.worldserver", "Cannot create PID file %s.\n", pidFile.c_str()); return 1; } } ///- Start the databases if (!_StartDB()) return 1; // set server offline (not connectable) LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = (flag & ~%u) | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, REALM_FLAG_INVALID, realmID); ///- Initialize the World sWorld->SetInitialWorldSettings(); ///- Initialize the signal handlers WorldServerSignalHandler signalINT, signalTERM; #ifdef _WIN32 WorldServerSignalHandler signalBREAK; #endif /* _WIN32 */ ///- Register worldserver's signal handlers ACE_Sig_Handler handle; handle.register_handler(SIGINT, &signalINT); handle.register_handler(SIGTERM, &signalTERM); #ifdef _WIN32 handle.register_handler(SIGBREAK, &signalBREAK); #endif ///- Launch WorldRunnable thread ACE_Based::Thread worldThread(new WorldRunnable); worldThread.setPriority(ACE_Based::Highest); ACE_Based::Thread* cliThread = nullptr; #ifdef _WIN32 if (sConfigMgr->GetBoolDefault("Console.Enable", true) && (m_ServiceStatus == -1)/* need disable console in service mode*/) #else if (sConfigMgr->GetBoolDefault("Console.Enable", true)) #endif { ///- Launch CliRunnable thread cliThread = new ACE_Based::Thread(new CliRunnable); } ACE_Based::Thread rarThread(new RARunnable); #if defined(_WIN32) || defined(__linux__) ///- Handle affinity for multiple processors and process priority uint32 affinity = sConfigMgr->GetIntDefault("UseProcessors", 0); bool highPriority = sConfigMgr->GetBoolDefault("ProcessPriority", false); #ifdef _WIN32 // Windows HANDLE hProcess = GetCurrentProcess(); if (affinity > 0) { ULONG_PTR appAff; ULONG_PTR sysAff; if (GetProcessAffinityMask(hProcess, &appAff, &sysAff)) { ULONG_PTR currentAffinity = affinity & appAff; // remove non accessible processors if (!currentAffinity) TC_LOG_ERROR("server.worldserver", "Processors marked in UseProcessors bitmask (hex) %x are not accessible for the worldserver. Accessible processors bitmask (hex): %x", affinity, appAff); else if (SetProcessAffinityMask(hProcess, currentAffinity)) TC_LOG_INFO("server.worldserver", "Using processors (bitmask, hex): %x", currentAffinity); else TC_LOG_ERROR("server.worldserver", "Can't set used processors (hex): %x", currentAffinity); } } if (highPriority) { if (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS)) TC_LOG_INFO("server.worldserver", "worldserver process priority class set to HIGH"); else TC_LOG_ERROR("server.worldserver", "Can't set worldserver process priority class."); } #else // Linux if (affinity > 0) { cpu_set_t mask; CPU_ZERO(&mask); for (unsigned int i = 0; i < sizeof(affinity) * 8; ++i) if (affinity & (1 << i)) CPU_SET(i, &mask); if (sched_setaffinity(0, sizeof(mask), &mask)) TC_LOG_ERROR("server.worldserver", "Can't set used processors (hex): %x, error: %s", affinity, strerror(errno)); else { CPU_ZERO(&mask); sched_getaffinity(0, sizeof(mask), &mask); TC_LOG_INFO("server.worldserver", "Using processors (bitmask, hex): %lx", *(__cpu_mask*)(&mask)); } } if (highPriority) { if (setpriority(PRIO_PROCESS, 0, PROCESS_HIGH_PRIORITY)) TC_LOG_ERROR("server.worldserver", "Can't set worldserver process priority class, error: %s", strerror(errno)); else TC_LOG_INFO("server.worldserver", "worldserver process priority class set to %i", getpriority(PRIO_PROCESS, 0)); } #endif #endif //Start soap serving thread ACE_Based::Thread* soapThread = nullptr; if (sConfigMgr->GetBoolDefault("SOAP.Enabled", false)) { TCSoapRunnable* runnable = new TCSoapRunnable(); runnable->SetListenArguments(sConfigMgr->GetStringDefault("SOAP.IP", "127.0.0.1"), uint16(sConfigMgr->GetIntDefault("SOAP.Port", 7878))); soapThread = new ACE_Based::Thread(runnable); } ///- Start up freeze catcher thread if (uint32 freezeDelay = sConfigMgr->GetIntDefault("MaxCoreStuckTime", 0)) { FreezeDetectorRunnable* fdr = new FreezeDetectorRunnable(); fdr->SetDelayTime(freezeDelay * 1000); ACE_Based::Thread freezeThread(fdr); freezeThread.setPriority(ACE_Based::Highest); } ///- Launch the world listener socket uint16 worldPort = uint16(sWorld->getIntConfig(CONFIG_PORT_WORLD)); std::string bindIp = sConfigMgr->GetStringDefault("BindIP", "0.0.0.0"); if (sWorldSocketMgr->StartNetwork(worldPort, bindIp.c_str()) == -1) { TC_LOG_ERROR("server.worldserver", "Failed to start network"); World::StopNow(ERROR_EXIT_CODE); // go down and shutdown the server } // set server online (allow connecting now) LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag & ~%u, population = 0 WHERE id = '%u'", REALM_FLAG_INVALID, realmID); TC_LOG_INFO("server.worldserver", "%s (worldserver-daemon) ready...", _FULLVERSION); #ifdef _DEBUG ASSERT(false); // my debugging stop #endif // when the main thread closes the singletons get unloaded // since worldrunnable uses them, it will crash if unloaded after master worldThread.wait(); rarThread.wait(); if (soapThread) { soapThread->wait(); soapThread->destroy(); delete soapThread; } // set server offline LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, realmID); ///- Clean database before leaving ClearOnlineAccounts(); _StopDB(); TC_LOG_INFO("server.worldserver", "Halting process..."); if (cliThread) { #ifdef _WIN32 // this only way to terminate CLI thread exist at Win32 (alt. way exist only in Windows Vista API) //_exit(1); // send keyboard input to safely unblock the CLI thread INPUT_RECORD b[4]; HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE); b[0].EventType = KEY_EVENT; b[0].Event.KeyEvent.bKeyDown = TRUE; b[0].Event.KeyEvent.uChar.AsciiChar = 'X'; b[0].Event.KeyEvent.wVirtualKeyCode = 'X'; b[0].Event.KeyEvent.wRepeatCount = 1; b[1].EventType = KEY_EVENT; b[1].Event.KeyEvent.bKeyDown = FALSE; b[1].Event.KeyEvent.uChar.AsciiChar = 'X'; b[1].Event.KeyEvent.wVirtualKeyCode = 'X'; b[1].Event.KeyEvent.wRepeatCount = 1; b[2].EventType = KEY_EVENT; b[2].Event.KeyEvent.bKeyDown = TRUE; b[2].Event.KeyEvent.dwControlKeyState = 0; b[2].Event.KeyEvent.uChar.AsciiChar = '\r'; b[2].Event.KeyEvent.wVirtualKeyCode = VK_RETURN; b[2].Event.KeyEvent.wRepeatCount = 1; b[2].Event.KeyEvent.wVirtualScanCode = 0x1c; b[3].EventType = KEY_EVENT; b[3].Event.KeyEvent.bKeyDown = FALSE; b[3].Event.KeyEvent.dwControlKeyState = 0; b[3].Event.KeyEvent.uChar.AsciiChar = '\r'; b[3].Event.KeyEvent.wVirtualKeyCode = VK_RETURN; b[3].Event.KeyEvent.wVirtualScanCode = 0x1c; b[3].Event.KeyEvent.wRepeatCount = 1; DWORD numb; WriteConsoleInput(hStdIn, b, 4, &numb); cliThread->wait(); #else cliThread->destroy(); #endif delete cliThread; } // for some unknown reason, unloading scripts here and not in worldrunnable // fixes a memory leak related to detaching threads from the module //UnloadScriptingModule(); OpenSSLCrypto::threadsCleanup(); // Exit the process with specified return value return World::GetExitCode(); }
// Main function int Master::Run() { sLog.outString("%s [core-daemon]", _FULLVERSION); sLog.outString("<Ctrl-C> to stop."); sLog.outString(" "); sLog.outString(" BBBBBB BBB "); sLog.outString(" BBBB:..:::BB BBBBBBBBB "); sLog.outString(" B:::::BBB:::B BB:....:::B "); sLog.outString(" BB:::B BB::B B:::BBBB:::B "); sLog.outString(" B:::B BB:.B B:::B BB.:B "); sLog.outString(" B:::BBB::BBB BB::B BB.B "); sLog.outString(" B.:..BBB....BBB.:.B "); sLog.outString(" B...BB BB..:BB...B "); sLog.outString(" B...B B..:BB...B "); sLog.outString(" B...B B..BBB...B "); sLog.outString(" B...B BB.BBBB...B "); sLog.outString(" B...B BB:.BB B...BB "); sLog.outString(" B: . B. :BB B . B BBB "); sLog.outString(" B: ..:BBBB B: .B BB .B "); sLog.outString(" BBBBB B. :B B.: B "); sLog.outString(" B. :BB BB:BB"); sLog.outString(" BlizzLikeCore 2012(c) BB BBBBBBB B "); sLog.outString(" <blizzlike.servegame.com> BBB. .BB "); sLog.outString(" BBBBBBBB "); sLog.outString(" "); // worldd PID file creation std::string pidfile = sConfig.GetStringDefault("PidFile", ""); if (!pidfile.empty()) { uint32 pid = CreatePIDFile(pidfile); if (!pid) { sLog.outError("Cannot create PID file %s.\n", pidfile.c_str()); return 1; } sLog.outString("Daemon PID: %u\n", pid); } // Start the databases if (!_StartDB()) return 1; // Initialize the World sWorld.SetInitialWorldSettings(); // Catch termination signals _HookSignals(); // Launch WorldRunnable thread ACE_Based::Thread world_thread(new WorldRunnable); world_thread.setPriority(ACE_Based::Highest); // set realmbuilds depend on BlizzLikeCore expected builds, and set server online std::string builds = AcceptableClientBuildsListStr(); LoginDatabase.escape_string(builds); LoginDatabase.PExecute("UPDATE realmlist SET realmflags = realmflags & ~(%u), population = 0, realmbuilds = '%s' WHERE id = '%d'", REALM_FLAG_OFFLINE, builds.c_str(), realmID); ACE_Based::Thread* cliThread = NULL; #ifdef _WIN32 if (sConfig.GetBoolDefault("Console.Enable", true) && (m_ServiceStatus == -1)/* need disable console in service mode*/) #else if (sConfig.GetBoolDefault("Console.Enable", true)) #endif { // Launch CliRunnable thread cliThread = new ACE_Based::Thread(new CliRunnable); } ACE_Based::Thread rar_thread(new RARunnable); // Handle affinity for multiple processors and process priority on Windows #ifdef _WIN32 { HANDLE hProcess = GetCurrentProcess(); uint32 Aff = sConfig.GetIntDefault("UseProcessors", 0); if (Aff > 0) { ULONG_PTR appAff; ULONG_PTR sysAff; if (GetProcessAffinityMask(hProcess,&appAff,&sysAff)) { ULONG_PTR curAff = Aff & appAff; // remove non accessible processors if (!curAff) { sLog.outError("Processors marked in UseProcessors bitmask (hex) %x not accessible for BlizzLikeCore. Accessible processors bitmask (hex): %x",Aff,appAff); } else { if (SetProcessAffinityMask(hProcess,curAff)) sLog.outString("Using processors (bitmask, hex): %x", curAff); else sLog.outError("Can't set used processors (hex): %x",curAff); } } sLog.outString(); } bool Prio = sConfig.GetBoolDefault("ProcessPriority", false); if (Prio) { if (SetPriorityClass(hProcess,HIGH_PRIORITY_CLASS)) sLog.outString("BlizzLikeCore process priority class set to HIGH"); else sLog.outError("ERROR: Can't set BlizzLikeCore process priority class."); sLog.outString(); } } #endif // Start soap serving thread ACE_Based::Thread* soap_thread = NULL; if (sConfig.GetBoolDefault("SOAP.Enabled", false)) { BCSoapRunnable *runnable = new BCSoapRunnable(); runnable->setListenArguments(sConfig.GetStringDefault("SOAP.IP", "127.0.0.1"), sConfig.GetIntDefault("SOAP.Port", 7878)); soap_thread = new ACE_Based::Thread(runnable); } uint32 realCurrTime, realPrevTime; realCurrTime = realPrevTime = getMSTime(); uint32 socketSelecttime = sWorld.getConfig(CONFIG_SOCKET_SELECTTIME); // Start up freeze catcher thread ACE_Based::Thread* freeze_thread = NULL; if (uint32 freeze_delay = sConfig.GetIntDefault("MaxCoreStuckTime", 0)) { FreezeDetectorRunnable *fdr = new FreezeDetectorRunnable(); fdr->SetDelayTime(freeze_delay*1000); freeze_thread = new ACE_Based::Thread(fdr); freeze_thread->setPriority(ACE_Based::Highest); } // Launch the world listener socket uint16 wsport = sWorld.getConfig(CONFIG_PORT_WORLD); std::string bind_ip = sConfig.GetStringDefault ("BindIP", "0.0.0.0"); if (sWorldSocketMgr->StartNetwork (wsport, bind_ip.c_str ()) == -1) { sLog.outError("Failed to start network"); World::StopNow(ERROR_EXIT_CODE); // go down and shutdown the server } sWorldSocketMgr->Wait(); // Stop freeze protection before shutdown tasks if (freeze_thread) { freeze_thread->destroy(); delete freeze_thread; } // Stop soap thread if (soap_thread) { soap_thread->wait(); soap_thread->destroy(); delete soap_thread; } // Set server offline in realmlist LoginDatabase.PExecute("UPDATE realmlist SET realmflags = realmflags | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, realmID); // Remove signal handling before leaving _UnhookSignals(); // when the main thread closes the singletons get unloaded // since worldrunnable uses them, it will crash if unloaded after master world_thread.wait(); rar_thread.wait (); // Clean account database before leaving clearOnlineAccounts(); // Wait for delay threads to end CharacterDatabase.HaltDelayThread(); WorldDatabase.HaltDelayThread(); LoginDatabase.HaltDelayThread(); sLog.outString("Halting process..."); if (cliThread) { #ifdef _WIN32 // this only way to terminate CLI thread exist at Win32 (alt. way exist only in Windows Vista API) //_exit(1); // send keyboard input to safely unblock the CLI thread INPUT_RECORD b[5]; HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE); b[0].EventType = KEY_EVENT; b[0].Event.KeyEvent.bKeyDown = TRUE; b[0].Event.KeyEvent.uChar.AsciiChar = 'X'; b[0].Event.KeyEvent.wVirtualKeyCode = 'X'; b[0].Event.KeyEvent.wRepeatCount = 1; b[1].EventType = KEY_EVENT; b[1].Event.KeyEvent.bKeyDown = FALSE; b[1].Event.KeyEvent.uChar.AsciiChar = 'X'; b[1].Event.KeyEvent.wVirtualKeyCode = 'X'; b[1].Event.KeyEvent.wRepeatCount = 1; b[2].EventType = KEY_EVENT; b[2].Event.KeyEvent.bKeyDown = TRUE; b[2].Event.KeyEvent.dwControlKeyState = 0; b[2].Event.KeyEvent.uChar.AsciiChar = '\r'; b[2].Event.KeyEvent.wVirtualKeyCode = VK_RETURN; b[2].Event.KeyEvent.wRepeatCount = 1; b[2].Event.KeyEvent.wVirtualScanCode = 0x1c; b[3].EventType = KEY_EVENT; b[3].Event.KeyEvent.bKeyDown = FALSE; b[3].Event.KeyEvent.dwControlKeyState = 0; b[3].Event.KeyEvent.uChar.AsciiChar = '\r'; b[3].Event.KeyEvent.wVirtualKeyCode = VK_RETURN; b[3].Event.KeyEvent.wVirtualScanCode = 0x1c; b[3].Event.KeyEvent.wRepeatCount = 1; DWORD numb; WriteConsoleInput(hStdIn, b, 4, &numb); cliThread->wait(); #else cliThread->destroy(); #endif delete cliThread; } // for some unknown reason, unloading scripts here and not in worldrunnable // fixes a memory leak related to detaching threads from the module //UnloadScriptingModule(); // Exit the process with specified return value return World::GetExitCode(); }