Rev 975 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | SVN | RSS feed
| Rev 975 | Rev 976 | ||
|---|---|---|---|
| Line 18... | Line 18... | ||
| 18 | * Free Software Foundation, Inc., * |
18 | * Free Software Foundation, Inc., * |
| 19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * |
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * |
| 20 | ***************************************************************************/ |
20 | ***************************************************************************/ |
| 21 | 21 | ||
| 22 | #include "asyncsocket.h" |
22 | #include "asyncsocket.h" |
| 23 | #include <iostream> |
- | |
| - | 23 | ||
| 24 | Semaphore AsyncSocket::mySemaphore; |
24 | Semaphore AsyncSocket::mySemaphore; |
| 25 | 25 | ||
| 26 | AsyncSocket::AsyncSocket() |
26 | AsyncSocket::AsyncSocket() |
| 27 | { |
27 | { |
| 28 | mySocket = -1; |
28 | mySocket = -1; |
| 29 | myReconnectTimeout = |
29 | myReconnectTimeout = 0; |
| 30 | myForceReconnect = false; |
30 | myForceReconnect = false; |
| 31 | 31 | ||
| 32 | Thread<AsyncSocket>(); |
32 | Thread<AsyncSocket>(); |
| 33 | } |
33 | } |
| 34 | 34 | ||
| 35 | AsyncSocket::~AsyncSocket() |
35 | AsyncSocket::~AsyncSocket() |
| 36 | { |
36 | { |
| 37 | if (mySocket != -1) |
37 | if (mySocket != -1) |
| 38 | { |
38 | { |
| 39 | ::close(mySocket); |
39 | ::close(mySocket); |
| 40 | mySocket = -1; |
40 | mySocket = -1; |
| 41 | } |
41 | } |
| 42 | 42 | ||
| 43 | stop(); |
43 | stop(); |
| Line 45... | Line 45... | ||
| 45 | 45 | ||
| 46 | void AsyncSocket::run() |
46 | void AsyncSocket::run() |
| 47 | { |
47 | { |
| 48 | SyslogStream &slog = SyslogStream::getInstance(); |
48 | SyslogStream &slog = SyslogStream::getInstance(); |
| 49 | 49 | ||
| - | 50 | if (myReconnectTimeout == 0) |
|
| - | 51 | { |
|
| - | 52 | connect(); |
|
| - | 53 | } |
|
| - | 54 | else |
|
| - | 55 | { |
|
| 50 | reconnectLoop(); |
56 | reconnectLoop(); |
| - | 57 | } |
|
| 51 | 58 | ||
| 52 | char buf[MAXBUFFER + 1]; |
59 | char buf[MAXBUFFER + 1]; |
| 53 | string data; |
60 | string data; |
| 54 | int status; |
61 | int status; |
| 55 | int rc; |
62 | int rc; |
| 56 | int timeSince = time(NULL) + 10; |
63 | int timeSince = time(NULL) + 10; |
| 57 | 64 | ||
| 58 | AsyncSocket::mySemaphore.lock(); |
- | |
| - | 65 | ||
| 59 | 66 | ||
| 60 | try |
67 | try |
| 61 | { |
68 | { |
| 62 | while (1) |
69 | while (1) |
| 63 | { |
70 | { |
| - | 71 | AsyncSocket::mySemaphore.lock(); |
|
| - | 72 | ||
| - | 73 | if (myReconnectTimeout == 0) |
|
| - | 74 | { |
|
| 64 |
|
75 | rc = mySemaphore.wait(); |
| - | 76 | } |
|
| - | 77 | else |
|
| - | 78 | { |
|
| - | 79 | rc = mySemaphore.wait(10); |
|
| - | 80 | } |
|
| - | 81 | ||
| - | 82 | AsyncSocket::mySemaphore.unlock(); |
|
| 65 | 83 | ||
| 66 | if (myForceReconnect) |
84 | if (myForceReconnect) |
| 67 | { |
85 | { |
| 68 | slog << "Disconnected from server.\n"; |
86 | slog << "Disconnected from server.\n"; |
| 69 | reconnectLoop(); |
87 | reconnectLoop(); |
| Line 145... | Line 163... | ||
| 145 | 163 | ||
| 146 | case EPIPE: |
164 | case EPIPE: |
| 147 | throw new SocketException("The local end has been shut down on a connection oriented socket. In this case the process will also receive a SIGPIPE unless MSG_NOSIGNAL is set."); |
165 | throw new SocketException("The local end has been shut down on a connection oriented socket. In this case the process will also receive a SIGPIPE unless MSG_NOSIGNAL is set."); |
| 148 | 166 | ||
| 149 | default: |
167 | default: |
| 150 | slog << "Unknow exception: " |
168 | slog << "Unknow exception: " + itos(errno) + "\n"; |
| 151 | break; |
169 | break; |
| 152 | } |
170 | } |
| 153 | } |
171 | } |
| 154 | } |
172 | } |
| 155 | 173 | ||
| 156 | memset(buf, 0, MAXBUFFER + 1); |
174 | memset(buf, 0, MAXBUFFER + 1); |
| 157 | 175 | ||
| 158 | status = ::recv(mySocket, buf, MAXBUFFER, 0); |
176 | status = ::recv(mySocket, buf, MAXBUFFER, 0); |
| 159 | 177 | ||
| 160 | //slog << "Receiving: " << buf << "\n"; |
- | |
| 161 | - | ||
| 162 | if (status == -1) |
178 | if (status == -1) |
| 163 | { |
179 | { |
| 164 | switch (errno) |
180 | switch (errno) |
| 165 | { |
181 | { |
| 166 | case EAGAIN: |
182 | case EAGAIN: |
| Line 176... | Line 192... | ||
| 176 | case EFAULT: |
192 | case EFAULT: |
| 177 | throw new SocketException("The receive buffer pointer(s) point outside the process's address space."); |
193 | throw new SocketException("The receive buffer pointer(s) point outside the process's address space."); |
| 178 | 194 | ||
| 179 | case EINTR: |
195 | case EINTR: |
| 180 | throw new SocketException("The receive was interrupted by delivery of a signal before any data were available; see signal(7)."); |
196 | throw new SocketException("The receive was interrupted by delivery of a signal before any data were available; see signal(7)."); |
| 181 | 197 | ||
| 182 | case EINVAL: |
198 | case EINVAL: |
| 183 | //throw new SocketException("2Invalid argument passed."); |
199 | //throw new SocketException("2Invalid argument passed."); |
| 184 | slog << "Disconnected from server.\n"; |
200 | slog << "Disconnected from server.\n"; |
| 185 | reconnectLoop(); |
201 | reconnectLoop(); |
| - | 202 | timeSince = time(NULL) + 10; |
|
| 186 | break; |
203 | break; |
| 187 | 204 | ||
| 188 | case ENOMEM: |
205 | case ENOMEM: |
| 189 | throw new SocketException("Could not allocate memory for recvmsg()."); |
206 | throw new SocketException("Could not allocate memory for recvmsg()."); |
| 190 | 207 | ||
| 191 | case ENOTCONN: |
208 | case ENOTCONN: |
| 192 | throw new SocketException("The socket is associated with a connection-oriented protocol and has not been connected (see connect(2) and accept(2))."); |
209 | throw new SocketException("The socket is associated with a connection-oriented protocol and has not been connected (see connect(2) and accept(2))."); |
| 193 | 210 | ||
| 194 | case ENOTSOCK: |
211 | case ENOTSOCK: |
| 195 | throw new SocketException("The argument s does not refer to a socket."); |
212 | throw new SocketException("The argument s does not refer to a socket."); |
| 196 | 213 | ||
| 197 | default: |
214 | default: |
| 198 | slog << "Unknow exception: " |
215 | slog << "Unknow exception: " + itos(errno) + "\n"; |
| 199 | break; |
216 | break; |
| 200 | } |
217 | } |
| 201 | } |
218 | } |
| 202 | else if (status == 0) |
219 | else if (status == 0) |
| 203 | { |
220 | { |
| 204 | slog << "Disconnected from server.\n"; |
221 | slog << "Disconnected from server.\n"; |
| 205 | reconnectLoop(); |
222 | reconnectLoop(); |
| - | 223 | timeSince = time(NULL); |
|
| 206 | } |
224 | } |
| 207 | else if (status > 0) |
225 | else if (status > 0) |
| 208 | { |
226 | { |
| - | 227 | timeSince = time(NULL) + 10; |
|
| - | 228 | ||
| 209 | data = buf; |
229 | data = buf; |
| - | 230 | ||
| - | 231 | //slog << "Receiving: " + data + "\n"; |
|
| 210 | 232 | ||
| 211 | myInQueue.push(data); |
233 | myInQueue.push(data); |
| 212 | 234 | ||
| 213 | setEvent(ASYNCSOCKET_EVENT_DATA); |
235 | setEvent(ASYNCSOCKET_EVENT_DATA); |
| 214 | - | ||
| 215 | timeSince = time(NULL); |
- | |
| 216 | } |
236 | } |
| 217 | 237 | ||
| 218 | if (timeSince + 10 < time(NULL)) |
238 | if (timeSince + 10 < time(NULL)) |
| 219 | { |
239 | { |
| 220 | setEvent(ASYNCSOCKET_EVENT_INACTIVITY); |
240 | setEvent(ASYNCSOCKET_EVENT_INACTIVITY); |
| Line 223... | Line 243... | ||
| 223 | } |
243 | } |
| 224 | } |
244 | } |
| 225 | } |
245 | } |
| 226 | catch (SocketException *e) |
246 | catch (SocketException *e) |
| 227 | { |
247 | { |
| 228 | slog << "Exception: " |
248 | slog << "Exception: " + e->getDescription() + "\n"; |
| 229 | mySemaphore. |
249 | //mySemaphore.unlock(); |
| 230 | setEvent(ASYNCSOCKET_EVENT_DIED); |
250 | setEvent(ASYNCSOCKET_EVENT_DIED); |
| 231 | stop(); |
251 | stop(); |
| 232 | } |
252 | } |
| 233 | 253 | ||
| 234 | close(); |
254 | close(); |
| 235 | 255 | ||
| 236 | mySemaphore. |
256 | //mySemaphore.unlock(); |
| 237 | } |
257 | } |
| 238 | 258 | ||
| 239 | void AsyncSocket::reconnectLoop() |
259 | void AsyncSocket::reconnectLoop() |
| 240 | { |
260 | { |
| - | 261 | if (myReconnectTimeout == 0) |
|
| - | 262 | { |
|
| - | 263 | throw new SocketException("Connection is closed."); |
|
| - | 264 | } |
|
| - | 265 | ||
| 241 | SyslogStream &slog = SyslogStream::getInstance(); |
266 | SyslogStream &slog = SyslogStream::getInstance(); |
| 242 | 267 | ||
| 243 | while (1) |
268 | while (1) |
| 244 | { |
269 | { |
| 245 | try |
270 | try |
| 246 | { |
271 | { |
| 247 | slog << "Trying to connect...\n"; |
- | |
| 248 | connect(); |
272 | connect(); |
| 249 | slog << "Connection established.\n"; |
- | |
| 250 | break; |
273 | break; |
| 251 | } |
274 | } |
| 252 | catch (SocketException *e) |
275 | catch (SocketException *e) |
| 253 | { |
276 | { |
| 254 | slog << "Could not connect: " |
277 | slog << "Could not connect: " + e->getDescription() + "\n"; |
| 255 | slog << "Will try again in " |
278 | slog << "Will try again in " + itos(myReconnectTimeout) + " seconds\n"; |
| 256 | sleep(myReconnectTimeout); |
279 | sleep(myReconnectTimeout); |
| 257 | } |
280 | } |
| 258 | } |
281 | } |
| 259 | } |
282 | } |
| 260 | 283 | ||
| 261 | void AsyncSocket::connect() |
284 | void AsyncSocket::connect() |
| 262 | { |
285 | { |
| - | 286 | SyslogStream &slog = SyslogStream::getInstance(); |
|
| - | 287 | ||
| 263 | close(); |
288 | close(); |
| - | 289 | ||
| - | 290 | slog << "Trying to connect...\n"; |
|
| 264 | 291 | ||
| 265 | mySocket = ::socket(AF_INET, SOCK_STREAM, 0); |
292 | mySocket = ::socket(AF_INET, SOCK_STREAM, 0); |
| 266 | 293 | ||
| 267 | int on = 1; |
294 | int on = 1; |
| 268 | int status = setsockopt(mySocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)); |
295 | int status = setsockopt(mySocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)); |
| 269 | if (status == -1) |
296 | if (status == -1) |
| 270 | { |
297 | { |
| 271 | throw new SocketException("Connect:Reuseaddress: " + itos(errno)); |
298 | throw new SocketException("Connect:Reuseaddress: " + itos(errno)); |
| 272 | } |
299 | } |
| 273 | 300 | ||
| 274 | ///FIXME: Verify that this works |
301 | ///FIXME: Verify that this works |
| 275 | status = setsockopt(mySocket, SOL_SOCKET, SO_KEEPALIVE, (const char*)&on, sizeof(on)); |
302 | status = setsockopt(mySocket, SOL_SOCKET, SO_KEEPALIVE, (const char*)&on, sizeof(on)); |
| 276 | if (status == -1) |
303 | if (status == -1) |
| 277 | { |
304 | { |
| 278 | throw new SocketException("Connect:Keepalive: " + itos(errno)); |
305 | throw new SocketException("Connect:Keepalive: " + itos(errno)); |
| 279 | } |
306 | } |
| 280 | 307 | ||
| 281 | ///FIXME: Verify that this works |
308 | ///FIXME: Verify that this works |
| 282 | status = setsockopt(mySocket, SOL_TCP, TCP_KEEPIDLE, (const char*)&on, sizeof(on)); |
309 | status = setsockopt(mySocket, SOL_TCP, TCP_KEEPIDLE, (const char*)&on, sizeof(on)); |
| 283 | if (status == -1) |
310 | if (status == -1) |
| 284 | { |
311 | { |
| 285 | throw new SocketException("Connect:Keepidle: " + itos(errno)); |
312 | throw new SocketException("Connect:Keepidle: " + itos(errno)); |
| 286 | } |
313 | } |
| 287 | 314 | ||
| 288 | memset(&myAddressStruct, 0, sizeof(myAddressStruct)); |
315 | memset(&myAddressStruct, 0, sizeof(myAddressStruct)); |
| 289 | 316 | ||
| 290 | myAddressStruct.sin_family = AF_INET; |
317 | myAddressStruct.sin_family = AF_INET; |
| 291 | myAddressStruct.sin_port = htons(myPort); |
318 | myAddressStruct.sin_port = htons(myPort); |
| 292 | 319 | ||
| - | 320 | struct hostent *hptr = gethostbyname(myAddress.c_str()); |
|
| - | 321 | if (hptr == NULL) |
|
| - | 322 | { |
|
| - | 323 | throw new SocketException("Connect: Could not resolv ip address"); |
|
| - | 324 | } |
|
| - | 325 | ||
| - | 326 | memcpy(&myAddressStruct.sin_addr, hptr->h_addr, hptr->h_length); |
|
| - | 327 | /* |
|
| 293 | status = inet_pton(AF_INET, myAddress.c_str(), &myAddressStruct.sin_addr); |
328 | status = inet_pton(AF_INET, myAddress.c_str(), &myAddressStruct.sin_addr); |
| 294 | 329 | ||
| 295 | if (status == -1) |
330 | if (status == -1) |
| 296 | { |
331 | { |
| 297 | if (errno == EAFNOSUPPORT) |
332 | if (errno == EAFNOSUPPORT) |
| 298 | throw new SocketException("Connect: EAFNOSUPPORT"); |
333 | throw new SocketException("Connect: EAFNOSUPPORT"); |
| 299 | } |
334 | } |
| - | 335 | */ |
|
| - | 336 | ||
| 300 | 337 | ||
| 301 | status = ::connect(mySocket, (sockaddr*)&myAddressStruct, sizeof(myAddressStruct)); |
338 | status = ::connect(mySocket, (sockaddr*)&myAddressStruct, sizeof(myAddressStruct)); |
| 302 | 339 | ||
| 303 | if (status == -1) |
340 | if (status == -1) |
| 304 | { |
341 | { |
| Line 368... | Line 405... | ||
| 368 | throw new SocketException("Async socket fcntl failed"); |
405 | throw new SocketException("Async socket fcntl failed"); |
| 369 | 406 | ||
| 370 | fcntl(mySocket, F_SETFL, flags | O_NONBLOCK | FASYNC); |
407 | fcntl(mySocket, F_SETFL, flags | O_NONBLOCK | FASYNC); |
| 371 | 408 | ||
| 372 | myForceReconnect = false; |
409 | myForceReconnect = false; |
| - | 410 | ||
| - | 411 | slog << "Connection established.\n"; |
|
| 373 | } |
412 | } |
| 374 | 413 | ||
| 375 | void AsyncSocket::close() |
414 | void AsyncSocket::close() |
| 376 | { |
415 | { |
| 377 | if (mySocket != -1) |
416 | if (mySocket != -1) |