Rev 981 | Rev 984 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | SVN | RSS feed
| Rev 981 | Rev 983 | ||
|---|---|---|---|
| Line 16... | Line 16... | ||
| 16 | * You should have received a copy of the GNU General Public License * |
16 | * You should have received a copy of the GNU General Public License * |
| 17 | * along with this program; if not, write to the * |
17 | * along with this program; if not, write to the * |
| 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 | - | ||
| 22 | #include <map> |
- | |
| 23 | - | ||
| 24 | - | ||
| 25 | #include <vector> |
- | |
| 26 | - | ||
| 27 | 21 | ||
| 28 | #include "asyncsocket.h" |
22 | #include "asyncsocket.h" |
| 29 | 23 | ||
| 30 | map<string, AsyncSocket*> AsyncSocket::mySockets; |
- | |
| 31 |
|
24 | int socketCount = 1; |
| 32 | 25 | ||
| 33 | AsyncSocket::AsyncSocket() |
26 | AsyncSocket::AsyncSocket() |
| 34 | { |
27 | { |
| 35 | myId = itos(time(NULL)) + itos(mySockets.size()); |
- | |
| 36 | - | ||
| 37 |
|
28 | myId = socketCount++; |
| 38 | - | ||
| 39 | cout << "DEBUG: Started " << myId << endl; |
- | |
| 40 | - | ||
| 41 | mySocket = -1; |
29 | mySocket = -1; |
| 42 | myReconnectTimeout = 0; |
30 | myReconnectTimeout = 0; |
| 43 | myForceReconnect = false; |
31 | myForceReconnect = false; |
| 44 | - | ||
| 45 | 32 | ||
| 46 | Thread<AsyncSocket>(); |
33 | Thread<AsyncSocket>(); |
| 47 | } |
34 | } |
| 48 | 35 | ||
| 49 | AsyncSocket::~AsyncSocket() |
36 | AsyncSocket::~AsyncSocket() |
| 50 | { |
37 | { |
| 51 | mySemaphore.unlock(); |
- | |
| 52 | - | ||
| 53 | if (mySocket != -1) |
38 | if (mySocket != -1) |
| 54 | { |
39 | { |
| 55 | ::close(mySocket); |
40 | ::close(mySocket); |
| 56 | mySocket = -1; |
- | |
| 57 | } |
41 | } |
| 58 | - | ||
| 59 | mySockets.erase(myId); |
- | |
| 60 | 42 | ||
| 61 | stop(); |
43 | stop(); |
| 62 | } |
44 | } |
| 63 | 45 | ||
| 64 | void AsyncSocket::run() |
46 | void AsyncSocket::run() |
| 65 | { |
47 | { |
| 66 | SyslogStream &slog = SyslogStream::getInstance(); |
48 | SyslogStream &slog = SyslogStream::getInstance(); |
| 67 | 49 | ||
| 68 | if (!isConnected()) |
50 | if (!isConnected()) |
| 69 | { |
51 | { |
| 70 | if (myReconnectTimeout == 0) |
52 | if (myReconnectTimeout == 0) |
| 71 | { |
53 | { |
| 72 | connect(); |
54 | connect(); |
| 73 | } |
55 | } |
| 74 | else |
56 | else |
| 75 | { |
57 | { |
| 76 | reconnectLoop(); |
58 | reconnectLoop(); |
| 77 | } |
59 | } |
| 78 | } |
60 | } |
| 79 | 61 | ||
| 80 | char buf[MAXBUFFER + 1]; |
62 | char buf[MAXBUFFER + 1]; |
| 81 | string data; |
63 | string data; |
| 82 | int status; |
64 | int status; |
| 83 | int rc; |
- | |
| 84 | int timeSince = time(NULL) + 10; |
- | |
| 85 | 65 | ||
| - | 66 | bool loop = true; |
|
| 86 | try |
67 | try |
| 87 | { |
68 | { |
| 88 | while ( |
69 | while (loop) |
| 89 | { |
70 | { |
| 90 | AsyncSocket::mySemaphore.lock(); |
- | |
| 91 | - | ||
| 92 | rc = mySemaphore.wait(10); |
- | |
| 93 | - | ||
| 94 | AsyncSocket::mySemaphore.unlock(); |
- | |
| 95 | - | ||
| 96 | if (myForceReconnect) |
71 | if (myForceReconnect) |
| 97 | { |
72 | { |
| 98 | slog << "Disconnected from server.\n"; |
- | |
| 99 | reconnectLoop(); |
73 | reconnectLoop(); |
| 100 | timeSince = time(NULL) + 10; |
- | |
| 101 | continue; |
- | |
| 102 | } |
74 | } |
| 103 | 75 | ||
| 104 | //cout << "Socket awoken...\n"; |
- | |
| 105 | - | ||
| 106 | if (rc == ETIMEDOUT) |
- | |
| 107 | { |
- | |
| 108 | /* Socket timed out, this means we have not received anything in some time |
- | |
| 109 | and we should check the connection */ |
- | |
| 110 | - | ||
| 111 | setEvent(ASYNCSOCKET_EVENT_INACTIVITY); |
- | |
| 112 | timeSince = time(NULL); |
- | |
| 113 | } |
- | |
| 114 | else |
- | |
| 115 | { |
- | |
| 116 | while (myOutQueue.size() > 0) |
- | |
| 117 | { |
- | |
| 118 | data = myOutQueue.pop(); |
- | |
| 119 | - | ||
| 120 | sendDataDirect(data); |
- | |
| 121 | } |
- | |
| 122 | - | ||
| 123 | memset(buf, 0, MAXBUFFER + 1); |
76 | memset(buf, 0, MAXBUFFER + 1); |
| 124 | - | ||
| 125 | status = ::recv(mySocket, buf, MAXBUFFER, 0); |
77 | status = ::recv(mySocket, buf, MAXBUFFER, 0); |
| 126 | 78 | ||
| 127 | if (status == -1) |
79 | if (status == -1) |
| 128 | { |
80 | { |
| 129 | switch (errno) |
81 | switch (errno) |
| 130 | { |
82 | { |
| 131 | case EAGAIN: |
83 | case EAGAIN: |
| 132 |
|
84 | throw new SocketException("The socket is marked non-blocking and the receive operation would block, or a receive timeout had been set and the timeout expired before data was received."); |
| 133 | break; |
85 | break; |
| 134 | 86 | ||
| 135 | case EBADF: |
87 | case EBADF: |
| 136 | throw new SocketException("The argument s is an invalid descriptor."); |
88 | throw new SocketException("The argument s is an invalid descriptor."); |
| 137 | 89 | ||
| Line 143... | Line 95... | ||
| 143 | 95 | ||
| 144 | case EINTR: |
96 | case EINTR: |
| 145 | throw new SocketException("The receive was interrupted by delivery of a signal before any data were available; see signal(7)."); |
97 | throw new SocketException("The receive was interrupted by delivery of a signal before any data were available; see signal(7)."); |
| 146 | 98 | ||
| 147 | case EINVAL: |
99 | case EINVAL: |
| 148 |
|
100 | throw new SocketException("Invalid argument passed."); |
| 149 | slog << "Disconnected from server.\n"; |
- | |
| 150 | reconnectLoop(); |
- | |
| 151 | timeSince = time(NULL) + 10; |
- | |
| 152 | break; |
101 | break; |
| 153 | 102 | ||
| 154 | case ENOMEM: |
103 | case ENOMEM: |
| 155 | throw new SocketException("Could not allocate memory for recvmsg()."); |
104 | throw new SocketException("Could not allocate memory for recvmsg()."); |
| 156 | 105 | ||
| 157 | case ENOTCONN: |
106 | case ENOTCONN: |
| 158 | throw new SocketException("The socket is associated with a connection-oriented protocol and has not been connected (see connect(2) and accept(2))."); |
107 | throw new SocketException("The socket is associated with a connection-oriented protocol and has not been connected (see connect(2) and accept(2))."); |
| 159 | 108 | ||
| 160 | case ENOTSOCK: |
109 | case ENOTSOCK: |
| 161 | throw new SocketException("The argument s does not refer to a socket."); |
110 | throw new SocketException("The argument s does not refer to a socket."); |
| - | 111 | ||
| - | 112 | case ECONNRESET: |
|
| - | 113 | setEvent(ASYNCSOCKET_EVENT_RESET); |
|
| - | 114 | if (myReconnectTimeout > 0) |
|
| - | 115 | { |
|
| - | 116 | reconnectLoop(); |
|
| - | 117 | } |
|
| - | 118 | else |
|
| - | 119 | { |
|
| - | 120 | loop = false; |
|
| - | 121 | } |
|
| - | 122 | break; |
|
| 162 | 123 | ||
| 163 | default: |
124 | default: |
| 164 |
|
125 | throw new SocketException("Unknow exception: " + itos(errno)); |
| 165 | break; |
126 | break; |
| 166 | } |
127 | } |
| 167 | } |
128 | } |
| 168 | else if (status == 0) |
129 | else if (status == 0) |
| 169 | { |
130 | { |
| - | 131 | setEvent(ASYNCSOCKET_EVENT_CLOSED); |
|
| 170 |
|
132 | if (myReconnectTimeout > 0) |
| - | 133 | { |
|
| 171 | reconnectLoop(); |
134 | reconnectLoop(); |
| - | 135 | } |
|
| - | 136 | else |
|
| - | 137 | { |
|
| 172 |
|
138 | loop = false; |
| - | 139 | } |
|
| 173 | } |
140 | } |
| 174 | else if (status > 0) |
141 | else if (status > 0) |
| 175 | { |
142 | { |
| 176 | timeSince = time(NULL) + 10; |
- | |
| 177 | - | ||
| 178 | data = buf; |
143 | data = buf; |
| 179 | 144 | ||
| 180 |
|
145 | //slog << "Received: " + data + "\n"; |
| 181 | 146 | ||
| 182 | myInQueue.push(data); |
147 | myInQueue.push(data); |
| 183 | - | ||
| 184 | setEvent(ASYNCSOCKET_EVENT_DATA); |
148 | setEvent(ASYNCSOCKET_EVENT_DATA); |
| 185 | } |
- | |
| 186 | - | ||
| 187 | if (timeSince + 10 < time(NULL)) |
- | |
| 188 | { |
- | |
| 189 | setEvent(ASYNCSOCKET_EVENT_INACTIVITY); |
- | |
| 190 | timeSince = time(NULL); |
- | |
| 191 | } |
- | |
| 192 | } |
149 | } |
| 193 | } |
150 | } |
| 194 | } |
151 | } |
| 195 | catch (SocketException *e) |
152 | catch (SocketException *e) |
| 196 | { |
153 | { |
| 197 | slog << "Exception: " + e->getDescription() + "\n"; |
154 | slog << "Exception: " + e->getDescription() + "\n"; |
| 198 | //mySemaphore.unlock(); |
- | |
| 199 | setEvent(ASYNCSOCKET_EVENT_DIED); |
155 | setEvent(ASYNCSOCKET_EVENT_DIED); |
| 200 | stop(); |
- | |
| 201 | } |
156 | } |
| 202 | 157 | ||
| 203 | close(); |
158 | close(); |
| 204 | - | ||
| 205 | //mySemaphore.unlock(); |
- | |
| 206 | } |
159 | } |
| 207 | 160 | ||
| 208 | void AsyncSocket::reconnectLoop() |
161 | void AsyncSocket::reconnectLoop() |
| 209 | { |
162 | { |
| 210 | if (myReconnectTimeout == 0) |
- | |
| 211 | { |
- | |
| 212 | close(); |
- | |
| 213 | throw new SocketException("Connection is closed."); |
- | |
| 214 | } |
- | |
| 215 | - | ||
| 216 | SyslogStream &slog = SyslogStream::getInstance(); |
163 | SyslogStream &slog = SyslogStream::getInstance(); |
| 217 | 164 | ||
| 218 | while (1) |
165 | while (1) |
| 219 | { |
166 | { |
| 220 | try |
167 | try |
| Line 222... | Line 169... | ||
| 222 | connect(); |
169 | connect(); |
| 223 | break; |
170 | break; |
| 224 | } |
171 | } |
| 225 | catch (SocketException *e) |
172 | catch (SocketException *e) |
| 226 | { |
173 | { |
| - | 174 | setEvent(ASYNCSOCKET_EVENT_CONNECT_FAILED); |
|
| - | 175 | setEvent(ASYNCSOCKET_EVENT_WAITING_TO_RECONNECT); |
|
| 227 | slog << "Could not connect: " + e->getDescription() + "\n"; |
176 | slog << "Could not connect: " + e->getDescription() + "\n";//FIXME: Remove these |
| 228 | slog << "Will try again in " + itos(myReconnectTimeout) + " seconds\n"; |
177 | slog << "Will try again in " + itos(myReconnectTimeout) + " seconds\n"; |
| 229 | sleep(myReconnectTimeout); |
178 | sleep(myReconnectTimeout); |
| 230 | } |
179 | } |
| 231 | } |
180 | } |
| 232 | } |
181 | } |
| Line 355... | Line 304... | ||
| 355 | void AsyncSocket::connect() |
304 | void AsyncSocket::connect() |
| 356 | { |
305 | { |
| 357 | SyslogStream &slog = SyslogStream::getInstance(); |
306 | SyslogStream &slog = SyslogStream::getInstance(); |
| 358 | 307 | ||
| 359 | create(); |
308 | create(); |
| 360 | - | ||
| 361 | int on = 1; |
- | |
| 362 | ///FIXME: Verify that this works |
- | |
| 363 | int status = setsockopt(mySocket, SOL_SOCKET, SO_KEEPALIVE, (const char*)&on, sizeof(on)); |
- | |
| 364 | if (status == -1) |
- | |
| 365 | { |
- | |
| 366 | close(); |
- | |
| 367 | throw new SocketException("Connect:Keepalive: " + itos(errno)); |
- | |
| 368 | } |
- | |
| 369 | - | ||
| 370 | ///FIXME: Verify that this works |
- | |
| 371 | status = setsockopt(mySocket, SOL_TCP, TCP_KEEPIDLE, (const char*)&on, sizeof(on)); |
- | |
| 372 | if (status == -1) |
- | |
| 373 | { |
- | |
| 374 | close(); |
- | |
| 375 | throw new SocketException("Connect:Keepidle: " + itos(errno)); |
- | |
| 376 | } |
- | |
| 377 | 309 | ||
| 378 | memset(&myAddressStruct, 0, sizeof(myAddressStruct)); |
310 | memset(&myAddressStruct, 0, sizeof(myAddressStruct)); |
| 379 | 311 | ||
| 380 | myAddressStruct.sin_family = AF_INET; |
312 | myAddressStruct.sin_family = AF_INET; |
| 381 | myAddressStruct.sin_port = htons(myPort); |
313 | myAddressStruct.sin_port = htons(myPort); |
| - | 314 | ||
| - | 315 | //slog << "Trying to resolv " + myAddress + "\n"; |
|
| 382 | 316 | ||
| 383 | struct hostent *hptr = gethostbyname(myAddress.c_str()); |
317 | struct hostent *hptr = gethostbyname(myAddress.c_str()); |
| 384 | if (hptr == NULL) |
318 | if (hptr == NULL) |
| 385 | { |
319 | { |
| 386 | close(); |
320 | close(); |
| 387 | throw new SocketException("Connect: Could not resolv ip address"); |
321 | throw new SocketException("Connect: Could not resolv ip address"); |
| 388 | } |
322 | } |
| 389 | 323 | ||
| - | 324 | ||
| 390 | memcpy(&myAddressStruct.sin_addr, hptr->h_addr, hptr->h_length); |
325 | memcpy(&myAddressStruct.sin_addr, hptr->h_addr, hptr->h_length); |
| 391 | /* |
- | |
| 392 | status = inet_pton(AF_INET, myAddress.c_str(), &myAddressStruct.sin_addr); |
- | |
| 393 | 326 | ||
| 394 | if (status == -1) |
- | |
| 395 | { |
- | |
| 396 | if (errno == EAFNOSUPPORT) |
- | |
| 397 | throw new SocketException("Connect: EAFNOSUPPORT"); |
- | |
| 398 | } |
- | |
| 399 | */ |
- | |
| 400 | - | ||
| 401 | slog << "Trying to connect...\n"; |
- | |
| 402 | - | ||
| 403 | status = ::connect(mySocket, (sockaddr*)&myAddressStruct, sizeof(myAddressStruct)); |
327 | int status = ::connect(mySocket, (sockaddr*)&myAddressStruct, sizeof(myAddressStruct)); |
| 404 | 328 | ||
| 405 | if (status == -1) |
329 | if (status == -1) |
| 406 | { |
330 | { |
| 407 | close(); |
331 | close(); |
| 408 | switch (errno) |
332 | switch (errno) |
| 409 | { |
333 | { |
| 410 | case EACCES: |
334 | case EACCES: |
| 411 | throw new SocketException("For Unix domain sockets, which are identified by pathname: Write permission is denied on the socket file, or search per- mission is denied for one of the directories in the path prefix. (See also path_resolution(7).)"); |
335 | throw new SocketException("For Unix domain sockets, which are identified by pathname: Write permission is denied on the socket file, or search per- mission is denied for one of the directories in the path prefix. (See also path_resolution(7).)"); |
| 412 | 336 | ||
| 413 | case EPERM: |
337 | case EPERM: |
| 414 | throw new SocketException("The user tried to connect to a broadcast address without having the socket broadcast flag enabled or the connection request failed because of a local firewall rule."); |
338 | throw new SocketException("The user tried to connect to a broadcast address without having the socket broadcast flag enabled or the connection request failed because of a local firewall rule."); |
| 415 | 339 | ||
| 416 | case EADDRINUSE: |
340 | case EADDRINUSE: |
| 417 | throw new SocketException("Local address is already in use."); |
341 | throw new SocketException("Local address is already in use."); |
| 418 | 342 | ||
| 419 | case EAFNOSUPPORT: |
343 | case EAFNOSUPPORT: |
| 420 | throw new SocketException("The passed address didn't have the correct address family in its sa_family field."); |
344 | throw new SocketException("The passed address didn't have the correct address family in its sa_family field."); |
| 421 | 345 | ||
| 422 | case EAGAIN: |
346 | case EAGAIN: |
| 423 | throw new SocketException("No more free local ports or insufficient entries in the routing cache. For AF_INET see the net.ipv4.ip_local_port_range sysctl in ip(7) on how to increase the number of local ports."); |
347 | throw new SocketException("No more free local ports or insufficient entries in the routing cache. For AF_INET see the net.ipv4.ip_local_port_range sysctl in ip(7) on how to increase the number of local ports."); |
| 424 | 348 | ||
| 425 | case EALREADY: |
349 | case EALREADY: |
| 426 | throw new SocketException("The socket is non-blocking and a previous connection attempt has not yet been completed."); |
350 | throw new SocketException("The socket is non-blocking and a previous connection attempt has not yet been completed."); |
| 427 | 351 | ||
| 428 | case EBADF: |
352 | case EBADF: |
| 429 | throw new SocketException("The file descriptor is not a valid index in the descriptor table."); |
353 | throw new SocketException("The file descriptor is not a valid index in the descriptor table."); |
| 430 | 354 | ||
| 431 | case ECONNREFUSED: |
355 | case ECONNREFUSED: |
| 432 | throw new SocketException("No-one listening on the remote address."); |
356 | throw new SocketException("No-one listening on the remote address."); |
| 433 | 357 | ||
| 434 | case EFAULT: |
358 | case EFAULT: |
| 435 | throw new SocketException("The socket structure address is outside the user's address space."); |
359 | throw new SocketException("The socket structure address is outside the user's address space."); |
| 436 | 360 | ||
| 437 | case EINPROGRESS: |
361 | case EINPROGRESS: |
| 438 | throw new SocketException("The socket is non-blocking and the connection cannot be completed immediately. It is possible to select(2) or poll(2) for completion by selecting the socket for writing. After select(2) indicates writability, use getsockopt(2) to read the SO_ERROR option at level SOL_SOCKET to determine whether connect() completed successfully (SO_ERROR is zero) or unsuccessfully (SO_ERROR is one of the usual error codes listed here, explaining the reason for the failure)."); |
362 | throw new SocketException("The socket is non-blocking and the connection cannot be completed immediately. It is possible to select(2) or poll(2) for completion by selecting the socket for writing. After select(2) indicates writability, use getsockopt(2) to read the SO_ERROR option at level SOL_SOCKET to determine whether connect() completed successfully (SO_ERROR is zero) or unsuccessfully (SO_ERROR is one of the usual error codes listed here, explaining the reason for the failure)."); |
| 439 | 363 | ||
| 440 | case EINTR: |
364 | case EINTR: |
| 441 | throw new SocketException("The system call was interrupted by a signal that was caught; see signal(7)."); |
365 | throw new SocketException("The system call was interrupted by a signal that was caught; see signal(7)."); |
| Line 452... | Line 376... | ||
| 452 | case ETIMEDOUT: |
376 | case ETIMEDOUT: |
| 453 | throw new SocketException("Timeout while attempting connection. The server may be too busy to accept new connections. Note that for IP sockets the timeout may be very long when syncookies are enabled on the server."); |
377 | throw new SocketException("Timeout while attempting connection. The server may be too busy to accept new connections. Note that for IP sockets the timeout may be very long when syncookies are enabled on the server."); |
| 454 | 378 | ||
| 455 | default: |
379 | default: |
| 456 | throw new SocketException("Other errors may be generated by the underlying protocol modules. : " + itos(errno)); |
380 | throw new SocketException("Other errors may be generated by the underlying protocol modules. : " + itos(errno)); |
| 457 | } |
381 | } |
| 458 | } |
- | |
| 459 | - | ||
| 460 | struct sigaction saio; |
- | |
| 461 | saio.sa_handler = AsyncSocket::signalHandler; |
- | |
| 462 | sigemptyset(&saio.sa_mask); |
- | |
| 463 | saio.sa_flags = 0; |
- | |
| 464 | saio.sa_restorer = NULL; |
- | |
| 465 | sigaction(SIGIO, &saio, NULL); |
- | |
| 466 | - | ||
| 467 | fcntl(mySocket, F_SETOWN, getpid()); |
- | |
| 468 | int flags = fcntl(mySocket, F_GETFL); |
- | |
| 469 | - | ||
| 470 | if (flags < 0) |
- | |
| 471 | { |
- | |
| 472 | close(); |
- | |
| 473 | throw new SocketException("Async socket fcntl failed"); |
- | |
| 474 | } |
382 | } |
| 475 | - | ||
| 476 | fcntl(mySocket, F_SETFL, flags | O_NONBLOCK | FASYNC); |
- | |
| 477 | 383 | ||
| 478 | myForceReconnect = false; |
384 | myForceReconnect = false; |
| 479 | 385 | ||
| 480 |
|
386 | setEvent(ASYNCSOCKET_EVENT_CONNECTED); |
| 481 | } |
387 | } |
| 482 | 388 | ||
| 483 | void AsyncSocket::close() |
389 | void AsyncSocket::close() |
| 484 | { |
390 | { |
| 485 | if (mySocket != -1) |
391 | if (mySocket != -1) |
| Line 501... | Line 407... | ||
| 501 | } |
407 | } |
| 502 | 408 | ||
| 503 | void AsyncSocket::startEvent() |
409 | void AsyncSocket::startEvent() |
| 504 | { |
410 | { |
| 505 | myEventSemaphore.lock(); |
411 | myEventSemaphore.lock(); |
| - | 412 | } |
|
| - | 413 | ||
| - | 414 | bool AsyncSocket::availableEvent() |
|
| - | 415 | { |
|
| - | 416 | return (myEventQueue.size() > 0); |
|
| 506 | } |
417 | } |
| 507 | 418 | ||
| 508 | int AsyncSocket::getEvent() |
419 | int AsyncSocket::getEvent() |
| 509 | { |
420 | { |
| 510 | int event = myEvent; |
- | |
| 511 | myEvent = ASYNCSOCKET_EVENT_NONE; |
- | |
| 512 | return |
421 | return myEventQueue.pop(); |
| 513 | } |
422 | } |
| 514 | 423 | ||
| 515 | void AsyncSocket::waitForEvent() |
424 | void AsyncSocket::waitForEvent() |
| 516 | { |
425 | { |
| 517 | myEventSemaphore.wait(); |
426 | myEventSemaphore.wait(); |
| 518 | } |
427 | } |
| 519 | 428 | ||
| 520 | void AsyncSocket::stopEvent() |
429 | void AsyncSocket::stopEvent() |
| 521 | { |
430 | { |
| 522 | myEventSemaphore.unlock(); |
431 | myEventSemaphore.unlock(); |
| 523 | } |
432 | } |
| 524 | 433 | ||
| 525 | void AsyncSocket::setAddress(string address, int port) |
434 | void AsyncSocket::setAddress(string address, int port) |
| 526 | { |
435 | { |
| 527 | myAddress = address; |
436 | myAddress = address; |
| 528 | myPort = port; |
437 | myPort = port; |
| Line 534... | Line 443... | ||
| 534 | } |
443 | } |
| 535 | 444 | ||
| 536 | void AsyncSocket::setSocket(int socket) |
445 | void AsyncSocket::setSocket(int socket) |
| 537 | { |
446 | { |
| 538 | mySocket = socket; |
447 | mySocket = socket; |
| 539 | } |
448 | } |
| 540 | 449 | ||
| 541 | int AsyncSocket::getSocket() |
450 | int AsyncSocket::getSocket() |
| 542 | { |
451 | { |
| 543 | return mySocket; |
452 | return mySocket; |
| 544 | } |
453 | } |
| 545 | 454 | ||
| 546 | bool AsyncSocket::availableData() |
455 | bool AsyncSocket::availableData() |
| 547 | { |
456 | { |
| 548 | return (myInQueue.size() > 0); |
457 | return (myInQueue.size() > 0); |
| 549 | } |
458 | } |
| 550 | 459 | ||
| 551 | string AsyncSocket::getData() |
460 | string AsyncSocket::getData() |
| 552 | { |
461 | { |
| 553 | return myInQueue.pop(); |
462 | return myInQueue.pop(); |
| 554 | } |
463 | } |
| 555 | 464 | ||
| 556 | bool AsyncSocket::sendData(string data) |
465 | bool AsyncSocket::sendData(string data) |
| 557 | { |
466 | { |
| - | 467 | //cout << "SendData on " + myAddress + ":" + itos(myPort) + ".\n"; |
|
| - | 468 | sendDataDirect(data); |
|
| 558 | myOutQueue. |
469 | //myOutQueue.push(data); |
| 559 | mySemaphore. |
470 | //mySemaphore.broadcast(); |
| 560 | return true; |
471 | return true; |
| 561 | } |
472 | } |
| 562 | 473 | ||
| 563 | void AsyncSocket::sendDataDirect(string data) |
474 | void AsyncSocket::sendDataDirect(string data) |
| 564 | { |
475 | { |
| Line 568... | Line 479... | ||
| 568 | 479 | ||
| 569 | int status = ::send(mySocket, data.c_str(), data.size(), 0); |
480 | int status = ::send(mySocket, data.c_str(), data.size(), 0); |
| 570 | 481 | ||
| 571 | //slog << "Status: " << status << "\n"; |
482 | //slog << "Status: " << status << "\n"; |
| 572 | 483 | ||
| - | 484 | try |
|
| - | 485 | { |
|
| 573 | if (status == -1) |
486 | if (status == -1) |
| 574 | { |
487 | { |
| 575 | switch (errno) |
488 | switch (errno) |
| 576 | { |
489 | { |
| 577 | case EACCES: |
490 | case EACCES: |
| 578 | throw new SocketException("(For Unix domain sockets, which are identified by pathname) Write permission is denied on the destination socket file, or search permission is denied for one of the directories the path prefix. (See path_resolution(7).)"); |
491 | throw new SocketException("(For Unix domain sockets, which are identified by pathname) Write permission is denied on the destination socket file, or search permission is denied for one of the directories the path prefix. (See path_resolution(7).)"); |
| 579 | 492 | ||
| 580 | case EAGAIN: |
493 | case EAGAIN: |
| 581 | //slog << "The socket is marked non-blocking and the requested operation would block.\n"; |
494 | //slog << "The socket is marked non-blocking and the requested operation would block.\n"; |
| 582 | break; |
495 | break; |
| 583 | 496 | ||
| 584 | case EBADF: |
497 | case EBADF: |
| 585 | throw new SocketException("An invalid descriptor was specified."); |
498 | throw new SocketException("An invalid descriptor was specified."); |
| 586 | 499 | ||
| 587 | case ECONNRESET: |
500 | case ECONNRESET: |
| Line 593... | Line 506... | ||
| 593 | case EFAULT: |
506 | case EFAULT: |
| 594 | throw new SocketException("An invalid user space address was specified for an argument."); |
507 | throw new SocketException("An invalid user space address was specified for an argument."); |
| 595 | 508 | ||
| 596 | case EINTR: |
509 | case EINTR: |
| 597 | throw new SocketException("A signal occurred before any data was transmitted; see signal(7)."); |
510 | throw new SocketException("A signal occurred before any data was transmitted; see signal(7)."); |
| 598 | 511 | ||
| 599 | case EINVAL: |
512 | case EINVAL: |
| 600 | throw new SocketException("1Invalid argument passed."); |
513 | throw new SocketException("1Invalid argument passed."); |
| 601 | 514 | ||
| 602 | case EISCONN: |
515 | case EISCONN: |
| 603 | throw new SocketException("The connection-mode socket was connected already but a recipient was specified. (Now either this error is returned, or the recipient specification is ignored.)"); |
516 | throw new SocketException("The connection-mode socket was connected already but a recipient was specified. (Now either this error is returned, or the recipient specification is ignored.)"); |
| Line 617... | Line 530... | ||
| 617 | case ENOTSOCK: |
530 | case ENOTSOCK: |
| 618 | throw new SocketException("The argument s is not a socket."); |
531 | throw new SocketException("The argument s is not a socket."); |
| 619 | 532 | ||
| 620 | case EOPNOTSUPP: |
533 | case EOPNOTSUPP: |
| 621 | throw new SocketException("Some bit in the flags argument is inappropriate for the socket type."); |
534 | throw new SocketException("Some bit in the flags argument is inappropriate for the socket type."); |
| 622 | 535 | ||
| 623 | case EPIPE: |
536 | case EPIPE: |
| 624 | 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."); |
537 | 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."); |
| 625 | 538 | ||
| 626 | default: |
539 | default: |
| 627 | slog << "Unknow exception: " + itos(errno) + "\n"; |
540 | slog << "Unknow exception: " + itos(errno) + "\n"; |
| 628 | break; |
541 | break; |
| 629 | } |
542 | } |
| 630 | } |
543 | } |
| - | 544 | } |
|
| - | 545 | catch (SocketException *e) |
|
| - | 546 | { |
|
| - | 547 | slog << "sendDataDirect: Exception: " + e->getDescription() + "\n"; |
|
| - | 548 | } |
|
| 631 | } |
549 | } |
| 632 | 550 | ||
| 633 | void AsyncSocket::setEvent(int event) |
551 | void AsyncSocket::setEvent(int event) |
| 634 | { |
552 | { |
| 635 | myEventSemaphore.lock(); |
- | |
| 636 |
|
553 | myEventQueue.push(event); |
| 637 | myEventSemaphore.unlock(); |
- | |
| 638 | myEventSemaphore.broadcast(); |
554 | myEventSemaphore.broadcast(); |
| 639 | } |
555 | } |
| 640 | 556 | ||
| 641 | void AsyncSocket::forceReconnect() |
557 | void AsyncSocket::forceReconnect() |
| 642 | { |
558 | { |
| - | 559 | ///FIXME: Threadsafe? |
|
| 643 | myForceReconnect = true; |
560 | myForceReconnect = true; |
| 644 | mySemaphore.broadcast(); |
- | |
| 645 | } |
561 | } |
| 646 | - | ||
| 647 | void AsyncSocket::signalHandler(int signum) |
- | |
| 648 | { |
- | |
| 649 | //FIXME: We must know which socket is ready to read by using select... |
- | |
| 650 | cout << "DEBUG: signalHandler signum: " << signum << endl; |
- | |
| 651 | - | ||
| 652 | map<string, AsyncSocket*>::iterator iter; |
- | |
| 653 | - | ||
| 654 | mySocketsMutex.lock(); |
- | |
| 655 | for (iter = mySockets.begin(); iter != mySockets.end(); iter++)///FIXME: We should check order and length |
- | |
| 656 | { |
- | |
| 657 | cout << "DEBUG: signalHandler: calling: " << iter->second->getId() << endl; |
- | |
| 658 | iter->second->mySemaphore.broadcast(); |
- | |
| 659 | } |
- | |
| 660 | mySocketsMutex.unlock(); |
- | |
| 661 | 562 | ||
| 662 | } |
- | |