Rev 984 | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | SVN | RSS feed
| Rev 984 | Rev 999 | ||
|---|---|---|---|
| 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 "socketeventcallback.h" |
|
| - | 23 | ||
| 21 | 24 | ||
| 22 | #include "asyncsocket.h" |
25 | #include "asyncsocket.h" |
| 23 | 26 | ||
| 24 | int socketCount = 1; |
27 | int socketCount = 1; |
| 25 | 28 | ||
| Line 27... | Line 30... | ||
| 27 | { |
30 | { |
| 28 | myId = socketCount++; |
31 | myId = socketCount++; |
| 29 | mySocket = -1; |
32 | mySocket = -1; |
| 30 | myReconnectTimeout = 0; |
33 | myReconnectTimeout = 0; |
| 31 | myForceReconnect = false; |
34 | myForceReconnect = false; |
| - | 35 | myEventCallback = NULL; |
|
| 32 | } |
36 | } |
| 33 | 37 | ||
| 34 | AsyncSocket::~AsyncSocket() |
38 | AsyncSocket::~AsyncSocket() |
| 35 | { |
39 | { |
| 36 | stop(); |
40 | stop(); |
| Line 45... | Line 49... | ||
| 45 | // If we have choosen to not use automatic reconnect do not start reconnect loop |
49 | // If we have choosen to not use automatic reconnect do not start reconnect loop |
| 46 | if (myReconnectTimeout == 0) |
50 | if (myReconnectTimeout == 0) |
| 47 | { |
51 | { |
| 48 | // Connect to somewhere |
52 | // Connect to somewhere |
| 49 | connect(); |
53 | connect(); |
| 50 | } |
54 | } |
| 51 | else |
55 | else |
| 52 | { |
56 | { |
| 53 | // Start the reconnect loop |
57 | // Start the reconnect loop |
| 54 | reconnectLoop(); |
58 | reconnectLoop(); |
| 55 | } |
59 | } |
| 56 | } |
60 | } |
| 57 | 61 | ||
| 58 | bool loop = true; |
62 | bool loop = true; |
| 59 | try |
63 | try |
| 60 | { |
64 | { |
| 61 | while (loop) |
65 | while (loop) |
| 62 | { |
66 | { |
| Line 73... | Line 77... | ||
| 73 | } |
77 | } |
| 74 | catch (SocketException *e) |
78 | catch (SocketException *e) |
| 75 | { |
79 | { |
| 76 | // Something bad happend and we can not continue |
80 | // Something bad happend and we can not continue |
| 77 | eventAdd(SocketEvent::TYPE_CONNECTION_DIED, e->getDescription()); |
81 | eventAdd(SocketEvent::TYPE_CONNECTION_DIED, e->getDescription()); |
| 78 | } |
82 | } |
| 79 | 83 | ||
| 80 | // Clean up socket if we would want to restart |
84 | // Clean up socket if we would want to restart |
| 81 | silentClose(); |
85 | silentClose(); |
| 82 | } |
86 | } |
| 83 | 87 | ||
| Line 107... | Line 111... | ||
| 107 | case EINTR: |
111 | case EINTR: |
| 108 | throw new SocketException("The receive was interrupted by delivery of a signal before any data were available; see signal(7)."); |
112 | throw new SocketException("The receive was interrupted by delivery of a signal before any data were available; see signal(7)."); |
| 109 | 113 | ||
| 110 | case EINVAL: |
114 | case EINVAL: |
| 111 | throw new SocketException("Invalid argument passed."); |
115 | throw new SocketException("Invalid argument passed."); |
| 112 | 116 | ||
| 113 | case ENOMEM: |
117 | case ENOMEM: |
| 114 | throw new SocketException("Could not allocate memory for recvmsg()."); |
118 | throw new SocketException("Could not allocate memory for recvmsg()."); |
| 115 | 119 | ||
| 116 | case ENOTCONN: |
120 | case ENOTCONN: |
| 117 | throw new SocketException("The socket is associated with a connection-oriented protocol and has not been connected (see connect(2) and accept(2))."); |
121 | throw new SocketException("The socket is associated with a connection-oriented protocol and has not been connected (see connect(2) and accept(2))."); |
| Line 128... | Line 132... | ||
| 128 | reconnectLoop(); |
132 | reconnectLoop(); |
| 129 | } |
133 | } |
| 130 | else |
134 | else |
| 131 | { |
135 | { |
| 132 | // Otherwise we would like to end the main loop |
136 | // Otherwise we would like to end the main loop |
| 133 | return false; |
137 | return false; |
| 134 | } |
138 | } |
| 135 | break; |
139 | break; |
| 136 | 140 | ||
| 137 | default: |
141 | default: |
| 138 | throw new SocketException("Unknow exception: " + itos(errno)); |
142 | throw new SocketException("Unknow exception: " + itos(errno)); |
| 139 | break; |
143 | break; |
| 140 | } |
144 | } |
| 141 | } |
145 | } |
| 142 | else if (status == 0) |
146 | else if (status == 0) |
| 143 | { |
147 | { |
| 144 | // Remote host have done a normal shutdown |
148 | // Remote host have done a normal shutdown |
| 145 | eventAdd(SocketEvent::TYPE_CONNECTION_CLOSED); |
149 | eventAdd(SocketEvent::TYPE_CONNECTION_CLOSED); |
| 146 | 150 | ||
| 147 | if (myReconnectTimeout > 0) |
151 | if (myReconnectTimeout > 0) |
| 148 | { |
152 | { |
| 149 | reconnectLoop(); |
153 | reconnectLoop(); |
| 150 | } |
154 | } |
| 151 | else |
155 | else |
| 152 | { |
156 | { |
| 153 | return false; |
157 | return false; |
| 154 | } |
158 | } |
| 155 | } |
159 | } |
| 156 | else if (status > 0) |
160 | else if (status > 0) |
| 157 | { |
161 | { |
| 158 | // We have received data |
162 | // We have received data |
| 159 | eventAdd(SocketEvent::TYPE_DATA, buffer); |
163 | eventAdd(SocketEvent::TYPE_DATA, buffer); |
| 160 | } |
164 | } |
| Line 178... | Line 182... | ||
| 178 | } |
182 | } |
| 179 | 183 | ||
| 180 | void AsyncSocket::reconnectLoop() |
184 | void AsyncSocket::reconnectLoop() |
| 181 | { |
185 | { |
| 182 | while (true) |
186 | while (true) |
| 183 | { |
187 | { |
| 184 | try |
188 | try |
| 185 | { |
189 | { |
| 186 | connect(); |
190 | connect(); |
| 187 | return; |
191 | return; |
| 188 | } |
192 | } |
| 189 | catch (SocketException *e) |
193 | catch (SocketException *e) |
| 190 | { |
194 | { |
| 191 | eventAdd(SocketEvent::TYPE_CONNECTION_FAILED, e->getDescription()); |
195 | eventAdd(SocketEvent::TYPE_CONNECTION_FAILED, e->getDescription()); |
| 192 | eventAdd(SocketEvent::TYPE_WAITING_RECONNECT); |
196 | eventAdd(SocketEvent::TYPE_WAITING_RECONNECT); |
| 193 | sleep(myReconnectTimeout); |
197 | sleep(myReconnectTimeout); |
| 194 | } |
198 | } |
| 195 | } |
199 | } |
| Line 297... | Line 301... | ||
| 297 | 301 | ||
| 298 | default: |
302 | default: |
| 299 | throw new SocketException("Unknow exception: " + itos(errno)); |
303 | throw new SocketException("Unknow exception: " + itos(errno)); |
| 300 | break; |
304 | break; |
| 301 | } |
305 | } |
| 302 | } |
306 | } |
| 303 | } |
307 | } |
| 304 | 308 | ||
| 305 | bool AsyncSocket::accept(AsyncSocket* newSocket) |
309 | bool AsyncSocket::accept(AsyncSocket* newSocket) |
| 306 | { |
310 | { |
| 307 | int addr_length = sizeof(myAddressStruct); |
311 | int addr_length = sizeof(myAddressStruct); |
| 308 | int socket = ::accept(mySocket, (sockaddr*)&myAddressStruct, (socklen_t*)&addr_length); |
312 | int socket = ::accept(mySocket, (sockaddr*)&myAddressStruct, (socklen_t*)&addr_length); |
| Line 312... | Line 316... | ||
| 312 | newSocket->setSocket(socket); |
316 | newSocket->setSocket(socket); |
| 313 | return true; |
317 | return true; |
| 314 | } |
318 | } |
| 315 | 319 | ||
| 316 | return false; |
320 | return false; |
| 317 | } |
321 | } |
| 318 | 322 | ||
| 319 | void AsyncSocket::connect() |
323 | void AsyncSocket::connect() |
| 320 | { |
324 | { |
| 321 | eventAdd(SocketEvent::TYPE_CONNECTING); |
325 | eventAdd(SocketEvent::TYPE_CONNECTING); |
| 322 | 326 | ||
| 323 | create(); |
327 | create(); |
| 324 | 328 | ||
| 325 | memset(&myAddressStruct, 0, sizeof(myAddressStruct)); |
329 | memset(&myAddressStruct, 0, sizeof(myAddressStruct)); |
| 326 | 330 | ||
| 327 | myAddressStruct.sin_family = AF_INET; |
331 | myAddressStruct.sin_family = AF_INET; |
| 328 | myAddressStruct.sin_port = htons(myPort); |
332 | myAddressStruct.sin_port = htons(myPort); |
| 329 | 333 | ||
| Line 333... | Line 337... | ||
| 333 | silentClose(); |
337 | silentClose(); |
| 334 | throw new SocketException("Connect: Could not resolv ip address"); |
338 | throw new SocketException("Connect: Could not resolv ip address"); |
| 335 | } |
339 | } |
| 336 | 340 | ||
| 337 | memcpy(&myAddressStruct.sin_addr, hptr->h_addr, hptr->h_length); |
341 | memcpy(&myAddressStruct.sin_addr, hptr->h_addr, hptr->h_length); |
| 338 | 342 | ||
| 339 | int status = ::connect(mySocket, (sockaddr*)&myAddressStruct, sizeof(myAddressStruct)); |
343 | int status = ::connect(mySocket, (sockaddr*)&myAddressStruct, sizeof(myAddressStruct)); |
| 340 | 344 | ||
| 341 | if (status == -1) |
345 | if (status == -1) |
| 342 | { |
346 | { |
| 343 | silentClose(); |
347 | silentClose(); |
| Line 352... | Line 356... | ||
| 352 | case EADDRINUSE: |
356 | case EADDRINUSE: |
| 353 | throw new SocketException("Local address is already in use."); |
357 | throw new SocketException("Local address is already in use."); |
| 354 | 358 | ||
| 355 | case EAFNOSUPPORT: |
359 | case EAFNOSUPPORT: |
| 356 | throw new SocketException("The passed address didn't have the correct address family in its sa_family field."); |
360 | throw new SocketException("The passed address didn't have the correct address family in its sa_family field."); |
| 357 | 361 | ||
| 358 | case EAGAIN: |
362 | case EAGAIN: |
| 359 | 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."); |
363 | 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."); |
| 360 | 364 | ||
| 361 | case EALREADY: |
365 | case EALREADY: |
| 362 | throw new SocketException("The socket is non-blocking and a previous connection attempt has not yet been completed."); |
366 | throw new SocketException("The socket is non-blocking and a previous connection attempt has not yet been completed."); |
| 363 | 367 | ||
| Line 464... | Line 468... | ||
| 464 | } |
468 | } |
| 465 | 469 | ||
| 466 | void AsyncSocket::eventAdd(unsigned int eventType, string eventData) |
470 | void AsyncSocket::eventAdd(unsigned int eventType, string eventData) |
| 467 | { |
471 | { |
| 468 | SocketEvent socketEvent(eventType, eventData); |
472 | SocketEvent socketEvent(eventType, eventData); |
| - | 473 | ||
| - | 474 | if (myEventCallback == NULL) |
|
| - | 475 | { |
|
| 469 | myEventQueue.push(socketEvent); |
476 | myEventQueue.push(socketEvent); |
| 470 | myEventSemaphore.broadcast(); |
477 | myEventSemaphore.broadcast(); |
| - | 478 | } |
|
| - | 479 | else |
|
| - | 480 | { |
|
| - | 481 | myEventCallback->handleEvent(myId, socketEvent); |
|
| - | 482 | } |
|
| - | 483 | } |
|
| - | 484 | ||
| - | 485 | void AsyncSocket::eventSetCallback(SocketEventCallback* eventCallback) |
|
| - | 486 | { |
|
| - | 487 | myEventCallback = eventCallback; |
|
| 471 | } |
488 | } |