Subversion Repositories HomeAutomation

Rev

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

Rev 969 Rev 974
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
 
21
 
22
#include "asyncsocket.h"
22
#include "asyncsocket.h"
23
#include <iostream>
23
#include <iostream>
24
Semaphore AsyncSocket::mySemaphore;
24
Semaphore AsyncSocket::mySemaphore;
25
 
25
 
26
AsyncSocket::AsyncSocket()
26
AsyncSocket::AsyncSocket()
27
{
27
{
28
    mySocket = -1;
28
    mySocket = -1;
29
    myReconnectTimeout = 10;
29
    myReconnectTimeout = 10;
-
 
30
    myForceReconnect = false;
30
 
31
 
31
    Thread<AsyncSocket>();
32
    Thread<AsyncSocket>();
32
}
33
}
33
 
34
 
34
AsyncSocket::~AsyncSocket()
35
AsyncSocket::~AsyncSocket()
35
{
36
{
36
    if (mySocket != -1)
37
    if (mySocket != -1)
37
    {
38
    {
38
        ::close(mySocket);
39
        ::close(mySocket);
39
        mySocket = -1;
40
        mySocket = -1;
40
    }
41
    }
41
   
42
   
42
    stop();
43
    stop();
43
}
44
}
44
 
45
 
45
void AsyncSocket::run()
46
void AsyncSocket::run()
46
{
47
{
47
    SyslogStream &slog = SyslogStream::getInstance();
48
    SyslogStream &slog = SyslogStream::getInstance();
48
 
49
 
49
    reconnectLoop();
50
    reconnectLoop();
50
 
51
 
51
    char buf[MAXBUFFER + 1];
52
    char buf[MAXBUFFER + 1];
52
    string data;
53
    string data;
53
    int status;
54
    int status;
-
 
55
    int rc;
-
 
56
    int timeSince = time(NULL) + 10;
54
 
57
   
55
    AsyncSocket::mySemaphore.lock();
58
    AsyncSocket::mySemaphore.lock();
56
 
59
 
57
    try
60
    try
58
    {
61
    {
59
        while (1)
62
        while (1)
60
        {
63
        {
61
            mySemaphore.wait();
64
            rc = mySemaphore.wait(5);
-
 
65
 
-
 
66
            if (myForceReconnect)
-
 
67
            {
-
 
68
                slog << "Disconnected from server.\n";
-
 
69
                reconnectLoop();
-
 
70
                timeSince = time(NULL) + 10;
-
 
71
                continue;
-
 
72
            }
62
 
73
 
63
            //cout << "Socket awoken...\n";
74
            //cout << "Socket awoken...\n";
64
 
75
           
-
 
76
            if (rc == ETIMEDOUT)
-
 
77
            {
-
 
78
                /* Socket timed out, this means we have not received anything in some time
-
 
79
                and we should check the connection */
-
 
80
 
-
 
81
                setEvent(ASYNCSOCKET_EVENT_INACTIVITY);
-
 
82
                timeSince = time(NULL);
-
 
83
            }
-
 
84
            else
-
 
85
            {
65
            while (myOutQueue.size() > 0)
86
                while (myOutQueue.size() > 0)
66
            {
87
                {
67
                data = myOutQueue.pop();
88
                    data = myOutQueue.pop();
68
 
89
 
69
                //slog << "Sending: " << data << "\n";
90
                    //slog << "Sending: " << data << "\n";
70
 
91
 
71
                status = ::send(mySocket, data.c_str(), data.size(), 0);
92
                    status = ::send(mySocket, data.c_str(), data.size(), 0);
-
 
93
 
-
 
94
                    //slog << "Status: " << status << "\n";
72
 
95
 
73
                if (status == -1)
96
                    if (status == -1)
74
                {
97
                    {
75
                    switch (errno)
98
                        switch (errno)
76
                    {
99
                        {
77
                        case EACCES:
100
                            case EACCES:
78
                        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).)");
101
                            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).)");
79
 
102
 
80
                        case EAGAIN:
103
                            case EAGAIN:
81
                        //slog << "The socket is marked non-blocking and the requested operation would block.\n";
104
                            //slog << "The socket is marked non-blocking and the requested operation would block.\n";
82
                        break;
105
                            break;
83
 
106
 
84
                        case EBADF:
107
                            case EBADF:
85
                        throw new SocketException("An invalid descriptor was specified.");
108
                            throw new SocketException("An invalid descriptor was specified.");
86
 
109
 
87
                        case ECONNRESET:
110
                            case ECONNRESET:
88
                        throw new SocketException("Connection reset by peer.");
111
                            throw new SocketException("Connection reset by peer.");
89
 
112
 
90
                        case EDESTADDRREQ:
113
                            case EDESTADDRREQ:
91
                        throw new SocketException("The socket is not connection-mode, and no peer address is set.");
114
                            throw new SocketException("The socket is not connection-mode, and no peer address is set.");
92
 
115
 
93
                        case EFAULT:
116
                            case EFAULT:
94
                        throw new SocketException("An invalid user space address was specified for an argument.");
117
                            throw new SocketException("An invalid user space address was specified for an argument.");
95
 
118
 
96
                        case EINTR:
119
                            case EINTR:
97
                        throw new SocketException("A signal occurred before any data was transmitted; see signal(7).");
120
                            throw new SocketException("A signal occurred before any data was transmitted; see signal(7).");
98
 
121
 
99
                        case EINVAL:
122
                            case EINVAL:
100
                        throw new SocketException("Invalid argument passed.");
123
                            throw new SocketException("1Invalid argument passed.");
101
 
124
 
102
                        case EISCONN:
125
                            case EISCONN:
103
                        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.)");
126
                            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.)");
104
 
127
 
105
                        case EMSGSIZE:
128
                            case EMSGSIZE:
106
                        throw new SocketException("The socket type requires that message be sent atomically, and the size of the message to be sent made this impossible.");
129
                            throw new SocketException("The socket type requires that message be sent atomically, and the size of the message to be sent made this impossible.");
107
 
130
 
108
                        case ENOBUFS:
131
                            case ENOBUFS:
109
                        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.)");
132
                            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.)");
110
 
133
 
111
                        case ENOMEM:
134
                            case ENOMEM:
112
                        throw new SocketException("No memory available.");
135
                            throw new SocketException("No memory available.");
113
 
136
 
114
                        case ENOTCONN:
137
                            case ENOTCONN:
115
                        throw new SocketException("The socket is not connected, and no target has been given.");
138
                            throw new SocketException("The socket is not connected, and no target has been given.");
116
 
139
 
117
                        case ENOTSOCK:
140
                            case ENOTSOCK:
118
                        throw new SocketException("The argument s is not a socket.");
141
                            throw new SocketException("The argument s is not a socket.");
119
 
142
 
120
                        case EOPNOTSUPP:
143
                            case EOPNOTSUPP:
121
                        throw new SocketException("Some bit in the flags argument is inappropriate for the socket type.");
144
                            throw new SocketException("Some bit in the flags argument is inappropriate for the socket type.");
122
 
145
 
123
                        case EPIPE:
146
                            case EPIPE:
124
                        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.");
147
                            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.");
125
 
148
 
126
                        default:
149
                            default:
127
                        slog << "Unknow exception: " << errno << "\n";
150
                            slog << "Unknow exception: " << errno << "\n";
128
                        break;
151
                            break;
129
                    }
152
                        }
130
                }
153
                    }
131
            }
154
                }
132
 
155
 
133
            memset(buf, 0, MAXBUFFER + 1);
156
                memset(buf, 0, MAXBUFFER + 1);
134
 
157
 
135
            status = ::recv(mySocket, buf, MAXBUFFER, 0);
158
                status = ::recv(mySocket, buf, MAXBUFFER, 0);
-
 
159
 
-
 
160
                //slog << "Receiving: " << buf << "\n";
136
 
161
 
137
            if (status == -1)
162
                if (status == -1)
138
            {
163
                {
139
                switch (errno)
164
                    switch (errno)
140
                {
165
                    {
141
                    case EAGAIN:
166
                        case EAGAIN:
142
                    //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";
167
                        //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";
143
                    break;
168
                        break;
144
 
169
 
145
                    case EBADF:
170
                        case EBADF:
146
                    throw new SocketException("The argument s is an invalid descriptor.");
171
                        throw new SocketException("The argument s is an invalid descriptor.");
147
 
172
 
148
                    case ECONNREFUSED:
173
                        case ECONNREFUSED:
149
                    throw new SocketException("A remote host refused to allow the network connection (typically because it is not running the requested service).");
174
                        throw new SocketException("A remote host refused to allow the network connection (typically because it is not running the requested service).");
150
 
175
 
151
                    case EFAULT:
176
                        case EFAULT:
152
                    throw new SocketException("The receive buffer pointer(s) point outside the process's address space.");
177
                        throw new SocketException("The receive buffer pointer(s) point outside the process's address space.");
153
 
178
 
154
                    case EINTR:
179
                        case EINTR:
155
                    throw new SocketException("The receive was interrupted by delivery of a signal before any data were available; see signal(7).");
180
                        throw new SocketException("The receive was interrupted by delivery of a signal before any data were available; see signal(7).");
156
 
181
 
157
                    case EINVAL:
182
                        case EINVAL:
158
                    throw new SocketException("Invalid argument passed.");
183
                        //throw new SocketException("2Invalid argument passed.");
-
 
184
                        slog << "Disconnected from server.\n";
-
 
185
                        reconnectLoop();
-
 
186
                        break;
159
 
187
 
160
                    case ENOMEM:
188
                        case ENOMEM:
161
                    throw new SocketException("Could not allocate memory for recvmsg().");
189
                        throw new SocketException("Could not allocate memory for recvmsg().");
162
 
190
 
163
                    case ENOTCONN:
191
                        case ENOTCONN:
164
                    throw new SocketException("The socket is associated with a connection-oriented protocol and has not been connected (see connect(2) and  accept(2)).");
192
                        throw new SocketException("The socket is associated with a connection-oriented protocol and has not been connected (see connect(2) and  accept(2)).");
165
 
193
 
166
                    case ENOTSOCK:
194
                        case ENOTSOCK:
167
                    throw new SocketException("The argument s does not refer to a socket.");
195
                        throw new SocketException("The argument s does not refer to a socket.");
168
 
196
 
169
                    default:
197
                        default:
170
                    slog << "Unknow exception: " << errno << "\n";
198
                        slog << "Unknow exception: " << errno << "\n";
171
                    break;
199
                        break;
172
                }
200
                    }
173
            }
201
                }
174
            else if (status == 0)
202
                else if (status == 0)
175
            {
203
                {
176
                slog << "Disconnected from server.\n";
204
                    slog << "Disconnected from server.\n";
177
                reconnectLoop();
205
                    reconnectLoop();
178
            }
206
                }
179
            else if (status > 0)
207
                else if (status > 0)
180
            {
208
                {
181
                data = buf;
209
                    data = buf;
182
 
210
 
183
                myInQueue.push(data);
211
                    myInQueue.push(data);
184
 
212
 
185
                setEvent(ASYNCSOCKET_EVENT_DATA);
213
                    setEvent(ASYNCSOCKET_EVENT_DATA);
-
 
214
                   
-
 
215
                    timeSince = time(NULL);
-
 
216
                }
-
 
217
               
-
 
218
                if (timeSince + 10 < time(NULL))
-
 
219
                {
-
 
220
                    setEvent(ASYNCSOCKET_EVENT_INACTIVITY);
-
 
221
                    timeSince = time(NULL);
-
 
222
                }
186
            }
223
            }
187
        }
224
        }
188
    }
225
    }
189
    catch (SocketException *e)
226
    catch (SocketException *e)
190
    {
227
    {
191
        slog << "Exception: " << e->getDescription() << "\n";
228
        slog << "Exception: " << e->getDescription() << "\n";
192
        mySemaphore.unlock();
229
        mySemaphore.unlock();
193
        setEvent(ASYNCSOCKET_EVENT_DIED);
230
        setEvent(ASYNCSOCKET_EVENT_DIED);
194
        stop();
231
        stop();
195
    }
232
    }
196
 
233
 
197
    close();
234
    close();
198
 
235
 
199
    mySemaphore.unlock();
236
    mySemaphore.unlock();
200
}
237
}
201
 
238
 
202
void AsyncSocket::reconnectLoop()
239
void AsyncSocket::reconnectLoop()
203
{
240
{
204
    SyslogStream &slog = SyslogStream::getInstance();
241
    SyslogStream &slog = SyslogStream::getInstance();
205
 
242
 
206
    while (1)
243
    while (1)
207
    {
244
    {
208
        try
245
        try
209
        {
246
        {
210
            slog << "Trying to connect...\n";
247
            slog << "Trying to connect...\n";
211
            connect();
248
            connect();
212
            slog << "Connection established.\n";
249
            slog << "Connection established.\n";
213
            break;
250
            break;
214
        }
251
        }
215
        catch (SocketException *e)
252
        catch (SocketException *e)
216
        {
253
        {
217
            slog << "Could not connect: " << e->getDescription() << "\n";
254
            slog << "Could not connect: " << e->getDescription() << "\n";
218
            slog << "Will try again in " << myReconnectTimeout << " seconds\n";
255
            slog << "Will try again in " << myReconnectTimeout << " seconds\n";
219
            sleep(myReconnectTimeout);
256
            sleep(myReconnectTimeout);
220
        }
257
        }
221
    }
258
    }
222
}
259
}
223
 
260
 
224
void AsyncSocket::connect()
261
void AsyncSocket::connect()
225
{
262
{
226
    if (mySocket != -1)
263
    if (mySocket != -1)
227
    {
264
    {
228
        ::close(mySocket);
265
        ::close(mySocket);
229
        mySocket = -1;
266
        mySocket = -1;
230
    }
267
    }
231
   
268
   
232
    mySocket = ::socket(AF_INET, SOCK_STREAM, 0);
269
    mySocket = ::socket(AF_INET, SOCK_STREAM, 0);
233
 
270
 
234
    // TIME_WAIT - argh
-
 
235
    int on = 1;
271
    int on = 1;
236
    int status = setsockopt(mySocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on));
272
    int status = setsockopt(mySocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on));
237
    if (status == -1)
273
    if (status == -1)
238
    {
274
    {
-
 
275
        throw new SocketException("Connect:Reuseaddress: " + itos(errno));
-
 
276
    }
-
 
277
 
-
 
278
    ///FIXME: Verify that this works
-
 
279
    status = setsockopt(mySocket, SOL_SOCKET, SO_KEEPALIVE, (const char*)&on, sizeof(on));
-
 
280
    if (status == -1)
-
 
281
    {
-
 
282
        throw new SocketException("Connect:Keepalive: " + itos(errno));
-
 
283
    }
-
 
284
 
-
 
285
    ///FIXME: Verify that this works
-
 
286
    status = setsockopt(mySocket, SOL_TCP, TCP_KEEPIDLE, (const char*)&on, sizeof(on));
-
 
287
    if (status == -1)
-
 
288
    {
239
        throw new SocketException("Connect: " + itos(errno));
289
        throw new SocketException("Connect:Keepidle: " + itos(errno));
240
    }
290
    }
241
 
291
 
242
    memset(&myAddressStruct, 0, sizeof(myAddressStruct));
292
    memset(&myAddressStruct, 0, sizeof(myAddressStruct));
243
 
293
 
244
    myAddressStruct.sin_family = AF_INET;
294
    myAddressStruct.sin_family = AF_INET;
245
    myAddressStruct.sin_port = htons(myPort);
295
    myAddressStruct.sin_port = htons(myPort);
246
 
296
 
247
    status = inet_pton(AF_INET, myAddress.c_str(), &myAddressStruct.sin_addr);
297
    status = inet_pton(AF_INET, myAddress.c_str(), &myAddressStruct.sin_addr);
248
 
298
 
249
    if (status == -1)
299
    if (status == -1)
250
    {
300
    {
251
        if (errno == EAFNOSUPPORT)
301
        if (errno == EAFNOSUPPORT)
252
            throw new SocketException("Connect: EAFNOSUPPORT");
302
            throw new SocketException("Connect: EAFNOSUPPORT");
253
    }
303
    }
254
   
304
   
255
    status = ::connect(mySocket, (sockaddr*)&myAddressStruct, sizeof(myAddressStruct));
305
    status = ::connect(mySocket, (sockaddr*)&myAddressStruct, sizeof(myAddressStruct));
256
 
306
 
257
    if (status == -1)
307
    if (status == -1)
258
    {
308
    {
259
        switch (errno)
309
        switch (errno)
260
        {
310
        {
261
            case EACCES:
311
            case EACCES:
262
            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).)");
312
            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).)");
263
 
313
 
264
            case EPERM:
314
            case EPERM:
265
            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.");
315
            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.");
266
 
316
 
267
            case EADDRINUSE:
317
            case EADDRINUSE:
268
            throw new SocketException("Local address is already in use.");
318
            throw new SocketException("Local address is already in use.");
269
 
319
 
270
            case EAFNOSUPPORT:
320
            case EAFNOSUPPORT:
271
            throw new SocketException("The passed address didn't have the correct address family in its sa_family field.");
321
            throw new SocketException("The passed address didn't have the correct address family in its sa_family field.");
272
 
322
 
273
            case EAGAIN:
323
            case EAGAIN:
274
            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.");
324
            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.");
275
 
325
 
276
            case EALREADY:
326
            case EALREADY:
277
            throw new SocketException("The socket is non-blocking and a previous connection attempt has not yet been completed.");
327
            throw new SocketException("The socket is non-blocking and a previous connection attempt has not yet been completed.");
278
 
328
 
279
            case EBADF:
329
            case EBADF:
280
            throw new SocketException("The file descriptor is not a valid index in the descriptor table.");
330
            throw new SocketException("The file descriptor is not a valid index in the descriptor table.");
281
 
331
 
282
            case ECONNREFUSED:
332
            case ECONNREFUSED:
283
            throw new SocketException("No-one listening on the remote address.");
333
            throw new SocketException("No-one listening on the remote address.");
284
 
334
 
285
            case EFAULT:
335
            case EFAULT:
286
            throw new SocketException("The socket structure address is outside the user's address space.");
336
            throw new SocketException("The socket structure address is outside the user's address space.");
287
 
337
 
288
            case EINPROGRESS:
338
            case EINPROGRESS:
289
            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).");
339
            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).");
290
 
340
 
291
            case EINTR:
341
            case EINTR:
292
            throw new SocketException("The system call was interrupted by a signal that was caught; see signal(7).");
342
            throw new SocketException("The system call was interrupted by a signal that was caught; see signal(7).");
293
 
343
 
294
            case EISCONN:
344
            case EISCONN:
295
            throw new SocketException("The socket is already connected.");
345
            throw new SocketException("The socket is already connected.");
296
 
346
 
297
            case ENETUNREACH:
347
            case ENETUNREACH:
298
            throw new SocketException("Network is unreachable.");
348
            throw new SocketException("Network is unreachable.");
299
 
349
 
300
            case ENOTSOCK:
350
            case ENOTSOCK:
301
            throw new SocketException("The file descriptor is not associated with a socket.");
351
            throw new SocketException("The file descriptor is not associated with a socket.");
302
 
352
 
303
            case ETIMEDOUT:
353
            case ETIMEDOUT:
304
            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.");
354
            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.");
305
 
355
 
306
            default:
356
            default:
307
            throw new SocketException("Other errors may be generated by the underlying protocol modules. : " + itos(errno));
357
            throw new SocketException("Other errors may be generated by the underlying protocol modules. : " + itos(errno));
308
        }
358
        }
309
    }
359
    }
310
 
360
 
311
    struct sigaction saio;
361
    struct sigaction saio;
312
    saio.sa_handler = AsyncSocket::signalHandler;
362
    saio.sa_handler = AsyncSocket::signalHandler;
313
    sigemptyset(&saio.sa_mask);
363
    sigemptyset(&saio.sa_mask);
314
    saio.sa_flags = 0;
364
    saio.sa_flags = 0;
315
    saio.sa_restorer = NULL;
365
    saio.sa_restorer = NULL;
316
    sigaction(SIGIO, &saio, NULL);
366
    sigaction(SIGIO, &saio, NULL);
317
 
367
 
318
    fcntl(mySocket, F_SETOWN, getpid());
368
    fcntl(mySocket, F_SETOWN, getpid());
319
    int flags = fcntl(mySocket, F_GETFL);
369
    int flags = fcntl(mySocket, F_GETFL);
320
 
370
 
321
    if (flags < 0)
371
    if (flags < 0)
322
        throw new SocketException("Async socket fcntl failed");
372
        throw new SocketException("Async socket fcntl failed");
323
 
373
 
324
    fcntl(mySocket, F_SETFL, flags | O_NONBLOCK | FASYNC);
374
    fcntl(mySocket, F_SETFL, flags | O_NONBLOCK | FASYNC);
-
 
375
 
-
 
376
    myForceReconnect = false;
325
}
377
}
326
 
378
 
327
void AsyncSocket::close()
379
void AsyncSocket::close()
328
{
380
{
329
    if (mySocket != -1)
381
    if (mySocket != -1)
330
    {
382
    {
331
        ::close(mySocket);
383
        ::close(mySocket);
332
        mySocket = -1;
384
        mySocket = -1;
333
        setEvent(ASYNCSOCKET_EVENT_CLOSED);
385
        setEvent(ASYNCSOCKET_EVENT_CLOSED);
334
    }
386
    }
335
}
387
}
336
 
388
 
337
void AsyncSocket::setReconnectTimeout(unsigned int timeout)
389
void AsyncSocket::setReconnectTimeout(unsigned int timeout)
338
{
390
{
339
    myReconnectTimeout = timeout;
391
    myReconnectTimeout = timeout;
340
}
392
}
341
 
393
 
342
void AsyncSocket::startEvent()
394
void AsyncSocket::startEvent()
343
{
395
{
344
    myEventSemaphore.lock();
396
    myEventSemaphore.lock();
345
}
397
}
346
 
398
 
347
int AsyncSocket::getEvent()
399
int AsyncSocket::getEvent()
348
{
400
{
349
    int event = myEvent;
401
    int event = myEvent;
350
    myEvent = ASYNCSOCKET_EVENT_NONE;
402
    myEvent = ASYNCSOCKET_EVENT_NONE;
351
    return event;
403
    return event;
352
}
404
}
353
 
405
 
354
void AsyncSocket::waitForEvent()
406
void AsyncSocket::waitForEvent()
355
{
407
{
356
    myEventSemaphore.wait();
408
    myEventSemaphore.wait();
357
}
409
}
358
 
410
 
359
void AsyncSocket::stopEvent()
411
void AsyncSocket::stopEvent()
360
{
412
{
361
    myEventSemaphore.unlock();
413
    myEventSemaphore.unlock();
362
}
414
}
363
 
415
 
364
void AsyncSocket::setAddress(string address, int port)
416
void AsyncSocket::setAddress(string address, int port)
365
{
417
{
366
    myAddress = address;
418
    myAddress = address;
367
    myPort = port;
419
    myPort = port;
368
}
420
}
369
 
421
 
370
bool AsyncSocket::availableData()
422
bool AsyncSocket::availableData()
371
{
423
{
372
    return (myInQueue.size() > 0);
424
    return (myInQueue.size() > 0);
373
}
425
}
374
 
426
 
375
string AsyncSocket::getData()
427
string AsyncSocket::getData()
376
{
428
{
377
    return myInQueue.pop();
429
    return myInQueue.pop();
378
}
430
}
379
 
431
 
380
bool AsyncSocket::sendData(string data)
432
bool AsyncSocket::sendData(string data)
381
{
433
{
382
    myOutQueue.push(data);
434
    myOutQueue.push(data);
383
    mySemaphore.broadcast();
435
    mySemaphore.broadcast();
384
    return true;
436
    return true;
385
}
437
}
386
 
438
 
387
void AsyncSocket::setEvent(int event)
439
void AsyncSocket::setEvent(int event)
388
{
440
{
389
    myEventSemaphore.lock();
441
    myEventSemaphore.lock();
390
    myEvent = event;
442
    myEvent = event;
391
    myEventSemaphore.unlock();
443
    myEventSemaphore.unlock();
392
    myEventSemaphore.broadcast();
444
    myEventSemaphore.broadcast();
-
 
445
}
-
 
446
 
-
 
447
void AsyncSocket::forceReconnect()
-
 
448
{
-
 
449
    myForceReconnect = true;
-
 
450
    mySemaphore.broadcast();
393
}
451
}
394
 
452
 
395
void AsyncSocket::signalHandler(int signum)
453
void AsyncSocket::signalHandler(int signum)
396
{
454
{
-
 
455
    //FIXME: We must know which socket is ready to read by using select... 
397
    //cout << "DEBUG: signalHandler signum: " << signum << endl;
456
    //cout << "DEBUG: signalHandler signum: " << signum << endl;
398
    mySemaphore.broadcast();
457
    mySemaphore.broadcast();
399
}
458
}
400
 
459