Subversion Repositories HomeAutomation

Rev

Rev 984 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | SVN | RSS feed

Rev 984 Rev 999
1
/***************************************************************************
1
/***************************************************************************
2
 *  Copyright (C) December 6, 2008 by Mattias Runge               *
2
 *  Copyright (C) December 6, 2008 by Mattias Runge               *
3
 *  mattias@runge.se                           *
3
 *  mattias@runge.se                           *
4
 *  asyncsocket.cpp                      *
4
 *  asyncsocket.cpp                      *
5
 *                                     *
5
 *                                     *
6
 *  This program is free software; you can redistribute it and/or modify *
6
 *  This program is free software; you can redistribute it and/or modify *
7
 *  it under the terms of the GNU General Public License as published by *
7
 *  it under the terms of the GNU General Public License as published by *
8
 *  the Free Software Foundation; either version 2 of the License, or   *
8
 *  the Free Software Foundation; either version 2 of the License, or   *
9
 *  (at your option) any later version.                  *
9
 *  (at your option) any later version.                  *
10
 *                                     *
10
 *                                     *
11
 *  This program is distributed in the hope that it will be useful,    *
11
 *  This program is distributed in the hope that it will be useful,    *
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of    *
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of    *
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the     *
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the     *
14
 *  GNU General Public License for more details.             *
14
 *  GNU General Public License for more details.             *
15
 *                                     *
15
 *                                     *
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
 
26
AsyncSocket::AsyncSocket()
29
AsyncSocket::AsyncSocket()
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();
37
    silentClose();
41
    silentClose();
38
}
42
}
39
 
43
 
40
void AsyncSocket::run()
44
void AsyncSocket::run()
41
{
45
{
42
    // If connection is already up then we should not connect again
46
    // If connection is already up then we should not connect again
43
    if (!isConnected())
47
    if (!isConnected())
44
    {
48
    {
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
        {
63
            // If we have triggered a forced reconnect do it here
67
            // If we have triggered a forced reconnect do it here
64
            if (myForceReconnect)
68
            if (myForceReconnect)
65
            {
69
            {
66
                myForceReconnect = false;
70
                myForceReconnect = false;
67
                reconnectLoop();
71
                reconnectLoop();
68
            }
72
            }
69
 
73
 
70
            // Receive data
74
            // Receive data
71
            loop = receiveData();
75
            loop = receiveData();
72
        }
76
        }
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
 
84
bool AsyncSocket::receiveData()
88
bool AsyncSocket::receiveData()
85
{
89
{
86
    char buffer[MAXBUFFER + 1];
90
    char buffer[MAXBUFFER + 1];
87
    memset(buffer, 0, MAXBUFFER + 1);
91
    memset(buffer, 0, MAXBUFFER + 1);
88
 
92
 
89
    int status = ::recv(mySocket, buffer, MAXBUFFER, 0);
93
    int status = ::recv(mySocket, buffer, MAXBUFFER, 0);
90
 
94
 
91
    if (status == -1)
95
    if (status == -1)
92
    {
96
    {
93
        switch (errno)
97
        switch (errno)
94
        {
98
        {
95
            case EAGAIN:
99
            case EAGAIN:
96
            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.");
100
            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.");
97
 
101
 
98
            case EBADF:
102
            case EBADF:
99
            throw new SocketException("The argument s is an invalid descriptor.");
103
            throw new SocketException("The argument s is an invalid descriptor.");
100
 
104
 
101
            case ECONNREFUSED:
105
            case ECONNREFUSED:
102
            throw new SocketException("A remote host refused to allow the network connection (typically because it is not running the requested service).");
106
            throw new SocketException("A remote host refused to allow the network connection (typically because it is not running the requested service).");
103
 
107
 
104
            case EFAULT:
108
            case EFAULT:
105
            throw new SocketException("The receive buffer pointer(s) point outside the process's address space.");
109
            throw new SocketException("The receive buffer pointer(s) point outside the process's address space.");
106
 
110
 
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)).");
118
 
122
 
119
            case ENOTSOCK:
123
            case ENOTSOCK:
120
            throw new SocketException("The argument s does not refer to a socket.");
124
            throw new SocketException("The argument s does not refer to a socket.");
121
 
125
 
122
            case ECONNRESET:
126
            case ECONNRESET:
123
            eventAdd(SocketEvent::TYPE_CONNECTION_RESET);
127
            eventAdd(SocketEvent::TYPE_CONNECTION_RESET);
124
 
128
 
125
            // If we have automatic reconnect we want to start it now
129
            // If we have automatic reconnect we want to start it now
126
            if (myReconnectTimeout == 0)
130
            if (myReconnectTimeout == 0)
127
            {
131
            {
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
    }
161
 
165
 
162
    return true;
166
    return true;
163
}
167
}
164
 
168
 
165
void AsyncSocket::silentClose()
169
void AsyncSocket::silentClose()
166
{
170
{
167
    if (mySocket != -1)
171
    if (mySocket != -1)
168
    {
172
    {
169
        ::close(mySocket);
173
        ::close(mySocket);
170
        mySocket = -1;
174
        mySocket = -1;
171
    }
175
    }
172
}
176
}
173
 
177
 
174
void AsyncSocket::close()
178
void AsyncSocket::close()
175
{
179
{
176
    silentClose();
180
    silentClose();
177
    eventAdd(SocketEvent::TYPE_CONNECTION_CLOSED);
181
    eventAdd(SocketEvent::TYPE_CONNECTION_CLOSED);
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
    }
196
}
200
}
197
 
201
 
198
void AsyncSocket::create()
202
void AsyncSocket::create()
199
{
203
{
200
    silentClose();
204
    silentClose();
201
 
205
 
202
    mySocket = ::socket(AF_INET, SOCK_STREAM, 0);
206
    mySocket = ::socket(AF_INET, SOCK_STREAM, 0);
203
 
207
 
204
    int on = 1;
208
    int on = 1;
205
    int status = setsockopt(mySocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on));
209
    int status = setsockopt(mySocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on));
206
    if (status == -1)
210
    if (status == -1)
207
    {
211
    {
208
        silentClose();
212
        silentClose();
209
        throw new SocketException("Create:Reuseaddress: " + itos(errno));
213
        throw new SocketException("Create:Reuseaddress: " + itos(errno));
210
    }
214
    }
211
}
215
}
212
 
216
 
213
void AsyncSocket::startListen()
217
void AsyncSocket::startListen()
214
{
218
{
215
    create();
219
    create();
216
 
220
 
217
    myAddressStruct.sin_family = AF_INET;
221
    myAddressStruct.sin_family = AF_INET;
218
    myAddressStruct.sin_addr.s_addr = INADDR_ANY;
222
    myAddressStruct.sin_addr.s_addr = INADDR_ANY;
219
    myAddressStruct.sin_port = htons(myPort);
223
    myAddressStruct.sin_port = htons(myPort);
220
 
224
 
221
    int status = ::bind(mySocket, (struct sockaddr *)&myAddressStruct, sizeof(myAddressStruct));
225
    int status = ::bind(mySocket, (struct sockaddr *)&myAddressStruct, sizeof(myAddressStruct));
222
 
226
 
223
    if (status == -1)
227
    if (status == -1)
224
    {
228
    {
225
        silentClose();
229
        silentClose();
226
        switch (errno)
230
        switch (errno)
227
        {
231
        {
228
            case EACCES:
232
            case EACCES:
229
            throw new SocketException("The address is protected, and the user is not the superuser.");
233
            throw new SocketException("The address is protected, and the user is not the superuser.");
230
 
234
 
231
            case EADDRINUSE:
235
            case EADDRINUSE:
232
            throw new SocketException("The given address is already in use.");
236
            throw new SocketException("The given address is already in use.");
233
 
237
 
234
            case EBADF:
238
            case EBADF:
235
            throw new SocketException("sockfd is not a valid descriptor.");
239
            throw new SocketException("sockfd is not a valid descriptor.");
236
 
240
 
237
            case EINVAL:
241
            case EINVAL:
238
            throw new SocketException("The socket is already bound to an address.");
242
            throw new SocketException("The socket is already bound to an address.");
239
 
243
 
240
            case ENOTSOCK:
244
            case ENOTSOCK:
241
            throw new SocketException("sockfd is a descriptor for a file, not a socket.");
245
            throw new SocketException("sockfd is a descriptor for a file, not a socket.");
242
 
246
 
243
            //case EACCES:
247
            //case EACCES:
244
            //throw new SocketException("Search permission is denied on a component of the path prefix. (See also path_resolution(7).)");
248
            //throw new SocketException("Search permission is denied on a component of the path prefix. (See also path_resolution(7).)");
245
 
249
 
246
            case EADDRNOTAVAIL:
250
            case EADDRNOTAVAIL:
247
            throw new SocketException("A nonexistent interface was requested or the requested address was not local.");
251
            throw new SocketException("A nonexistent interface was requested or the requested address was not local.");
248
 
252
 
249
            case EFAULT:
253
            case EFAULT:
250
            throw new SocketException("addr points outside the user's accessible address space.");
254
            throw new SocketException("addr points outside the user's accessible address space.");
251
 
255
 
252
            //case EINVAL:
256
            //case EINVAL:
253
            //throw new SocketException("The addrlen is wrong, or the socket was not in the AF_UNIX family.");
257
            //throw new SocketException("The addrlen is wrong, or the socket was not in the AF_UNIX family.");
254
 
258
 
255
            case ELOOP:
259
            case ELOOP:
256
            throw new SocketException("Too many symbolic links were encountered in resolving addr.");
260
            throw new SocketException("Too many symbolic links were encountered in resolving addr.");
257
 
261
 
258
            case ENAMETOOLONG:
262
            case ENAMETOOLONG:
259
            throw new SocketException("addr is too long.");
263
            throw new SocketException("addr is too long.");
260
 
264
 
261
            case ENOENT:
265
            case ENOENT:
262
            throw new SocketException("The file does not exist.");
266
            throw new SocketException("The file does not exist.");
263
 
267
 
264
            case ENOMEM:
268
            case ENOMEM:
265
            throw new SocketException("Insufficient kernel memory was available.");
269
            throw new SocketException("Insufficient kernel memory was available.");
266
 
270
 
267
            case ENOTDIR:
271
            case ENOTDIR:
268
            throw new SocketException("A component of the path prefix is not a directory.");
272
            throw new SocketException("A component of the path prefix is not a directory.");
269
 
273
 
270
            case EROFS:
274
            case EROFS:
271
            throw new SocketException("The socket inode would reside on a read-only file system.");
275
            throw new SocketException("The socket inode would reside on a read-only file system.");
272
 
276
 
273
            default:
277
            default:
274
            throw new SocketException("Unknow exception: " + itos(errno));
278
            throw new SocketException("Unknow exception: " + itos(errno));
275
            break;
279
            break;
276
        }
280
        }
277
    }
281
    }
278
 
282
 
279
    status = ::listen(mySocket, MAXCONNECTIONS);
283
    status = ::listen(mySocket, MAXCONNECTIONS);
280
 
284
 
281
    if (status == -1)
285
    if (status == -1)
282
    {
286
    {
283
        silentClose();
287
        silentClose();
284
        switch (errno)
288
        switch (errno)
285
        {
289
        {
286
            case EADDRINUSE:
290
            case EADDRINUSE:
287
            throw new SocketException("Another socket is already listening on the same port.");
291
            throw new SocketException("Another socket is already listening on the same port.");
288
 
292
 
289
            case EBADF:
293
            case EBADF:
290
            throw new SocketException("The argument sockfd is not a valid descriptor.");
294
            throw new SocketException("The argument sockfd is not a valid descriptor.");
291
 
295
 
292
            case ENOTSOCK:
296
            case ENOTSOCK:
293
            throw new SocketException("The argument sockfd is not a socket.");
297
            throw new SocketException("The argument sockfd is not a socket.");
294
 
298
 
295
            case EOPNOTSUPP:
299
            case EOPNOTSUPP:
296
            throw new SocketException("The socket is not of a type that supports the listen() operation.");
300
            throw new SocketException("The socket is not of a type that supports the listen() operation.");
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);
309
 
313
 
310
    if (socket > 0)
314
    if (socket > 0)
311
    {
315
    {
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
 
330
    struct hostent *hptr = gethostbyname(myAddress.c_str());
334
    struct hostent *hptr = gethostbyname(myAddress.c_str());
331
    if (hptr == NULL)
335
    if (hptr == NULL)
332
    {
336
    {
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();
344
        switch (errno)
348
        switch (errno)
345
        {
349
        {
346
            case EACCES:
350
            case EACCES:
347
            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).)");
351
            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).)");
348
 
352
 
349
            case EPERM:
353
            case EPERM:
350
            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.");
354
            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.");
351
 
355
 
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
 
364
            case EBADF:
368
            case EBADF:
365
            throw new SocketException("The file descriptor is not a valid index in the descriptor table.");
369
            throw new SocketException("The file descriptor is not a valid index in the descriptor table.");
366
 
370
 
367
            case ECONNREFUSED:
371
            case ECONNREFUSED:
368
            throw new SocketException("No-one listening on the remote address.");
372
            throw new SocketException("No-one listening on the remote address.");
369
 
373
 
370
            case EFAULT:
374
            case EFAULT:
371
            throw new SocketException("The socket structure address is outside the user's address space.");
375
            throw new SocketException("The socket structure address is outside the user's address space.");
372
 
376
 
373
            case EINPROGRESS:
377
            case EINPROGRESS:
374
            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).");
378
            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).");
375
 
379
 
376
            case EINTR:
380
            case EINTR:
377
            throw new SocketException("The system call was interrupted by a signal that was caught; see signal(7).");
381
            throw new SocketException("The system call was interrupted by a signal that was caught; see signal(7).");
378
 
382
 
379
            case EISCONN:
383
            case EISCONN:
380
            throw new SocketException("The socket is already connected.");
384
            throw new SocketException("The socket is already connected.");
381
 
385
 
382
            case ENETUNREACH:
386
            case ENETUNREACH:
383
            throw new SocketException("Network is unreachable.");
387
            throw new SocketException("Network is unreachable.");
384
 
388
 
385
            case ENOTSOCK:
389
            case ENOTSOCK:
386
            throw new SocketException("The file descriptor is not associated with a socket.");
390
            throw new SocketException("The file descriptor is not associated with a socket.");
387
 
391
 
388
            case ETIMEDOUT:
392
            case ETIMEDOUT:
389
            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.");
393
            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.");
390
 
394
 
391
            default:
395
            default:
392
            throw new SocketException("Other errors may be generated by the underlying protocol modules. : " + itos(errno));
396
            throw new SocketException("Other errors may be generated by the underlying protocol modules. : " + itos(errno));
393
        }
397
        }
394
    }
398
    }
395
 
399
 
396
    eventAdd(SocketEvent::TYPE_CONNECTED);
400
    eventAdd(SocketEvent::TYPE_CONNECTED);
397
}
401
}
398
 
402
 
399
void AsyncSocket::sendData(string data)
403
void AsyncSocket::sendData(string data)
400
{
404
{
401
    int status = ::send(mySocket, data.c_str(), data.size(), 0);
405
    int status = ::send(mySocket, data.c_str(), data.size(), 0);
402
 
406
 
403
    if (status == -1)
407
    if (status == -1)
404
    {
408
    {
405
        switch (errno)
409
        switch (errno)
406
        {
410
        {
407
            case EACCES:
411
            case EACCES:
408
            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).)");
412
            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).)");
409
 
413
 
410
            case EAGAIN:
414
            case EAGAIN:
411
            throw new SocketException("The socket is marked non-blocking and the requested operation would block.");
415
            throw new SocketException("The socket is marked non-blocking and the requested operation would block.");
412
 
416
 
413
            case EBADF:
417
            case EBADF:
414
            throw new SocketException("An invalid descriptor was specified.");
418
            throw new SocketException("An invalid descriptor was specified.");
415
 
419
 
416
            case ECONNRESET:
420
            case ECONNRESET:
417
            throw new SocketException("Connection reset by peer.");
421
            throw new SocketException("Connection reset by peer.");
418
 
422
 
419
            case EDESTADDRREQ:
423
            case EDESTADDRREQ:
420
            throw new SocketException("The socket is not connection-mode, and no peer address is set.");
424
            throw new SocketException("The socket is not connection-mode, and no peer address is set.");
421
 
425
 
422
            case EFAULT:
426
            case EFAULT:
423
            throw new SocketException("An invalid user space address was specified for an argument.");
427
            throw new SocketException("An invalid user space address was specified for an argument.");
424
 
428
 
425
            case EINTR:
429
            case EINTR:
426
            throw new SocketException("A signal occurred before any data was transmitted; see signal(7).");
430
            throw new SocketException("A signal occurred before any data was transmitted; see signal(7).");
427
 
431
 
428
            case EINVAL:
432
            case EINVAL:
429
            throw new SocketException("1Invalid argument passed.");
433
            throw new SocketException("1Invalid argument passed.");
430
 
434
 
431
            case EISCONN:
435
            case EISCONN:
432
            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.)");
436
            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.)");
433
 
437
 
434
            case EMSGSIZE:
438
            case EMSGSIZE:
435
            throw new SocketException("The socket type requires that message be sent atomically, and the size of the message to be sent made this impossible.");
439
            throw new SocketException("The socket type requires that message be sent atomically, and the size of the message to be sent made this impossible.");
436
 
440
 
437
            case ENOBUFS:
441
            case ENOBUFS:
438
            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.)");
442
            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.)");
439
 
443
 
440
            case ENOMEM:
444
            case ENOMEM:
441
            throw new SocketException("No memory available.");
445
            throw new SocketException("No memory available.");
442
 
446
 
443
            case ENOTCONN:
447
            case ENOTCONN:
444
            throw new SocketException("The socket is not connected, and no target has been given.");
448
            throw new SocketException("The socket is not connected, and no target has been given.");
445
 
449
 
446
            case ENOTSOCK:
450
            case ENOTSOCK:
447
            throw new SocketException("The argument s is not a socket.");
451
            throw new SocketException("The argument s is not a socket.");
448
 
452
 
449
            case EOPNOTSUPP:
453
            case EOPNOTSUPP:
450
            throw new SocketException("Some bit in the flags argument is inappropriate for the socket type.");
454
            throw new SocketException("Some bit in the flags argument is inappropriate for the socket type.");
451
 
455
 
452
            case EPIPE:
456
            case EPIPE:
453
            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.");
457
            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.");
454
 
458
 
455
            default:
459
            default:
456
            throw new SocketException("Unknow exception: " + itos(errno));
460
            throw new SocketException("Unknow exception: " + itos(errno));
457
        }
461
        }
458
    }
462
    }
459
}
463
}
460
 
464
 
461
void AsyncSocket::eventAdd(unsigned int eventType)
465
void AsyncSocket::eventAdd(unsigned int eventType)
462
{
466
{
463
    eventAdd(eventType, "");
467
    eventAdd(eventType, "");
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
}
472
 
489