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