/* *(C) 2006 Roku LLC * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License Version 2 as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * without any warranty; without even the implied warranty of * merchantability or fitness for a particular purpose. See the GNU General * Public License for more details. * * Please read README.txt in the same directory as this source file for * further license information. */ #include "stdafx.h" #include "ServerEvents.h" ServerEvents::ServerEvents(Observer *obs) : m_thread(INVALID_HANDLE_VALUE), m_mailslot(INVALID_HANDLE_VALUE), m_obs(obs) { } ServerEvents::~ServerEvents() { ATLASSERT(m_mailslot == INVALID_HANDLE_VALUE); ATLASSERT(m_thread == INVALID_HANDLE_VALUE); } bool ServerEvents::Start() { ATLASSERT(m_mailslot == INVALID_HANDLE_VALUE); ATLASSERT(m_thread == INVALID_HANDLE_VALUE); ATLASSERT(m_obs != NULL); m_mailslot = ::CreateMailslot(_T("\\\\.\\mailslot\\FireflyMediaServer--67A72768-4154-417e-BFA0-FA9B50C342DE"), 0, MAILSLOT_WAIT_FOREVER, NULL); if (m_mailslot != INVALID_HANDLE_VALUE) { //m_thread = ::CreateThread(NULL, 0, &StaticThreadProc, this, 0, &thread_id); m_thread = (HANDLE)_beginthreadex(NULL, 0, &StaticThreadProc, this, 0, NULL); if (m_thread == NULL) { // Failed ATLTRACE("beginthreadex failed: %d\n", errno); ::CloseHandle(m_mailslot); m_mailslot = INVALID_HANDLE_VALUE; return false; } } else { return false; } return true; } void ServerEvents::Stop() { ATLASSERT(m_mailslot != INVALID_HANDLE_VALUE); ATLASSERT(m_thread != INVALID_HANDLE_VALUE); // Force the thread to give up. This could be done with a separate event // and overlapped IO but this is cheap. CloseHandle(m_mailslot); m_mailslot = INVALID_HANDLE_VALUE; // Wait for it to finish. WaitForSingleObject(m_thread, INFINITE); CloseHandle(m_thread); m_thread = INVALID_HANDLE_VALUE; } //DWORD ServerEvents::StaticThreadProc(LPVOID param) unsigned ServerEvents::StaticThreadProc(void *param) { return reinterpret_cast(param)->ThreadProc(); } DWORD ServerEvents::ThreadProc() { const size_t BUFFER_SIZE = 65536; void *buffer = operator new(BUFFER_SIZE); bool finished = false; while (!finished) { DWORD bytes_read; if (ReadFile(m_mailslot, buffer, BUFFER_SIZE, &bytes_read, NULL)) { TCHAR *b = (TCHAR *)buffer; b[bytes_read/sizeof(TCHAR)] = 0; ATLTRACE("%ls\n", b); OnEvent(buffer, bytes_read); } else { ATLTRACE("Read failed: error %d\n", GetLastError()); finished = true; } } return 0; } void ServerEvents::OnEvent(const void *buffer, size_t bytes_received) { const BYTE *received = reinterpret_cast(buffer); if (bytes_received >= 12) { UINT32 packet_size = received[0] | (received[1] << 8) | (received[2] << 16) | (received[3] << 24); UINT32 id = received[4] | (received[5] << 8) | (received[6] << 16) | (received[7] << 24); UINT32 intval = received[8] | (received[9] << 8) | (received[10] << 16) | (received[11] << 24); int string_length = static_cast(bytes_received) - 12; if ((packet_size < bytes_received) && (packet_size >= 12)) string_length = packet_size - 12; CString str; if (string_length > 0) { #ifdef UNICODE // It might be less that string_length long after conversion but it shouldn't be more unless // our codepage is extremely weird. str.ReleaseBuffer(MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, reinterpret_cast(received + 12), string_length, str.GetBufferSetLength(string_length), string_length)); #else SafeStringCopy(str.GetBufferSetLength(string_length), received + 12, string_length); #endif str.ReleaseBuffer(string_length); } m_obs->OnServerEvent(id, intval, str); } }