Subversion Repositories HomeAutomation

Rev

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

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