blob: 1f0415915b09de08707ff52200ccebe888b54d4d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
#include "stdafx.h"
#include "WindowsSocketConnection.h"
/* initialize statics */
std::map<HWND, WindowsSocketConnection*>* WindowsSocketConnection::s_connections = new std::map<HWND, WindowsSocketConnection*>; /* leaked */
WindowsSocketConnection::WindowsSocketConnection(CrossfireServer* server) {
m_clientSocket = INVALID_SOCKET;
m_server = server;
m_hWnd = NULL;
m_listenSocket = INVALID_SOCKET;
}
WindowsSocketConnection::~WindowsSocketConnection() {
}
bool WindowsSocketConnection::acceptConnection() {
int rc = WSAAsyncSelect(m_listenSocket, m_hWnd, EW_SOCKET_MSG, FD_ACCEPT);
if (rc != 0) {
Logger::error("WindowsSocketConnection.acceptConnection(): WSAAsyncSelect() failed", rc);
return false;
}
return true;
}
bool WindowsSocketConnection::close() {
deregisterConnection(m_hWnd);
closesocket(m_clientSocket);
closesocket(m_listenSocket);
m_clientSocket = m_listenSocket = INVALID_SOCKET;
return true;
}
void WindowsSocketConnection::handleSocketAccept() {
m_clientSocket = accept(m_listenSocket, NULL, NULL);
if (m_clientSocket == INVALID_SOCKET) {
Logger::error("WindowsSocketConnection.handleSocketAccept(): accept() failed", WSAGetLastError());
return;
}
int rc = WSAAsyncSelect(m_clientSocket, m_hWnd, EW_SOCKET_MSG, FD_READ | FD_CLOSE);
if (rc == SOCKET_ERROR) {
closesocket(m_clientSocket);
m_clientSocket = INVALID_SOCKET;
Logger::error("WindowsSocketConnection.handleSocketAccept(): WSAAsyncSelect() failed", WSAGetLastError());
return;
}
/* remove the listenSocket listener */
WSAAsyncSelect(m_listenSocket, m_hWnd, EW_SOCKET_MSG, 0);
}
void WindowsSocketConnection::handleSocketClose() {
m_server->disconnected();
}
void WindowsSocketConnection::handleSocketRead() {
const int LENGTH_BUFFER = 4096;
char buffer[LENGTH_BUFFER];
ZeroMemory(buffer, LENGTH_BUFFER);
int length = recv(m_clientSocket, buffer, LENGTH_BUFFER, 0);
if (length == SOCKET_ERROR) {
Logger::error("WindowsSocketConnection.handleSocketRead(): recv() failed", errno);
return;
}
if (length == 0) {
/* connection closed */
Logger::log("WindowsSocketConnection.handleSocketRead(): recv() length 0, implies socket closed");
PostQuitMessage(0);
return;
}
length = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)buffer, -1, NULL, 0);
wchar_t* content = new wchar_t[length];
MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)buffer, -1, content, length);
//Logger::log("-----\nReceived:");
//Logger::log(content);
m_server->received(content);
delete[] content;
}
bool WindowsSocketConnection::init(unsigned int port) {
WSADATA wsaData;
int rc = WSAStartup(MAKEWORD(2,2), &wsaData);
if (rc != 0) {
Logger::error("WindowsSocketConnection.init(): WSAStartup() failed", rc);
return false;
}
char portString[6];
ZeroMemory(portString, 6);
_ltoa_s(port, portString, 6, 10);
struct addrinfo hints;
ZeroMemory(&hints, sizeof(hints));
hints.ai_flags = AI_PASSIVE;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
struct addrinfo* result = NULL;
rc = getaddrinfo(NULL, portString, &hints, &result);
if (rc != 0) {
WSACleanup();
Logger::error("WindowsSocketConnection.init(): getaddrinfo() failed", rc);
return false;
}
m_listenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (m_listenSocket == INVALID_SOCKET) {
freeaddrinfo(result);
WSACleanup();
Logger::error("WindowsSocketConnection.init(): socket() failed", WSAGetLastError());
return false;
}
if (bind(m_listenSocket, result->ai_addr, (int)result->ai_addrlen) == SOCKET_ERROR) {
closesocket(m_listenSocket);
m_listenSocket = INVALID_SOCKET;
freeaddrinfo(result);
WSACleanup();
Logger::error("WindowsSocketConnection.init(): bind() failed", WSAGetLastError());
return false;
}
rc = listen(m_listenSocket, SOMAXCONN);
freeaddrinfo(result);
if (rc == SOCKET_ERROR) {
closesocket(m_listenSocket);
m_listenSocket = INVALID_SOCKET;
WSACleanup();
Logger::error("WindowsSocketConnection.init(): listen() failed", WSAGetLastError());
return false;
}
std::wstringstream stream;
stream << "Listening for a connection on localhost:";
stream << portString;
Logger::log((wchar_t*)stream.str().c_str());
static LPCWSTR s_windowClass = _T("CrossfireSocketConnection"); // TODO differentiate by port?
HINSTANCE module = GetModuleHandle(NULL);
WNDCLASS ex;
ex.style = 0;
ex.lpfnWndProc = WndProc;
ex.cbClsExtra = 0;
ex.cbWndExtra = 0;
ex.hInstance = module;
ex.hIcon = NULL;
ex.hCursor = NULL;
ex.hbrBackground = NULL;
ex.lpszMenuName = NULL;
ex.lpszClassName = s_windowClass;
RegisterClass(&ex);
m_hWnd = CreateWindow(s_windowClass, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, module, NULL);
if (!m_hWnd) {
Logger::error("WindowsSocketConnection.init(): CreateWindow() failed", GetLastError());
return false;
}
WindowsSocketConnection::registerConnection(m_hWnd, this);
return true;
}
bool WindowsSocketConnection::send(const wchar_t* msg) {
//Logger::log("-----\nSent:");
//Logger::log((wchar_t*)msg);
int length = WideCharToMultiByte(CP_UTF8, 0, msg, -1, NULL, 0, NULL, NULL);
char* content = new char[length];
WideCharToMultiByte(CP_UTF8, 0, msg, -1, content, length, NULL, NULL);
if (::send(m_clientSocket, content, length - 1, 0) == SOCKET_ERROR) { /* uses length - 1 to not send null terminator */
Logger::error("WindowsSocketConnection.send(): send() failed", errno);
return false;
}
return true;
}
bool WindowsSocketConnection::deregisterConnection(HWND hWnd) {
std::map<HWND, WindowsSocketConnection*>::iterator iterator = s_connections->find(hWnd);
if (iterator != s_connections->end()) {
s_connections->erase(iterator);
return true;
}
/* not found */
return false;
}
WindowsSocketConnection* WindowsSocketConnection::getConnection(HWND hWnd) {
std::map<HWND, WindowsSocketConnection*>::iterator iterator = s_connections->find(hWnd);
if (iterator == s_connections->end()) {
/* not found */
return NULL;
}
return iterator->second;
}
void WindowsSocketConnection::registerConnection(HWND hWnd, WindowsSocketConnection* connection) {
s_connections->insert(std::pair<HWND,WindowsSocketConnection*>(hWnd, connection));
}
LRESULT CALLBACK WindowsSocketConnection::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case EW_SOCKET_MSG: {
WindowsSocketConnection* instance = WindowsSocketConnection::getConnection(hWnd);
if (!instance) {
Logger::error("WindowsSocketConnection:WndProc(): received EW_SOCKET_MSG for unregistered hWnd");
break;
}
switch (WSAGETSELECTEVENT(lParam)) {
case FD_READ: {
instance->handleSocketRead();
break;
}
case FD_ACCEPT: {
instance->handleSocketAccept();
break;
}
case FD_CLOSE: {
instance->handleSocketClose();
break;
}
default: {
Logger::error("WindowsSocketConnection:WndProc(): received EW_SOCKET_MSG for unexpected event");
break;
}
}
break;
}
default: {
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
return 0;
}