Subversion Repositories HomeAutomation

Rev

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

Rev 981 Rev 983
1
/***************************************************************************
1
/***************************************************************************
2
 *   Copyright (C) December 6, 2008 by Mattias Runge                             *
2
 *   Copyright (C) December 6, 2008 by Mattias Runge                             *
3
 *   mattias@runge.se                                                      *
3
 *   mattias@runge.se                                                      *
4
 *   asyncsocket.cpp                                            *
4
 *   asyncsocket.cpp                                            *
5
 *                                                                         *
5
 *                                                                         *
6
 *   This program is free software; you can redistribute it and/or modify  *
6
 *   This program is free software; you can redistribute it and/or modify  *
7
 *   it under the terms of the GNU General Public License as published by  *
7
 *   it under the terms of the GNU General Public License as published by  *
8
 *   the Free Software Foundation; either version 2 of the License, or     *
8
 *   the Free Software Foundation; either version 2 of the License, or     *
9
 *   (at your option) any later version.                                   *
9
 *   (at your option) any later version.                                   *
10
 *                                                                         *
10
 *                                                                         *
11
 *   This program is distributed in the hope that it will be useful,       *
11
 *   This program is distributed in the hope that it will be useful,       *
12
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
14
 *   GNU General Public License for more details.                          *
14
 *   GNU General Public License for more details.                          *
15
 *                                                                         *
15
 *                                                                         *
16
 *   You should have received a copy of the GNU General Public License     *
16
 *   You should have received a copy of the GNU General Public License     *
17
 *   along with this program; if not, write to the                         *
17
 *   along with this program; if not, write to the                         *
18
 *   Free Software Foundation, Inc.,                                       *
18
 *   Free Software Foundation, Inc.,                                       *
19
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
20
 ***************************************************************************/
20
 ***************************************************************************/
21
 
-
 
22
#include <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
75
        {
57
        {
76
            reconnectLoop();
58
            reconnectLoop();
77
        }
59
        }
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
 
104
            //cout << "Socket awoken...\n";
-
 
105
           
-
 
106
            if (rc == ETIMEDOUT)
-
 
107
            {
-
 
108
                /* Socket timed out, this means we have not received anything in some time
-
 
109
                and we should check the connection */
-
 
110
 
-
 
111
                setEvent(ASYNCSOCKET_EVENT_INACTIVITY);
-
 
112
                timeSince = time(NULL);
-
 
113
            }
-
 
114
            else
-
 
115
            {
-
 
116
                while (myOutQueue.size() > 0)
-
 
117
                {
-
 
118
                    data = myOutQueue.pop();
-
 
119
 
-
 
120
                    sendDataDirect(data);
-
 
121
                }
-
 
122
 
-
 
123
                memset(buf, 0, MAXBUFFER + 1);
76
            memset(buf, 0, MAXBUFFER + 1);
124
 
-
 
125
                status = ::recv(mySocket, buf, MAXBUFFER, 0);
77
            status = ::recv(mySocket, buf, MAXBUFFER, 0);
126
 
78
 
127
                if (status == -1)
79
            if (status == -1)
128
                {
80
            {
129
                    switch (errno)
81
                switch (errno)
130
                    {
82
                {
131
                        case EAGAIN:
83
                    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";
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.");
133
                        break;
85
                    break;
134
 
86
 
135
                        case EBADF:
87
                    case EBADF:
136
                        throw new SocketException("The argument s is an invalid descriptor.");
88
                    throw new SocketException("The argument s is an invalid descriptor.");
137
 
89
 
138
                        case ECONNREFUSED:
90
                    case ECONNREFUSED:
139
                        throw new SocketException("A remote host refused to allow the network connection (typically because it is not running the requested service).");
91
                    throw new SocketException("A remote host refused to allow the network connection (typically because it is not running the requested service).");
140
 
92
 
141
                        case EFAULT:
93
                    case EFAULT:
142
                        throw new SocketException("The receive buffer pointer(s) point outside the process's address space.");
94
                    throw new SocketException("The receive buffer pointer(s) point outside the process's address space.");
143
 
95
 
144
                        case EINTR:
96
                    case EINTR:
145
                        throw new SocketException("The receive was interrupted by delivery of a signal before any data were available; see signal(7).");
97
                    throw new SocketException("The receive was interrupted by delivery of a signal before any data were available; see signal(7).");
146
 
98
 
147
                        case EINVAL:
99
                    case EINVAL:
148
                        //throw new SocketException("2Invalid argument passed.");
100
                    throw new SocketException("Invalid argument passed.");
149
                        slog << "Disconnected from server.\n";
-
 
150
                        reconnectLoop();
-
 
151
                        timeSince = time(NULL) + 10;
-
 
152
                        break;
101
                    break;
153
 
102
 
154
                        case ENOMEM:
103
                    case ENOMEM:
155
                        throw new SocketException("Could not allocate memory for recvmsg().");
104
                    throw new SocketException("Could not allocate memory for recvmsg().");
156
 
105
 
157
                        case ENOTCONN:
106
                    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)).");
107
                    throw new SocketException("The socket is associated with a connection-oriented protocol and has not been connected (see connect(2) and  accept(2)).");
159
 
108
 
160
                        case ENOTSOCK:
109
                    case ENOTSOCK:
161
                        throw new SocketException("The argument s does not refer to a socket.");
110
                    throw new SocketException("The argument s does not refer to a socket.");
-
 
111
 
-
 
112
                    case ECONNRESET:
-
 
113
                    setEvent(ASYNCSOCKET_EVENT_RESET);
-
 
114
                    if (myReconnectTimeout > 0)
-
 
115
                    {
-
 
116
                        reconnectLoop();
-
 
117
                    }
-
 
118
                    else
-
 
119
                    {
-
 
120
                        loop = false;
-
 
121
                    }
-
 
122
                    break;
162
 
123
 
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();
-
 
135
                }
-
 
136
                else
-
 
137
                {
172
                    timeSince = time(NULL);
138
                    loop = false;
-
 
139
                }
173
                }
140
            }
174
                else if (status > 0)
141
            else if (status > 0)
175
                {
142
            {
176
                    timeSince = time(NULL) + 10;
-
 
177
 
-
 
178
                    data = buf;
143
                data = buf;
179
 
144
 
180
                    //slog << "Receiving: " + data + "\n";
145
                //slog << "Received: " + data + "\n";
181
 
146
 
182
                    myInQueue.push(data);
147
                myInQueue.push(data);
183
 
-
 
184
                    setEvent(ASYNCSOCKET_EVENT_DATA);
148
                setEvent(ASYNCSOCKET_EVENT_DATA);
185
                }
-
 
186
               
-
 
187
                if (timeSince + 10 < time(NULL))
-
 
188
                {
-
 
189
                    setEvent(ASYNCSOCKET_EVENT_INACTIVITY);
-
 
190
                    timeSince = time(NULL);
-
 
191
                }
-
 
192
            }
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
221
        {
168
        {
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
 
249
void AsyncSocket::startListen()
198
void AsyncSocket::startListen()
250
{
199
{
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();
262
        switch (errno)
211
        switch (errno)
263
        {
212
        {
264
            case EACCES:
213
            case EACCES:
265
            throw new SocketException("The address is protected, and the user is not the superuser.");
214
            throw new SocketException("The address is protected, and the user is not the superuser.");
266
 
215
 
267
            case EADDRINUSE:
216
            case EADDRINUSE:
268
            throw new SocketException("The given address is already in use.");
217
            throw new SocketException("The given address is already in use.");
269
 
218
 
270
            case EBADF:
219
            case EBADF:
271
            throw new SocketException("sockfd is not a valid descriptor.");
220
            throw new SocketException("sockfd is not a valid descriptor.");
272
 
221
 
273
            case EINVAL:
222
            case EINVAL:
274
            throw new SocketException("The socket is already bound to an address.");
223
            throw new SocketException("The socket is already bound to an address.");
275
 
224
 
276
            case ENOTSOCK:
225
            case ENOTSOCK:
277
            throw new SocketException("sockfd is a descriptor for a file, not a socket.");
226
            throw new SocketException("sockfd is a descriptor for a file, not a socket.");
278
 
227
 
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.");
293
 
242
 
294
            case ENAMETOOLONG:
243
            case ENAMETOOLONG:
295
            throw new SocketException("addr is too long.");
244
            throw new SocketException("addr is too long.");
296
 
245
 
297
            case ENOENT:
246
            case ENOENT:
298
            throw new SocketException("The file does not exist.");
247
            throw new SocketException("The file does not exist.");
299
 
248
 
300
            case ENOMEM:
249
            case ENOMEM:
301
            throw new SocketException("Insufficient kernel memory was available.");
250
            throw new SocketException("Insufficient kernel memory was available.");
302
 
251
 
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)
321
        {
270
        {
322
            case EADDRINUSE:
271
            case EADDRINUSE:
323
            throw new SocketException("Another socket is already listening on the same port.");
272
            throw new SocketException("Another socket is already listening on the same port.");
324
 
273
 
325
            case EBADF:
274
            case EBADF:
326
            throw new SocketException("The argument sockfd is not a valid descriptor.");
275
            throw new SocketException("The argument sockfd is not a valid descriptor.");
327
 
276
 
328
            case ENOTSOCK:
277
            case ENOTSOCK:
329
            throw new SocketException("The argument sockfd is not a socket.");
278
            throw new SocketException("The argument sockfd is not a socket.");
330
 
279
 
331
            case EOPNOTSUPP:
280
            case EOPNOTSUPP:
332
            throw new SocketException("The socket is not of a type that supports the listen() operation.");
281
            throw new SocketException("The socket is not of a type that supports the listen() operation.");
333
 
282
 
334
            default:
283
            default:
335
            throw new SocketException("Unknow exception: " + itos(errno));
284
            throw new SocketException("Unknow exception: " + itos(errno));
336
            break;
285
            break;
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
    {
348
        newSocket->setSocket(socket);
297
        newSocket->setSocket(socket);
349
        return true;
298
        return true;
350
    }
299
    }
351
 
300
 
352
    return false;
301
    return false;
353
}
302
}
354
 
303
 
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
 
323
 
-
 
324
   
390
    memcpy(&myAddressStruct.sin_addr, hptr->h_addr, hptr->h_length);
325
    memcpy(&myAddressStruct.sin_addr, hptr->h_addr, hptr->h_length);
391
    /*
-
 
392
    status = inet_pton(AF_INET, myAddress.c_str(), &myAddressStruct.sin_addr);
-
 
393
 
326
 
394
    if (status == -1)
-
 
395
    {
-
 
396
        if (errno == EAFNOSUPPORT)
-
 
397
            throw new SocketException("Connect: EAFNOSUPPORT");
-
 
398
    }
-
 
399
    */
-
 
400
 
-
 
401
    slog << "Trying to connect...\n";
-
 
402
 
-
 
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
        {
410
            case EACCES:
334
            case EACCES:
411
            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).)");
335
            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).)");
412
 
336
 
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).");
439
 
363
 
440
            case EINTR:
364
            case EINTR:
441
            throw new SocketException("The system call was interrupted by a signal that was caught; see signal(7).");
365
            throw new SocketException("The system call was interrupted by a signal that was caught; see signal(7).");
442
 
366
 
443
            case EISCONN:
367
            case EISCONN:
444
            throw new SocketException("The socket is already connected.");
368
            throw new SocketException("The socket is already connected.");
445
 
369
 
446
            case ENETUNREACH:
370
            case ENETUNREACH:
447
            throw new SocketException("Network is unreachable.");
371
            throw new SocketException("Network is unreachable.");
448
 
372
 
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
    }
-
 
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
    }
382
    }
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)
486
    {
392
    {
487
        ::close(mySocket);
393
        ::close(mySocket);
488
        mySocket = -1;
394
        mySocket = -1;
489
        setEvent(ASYNCSOCKET_EVENT_CLOSED);
395
        setEvent(ASYNCSOCKET_EVENT_CLOSED);
490
    }
396
    }
491
}
397
}
492
 
398
 
493
bool AsyncSocket::isConnected()
399
bool AsyncSocket::isConnected()
494
{
400
{
495
    return mySocket != -1;
401
    return mySocket != -1;
496
}
402
}
497
 
403
 
498
void AsyncSocket::setReconnectTimeout(unsigned int timeout)
404
void AsyncSocket::setReconnectTimeout(unsigned int timeout)
499
{
405
{
500
    myReconnectTimeout = timeout;
406
    myReconnectTimeout = timeout;
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();
518
}
427
}
519
 
428
 
520
void AsyncSocket::stopEvent()
429
void AsyncSocket::stopEvent()
521
{
430
{
522
    myEventSemaphore.unlock();
431
    myEventSemaphore.unlock();
523
}
432
}
524
 
433
 
525
void AsyncSocket::setAddress(string address, int port)
434
void AsyncSocket::setAddress(string address, int port)
526
{
435
{
527
    myAddress = address;
436
    myAddress = address;
528
    myPort = port;
437
    myPort = port;
529
}
438
}
530
 
439
 
531
void AsyncSocket::setPort(int port)
440
void AsyncSocket::setPort(int port)
532
{
441
{
533
    myPort = port;
442
    myPort = port;
534
}
443
}
535
 
444
 
536
void AsyncSocket::setSocket(int socket)
445
void AsyncSocket::setSocket(int socket)
537
{
446
{
538
    mySocket = socket;
447
    mySocket = socket;
539
}
448
}
540
 
449
 
541
int AsyncSocket::getSocket()
450
int AsyncSocket::getSocket()
542
{
451
{
543
    return mySocket;
452
    return mySocket;
544
}
453
}
545
 
454
 
546
bool AsyncSocket::availableData()
455
bool AsyncSocket::availableData()
547
{
456
{
548
    return (myInQueue.size() > 0);
457
    return (myInQueue.size() > 0);
549
}
458
}
550
 
459
 
551
string AsyncSocket::getData()
460
string AsyncSocket::getData()
552
{
461
{
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
{
565
    SyslogStream &slog = SyslogStream::getInstance();
476
    SyslogStream &slog = SyslogStream::getInstance();
566
 
477
 
567
    //slog << "Sending: " << data << "\n";
478
    //slog << "Sending: " << data << "\n";
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
 
-
 
484
    try
-
 
485
    {
573
    if (status == -1)
486
        if (status == -1)
574
    {
487
        {
575
        switch (errno)
488
            switch (errno)
576
        {
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;
629
        }
542
            }
630
    }
543
        }
-
 
544
    }
-
 
545
    catch (SocketException *e)
-
 
546
    {
-
 
547
        slog << "sendDataDirect: Exception: " + e->getDescription() + "\n";
-
 
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
 
-
 
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
   
562
 
662
}
-
 
663
 
563