Subversion Repositories HomeAutomation

Rev

Rev 981 | Show entire file | Ignore 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
Mutex AsyncSocket::mySocketsMutex;
24
int socketCount = 1;
32
 
25
 
33
AsyncSocket::AsyncSocket()
26
AsyncSocket::AsyncSocket()
34
{
27
{
35
    myId = itos(time(NULL)) + itos(mySockets.size());
-
 
36
 
-
 
37
    mySockets[myId] = this;
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
Line 78... Line 60...
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 (1)
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
 
-
 
76
            memset(buf, 0, MAXBUFFER + 1);
104
            //cout << "Socket awoken...\n";
77
            status = ::recv(mySocket, buf, MAXBUFFER, 0);
105
           
78
 
106
            if (rc == ETIMEDOUT)
79
            if (status == -1)
107
            {
80
            {
-
 
81
                switch (errno)
-
 
82
                {
-
 
83
                    case EAGAIN:
108
                /* Socket timed out, this means we have not received anything in some time
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.");
-
 
85
                    break;
-
 
86
 
-
 
87
                    case EBADF:
109
                and we should check the connection */
88
                    throw new SocketException("The argument s is an invalid descriptor.");
110
 
89
 
111
                setEvent(ASYNCSOCKET_EVENT_INACTIVITY);
-
 
112
                timeSince = time(NULL);
90
                    case ECONNREFUSED:
-
 
91
                    throw new SocketException("A remote host refused to allow the network connection (typically because it is not running the requested service).");
113
            }
92
 
114
            else
93
                    case EFAULT:
115
            {
-
 
116
                while (myOutQueue.size() > 0)
94
                    throw new SocketException("The receive buffer pointer(s) point outside the process's address space.");
117
                {
95
 
118
                    data = myOutQueue.pop();
96
                    case EINTR:
-
 
97
                    throw new SocketException("The receive was interrupted by delivery of a signal before any data were available; see signal(7).");
119
 
98
 
120
                    sendDataDirect(data);
99
                    case EINVAL:
-
 
100
                    throw new SocketException("Invalid argument passed.");
121
                }
101
                    break;
122
 
102
 
123
                memset(buf, 0, MAXBUFFER + 1);
103
                    case ENOMEM:
-
 
104
                    throw new SocketException("Could not allocate memory for recvmsg().");
124
 
105
 
125
                status = ::recv(mySocket, buf, MAXBUFFER, 0);
106
                    case ENOTCONN:
-
 
107
                    throw new SocketException("The socket is associated with a connection-oriented protocol and has not been connected (see connect(2) and  accept(2)).");
126
 
108
 
127
                if (status == -1)
109
                    case ENOTSOCK:
-
 
110
                    throw new SocketException("The argument s does not refer to a socket.");
128
                {
111
 
129
                    switch (errno)
112
                    case ECONNRESET:
-
 
113
                    setEvent(ASYNCSOCKET_EVENT_RESET);
-
 
114
                    if (myReconnectTimeout > 0)
130
                    {
115
                    {
131
                        case EAGAIN:
-
 
132
                        //slog << "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.\n";
-
 
133
                        break;
-
 
134
 
-
 
135
                        case EBADF:
-
 
136
                        throw new SocketException("The argument s is an invalid descriptor.");
-
 
137
 
-
 
138
                        case ECONNREFUSED:
-
 
139
                        throw new SocketException("A remote host refused to allow the network connection (typically because it is not running the requested service).");
-
 
140
 
-
 
141
                        case EFAULT:
-
 
142
                        throw new SocketException("The receive buffer pointer(s) point outside the process's address space.");
-
 
143
 
-
 
144
                        case EINTR:
-
 
145
                        throw new SocketException("The receive was interrupted by delivery of a signal before any data were available; see signal(7).");
-
 
146
 
-
 
147
                        case EINVAL:
-
 
148
                        //throw new SocketException("2Invalid argument passed.");
-
 
149
                        slog << "Disconnected from server.\n";
-
 
150
                        reconnectLoop();
116
                        reconnectLoop();
-
 
117
                    }
-
 
118
                    else
-
 
119
                    {
151
                        timeSince = time(NULL) + 10;
120
                        loop = false;
-
 
121
                    }
152
                        break;
122
                    break;
153
 
123
 
154
                        case ENOMEM:
-
 
155
                        throw new SocketException("Could not allocate memory for recvmsg().");
-
 
156
 
-
 
157
                        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)).");
-
 
159
 
-
 
160
                        case ENOTSOCK:
-
 
161
                        throw new SocketException("The argument s does not refer to a socket.");
-
 
162
 
-
 
163
                        default:
124
                    default:
164
                        slog << "Unknow exception: " + itos(errno) + "\n";
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
                    slog << "Disconnected from server.\n";
132
                if (myReconnectTimeout > 0)
-
 
133
                {
171
                    reconnectLoop();
134
                    reconnectLoop();
172
                    timeSince = time(NULL);
-
 
173
                }
-
 
174
                else if (status > 0)
-
 
175
                {
-
 
176
                    timeSince = time(NULL) + 10;
-
 
177
 
-
 
178
                    data = buf;
-
 
179
 
-
 
180
                    //slog << "Receiving: " + data + "\n";
-
 
181
 
-
 
182
                    myInQueue.push(data);
-
 
183
 
-
 
184
                    setEvent(ASYNCSOCKET_EVENT_DATA);
-
 
185
                }
135
                }
186
               
136
                else
187
                if (timeSince + 10 < time(NULL))
-
 
188
                {
137
                {
189
                    setEvent(ASYNCSOCKET_EVENT_INACTIVITY);
-
 
190
                    timeSince = time(NULL);
138
                    loop = false;
191
                }
139
                }
192
            }
140
            }
-
 
141
            else if (status > 0)
-
 
142
            {
-
 
143
                data = buf;
-
 
144
 
-
 
145
                //slog << "Received: " + data + "\n";
-
 
146
 
-
 
147
                myInQueue.push(data);
-
 
148
                setEvent(ASYNCSOCKET_EVENT_DATA);
-
 
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
}
233
 
182
 
234
void AsyncSocket::create()
183
void AsyncSocket::create()
235
{
184
{
236
    close();
185
    close();
237
 
186
 
238
    mySocket = ::socket(AF_INET, SOCK_STREAM, 0);
187
    mySocket = ::socket(AF_INET, SOCK_STREAM, 0);
239
 
188
 
240
    int on = 1;
189
    int on = 1;
241
    int status = setsockopt(mySocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on));
190
    int status = setsockopt(mySocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on));
242
    if (status == -1)
191
    if (status == -1)
243
    {
192
    {
244
        close();
193
        close();
245
        throw new SocketException("Create:Reuseaddress: " + itos(errno));
194
        throw new SocketException("Create:Reuseaddress: " + itos(errno));
246
    }
195
    }
247
}
196
}
248
 
197
 
Line 251... Line 200...
251
    create();
200
    create();
252
 
201
 
253
    myAddressStruct.sin_family = AF_INET;
202
    myAddressStruct.sin_family = AF_INET;
254
    myAddressStruct.sin_addr.s_addr = INADDR_ANY;
203
    myAddressStruct.sin_addr.s_addr = INADDR_ANY;
255
    myAddressStruct.sin_port = htons(myPort);
204
    myAddressStruct.sin_port = htons(myPort);
256
 
205
 
257
    int status = ::bind(mySocket, (struct sockaddr *)&myAddressStruct, sizeof(myAddressStruct));
206
    int status = ::bind(mySocket, (struct sockaddr *)&myAddressStruct, sizeof(myAddressStruct));
258
 
207
 
259
    if (status == -1)
208
    if (status == -1)
260
    {
209
    {
261
        close();
210
        close();
Line 279... Line 228...
279
            //case EACCES:
228
            //case EACCES:
280
            //throw new SocketException("Search permission is denied on a component of the path prefix. (See also path_resolution(7).)");
229
            //throw new SocketException("Search permission is denied on a component of the path prefix. (See also path_resolution(7).)");
281
 
230
 
282
            case EADDRNOTAVAIL:
231
            case EADDRNOTAVAIL:
283
            throw new SocketException("A nonexistent interface was requested or the requested address was not local.");
232
            throw new SocketException("A nonexistent interface was requested or the requested address was not local.");
284
 
233
 
285
            case EFAULT:
234
            case EFAULT:
286
            throw new SocketException("addr points outside the user's accessible address space.");
235
            throw new SocketException("addr points outside the user's accessible address space.");
287
 
236
 
288
            //case EINVAL:
237
            //case EINVAL:
289
            //throw new SocketException("The addrlen is wrong, or the socket was not in the AF_UNIX family.");
238
            //throw new SocketException("The addrlen is wrong, or the socket was not in the AF_UNIX family.");
290
 
239
 
291
            case ELOOP:
240
            case ELOOP:
292
            throw new SocketException("Too many symbolic links were encountered in resolving addr.");
241
            throw new SocketException("Too many symbolic links were encountered in resolving addr.");
Line 303... Line 252...
303
            case ENOTDIR:
252
            case ENOTDIR:
304
            throw new SocketException("A component of the path prefix is not a directory.");
253
            throw new SocketException("A component of the path prefix is not a directory.");
305
 
254
 
306
            case EROFS:
255
            case EROFS:
307
            throw new SocketException("The socket inode would reside on a read-only file system.");
256
            throw new SocketException("The socket inode would reside on a read-only file system.");
308
 
257
 
309
            default:
258
            default:
310
            throw new SocketException("Unknow exception: " + itos(errno));
259
            throw new SocketException("Unknow exception: " + itos(errno));
311
            break;
260
            break;
312
        }
261
        }
313
    }
262
    }
314
 
263
 
315
    status = ::listen(mySocket, MAXCONNECTIONS);
264
    status = ::listen(mySocket, MAXCONNECTIONS);
316
 
265
 
317
    if (status == -1)
266
    if (status == -1)
318
    {
267
    {
319
        close();
268
        close();
320
        switch (errno)
269
        switch (errno)
Line 337... Line 286...
337
        }
286
        }
338
    }
287
    }
339
}
288
}
340
 
289
 
341
bool AsyncSocket::accept(AsyncSocket* newSocket)
290
bool AsyncSocket::accept(AsyncSocket* newSocket)
342
{
291
{
343
    int addr_length = sizeof(myAddressStruct);
292
    int addr_length = sizeof(myAddressStruct);
344
    int socket = ::accept(mySocket, (sockaddr*)&myAddressStruct, (socklen_t*)&addr_length);
293
    int socket = ::accept(mySocket, (sockaddr*)&myAddressStruct, (socklen_t*)&addr_length);
345
 
294
 
346
    if (socket > 0)
295
    if (socket > 0)
347
    {
296
    {
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
 
-
 
390
    memcpy(&myAddressStruct.sin_addr, hptr->h_addr, hptr->h_length);
-
 
391
    /*
-
 
392
    status = inet_pton(AF_INET, myAddress.c_str(), &myAddressStruct.sin_addr);
-
 
393
 
323
 
394
    if (status == -1)
-
 
395
    {
324
   
396
        if (errno == EAFNOSUPPORT)
-
 
397
            throw new SocketException("Connect: EAFNOSUPPORT");
325
    memcpy(&myAddressStruct.sin_addr, hptr->h_addr, hptr->h_length);
398
    }
-
 
399
    */
-
 
400
 
-
 
401
    slog << "Trying to connect...\n";
-
 
402
 
326
 
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
        {
Line 413... Line 337...
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).");
Line 449... Line 373...
449
            case ENOTSOCK:
373
            case ENOTSOCK:
450
            throw new SocketException("The file descriptor is not associated with a socket.");
374
            throw new SocketException("The file descriptor is not associated with a socket.");
451
 
375
 
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
    }
382
    }
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
    }
-
 
475
 
-
 
476
    fcntl(mySocket, F_SETFL, flags | O_NONBLOCK | FASYNC);
-
 
477
 
383
 
478
    myForceReconnect = false;
384
    myForceReconnect = false;
479
 
385
 
480
    slog << "Connection established.\n";
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 event;
421
    return myEventQueue.pop();
513
}
422
}
514
 
423
 
515
void AsyncSocket::waitForEvent()
424
void AsyncSocket::waitForEvent()
516
{
425
{
517
    myEventSemaphore.wait();
426
    myEventSemaphore.wait();
Line 553... Line 462...
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.push(data);
469
    //myOutQueue.push(data);
559
    mySemaphore.broadcast();
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
 
573
    if (status == -1)
484
    try
574
    {
485
    {
575
        switch (errno)
486
        if (status == -1)
576
        {
487
        {
-
 
488
            switch (errno)
-
 
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:
588
            throw new SocketException("Connection reset by peer.");
501
                throw new SocketException("Connection reset by peer.");
589
 
502
 
590
            case EDESTADDRREQ:
503
                case EDESTADDRREQ:
591
            throw new SocketException("The socket is not connection-mode, and no peer address is set.");
504
                throw new SocketException("The socket is not connection-mode, and no peer address is set.");
592
 
505
 
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.)");
604
 
517
 
605
            case EMSGSIZE:
518
                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.");
519
                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
 
520
 
608
            case ENOBUFS:
521
                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.)");
522
                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
 
523
 
611
            case ENOMEM:
524
                case ENOMEM:
612
            throw new SocketException("No memory available.");
525
                throw new SocketException("No memory available.");
613
 
526
 
614
            case ENOTCONN:
527
                case ENOTCONN:
615
            throw new SocketException("The socket is not connected, and no target has been given.");
528
                throw new SocketException("The socket is not connected, and no target has been given.");
616
 
529
 
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;
-
 
542
            }
629
        }
543
        }
-
 
544
    }
-
 
545
    catch (SocketException *e)
-
 
546
    {
-
 
547
        slog << "sendDataDirect: Exception: " + e->getDescription() + "\n";
630
    }
548
    }
631
}
549
}
632
 
550
 
633
void AsyncSocket::setEvent(int event)
551
void AsyncSocket::setEvent(int event)
634
{
552
{
635
    myEventSemaphore.lock();
-
 
636
    myEvent = event;
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
 
562
 
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
   
-
 
662
}
-