reactos/modules/rosapps/applications/net/roshttpd/common/socket.cpp

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."));
}