:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / apps / utils / net / roshttpd / common / socket.cpp
1 /*
2  * COPYRIGHT:   See COPYING in the top level directory
3  * PROJECT:     ReactOS HTTP Daemon
4  * FILE:        socket.cpp
5  * PURPOSE:     Socket classes
6  * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7  * REVISIONS:
8  *   CSH  01/09/2000 Created
9  */
10 #include <error.h>
11 #include <socket.h>
12 #include <iterator.h>
13
14 // ***************************** CSocket *****************************
15
16 // Default constructor
17 CSocket::CSocket()
18 {
19     Active = FALSE;
20         Event  = WSA_INVALID_EVENT;
21         Events = 0;
22         Socket = INVALID_SOCKET;
23
24         // INET address family
25         SockAddrIn.sin_family = AF_INET;
26
27     // Any address will do
28     SockAddrIn.sin_addr.s_addr = INADDR_ANY;
29
30     // Convert to network ordering 
31     SockAddrIn.sin_port = htons(0);
32 }
33
34 // Default destructor
35 CSocket::~CSocket()
36 {
37 }
38
39 // Return winsock socket handle
40 SOCKET CSocket::GetSocket()
41 {
42         return Socket;
43 }
44
45 // Set winsock socket handle
46 VOID CSocket::SetSocket(SOCKET socket)
47 {
48         Socket = socket;
49 }
50         
51
52 // Return socket address
53 SOCKADDR_IN CSocket::GetSockAddrIn()
54 {
55         return SockAddrIn;
56 }
57
58 // Set socket address
59 VOID CSocket::SetSockAddrIn(SOCKADDR_IN sockaddrin)
60 {
61         SockAddrIn = sockaddrin;
62 }
63
64 // Associate winsock events with socket
65 VOID CSocket::SetEvents(LONG lEvents)
66 {
67         if (Event == WSA_INVALID_EVENT) {
68                 // Create socket event
69                 Event = WSACreateEvent();
70                 if (Event == WSA_INVALID_EVENT)
71                         throw ESocketOpen(TS("Unable to create event."));
72         }
73         
74         if (lEvents != Events) {
75                 // Associate network events with socket
76                 if (WSAEventSelect(Socket, Event, lEvents) == SOCKET_ERROR)
77                         throw ESocketOpen(TS("Unable to select socket events."));
78                 Events = lEvents;
79         }
80 }
81
82 // Return associated winsock events
83 LONG CSocket::GetEvents()
84 {
85         return Events;
86 }
87
88 // Open socket
89 VOID CSocket::Open()
90 {
91 }
92
93 // Close socket
94 VOID CSocket::Close()
95 {
96 }
97
98
99 // *********************** CServerClientSocket ***********************
100
101 // Constructor with serversocket as parameter
102 CServerClientSocket::CServerClientSocket(LPCServerSocket lpServerSocket)
103 {
104         ServerSocket = lpServerSocket;
105 }
106
107 // Transmit data to socket
108 INT CServerClientSocket::Transmit( LPSTR lpsBuffer, UINT nLength)
109 {
110     return send(Socket, lpsBuffer, nLength, 0);
111 }
112
113 // Send a string to socket
114 INT CServerClientSocket::SendText( LPSTR lpsText)
115 {
116     static CHAR crlf[3] = {0x0D, 0x0A, 0x00};
117         INT nCount;
118
119     nCount = Transmit(lpsText, strlen(lpsText));
120         nCount += Transmit(crlf, strlen(crlf));
121         return nCount;
122 }
123
124 // Receive data from socket
125 INT CServerClientSocket::Receive(LPSTR lpsBuffer, UINT nLength)
126 {
127         return recv(Socket, lpsBuffer, nLength, 0);
128 }
129
130 // Process winsock messages if any
131 VOID CServerClientSocket::MessageLoop()
132 {
133         UINT nStatus;
134     WSANETWORKEVENTS NetworkEvents;
135
136     nStatus = WSAWaitForMultipleEvents(1, &Event, FALSE, 0, FALSE);
137     if ((nStatus == 0) && (WSAEnumNetworkEvents(Socket, Event, &NetworkEvents) != SOCKET_ERROR)) {
138         if ((NetworkEvents.lNetworkEvents & FD_READ) != 0) {
139                         OnRead();
140                 } 
141         if ((NetworkEvents.lNetworkEvents & FD_CLOSE) != 0) {
142                         OnClose();
143         }
144     }
145 }
146
147 // Return server socket that own this socket
148 LPCServerSocket CServerClientSocket::GetServerSocket()
149 {
150         return ServerSocket;
151 }
152
153
154 // *********************** CServerClientThread ***********************
155
156 CServerClientThread::CServerClientThread(LPCServerClientSocket lpSocket)
157 {
158         ClientSocket = lpSocket;
159 }
160
161 CServerClientThread::~CServerClientThread()
162 {
163         ClientSocket->GetServerSocket()->RemoveClient((LPCServerClientThread) this);
164 }
165
166
167 // ************************** CServerSocket **************************  
168
169 // Default constructor
170 CServerSocket::CServerSocket()
171 {
172 }
173
174 // Default destructor
175 CServerSocket::~CServerSocket()
176 {
177         if (Active)
178                 Close();
179 }
180
181 // Open server socket so clients can connect
182 VOID CServerSocket::Open()
183 {
184         assert(!Active);
185         
186         // Convert to network ordering 
187         SockAddrIn.sin_port = htons(Port);
188
189         if (Socket == INVALID_SOCKET) {
190                 // Create socket
191                 Socket = socket(AF_INET, SOCK_STREAM, 0);
192                 if (Socket == INVALID_SOCKET)
193                 throw ESocketOpen(TS("Unable to allocate a socket."));
194         }
195
196         // Associate an address with server socket
197         if (bind(Socket, (struct sockaddr FAR *) &SockAddrIn, sizeof(SockAddrIn)) == SOCKET_ERROR)
198                 throw ESocketOpen(TS("Unable to associate address with socket."));
199
200         // Listen for incoming connections
201         if (listen(Socket, MAX_PENDING_CONNECTS) != 0)
202                 throw ESocketOpen(TS("Unable to listen on socket."));
203
204         // Associate network events with socket
205         SetEvents(FD_ACCEPT | FD_CONNECT | FD_CLOSE);
206
207         Active = TRUE;
208 }
209
210 // Close server socket and all current connections
211 VOID CServerSocket::Close()
212 {
213         assert(Active);
214
215         if (Event != WSA_INVALID_EVENT) {
216                 // Tell winsock not to notify us about any events
217                 if (WSAEventSelect(Socket, Event, 0) == SOCKET_ERROR)
218                         throw ESocketClose(TS("Unable to select socket events."));
219
220                 if (!WSACloseEvent(Event))
221                         throw ESocketClose(TS("Unable to close socket event."));
222                 Event = WSA_INVALID_EVENT;
223         }
224         
225         CIterator<LPCServerClientThread> *i = Connections.CreateIterator();
226
227         // Terminate and free all client threads
228         for (i->First(); !i->IsDone(); i->Next()) {
229                 //i->CurrentItem()->Terminate();
230                 delete i->CurrentItem();
231         }
232         delete i;
233         Connections.RemoveAll();
234
235         closesocket(Socket);
236         Socket = INVALID_SOCKET;
237
238         Active = FALSE;
239 }
240
241 // Set port number to listen on
242 VOID CServerSocket::SetPort(UINT nPort)
243 {
244         assert(!Active);
245
246         Port = nPort;
247 }
248
249 // Process messages from winsock if any
250 VOID CServerSocket::MessageLoop()
251 {
252     UINT nStatus;
253         INT nAddrLen;
254         SOCKET ClientSocket;
255         SOCKADDR_IN SockAddrIn;
256     WSANETWORKEVENTS NetworkEvents;
257         LPCServerClientSocket lpClient;
258         LPCServerClientThread lpThread;
259         
260     nStatus = WSAWaitForMultipleEvents(1, &Event, FALSE, 0, FALSE);
261     if ((nStatus == 0) && (WSAEnumNetworkEvents(Socket, Event, &NetworkEvents) != SOCKET_ERROR)) {
262         if ((NetworkEvents.lNetworkEvents & FD_ACCEPT) != 0) {
263                         lpClient = OnGetSocket(this);
264                         nAddrLen = sizeof(SockAddrIn);
265                         ClientSocket = accept(Socket, (SOCKADDR *) &SockAddrIn, &nAddrLen);
266                         if (ClientSocket != INVALID_SOCKET) {
267                                 // Set socket handle
268                                 lpClient->SetSocket(ClientSocket);
269                                 // Set socket address
270                                 lpClient->SetSockAddrIn(SockAddrIn);
271                                 // Set winsock events
272                                 lpClient->SetEvents(FD_READ | FD_CLOSE);
273                                 // Create client connection thread
274                                 lpThread = OnGetThread(lpClient);
275                                 // Add client thread to connection list
276                                 InsertClient(lpThread);
277                                 // Call OnAccept event handler
278                                 OnAccept(lpThread);
279                         } else {
280                                 delete lpClient;
281                                 lpClient = NULL;
282                                 throw ESocketOpen(TS("No more sockets available."));
283                         }
284                 }
285         /*if ((NetworkEvents.lNetworkEvents & FD_CONNECT) != 0) {
286         }
287         if ((NetworkEvents.lNetworkEvents & FD_CLOSE) != 0) {
288         }*/
289     }
290 }
291
292 // Insert client into connection list
293 VOID CServerSocket::InsertClient(LPCServerClientThread lpClient)
294 {
295         Connections.Insert(lpClient);
296 }
297
298 // Remove client from connection list
299 VOID CServerSocket::RemoveClient(LPCServerClientThread lpClient)
300 {
301         Connections.Remove(lpClient);
302 }
303
304 // OnGetSocket event handler
305 LPCServerClientSocket CServerSocket::OnGetSocket(LPCServerSocket lpServerSocket)
306 {
307         return NULL;
308 }
309
310 // OnGetThread event handler
311 LPCServerClientThread CServerSocket::OnGetThread(LPCServerClientSocket lpSocket)
312 {
313         return NULL;
314 }
315
316
317 // Initialize WinSock DLL
318 VOID InitWinsock()
319 {
320     WORD wVersionRequested;
321     WSADATA wsaData;
322
323     wVersionRequested = MAKEWORD(2, 0);
324  
325     if (WSAStartup(wVersionRequested, &wsaData) != 0)
326         // Return FALSE as we couldn't find a usable WinSock DLL
327                 throw ESocketWinsock(TS("Unable to initialize winsock dll."));
328    
329     /* Confirm that the WinSock DLL supports 2.0 */
330  
331     if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 0) {
332         // We couldn't find a usable winsock dll
333         WSACleanup();
334                 throw ESocketDll(TS("Winsock dll version is not 2.0 or higher."));
335     }
336 }
337
338 // Deinitialize WinSock DLL
339 VOID DeinitWinsock()
340 {
341         if (WSACleanup() != 0)
342                 throw ESocketWinsock(TS("Unable to deinitialize winsock dll."));
343 }