mirror of
https://github.com/reactos/reactos.git
synced 2024-11-01 12:26:32 +00:00
345 lines
7.8 KiB
C++
345 lines
7.8 KiB
C++
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS HTTP Daemon
|
|
* FILE: socket.cpp
|
|
* PURPOSE: Socket classes
|
|
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
|
|
* REVISIONS:
|
|
* CSH 01/09/2000 Created
|
|
*/
|
|
#include <socket.h>
|
|
#include <string.h>
|
|
#include <error.h>
|
|
#include <iterator.h>
|
|
|
|
// ***************************** CSocket *****************************
|
|
|
|
// Default constructor
|
|
CSocket::CSocket()
|
|
{
|
|
Active = FALSE;
|
|
Event = WSA_INVALID_EVENT;
|
|
Events = 0;
|
|
Socket = INVALID_SOCKET;
|
|
|
|
// INET address family
|
|
SockAddrIn.sin_family = AF_INET;
|
|
|
|
// Any address will do
|
|
SockAddrIn.sin_addr.s_addr = INADDR_ANY;
|
|
|
|
// Convert to network ordering
|
|
SockAddrIn.sin_port = htons(0);
|
|
}
|
|
|
|
// Default destructor
|
|
CSocket::~CSocket()
|
|
{
|
|
}
|
|
|
|
// Return winsock socket handle
|
|
SOCKET CSocket::GetSocket()
|
|
{
|
|
return Socket;
|
|
}
|
|
|
|
// Set winsock socket handle
|
|
VOID CSocket::SetSocket(SOCKET socket)
|
|
{
|
|
Socket = socket;
|
|
}
|
|
|
|
|
|
// Return socket address
|
|
SOCKADDR_IN CSocket::GetSockAddrIn()
|
|
{
|
|
return SockAddrIn;
|
|
}
|
|
|
|
// Set socket address
|
|
VOID CSocket::SetSockAddrIn(SOCKADDR_IN sockaddrin)
|
|
{
|
|
SockAddrIn = sockaddrin;
|
|
}
|
|
|
|
// Associate winsock events with socket
|
|
VOID CSocket::SetEvents(LONG lEvents)
|
|
{
|
|
if (Event == WSA_INVALID_EVENT) {
|
|
// Create socket event
|
|
Event = WSACreateEvent();
|
|
if (Event == WSA_INVALID_EVENT)
|
|
throw ESocketOpen(TS("Unable to create event."));
|
|
}
|
|
|
|
if (lEvents != Events) {
|
|
// Associate network events with socket
|
|
if (WSAEventSelect(Socket, Event, lEvents) == SOCKET_ERROR)
|
|
throw ESocketOpen(TS("Unable to select socket events."));
|
|
Events = lEvents;
|
|
}
|
|
}
|
|
|
|
// Return associated winsock events
|
|
LONG CSocket::GetEvents()
|
|
{
|
|
return Events;
|
|
}
|
|
|
|
// Open socket
|
|
VOID CSocket::Open()
|
|
{
|
|
}
|
|
|
|
// Close socket
|
|
VOID CSocket::Close()
|
|
{
|
|
}
|
|
|
|
|
|
// *********************** CServerClientSocket ***********************
|
|
|
|
// Constructor with serversocket as parameter
|
|
CServerClientSocket::CServerClientSocket(LPCServerSocket lpServerSocket)
|
|
{
|
|
ServerSocket = lpServerSocket;
|
|
}
|
|
|
|
// Transmit data to socket
|
|
INT CServerClientSocket::Transmit( LPCSTR lpsBuffer, UINT nLength)
|
|
{
|
|
return send(Socket, lpsBuffer, nLength, 0);
|
|
}
|
|
|
|
// Send a string to socket
|
|
INT CServerClientSocket::SendText( LPCSTR lpsText)
|
|
{
|
|
static CHAR crlf[3] = {0x0D, 0x0A, 0x00};
|
|
INT nCount;
|
|
|
|
nCount = Transmit(lpsText, strlen(lpsText));
|
|
nCount += Transmit(crlf, strlen(crlf));
|
|
return nCount;
|
|
}
|
|
|
|
// Receive data from socket
|
|
INT CServerClientSocket::Receive(LPSTR lpsBuffer, UINT nLength)
|
|
{
|
|
return recv(Socket, lpsBuffer, nLength, 0);
|
|
}
|
|
|
|
// Process winsock messages if any
|
|
VOID CServerClientSocket::MessageLoop()
|
|
{
|
|
UINT nStatus;
|
|
WSANETWORKEVENTS NetworkEvents;
|
|
|
|
nStatus = WSAWaitForMultipleEvents(1, &Event, FALSE, 0, FALSE);
|
|
if ((nStatus == 0) && (WSAEnumNetworkEvents(Socket, Event, &NetworkEvents) != SOCKET_ERROR)) {
|
|
if ((NetworkEvents.lNetworkEvents & FD_READ) != 0) {
|
|
OnRead();
|
|
}
|
|
if ((NetworkEvents.lNetworkEvents & FD_CLOSE) != 0) {
|
|
OnClose();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Return server socket that own this socket
|
|
LPCServerSocket CServerClientSocket::GetServerSocket()
|
|
{
|
|
return ServerSocket;
|
|
}
|
|
|
|
|
|
// *********************** CServerClientThread ***********************
|
|
|
|
CServerClientThread::CServerClientThread(LPCServerClientSocket lpSocket)
|
|
{
|
|
ClientSocket = lpSocket;
|
|
}
|
|
|
|
CServerClientThread::~CServerClientThread()
|
|
{
|
|
ClientSocket->GetServerSocket()->RemoveClient((LPCServerClientThread) this);
|
|
}
|
|
|
|
|
|
// ************************** CServerSocket **************************
|
|
|
|
// Default constructor
|
|
CServerSocket::CServerSocket()
|
|
{
|
|
}
|
|
|
|
// Default destructor
|
|
CServerSocket::~CServerSocket()
|
|
{
|
|
if (Active)
|
|
Close();
|
|
}
|
|
|
|
// Open server socket so clients can connect
|
|
VOID CServerSocket::Open()
|
|
{
|
|
assert(!Active);
|
|
|
|
// Convert to network ordering
|
|
SockAddrIn.sin_port = htons(Port);
|
|
|
|
if (Socket == INVALID_SOCKET) {
|
|
// Create socket
|
|
Socket = socket(AF_INET, SOCK_STREAM, 0);
|
|
if (Socket == INVALID_SOCKET)
|
|
throw ESocketOpen(TS("Unable to allocate a socket."));
|
|
}
|
|
|
|
// Associate an address with server socket
|
|
if (bind(Socket, (struct sockaddr FAR *) &SockAddrIn, sizeof(SockAddrIn)) == SOCKET_ERROR)
|
|
throw ESocketOpen(TS("Unable to associate address with socket."));
|
|
|
|
// Listen for incoming connections
|
|
if (listen(Socket, MAX_PENDING_CONNECTS) != 0)
|
|
throw ESocketOpen(TS("Unable to listen on socket."));
|
|
|
|
// Associate network events with socket
|
|
SetEvents(FD_ACCEPT | FD_CONNECT | FD_CLOSE);
|
|
|
|
Active = TRUE;
|
|
}
|
|
|
|
// Close server socket and all current connections
|
|
VOID CServerSocket::Close()
|
|
{
|
|
assert(Active);
|
|
|
|
if (Event != WSA_INVALID_EVENT) {
|
|
// Tell winsock not to notify us about any events
|
|
if (WSAEventSelect(Socket, Event, 0) == SOCKET_ERROR)
|
|
throw ESocketClose(TS("Unable to select socket events."));
|
|
|
|
if (!WSACloseEvent(Event))
|
|
throw ESocketClose(TS("Unable to close socket event."));
|
|
Event = WSA_INVALID_EVENT;
|
|
}
|
|
|
|
CIterator<LPCServerClientThread> *i = Connections.CreateIterator();
|
|
|
|
// Terminate and free all client threads
|
|
for (i->First(); !i->IsDone(); i->Next()) {
|
|
//i->CurrentItem()->Terminate();
|
|
delete i->CurrentItem();
|
|
}
|
|
delete i;
|
|
Connections.RemoveAll();
|
|
|
|
closesocket(Socket);
|
|
Socket = INVALID_SOCKET;
|
|
|
|
Active = FALSE;
|
|
}
|
|
|
|
// Set port number to listen on
|
|
VOID CServerSocket::SetPort(UINT nPort)
|
|
{
|
|
assert(!Active);
|
|
|
|
Port = nPort;
|
|
}
|
|
|
|
// Process messages from winsock if any
|
|
VOID CServerSocket::MessageLoop()
|
|
{
|
|
UINT nStatus;
|
|
INT nAddrLen;
|
|
SOCKET ClientSocket;
|
|
SOCKADDR_IN SockAddrIn;
|
|
WSANETWORKEVENTS NetworkEvents;
|
|
LPCServerClientSocket lpClient;
|
|
LPCServerClientThread lpThread;
|
|
|
|
nStatus = WSAWaitForMultipleEvents(1, &Event, FALSE, 0, FALSE);
|
|
if ((nStatus == 0) && (WSAEnumNetworkEvents(Socket, Event, &NetworkEvents) != SOCKET_ERROR)) {
|
|
if ((NetworkEvents.lNetworkEvents & FD_ACCEPT) != 0) {
|
|
lpClient = OnGetSocket(this);
|
|
nAddrLen = sizeof(SockAddrIn);
|
|
ClientSocket = accept(Socket, (SOCKADDR *) &SockAddrIn, &nAddrLen);
|
|
if (ClientSocket != INVALID_SOCKET) {
|
|
// Set socket handle
|
|
lpClient->SetSocket(ClientSocket);
|
|
// Set socket address
|
|
lpClient->SetSockAddrIn(SockAddrIn);
|
|
// Set winsock events
|
|
lpClient->SetEvents(FD_READ | FD_CLOSE);
|
|
// Create client connection thread
|
|
lpThread = OnGetThread(lpClient);
|
|
// Add client thread to connection list
|
|
InsertClient(lpThread);
|
|
// Call OnAccept event handler
|
|
OnAccept(lpThread);
|
|
} else {
|
|
delete lpClient;
|
|
lpClient = NULL;
|
|
throw ESocketOpen(TS("No more sockets available."));
|
|
}
|
|
}
|
|
/*if ((NetworkEvents.lNetworkEvents & FD_CONNECT) != 0) {
|
|
}
|
|
if ((NetworkEvents.lNetworkEvents & FD_CLOSE) != 0) {
|
|
}*/
|
|
}
|
|
}
|
|
|
|
// Insert client into connection list
|
|
VOID CServerSocket::InsertClient(LPCServerClientThread lpClient)
|
|
{
|
|
Connections.Insert(lpClient);
|
|
}
|
|
|
|
// Remove client from connection list
|
|
VOID CServerSocket::RemoveClient(LPCServerClientThread lpClient)
|
|
{
|
|
Connections.Remove(lpClient);
|
|
}
|
|
|
|
// OnGetSocket event handler
|
|
LPCServerClientSocket CServerSocket::OnGetSocket(LPCServerSocket lpServerSocket)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
// OnGetThread event handler
|
|
LPCServerClientThread CServerSocket::OnGetThread(LPCServerClientSocket lpSocket)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
|
|
// Initialize WinSock DLL
|
|
VOID InitWinsock()
|
|
{
|
|
WORD wVersionRequested;
|
|
WSADATA wsaData;
|
|
|
|
wVersionRequested = MAKEWORD(2, 0);
|
|
|
|
if (WSAStartup(wVersionRequested, &wsaData) != 0)
|
|
// Return FALSE as we couldn't find a usable WinSock DLL
|
|
throw ESocketWinsock(TS("Unable to initialize winsock dll."));
|
|
|
|
/* Confirm that the WinSock DLL supports 2.0 */
|
|
|
|
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 0) {
|
|
// We couldn't find a usable winsock dll
|
|
WSACleanup();
|
|
throw ESocketDll(TS("Winsock dll version is not 2.0 or higher."));
|
|
}
|
|
}
|
|
|
|
// Deinitialize WinSock DLL
|
|
VOID DeinitWinsock()
|
|
{
|
|
if (WSACleanup() != 0)
|
|
throw ESocketWinsock(TS("Unable to deinitialize winsock dll."));
|
|
}
|