1 mike 1.1.2.1 //%/////////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2000, 2001 BMC Software, Hewlett-Packard Company, IBM,
4 // The Open Group, Tivoli Systems
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a copy
7 // of this software and associated documentation files (the "Software"), to
8 // deal in the Software without restriction, including without limitation the
9 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 // sell copies of the Software, and to permit persons to whom the Software is
11 // furnished to do so, subject to the following conditions:
12 //
13 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
14 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
15 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
16 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
17 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
18 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
19 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 //
22 mike 1.1.2.1 //==============================================================================
23 //
24 // Author: Mike Brasher (mbrasher@bmc.com)
25 //
26 // Modified By:
27 //
28 //%/////////////////////////////////////////////////////////////////////////////
29
30 #include <iostream>
31 #include "Config.h"
32 #include "Socket.h"
33
34 #ifdef PEGASUS_OS_TYPE_WINDOWS
35 # include <winsock.h>
36 #else
37 # include <cctype>
38 # include <unistd.h>
39 # include <cstdlib>
40 # include <errno.h>
41 # include <fcntl.h>
42 # include <netdb.h>
43 mike 1.1.2.1 # include <netinet/in.h>
44 # include <arpa/inet.h>
45 # include <sys/socket.h>
46 #endif
47
48 #include "Socket.h"
49 #include "HTTPAcceptor.h"
50 #include "HTTPConnection.h"
51
52 PEGASUS_USING_STD;
53
54 PEGASUS_NAMESPACE_BEGIN
55
56 ////////////////////////////////////////////////////////////////////////////////
57 //
58 // HTTPAcceptorRep
59 //
60 ////////////////////////////////////////////////////////////////////////////////
61
62 struct HTTPAcceptorRep
63 {
64 mike 1.1.2.1 struct sockaddr_in address;
65 Sint32 socket;
66 Array<HTTPConnection*> connections;
67 };
68
69 ////////////////////////////////////////////////////////////////////////////////
70 //
71 // HTTPAcceptor
72 //
73 ////////////////////////////////////////////////////////////////////////////////
74
75 HTTPAcceptor::HTTPAcceptor(Monitor* monitor) : _monitor(monitor), _rep(0)
76 {
77 // Note: we are counting on the monitor to initialize the socket
78 // interface (in Windows you have to call WSAInitialize() and
79 // WSAShutDown()).
80 }
81
82 HTTPAcceptor::~HTTPAcceptor()
83 {
84 unbind();
85 mike 1.1.2.1 }
86
87 void HTTPAcceptor::handleEnqueue()
88 {
89 cout << "HTTPAcceptor::handleEnqueue()" << endl;
90
91 Message* message = dequeue();
92
93 if (!message)
94 return;
95
96 if (getenv("PEGASUS_TRACE"))
97 message->print(cout);
98
99 switch (message->getType())
100 {
101 case SOCKET_MESSAGE:
102 {
103 SocketMessage* socketMessage = (SocketMessage*)message;
104
105 // If this is a connection request:
106 mike 1.1.2.1
107 if (socketMessage->socket == _rep->socket &&
108 socketMessage->events | SocketMessage::READ)
109 {
110 _acceptConnection();
111 }
112 else
113 {
114 // ATTN! this can't happen!
115 }
116
117 break;
118 }
119
120 case CLOSE_CONNECTION_MESSAGE:
121 {
122 CloseConnectionMessage* closeConnectionMessage
123 = (CloseConnectionMessage*)message;
124
125 for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
126 {
127 mike 1.1.2.1 HTTPConnection* connection = _rep->connections[i];
128 Sint32 socket = connection->getSocket();
129
130 if (socket == closeConnectionMessage->socket)
131 {
132 _monitor->unsolicitSocketMessages(socket);
133 _rep->connections.remove(i);
134 delete connection;
135 break;
136 }
137 }
138 }
139
140 default:
141 // ATTN: need unexpected message error!
142 break;
143 };
144
145 delete message;
146 }
147
148 mike 1.1.2.1 void HTTPAcceptor::bind(Uint32 portNumber)
149 {
150 if (_rep)
151 throw BindFailed("HTTPAcceptor already bound");
152
153 _rep = new HTTPAcceptorRep;
154
155 // Create address:
156
157 memset(&_rep->address, 0, sizeof(_rep->address));
158 _rep->address.sin_addr.s_addr = INADDR_ANY;
159 _rep->address.sin_family = AF_INET;
160 _rep->address.sin_port = htons(portNumber);
161
162 // Create socket:
163
164 _rep->socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
165
166 if (_rep->socket < 0)
167 {
168 delete _rep;
169 mike 1.1.2.1 _rep = 0;
170 throw BindFailed("Failed to create socket");
171 }
172
173 // Bind socket to port:
174
175 if (::bind(_rep->socket,
176 (struct sockaddr*)(void*)&_rep->address,
177 sizeof(_rep->address)) < 0)
178 {
179 Socket::close(_rep->socket);
180 delete _rep;
181 _rep = 0;
182 throw BindFailed("Failed to bind socket to port");
183 }
184
185 // Set up listening on the given port:
186
187 int const MAX_CONNECTION_QUEUE_LENGTH = 5;
188
189 if (listen(_rep->socket, MAX_CONNECTION_QUEUE_LENGTH) < 0)
190 mike 1.1.2.1 {
191 Socket::close(_rep->socket);
192 delete _rep;
193 _rep = 0;
194 throw BindFailed("Failed to bind socket to port");
195 }
196
197 // Register to receive SocketMessages on this socket:
198
199 if (!_monitor->solicitSocketMessages(
200 _rep->socket,
201 SocketMessage::READ | SocketMessage::EXCEPTION,
202 getQueueId()))
203 {
204 Socket::close(_rep->socket);
205 delete _rep;
206 _rep = 0;
207 throw BindFailed("Failed to solicit socket messaeges");
208 }
209 }
210
211 mike 1.1.2.1 void HTTPAcceptor::unbind()
212 {
213 if (_rep)
214 {
215 Socket::close(_rep->socket);
216 delete _rep;
217 _rep = 0;
218 }
219 }
220
221 void HTTPAcceptor::destroyConnections()
222 {
223 // For each connection created by this object:
224
225 for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
226 {
227 HTTPConnection* connection = _rep->connections[i];
228 Sint32 socket = connection->getSocket();
229
230 // Unsolicit SocketMessages:
231
232 mike 1.1.2.1 _monitor->unsolicitSocketMessages(socket);
233
234 // Destroy the connection (causing it to close):
235
236 delete connection;
237 }
238
239 _rep->connections.clear();
240 }
241
242 void HTTPAcceptor::_acceptConnection()
243 {
244 // This function cannot be called on an invalid socket!
245
246 PEGASUS_ASSERT(_rep != 0);
247
248 if (!_rep)
249 return;
250
251 // Accept the connection (populate the address):
252
253 mike 1.1.2.1 sockaddr_in address;
254 int n = sizeof(address);
255 Sint32 socket = accept(_rep->socket, (struct sockaddr*)&address, &n);
256
257 if (socket < 0)
258 {
259 if (getenv("PEGASUS_TRACE"))
260 cerr <<"HTTPAcceptor: accept() failed" << endl;
261
262 return;
263 }
264
265 // Create a new conection and add it to the connection list:
266
267 HTTPConnection* connection = new HTTPConnection(socket, this);
268
269 // Solicit events on this new connection socket:
270
271 if (!_monitor->solicitSocketMessages(
272 socket,
273 SocketMessage::READ | SocketMessage::EXCEPTION,
274 mike 1.1.2.1 connection->getQueueId()))
275 {
276 delete connection;
277 Socket::close(socket);
278 }
279
280 // Save the socket for cleanup later:
281
282 _rep->connections.append(connection);
283 }
284
285 PEGASUS_NAMESPACE_END
|