Rev 976 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | SVN | RSS feed
| Rev 976 | Rev 981 | ||
|---|---|---|---|
| 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 | ||
| 21 | 27 | ||
| 22 | #include "asyncsocket.h" |
28 | #include "asyncsocket.h" |
| 23 | 29 | ||
| - | 30 | map<string, AsyncSocket*> AsyncSocket::mySockets; |
|
| 24 |
|
31 | Mutex AsyncSocket::mySocketsMutex; |
| 25 | 32 | ||
| 26 | AsyncSocket::AsyncSocket() |
33 | AsyncSocket::AsyncSocket() |
| 27 | { |
34 | { |
| - | 35 | myId = itos(time(NULL)) + itos(mySockets.size()); |
|
| - | 36 | ||
| - | 37 | mySockets[myId] = this; |
|
| - | 38 | ||
| - | 39 | cout << "DEBUG: Started " << myId << endl; |
|
| - | 40 | ||
| 28 | mySocket = -1; |
41 | mySocket = -1; |
| 29 | myReconnectTimeout = 0; |
42 | myReconnectTimeout = 0; |
| 30 | myForceReconnect = false; |
43 | myForceReconnect = false; |
| - | 44 | ||
| 31 | 45 | ||
| 32 | Thread<AsyncSocket>(); |
46 | Thread<AsyncSocket>(); |
| 33 | } |
47 | } |
| 34 | 48 | ||
| 35 | AsyncSocket::~AsyncSocket() |
49 | AsyncSocket::~AsyncSocket() |
| 36 | { |
50 | { |
| - | 51 | mySemaphore.unlock(); |
|
| - | 52 | ||
| 37 | if (mySocket != -1) |
53 | if (mySocket != -1) |
| 38 | { |
54 | { |
| 39 | ::close(mySocket); |
55 | ::close(mySocket); |
| 40 | mySocket = -1; |
56 | mySocket = -1; |
| 41 | } |
57 | } |
| - | 58 | ||
| - | 59 | mySockets.erase(myId); |
|
| 42 | 60 | ||
| 43 | stop(); |
61 | stop(); |
| 44 | } |
62 | } |
| 45 | 63 | ||
| 46 | void AsyncSocket::run() |
64 | void AsyncSocket::run() |
| 47 | { |
65 | { |
| 48 | SyslogStream &slog = SyslogStream::getInstance(); |
66 | SyslogStream &slog = SyslogStream::getInstance(); |
| 49 | 67 | ||
| 50 | if ( |
68 | if (!isConnected()) |
| 51 | { |
69 | { |
| - | 70 | if (myReconnectTimeout == 0) |
|
| - | 71 | { |
|
| 52 | connect(); |
72 | connect(); |
| 53 | } |
73 | } |
| 54 | else |
74 | else |
| 55 | { |
75 | { |
| 56 | reconnectLoop(); |
76 | reconnectLoop(); |
| - | 77 | } |
|
| 57 | } |
78 | } |
| 58 | 79 | ||
| 59 | char buf[MAXBUFFER + 1]; |
80 | char buf[MAXBUFFER + 1]; |
| 60 | string data; |
81 | string data; |
| 61 | int status; |
82 | int status; |
| 62 | int rc; |
83 | int rc; |
| 63 | int timeSince = time(NULL) + 10; |
84 | int timeSince = time(NULL) + 10; |
| 64 | - | ||
| 65 | - | ||
| 66 | 85 | ||
| 67 | try |
86 | try |
| 68 | { |
87 | { |
| 69 | while (1) |
88 | while (1) |
| 70 | { |
89 | { |
| 71 | AsyncSocket::mySemaphore.lock(); |
90 | AsyncSocket::mySemaphore.lock(); |
| 72 | 91 | ||
| 73 | if (myReconnectTimeout == 0) |
- | |
| 74 | { |
- | |
| 75 | rc = mySemaphore.wait(); |
- | |
| 76 | } |
- | |
| 77 | else |
- | |
| 78 | { |
- | |
| 79 |
|
92 | rc = mySemaphore.wait(10); |
| 80 | } |
- | |
| 81 | 93 | ||
| 82 | AsyncSocket::mySemaphore.unlock(); |
94 | AsyncSocket::mySemaphore.unlock(); |
| 83 | 95 | ||
| 84 | if (myForceReconnect) |
96 | if (myForceReconnect) |
| 85 | { |
97 | { |
| 86 | slog << "Disconnected from server.\n"; |
98 | slog << "Disconnected from server.\n"; |
| 87 | reconnectLoop(); |
99 | reconnectLoop(); |
| 88 | timeSince = time(NULL) + 10; |
100 | timeSince = time(NULL) + 10; |
| 89 | continue; |
101 | continue; |
| 90 | } |
102 | } |
| 91 | 103 | ||
| 92 | //cout << "Socket awoken...\n"; |
104 | //cout << "Socket awoken...\n"; |
| 93 | 105 | ||
| 94 | if (rc == ETIMEDOUT) |
106 | if (rc == ETIMEDOUT) |
| 95 | { |
107 | { |
| Line 103... | Line 115... | ||
| 103 | { |
115 | { |
| 104 | while (myOutQueue.size() > 0) |
116 | while (myOutQueue.size() > 0) |
| 105 | { |
117 | { |
| 106 | data = myOutQueue.pop(); |
118 | data = myOutQueue.pop(); |
| 107 | 119 | ||
| 108 | //slog << "Sending: " << data << "\n"; |
- | |
| 109 | - | ||
| 110 | status = ::send(mySocket, data.c_str(), data.size(), 0); |
- | |
| 111 | - | ||
| 112 | //slog << "Status: " << status << "\n"; |
- | |
| 113 | - | ||
| 114 | if (status == -1) |
- | |
| 115 | { |
- | |
| 116 | switch (errno) |
- | |
| 117 | { |
- | |
| 118 | case EACCES: |
- | |
| 119 |
|
120 | sendDataDirect(data); |
| 120 | - | ||
| 121 | case EAGAIN: |
- | |
| 122 | //slog << "The socket is marked non-blocking and the requested operation would block.\n"; |
- | |
| 123 | break; |
- | |
| 124 | - | ||
| 125 | case EBADF: |
- | |
| 126 | throw new SocketException("An invalid descriptor was specified."); |
- | |
| 127 | - | ||
| 128 | case ECONNRESET: |
- | |
| 129 | throw new SocketException("Connection reset by peer."); |
- | |
| 130 | - | ||
| 131 | case EDESTADDRREQ: |
- | |
| 132 | throw new SocketException("The socket is not connection-mode, and no peer address is set."); |
- | |
| 133 | - | ||
| 134 | case EFAULT: |
- | |
| 135 | throw new SocketException("An invalid user space address was specified for an argument."); |
- | |
| 136 | - | ||
| 137 | case EINTR: |
- | |
| 138 | throw new SocketException("A signal occurred before any data was transmitted; see signal(7)."); |
- | |
| 139 | - | ||
| 140 | case EINVAL: |
- | |
| 141 | throw new SocketException("1Invalid argument passed."); |
- | |
| 142 | - | ||
| 143 | case EISCONN: |
- | |
| 144 | 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.)"); |
- | |
| 145 | - | ||
| 146 | case EMSGSIZE: |
- | |
| 147 | throw new SocketException("The socket type requires that message be sent atomically, and the size of the message to be sent made this impossible."); |
- | |
| 148 | - | ||
| 149 | case ENOBUFS: |
- | |
| 150 | throw new SocketException("The output queue for a network interface was full. This generally indicates that the interface has stopped sending, but may be caused by transient congestion. (Normally, this does not occur in Linux. Packets are just silently dropped when a device queue overflows.)"); |
- | |
| 151 | - | ||
| 152 | case ENOMEM: |
- | |
| 153 | throw new SocketException("No memory available."); |
- | |
| 154 | - | ||
| 155 | case ENOTCONN: |
- | |
| 156 | throw new SocketException("The socket is not connected, and no target has been given."); |
- | |
| 157 | - | ||
| 158 | case ENOTSOCK: |
- | |
| 159 | throw new SocketException("The argument s is not a socket."); |
- | |
| 160 | - | ||
| 161 | case EOPNOTSUPP: |
- | |
| 162 | throw new SocketException("Some bit in the flags argument is inappropriate for the socket type."); |
- | |
| 163 | - | ||
| 164 | case EPIPE: |
- | |
| 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."); |
- | |
| 166 | - | ||
| 167 | default: |
- | |
| 168 | slog << "Unknow exception: " + itos(errno) + "\n"; |
- | |
| 169 | break; |
- | |
| 170 | } |
- | |
| 171 | } |
- | |
| 172 | } |
121 | } |
| 173 | 122 | ||
| 174 | memset(buf, 0, MAXBUFFER + 1); |
123 | memset(buf, 0, MAXBUFFER + 1); |
| 175 | 124 | ||
| 176 | status = ::recv(mySocket, buf, MAXBUFFER, 0); |
125 | status = ::recv(mySocket, buf, MAXBUFFER, 0); |
| Line 223... | Line 172... | ||
| 223 | timeSince = time(NULL); |
172 | timeSince = time(NULL); |
| 224 | } |
173 | } |
| 225 | else if (status > 0) |
174 | else if (status > 0) |
| 226 | { |
175 | { |
| 227 | timeSince = time(NULL) + 10; |
176 | timeSince = time(NULL) + 10; |
| 228 | 177 | ||
| 229 | data = buf; |
178 | data = buf; |
| 230 | 179 | ||
| 231 | //slog << "Receiving: " + data + "\n"; |
180 | //slog << "Receiving: " + data + "\n"; |
| 232 | 181 | ||
| 233 | myInQueue.push(data); |
182 | myInQueue.push(data); |
| Line 247... | Line 196... | ||
| 247 | { |
196 | { |
| 248 | slog << "Exception: " + e->getDescription() + "\n"; |
197 | slog << "Exception: " + e->getDescription() + "\n"; |
| 249 | //mySemaphore.unlock(); |
198 | //mySemaphore.unlock(); |
| 250 | setEvent(ASYNCSOCKET_EVENT_DIED); |
199 | setEvent(ASYNCSOCKET_EVENT_DIED); |
| 251 | stop(); |
200 | stop(); |
| 252 | } |
201 | } |
| 253 | 202 | ||
| 254 | close(); |
203 | close(); |
| 255 | 204 | ||
| 256 | //mySemaphore.unlock(); |
205 | //mySemaphore.unlock(); |
| 257 | } |
206 | } |
| 258 | 207 | ||
| 259 | void AsyncSocket::reconnectLoop() |
208 | void AsyncSocket::reconnectLoop() |
| 260 | { |
209 | { |
| 261 | if (myReconnectTimeout == 0) |
210 | if (myReconnectTimeout == 0) |
| 262 | { |
211 | { |
| - | 212 | close(); |
|
| 263 | throw new SocketException("Connection is closed."); |
213 | throw new SocketException("Connection is closed."); |
| 264 | } |
214 | } |
| 265 | 215 | ||
| 266 | SyslogStream &slog = SyslogStream::getInstance(); |
216 | SyslogStream &slog = SyslogStream::getInstance(); |
| 267 | 217 | ||
| Line 275... | Line 225... | ||
| 275 | catch (SocketException *e) |
225 | catch (SocketException *e) |
| 276 | { |
226 | { |
| 277 | slog << "Could not connect: " + e->getDescription() + "\n"; |
227 | slog << "Could not connect: " + e->getDescription() + "\n"; |
| 278 | slog << "Will try again in " + itos(myReconnectTimeout) + " seconds\n"; |
228 | slog << "Will try again in " + itos(myReconnectTimeout) + " seconds\n"; |
| 279 | sleep(myReconnectTimeout); |
229 | sleep(myReconnectTimeout); |
| - | 230 | } |
|
| - | 231 | } |
|
| - | 232 | } |
|
| - | 233 | ||
| - | 234 | void AsyncSocket::create() |
|
| - | 235 | { |
|
| - | 236 | close(); |
|
| - | 237 | ||
| - | 238 | mySocket = ::socket(AF_INET, SOCK_STREAM, 0); |
|
| - | 239 | ||
| - | 240 | int on = 1; |
|
| - | 241 | int status = setsockopt(mySocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)); |
|
| - | 242 | if (status == -1) |
|
| - | 243 | { |
|
| - | 244 | close(); |
|
| - | 245 | throw new SocketException("Create:Reuseaddress: " + itos(errno)); |
|
| - | 246 | } |
|
| - | 247 | } |
|
| - | 248 | ||
| - | 249 | void AsyncSocket::startListen() |
|
| - | 250 | { |
|
| - | 251 | create(); |
|
| - | 252 | ||
| - | 253 | myAddressStruct.sin_family = AF_INET; |
|
| - | 254 | myAddressStruct.sin_addr.s_addr = INADDR_ANY; |
|
| - | 255 | myAddressStruct.sin_port = htons(myPort); |
|
| - | 256 | ||
| - | 257 | int status = ::bind(mySocket, (struct sockaddr *)&myAddressStruct, sizeof(myAddressStruct)); |
|
| - | 258 | ||
| - | 259 | if (status == -1) |
|
| - | 260 | { |
|
| - | 261 | close(); |
|
| - | 262 | switch (errno) |
|
| - | 263 | { |
|
| - | 264 | case EACCES: |
|
| - | 265 | throw new SocketException("The address is protected, and the user is not the superuser."); |
|
| - | 266 | ||
| - | 267 | case EADDRINUSE: |
|
| - | 268 | throw new SocketException("The given address is already in use."); |
|
| - | 269 | ||
| - | 270 | case EBADF: |
|
| - | 271 | throw new SocketException("sockfd is not a valid descriptor."); |
|
| - | 272 | ||
| - | 273 | case EINVAL: |
|
| - | 274 | throw new SocketException("The socket is already bound to an address."); |
|
| - | 275 | ||
| - | 276 | case ENOTSOCK: |
|
| - | 277 | throw new SocketException("sockfd is a descriptor for a file, not a socket."); |
|
| - | 278 | ||
| - | 279 | //case EACCES: |
|
| - | 280 | //throw new SocketException("Search permission is denied on a component of the path prefix. (See also path_resolution(7).)"); |
|
| - | 281 | ||
| - | 282 | case EADDRNOTAVAIL: |
|
| - | 283 | throw new SocketException("A nonexistent interface was requested or the requested address was not local."); |
|
| - | 284 | ||
| - | 285 | case EFAULT: |
|
| - | 286 | throw new SocketException("addr points outside the user's accessible address space."); |
|
| - | 287 | ||
| - | 288 | //case EINVAL: |
|
| - | 289 | //throw new SocketException("The addrlen is wrong, or the socket was not in the AF_UNIX family."); |
|
| - | 290 | ||
| - | 291 | case ELOOP: |
|
| - | 292 | throw new SocketException("Too many symbolic links were encountered in resolving addr."); |
|
| - | 293 | ||
| - | 294 | case ENAMETOOLONG: |
|
| - | 295 | throw new SocketException("addr is too long."); |
|
| - | 296 | ||
| - | 297 | case ENOENT: |
|
| - | 298 | throw new SocketException("The file does not exist."); |
|
| - | 299 | ||
| - | 300 | case ENOMEM: |
|
| - | 301 | throw new SocketException("Insufficient kernel memory was available."); |
|
| - | 302 | ||
| - | 303 | case ENOTDIR: |
|
| - | 304 | throw new SocketException("A component of the path prefix is not a directory."); |
|
| - | 305 | ||
| - | 306 | case EROFS: |
|
| - | 307 | throw new SocketException("The socket inode would reside on a read-only file system."); |
|
| - | 308 | ||
| - | 309 | default: |
|
| - | 310 | throw new SocketException("Unknow exception: " + itos(errno)); |
|
| - | 311 | break; |
|
| - | 312 | } |
|
| - | 313 | } |
|
| - | 314 | ||
| - | 315 | status = ::listen(mySocket, MAXCONNECTIONS); |
|
| - | 316 | ||
| - | 317 | if (status == -1) |
|
| - | 318 | { |
|
| - | 319 | close(); |
|
| - | 320 | switch (errno) |
|
| - | 321 | { |
|
| - | 322 | case EADDRINUSE: |
|
| - | 323 | throw new SocketException("Another socket is already listening on the same port."); |
|
| - | 324 | ||
| - | 325 | case EBADF: |
|
| - | 326 | throw new SocketException("The argument sockfd is not a valid descriptor."); |
|
| - | 327 | ||
| - | 328 | case ENOTSOCK: |
|
| - | 329 | throw new SocketException("The argument sockfd is not a socket."); |
|
| - | 330 | ||
| - | 331 | case EOPNOTSUPP: |
|
| - | 332 | throw new SocketException("The socket is not of a type that supports the listen() operation."); |
|
| - | 333 | ||
| - | 334 | default: |
|
| - | 335 | throw new SocketException("Unknow exception: " + itos(errno)); |
|
| - | 336 | break; |
|
| 280 | } |
337 | } |
| - | 338 | } |
|
| - | 339 | } |
|
| - | 340 | ||
| - | 341 | bool AsyncSocket::accept(AsyncSocket* newSocket) |
|
| - | 342 | { |
|
| - | 343 | int addr_length = sizeof(myAddressStruct); |
|
| - | 344 | int socket = ::accept(mySocket, (sockaddr*)&myAddressStruct, (socklen_t*)&addr_length); |
|
| - | 345 | ||
| - | 346 | if (socket > 0) |
|
| - | 347 | { |
|
| - | 348 | newSocket->setSocket(socket); |
|
| - | 349 | return true; |
|
| 281 | } |
350 | } |
| - | 351 | ||
| - | 352 | return false; |
|
| 282 | } |
353 | } |
| 283 | 354 | ||
| 284 | void AsyncSocket::connect() |
355 | void AsyncSocket::connect() |
| 285 | { |
356 | { |
| 286 | SyslogStream &slog = SyslogStream::getInstance(); |
357 | SyslogStream &slog = SyslogStream::getInstance(); |
| 287 | 358 | ||
| 288 |
|
359 | create(); |
| 289 | - | ||
| 290 | slog << "Trying to connect...\n"; |
- | |
| 291 | - | ||
| 292 | mySocket = ::socket(AF_INET, SOCK_STREAM, 0); |
- | |
| 293 | 360 | ||
| 294 | int on = 1; |
361 | int on = 1; |
| 295 | int status = setsockopt(mySocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)); |
- | |
| 296 | if (status == -1) |
- | |
| 297 | { |
- | |
| 298 | throw new SocketException("Connect:Reuseaddress: " + itos(errno)); |
- | |
| 299 | } |
- | |
| 300 | - | ||
| 301 | ///FIXME: Verify that this works |
362 | ///FIXME: Verify that this works |
| 302 | status = setsockopt(mySocket, SOL_SOCKET, SO_KEEPALIVE, (const char*)&on, sizeof(on)); |
363 | int status = setsockopt(mySocket, SOL_SOCKET, SO_KEEPALIVE, (const char*)&on, sizeof(on)); |
| 303 | if (status == -1) |
364 | if (status == -1) |
| 304 | { |
365 | { |
| - | 366 | close(); |
|
| 305 | throw new SocketException("Connect:Keepalive: " + itos(errno)); |
367 | throw new SocketException("Connect:Keepalive: " + itos(errno)); |
| 306 | } |
368 | } |
| 307 | 369 | ||
| 308 | ///FIXME: Verify that this works |
370 | ///FIXME: Verify that this works |
| 309 | status = setsockopt(mySocket, SOL_TCP, TCP_KEEPIDLE, (const char*)&on, sizeof(on)); |
371 | status = setsockopt(mySocket, SOL_TCP, TCP_KEEPIDLE, (const char*)&on, sizeof(on)); |
| 310 | if (status == -1) |
372 | if (status == -1) |
| 311 | { |
373 | { |
| - | 374 | close(); |
|
| 312 | throw new SocketException("Connect:Keepidle: " + itos(errno)); |
375 | throw new SocketException("Connect:Keepidle: " + itos(errno)); |
| 313 | } |
376 | } |
| 314 | 377 | ||
| 315 | memset(&myAddressStruct, 0, sizeof(myAddressStruct)); |
378 | memset(&myAddressStruct, 0, sizeof(myAddressStruct)); |
| 316 | 379 | ||
| Line 318... | Line 381... | ||
| 318 | myAddressStruct.sin_port = htons(myPort); |
381 | myAddressStruct.sin_port = htons(myPort); |
| 319 | 382 | ||
| 320 | struct hostent *hptr = gethostbyname(myAddress.c_str()); |
383 | struct hostent *hptr = gethostbyname(myAddress.c_str()); |
| 321 | if (hptr == NULL) |
384 | if (hptr == NULL) |
| 322 | { |
385 | { |
| - | 386 | close(); |
|
| 323 | throw new SocketException("Connect: Could not resolv ip address"); |
387 | throw new SocketException("Connect: Could not resolv ip address"); |
| 324 | } |
388 | } |
| 325 | 389 | ||
| 326 | memcpy(&myAddressStruct.sin_addr, hptr->h_addr, hptr->h_length); |
390 | memcpy(&myAddressStruct.sin_addr, hptr->h_addr, hptr->h_length); |
| 327 | /* |
391 | /* |
| Line 332... | Line 396... | ||
| 332 | if (errno == EAFNOSUPPORT) |
396 | if (errno == EAFNOSUPPORT) |
| 333 | throw new SocketException("Connect: EAFNOSUPPORT"); |
397 | throw new SocketException("Connect: EAFNOSUPPORT"); |
| 334 | } |
398 | } |
| 335 | */ |
399 | */ |
| 336 | 400 | ||
| - | 401 | slog << "Trying to connect...\n"; |
|
| 337 | 402 | ||
| 338 | status = ::connect(mySocket, (sockaddr*)&myAddressStruct, sizeof(myAddressStruct)); |
403 | status = ::connect(mySocket, (sockaddr*)&myAddressStruct, sizeof(myAddressStruct)); |
| 339 | 404 | ||
| 340 | if (status == -1) |
405 | if (status == -1) |
| 341 | { |
406 | { |
| - | 407 | close(); |
|
| 342 | switch (errno) |
408 | switch (errno) |
| 343 | { |
409 | { |
| 344 | case EACCES: |
410 | case EACCES: |
| 345 | 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).)"); |
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).)"); |
| 346 | 412 | ||
| Line 400... | Line 466... | ||
| 400 | 466 | ||
| 401 | fcntl(mySocket, F_SETOWN, getpid()); |
467 | fcntl(mySocket, F_SETOWN, getpid()); |
| 402 | int flags = fcntl(mySocket, F_GETFL); |
468 | int flags = fcntl(mySocket, F_GETFL); |
| 403 | 469 | ||
| 404 | if (flags < 0) |
470 | if (flags < 0) |
| - | 471 | { |
|
| - | 472 | close(); |
|
| 405 | throw new SocketException("Async socket fcntl failed"); |
473 | throw new SocketException("Async socket fcntl failed"); |
| - | 474 | } |
|
| 406 | 475 | ||
| 407 | fcntl(mySocket, F_SETFL, flags | O_NONBLOCK | FASYNC); |
476 | fcntl(mySocket, F_SETFL, flags | O_NONBLOCK | FASYNC); |
| 408 | 477 | ||
| 409 | myForceReconnect = false; |
478 | myForceReconnect = false; |
| 410 | 479 | ||
| 411 | slog << "Connection established.\n"; |
480 | slog << "Connection established.\n"; |
| 412 | } |
481 | } |
| 413 | 482 | ||
| 414 | void AsyncSocket::close() |
483 | void AsyncSocket::close() |
| 415 | { |
484 | { |
| 416 | if (mySocket != -1) |
485 | if (mySocket != -1) |
| 417 | { |
486 | { |
| 418 | ::close(mySocket); |
487 | ::close(mySocket); |
| 419 | mySocket = -1; |
488 | mySocket = -1; |
| 420 | setEvent(ASYNCSOCKET_EVENT_CLOSED); |
489 | setEvent(ASYNCSOCKET_EVENT_CLOSED); |
| 421 | } |
490 | } |
| 422 | } |
491 | } |
| - | 492 | ||
| - | 493 | bool AsyncSocket::isConnected() |
|
| - | 494 | { |
|
| - | 495 | return mySocket != -1; |
|
| - | 496 | } |
|
| 423 | 497 | ||
| 424 | void AsyncSocket::setReconnectTimeout(unsigned int timeout) |
498 | void AsyncSocket::setReconnectTimeout(unsigned int timeout) |
| 425 | { |
499 | { |
| 426 | myReconnectTimeout = timeout; |
500 | myReconnectTimeout = timeout; |
| 427 | } |
501 | } |
| Line 434... | Line 508... | ||
| 434 | int AsyncSocket::getEvent() |
508 | int AsyncSocket::getEvent() |
| 435 | { |
509 | { |
| 436 | int event = myEvent; |
510 | int event = myEvent; |
| 437 | myEvent = ASYNCSOCKET_EVENT_NONE; |
511 | myEvent = ASYNCSOCKET_EVENT_NONE; |
| 438 | return event; |
512 | return event; |
| 439 | } |
513 | } |
| 440 | 514 | ||
| 441 | void AsyncSocket::waitForEvent() |
515 | void AsyncSocket::waitForEvent() |
| 442 | { |
516 | { |
| 443 | myEventSemaphore.wait(); |
517 | myEventSemaphore.wait(); |
| 444 | } |
518 | } |
| Line 447... | Line 521... | ||
| 447 | { |
521 | { |
| 448 | myEventSemaphore.unlock(); |
522 | myEventSemaphore.unlock(); |
| 449 | } |
523 | } |
| 450 | 524 | ||
| 451 | void AsyncSocket::setAddress(string address, int port) |
525 | void AsyncSocket::setAddress(string address, int port) |
| 452 | { |
526 | { |
| 453 | myAddress = address; |
527 | myAddress = address; |
| 454 | myPort = port; |
528 | myPort = port; |
| - | 529 | } |
|
| - | 530 | ||
| - | 531 | void AsyncSocket::setPort(int port) |
|
| - | 532 | { |
|
| - | 533 | myPort = port; |
|
| - | 534 | } |
|
| - | 535 | ||
| - | 536 | void AsyncSocket::setSocket(int socket) |
|
| - | 537 | { |
|
| - | 538 | mySocket = socket; |
|
| - | 539 | } |
|
| - | 540 | ||
| - | 541 | int AsyncSocket::getSocket() |
|
| - | 542 | { |
|
| - | 543 | return mySocket; |
|
| 455 | } |
544 | } |
| 456 | 545 | ||
| 457 | bool AsyncSocket::availableData() |
546 | bool AsyncSocket::availableData() |
| 458 | { |
547 | { |
| 459 | return (myInQueue.size() > 0); |
548 | return (myInQueue.size() > 0); |
| 460 | } |
549 | } |
| 461 | 550 | ||
| 462 | string AsyncSocket::getData() |
551 | string AsyncSocket::getData() |
| 463 | { |
552 | { |
| 464 | return myInQueue.pop(); |
553 | return myInQueue.pop(); |
| 465 | } |
554 | } |
| 466 | 555 | ||
| 467 | bool AsyncSocket::sendData(string data) |
556 | bool AsyncSocket::sendData(string data) |
| 468 | { |
557 | { |
| 469 | myOutQueue.push(data); |
558 | myOutQueue.push(data); |
| 470 | mySemaphore.broadcast(); |
559 | mySemaphore.broadcast(); |
| 471 | return true; |
560 | return true; |
| - | 561 | } |
|
| - | 562 | ||
| - | 563 | void AsyncSocket::sendDataDirect(string data) |
|
| - | 564 | { |
|
| - | 565 | SyslogStream &slog = SyslogStream::getInstance(); |
|
| - | 566 | ||
| - | 567 | //slog << "Sending: " << data << "\n"; |
|
| - | 568 | ||
| - | 569 | int status = ::send(mySocket, data.c_str(), data.size(), 0); |
|
| - | 570 | ||
| - | 571 | //slog << "Status: " << status << "\n"; |
|
| - | 572 | ||
| - | 573 | if (status == -1) |
|
| - | 574 | { |
|
| - | 575 | switch (errno) |
|
| - | 576 | { |
|
| - | 577 | 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).)"); |
|
| - | 579 | ||
| - | 580 | case EAGAIN: |
|
| - | 581 | //slog << "The socket is marked non-blocking and the requested operation would block.\n"; |
|
| - | 582 | break; |
|
| - | 583 | ||
| - | 584 | case EBADF: |
|
| - | 585 | throw new SocketException("An invalid descriptor was specified."); |
|
| - | 586 | ||
| - | 587 | case ECONNRESET: |
|
| - | 588 | throw new SocketException("Connection reset by peer."); |
|
| - | 589 | ||
| - | 590 | case EDESTADDRREQ: |
|
| - | 591 | throw new SocketException("The socket is not connection-mode, and no peer address is set."); |
|
| - | 592 | ||
| - | 593 | case EFAULT: |
|
| - | 594 | throw new SocketException("An invalid user space address was specified for an argument."); |
|
| - | 595 | ||
| - | 596 | case EINTR: |
|
| - | 597 | throw new SocketException("A signal occurred before any data was transmitted; see signal(7)."); |
|
| - | 598 | ||
| - | 599 | case EINVAL: |
|
| - | 600 | throw new SocketException("1Invalid argument passed."); |
|
| - | 601 | ||
| - | 602 | 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.)"); |
|
| - | 604 | ||
| - | 605 | case EMSGSIZE: |
|
| - | 606 | throw new SocketException("The socket type requires that message be sent atomically, and the size of the message to be sent made this impossible."); |
|
| - | 607 | ||
| - | 608 | case ENOBUFS: |
|
| - | 609 | throw new SocketException("The output queue for a network interface was full. This generally indicates that the interface has stopped sending, but may be caused by transient congestion. (Normally, this does not occur in Linux. Packets are just silently dropped when a device queue overflows.)"); |
|
| - | 610 | ||
| - | 611 | case ENOMEM: |
|
| - | 612 | throw new SocketException("No memory available."); |
|
| - | 613 | ||
| - | 614 | case ENOTCONN: |
|
| - | 615 | throw new SocketException("The socket is not connected, and no target has been given."); |
|
| - | 616 | ||
| - | 617 | case ENOTSOCK: |
|
| - | 618 | throw new SocketException("The argument s is not a socket."); |
|
| - | 619 | ||
| - | 620 | case EOPNOTSUPP: |
|
| - | 621 | throw new SocketException("Some bit in the flags argument is inappropriate for the socket type."); |
|
| - | 622 | ||
| - | 623 | 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."); |
|
| - | 625 | ||
| - | 626 | default: |
|
| - | 627 | slog << "Unknow exception: " + itos(errno) + "\n"; |
|
| - | 628 | break; |
|
| - | 629 | } |
|
| - | 630 | } |
|
| 472 | } |
631 | } |
| 473 | 632 | ||
| 474 | void AsyncSocket::setEvent(int event) |
633 | void AsyncSocket::setEvent(int event) |
| 475 | { |
634 | { |
| 476 | myEventSemaphore.lock(); |
635 | myEventSemaphore.lock(); |
| 477 | myEvent = event; |
636 | myEvent = event; |
| Line 486... | Line 645... | ||
| 486 | } |
645 | } |
| 487 | 646 | ||
| 488 | void AsyncSocket::signalHandler(int signum) |
647 | void AsyncSocket::signalHandler(int signum) |
| 489 | { |
648 | { |
| 490 | //FIXME: We must know which socket is ready to read by using select... |
649 | //FIXME: We must know which socket is ready to read by using select... |
| 491 |
|
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; |
|
| 492 | mySemaphore.broadcast(); |
658 | iter->second->mySemaphore.broadcast(); |
| - | 659 | } |
|
| - | 660 | mySocketsMutex.unlock(); |
|
| - | 661 | ||
| 493 | } |
662 | } |