Subversion Repositories HomeAutomation

Rev

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

Rev 976 Rev 981
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 <map>
-
 
23
 
-
 
24
 
-
 
25
#include <vector>
-
 
26
 
-
 
27
 
22
#include "asyncsocket.h"
28
#include "asyncsocket.h"
23
 
29
 
-
 
30
map<string, AsyncSocket*> AsyncSocket::mySockets;
24
Semaphore AsyncSocket::mySemaphore;
31
Mutex AsyncSocket::mySocketsMutex;
25
 
32
 
26
AsyncSocket::AsyncSocket()
33
AsyncSocket::AsyncSocket()
27
{
34
{
-
 
35
    myId = itos(time(NULL)) + itos(mySockets.size());
-
 
36
 
-
 
37
    mySockets[myId] = this;
-
 
38
 
-
 
39
    cout << "DEBUG: Started " << myId << endl;
-
 
40
 
28
    mySocket = -1;
41
    mySocket = -1;
29
    myReconnectTimeout = 0;
42
    myReconnectTimeout = 0;
30
    myForceReconnect = false;
43
    myForceReconnect = false;
-
 
44
 
31
 
45
 
32
    Thread<AsyncSocket>();
46
    Thread<AsyncSocket>();
33
}
47
}
34
 
48
 
35
AsyncSocket::~AsyncSocket()
49
AsyncSocket::~AsyncSocket()
36
{
50
{
-
 
51
    mySemaphore.unlock();
-
 
52
 
37
    if (mySocket != -1)
53
    if (mySocket != -1)
38
    {
54
    {
39
        ::close(mySocket);
55
        ::close(mySocket);
40
        mySocket = -1;
56
        mySocket = -1;
41
    }
57
    }
-
 
58
 
-
 
59
    mySockets.erase(myId);
42
   
60
 
43
    stop();
61
    stop();
44
}
62
}
45
 
63
 
46
void AsyncSocket::run()
64
void AsyncSocket::run()
47
{
65
{
48
    SyslogStream &slog = SyslogStream::getInstance();
66
    SyslogStream &slog = SyslogStream::getInstance();
49
 
67
 
-
 
68
    if (!isConnected())
-
 
69
    {
50
    if (myReconnectTimeout == 0)
70
        if (myReconnectTimeout == 0)
51
    {
71
        {
52
        connect();
72
            connect();
53
    }
73
        }
54
    else
74
        else
55
    {
75
        {
56
        reconnectLoop();
76
            reconnectLoop();
-
 
77
        }
57
    }
78
    }
58
 
79
 
59
    char buf[MAXBUFFER + 1];
80
    char buf[MAXBUFFER + 1];
60
    string data;
81
    string data;
61
    int status;
82
    int status;
62
    int rc;
83
    int rc;
63
    int timeSince = time(NULL) + 10;
84
    int timeSince = time(NULL) + 10;
64
   
-
 
65
   
-
 
66
 
85
 
67
    try
86
    try
68
    {
87
    {
69
        while (1)
88
        while (1)
70
        {
89
        {
71
            AsyncSocket::mySemaphore.lock();
90
            AsyncSocket::mySemaphore.lock();
72
 
91
 
73
            if (myReconnectTimeout == 0)
-
 
74
            {
-
 
75
                rc = mySemaphore.wait();
-
 
76
            }
-
 
77
            else
-
 
78
            {
-
 
79
                rc = mySemaphore.wait(10);
92
            rc = mySemaphore.wait(10);
80
            }
-
 
81
 
93
 
82
            AsyncSocket::mySemaphore.unlock();
94
            AsyncSocket::mySemaphore.unlock();
83
 
95
 
84
            if (myForceReconnect)
96
            if (myForceReconnect)
85
            {
97
            {
86
                slog << "Disconnected from server.\n";
98
                slog << "Disconnected from server.\n";
87
                reconnectLoop();
99
                reconnectLoop();
88
                timeSince = time(NULL) + 10;
100
                timeSince = time(NULL) + 10;
89
                continue;
101
                continue;
90
            }
102
            }
91
 
103
 
92
            //cout << "Socket awoken...\n";
104
            //cout << "Socket awoken...\n";
93
           
105
           
94
            if (rc == ETIMEDOUT)
106
            if (rc == ETIMEDOUT)
95
            {
107
            {
96
                /* Socket timed out, this means we have not received anything in some time
108
                /* Socket timed out, this means we have not received anything in some time
97
                and we should check the connection */
109
                and we should check the connection */
98
 
110
 
99
                setEvent(ASYNCSOCKET_EVENT_INACTIVITY);
111
                setEvent(ASYNCSOCKET_EVENT_INACTIVITY);
100
                timeSince = time(NULL);
112
                timeSince = time(NULL);
101
            }
113
            }
102
            else
114
            else
103
            {
115
            {
104
                while (myOutQueue.size() > 0)
116
                while (myOutQueue.size() > 0)
105
                {
117
                {
106
                    data = myOutQueue.pop();
118
                    data = myOutQueue.pop();
107
 
119
 
108
                    //slog << "Sending: " << data << "\n";
-
 
109
 
-
 
110
                    status = ::send(mySocket, data.c_str(), data.size(), 0);
-
 
111
 
-
 
112
                    //slog << "Status: " << status << "\n";
-
 
113
 
-
 
114
                    if (status == -1)
-
 
115
                    {
-
 
116
                        switch (errno)
-
 
117
                        {
-
 
118
                            case EACCES:
-
 
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).)");
120
                    sendDataDirect(data);
120
 
-
 
121
                            case EAGAIN:
-
 
122
                            //slog << "The socket is marked non-blocking and the requested operation would block.\n";
-
 
123
                            break;
-
 
124
 
-
 
125
                            case EBADF:
-
 
126
                            throw new SocketException("An invalid descriptor was specified.");
-
 
127
 
-
 
128
                            case ECONNRESET:
-
 
129
                            throw new SocketException("Connection reset by peer.");
-
 
130
 
-
 
131
                            case EDESTADDRREQ:
-
 
132
                            throw new SocketException("The socket is not connection-mode, and no peer address is set.");
-
 
133
 
-
 
134
                            case EFAULT:
-
 
135
                            throw new SocketException("An invalid user space address was specified for an argument.");
-
 
136
 
-
 
137
                            case EINTR:
-
 
138
                            throw new SocketException("A signal occurred before any data was transmitted; see signal(7).");
-
 
139
 
-
 
140
                            case EINVAL:
-
 
141
                            throw new SocketException("1Invalid argument passed.");
-
 
142
 
-
 
143
                            case EISCONN:
-
 
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.)");
-
 
145
 
-
 
146
                            case EMSGSIZE:
-
 
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.");
-
 
148
 
-
 
149
                            case ENOBUFS:
-
 
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.)");
-
 
151
 
-
 
152
                            case ENOMEM:
-
 
153
                            throw new SocketException("No memory available.");
-
 
154
 
-
 
155
                            case ENOTCONN:
-
 
156
                            throw new SocketException("The socket is not connected, and no target has been given.");
-
 
157
 
-
 
158
                            case ENOTSOCK:
-
 
159
                            throw new SocketException("The argument s is not a socket.");
-
 
160
 
-
 
161
                            case EOPNOTSUPP:
-
 
162
                            throw new SocketException("Some bit in the flags argument is inappropriate for the socket type.");
-
 
163
 
-
 
164
                            case EPIPE:
-
 
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.");
-
 
166
 
-
 
167
                            default:
-
 
168
                            slog << "Unknow exception: " + itos(errno) + "\n";
-
 
169
                            break;
-
 
170
                        }
-
 
171
                    }
-
 
172
                }
121
                }
173
 
122
 
174
                memset(buf, 0, MAXBUFFER + 1);
123
                memset(buf, 0, MAXBUFFER + 1);
175
 
124
 
176
                status = ::recv(mySocket, buf, MAXBUFFER, 0);
125
                status = ::recv(mySocket, buf, MAXBUFFER, 0);
177
 
126
 
178
                if (status == -1)
127
                if (status == -1)
179
                {
128
                {
180
                    switch (errno)
129
                    switch (errno)
181
                    {
130
                    {
182
                        case EAGAIN:
131
                        case EAGAIN:
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";
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";
184
                        break;
133
                        break;
185
 
134
 
186
                        case EBADF:
135
                        case EBADF:
187
                        throw new SocketException("The argument s is an invalid descriptor.");
136
                        throw new SocketException("The argument s is an invalid descriptor.");
188
 
137
 
189
                        case ECONNREFUSED:
138
                        case ECONNREFUSED:
190
                        throw new SocketException("A remote host refused to allow the network connection (typically because it is not running the requested service).");
139
                        throw new SocketException("A remote host refused to allow the network connection (typically because it is not running the requested service).");
191
 
140
 
192
                        case EFAULT:
141
                        case EFAULT:
193
                        throw new SocketException("The receive buffer pointer(s) point outside the process's address space.");
142
                        throw new SocketException("The receive buffer pointer(s) point outside the process's address space.");
194
 
143
 
195
                        case EINTR:
144
                        case EINTR:
196
                        throw new SocketException("The receive was interrupted by delivery of a signal before any data were available; see signal(7).");
145
                        throw new SocketException("The receive was interrupted by delivery of a signal before any data were available; see signal(7).");
197
 
146
 
198
                        case EINVAL:
147
                        case EINVAL:
199
                        //throw new SocketException("2Invalid argument passed.");
148
                        //throw new SocketException("2Invalid argument passed.");
200
                        slog << "Disconnected from server.\n";
149
                        slog << "Disconnected from server.\n";
201
                        reconnectLoop();
150
                        reconnectLoop();
202
                        timeSince = time(NULL) + 10;
151
                        timeSince = time(NULL) + 10;
203
                        break;
152
                        break;
204
 
153
 
205
                        case ENOMEM:
154
                        case ENOMEM:
206
                        throw new SocketException("Could not allocate memory for recvmsg().");
155
                        throw new SocketException("Could not allocate memory for recvmsg().");
207
 
156
 
208
                        case ENOTCONN:
157
                        case ENOTCONN:
209
                        throw new SocketException("The socket is associated with a connection-oriented protocol and has not been connected (see connect(2) and  accept(2)).");
158
                        throw new SocketException("The socket is associated with a connection-oriented protocol and has not been connected (see connect(2) and  accept(2)).");
210
 
159
 
211
                        case ENOTSOCK:
160
                        case ENOTSOCK:
212
                        throw new SocketException("The argument s does not refer to a socket.");
161
                        throw new SocketException("The argument s does not refer to a socket.");
213
 
162
 
214
                        default:
163
                        default:
215
                        slog << "Unknow exception: " + itos(errno) + "\n";
164
                        slog << "Unknow exception: " + itos(errno) + "\n";
216
                        break;
165
                        break;
217
                    }
166
                    }
218
                }
167
                }
219
                else if (status == 0)
168
                else if (status == 0)
220
                {
169
                {
221
                    slog << "Disconnected from server.\n";
170
                    slog << "Disconnected from server.\n";
222
                    reconnectLoop();
171
                    reconnectLoop();
223
                    timeSince = time(NULL);
172
                    timeSince = time(NULL);
224
                }
173
                }
225
                else if (status > 0)
174
                else if (status > 0)
226
                {
175
                {
227
                    timeSince = time(NULL) + 10;
176
                    timeSince = time(NULL) + 10;
228
 
177
 
229
                    data = buf;
178
                    data = buf;
230
 
179
 
231
                    //slog << "Receiving: " + data + "\n";
180
                    //slog << "Receiving: " + data + "\n";
232
 
181
 
233
                    myInQueue.push(data);
182
                    myInQueue.push(data);
234
 
183
 
235
                    setEvent(ASYNCSOCKET_EVENT_DATA);
184
                    setEvent(ASYNCSOCKET_EVENT_DATA);
236
                }
185
                }
237
               
186
               
238
                if (timeSince + 10 < time(NULL))
187
                if (timeSince + 10 < time(NULL))
239
                {
188
                {
240
                    setEvent(ASYNCSOCKET_EVENT_INACTIVITY);
189
                    setEvent(ASYNCSOCKET_EVENT_INACTIVITY);
241
                    timeSince = time(NULL);
190
                    timeSince = time(NULL);
242
                }
191
                }
243
            }
192
            }
244
        }
193
        }
245
    }
194
    }
246
    catch (SocketException *e)
195
    catch (SocketException *e)
247
    {
196
    {
248
        slog << "Exception: " + e->getDescription() + "\n";
197
        slog << "Exception: " + e->getDescription() + "\n";
249
        //mySemaphore.unlock();
198
        //mySemaphore.unlock();
250
        setEvent(ASYNCSOCKET_EVENT_DIED);
199
        setEvent(ASYNCSOCKET_EVENT_DIED);
251
        stop();
200
        stop();
252
    }
201
    }
253
 
202
 
254
    close();
203
    close();
255
 
204
 
256
    //mySemaphore.unlock();
205
    //mySemaphore.unlock();
257
}
206
}
258
 
207
 
259
void AsyncSocket::reconnectLoop()
208
void AsyncSocket::reconnectLoop()
260
{
209
{
261
    if (myReconnectTimeout == 0)
210
    if (myReconnectTimeout == 0)
262
    {
211
    {
-
 
212
        close();
263
        throw new SocketException("Connection is closed.");
213
        throw new SocketException("Connection is closed.");
264
    }
214
    }
265
 
215
 
266
    SyslogStream &slog = SyslogStream::getInstance();
216
    SyslogStream &slog = SyslogStream::getInstance();
267
 
217
 
268
    while (1)
218
    while (1)
269
    {
219
    {
270
        try
220
        try
271
        {
221
        {
272
            connect();
222
            connect();
273
            break;
223
            break;
274
        }
224
        }
275
        catch (SocketException *e)
225
        catch (SocketException *e)
276
        {
226
        {
277
            slog << "Could not connect: " + e->getDescription() + "\n";
227
            slog << "Could not connect: " + e->getDescription() + "\n";
278
            slog << "Will try again in " + itos(myReconnectTimeout) + " seconds\n";
228
            slog << "Will try again in " + itos(myReconnectTimeout) + " seconds\n";
279
            sleep(myReconnectTimeout);
229
            sleep(myReconnectTimeout);
280
        }
230
        }
281
    }
231
    }
-
 
232
}
-
 
233
 
-
 
234
void AsyncSocket::create()
-
 
235
{
-
 
236
    close();
-
 
237
 
-
 
238
    mySocket = ::socket(AF_INET, SOCK_STREAM, 0);
-
 
239
 
-
 
240
    int on = 1;
-
 
241
    int status = setsockopt(mySocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on));
-
 
242
    if (status == -1)
-
 
243
    {
-
 
244
        close();
-
 
245
        throw new SocketException("Create:Reuseaddress: " + itos(errno));
-
 
246
    }
-
 
247
}
-
 
248
 
-
 
249
void AsyncSocket::startListen()
-
 
250
{
-
 
251
    create();
-
 
252
 
-
 
253
    myAddressStruct.sin_family = AF_INET;
-
 
254
    myAddressStruct.sin_addr.s_addr = INADDR_ANY;
-
 
255
    myAddressStruct.sin_port = htons(myPort);
-
 
256
 
-
 
257
    int status = ::bind(mySocket, (struct sockaddr *)&myAddressStruct, sizeof(myAddressStruct));
-
 
258
 
-
 
259
    if (status == -1)
-
 
260
    {
-
 
261
        close();
-
 
262
        switch (errno)
-
 
263
        {
-
 
264
            case EACCES:
-
 
265
            throw new SocketException("The address is protected, and the user is not the superuser.");
-
 
266
 
-
 
267
            case EADDRINUSE:
-
 
268
            throw new SocketException("The given address is already in use.");
-
 
269
 
-
 
270
            case EBADF:
-
 
271
            throw new SocketException("sockfd is not a valid descriptor.");
-
 
272
 
-
 
273
            case EINVAL:
-
 
274
            throw new SocketException("The socket is already bound to an address.");
-
 
275
 
-
 
276
            case ENOTSOCK:
-
 
277
            throw new SocketException("sockfd is a descriptor for a file, not a socket.");
-
 
278
 
-
 
279
            //case EACCES:
-
 
280
            //throw new SocketException("Search permission is denied on a component of the path prefix. (See also path_resolution(7).)");
-
 
281
 
-
 
282
            case EADDRNOTAVAIL:
-
 
283
            throw new SocketException("A nonexistent interface was requested or the requested address was not local.");
-
 
284
 
-
 
285
            case EFAULT:
-
 
286
            throw new SocketException("addr points outside the user's accessible address space.");
-
 
287
 
-
 
288
            //case EINVAL:
-
 
289
            //throw new SocketException("The addrlen is wrong, or the socket was not in the AF_UNIX family.");
-
 
290
 
-
 
291
            case ELOOP:
-
 
292
            throw new SocketException("Too many symbolic links were encountered in resolving addr.");
-
 
293
 
-
 
294
            case ENAMETOOLONG:
-
 
295
            throw new SocketException("addr is too long.");
-
 
296
 
-
 
297
            case ENOENT:
-
 
298
            throw new SocketException("The file does not exist.");
-
 
299
 
-
 
300
            case ENOMEM:
-
 
301
            throw new SocketException("Insufficient kernel memory was available.");
-
 
302
 
-
 
303
            case ENOTDIR:
-
 
304
            throw new SocketException("A component of the path prefix is not a directory.");
-
 
305
 
-
 
306
            case EROFS:
-
 
307
            throw new SocketException("The socket inode would reside on a read-only file system.");
-
 
308
 
-
 
309
            default:
-
 
310
            throw new SocketException("Unknow exception: " + itos(errno));
-
 
311
            break;
-
 
312
        }
-
 
313
    }
-
 
314
 
-
 
315
    status = ::listen(mySocket, MAXCONNECTIONS);
-
 
316
 
-
 
317
    if (status == -1)
-
 
318
    {
-
 
319
        close();
-
 
320
        switch (errno)
-
 
321
        {
-
 
322
            case EADDRINUSE:
-
 
323
            throw new SocketException("Another socket is already listening on the same port.");
-
 
324
 
-
 
325
            case EBADF:
-
 
326
            throw new SocketException("The argument sockfd is not a valid descriptor.");
-
 
327
 
-
 
328
            case ENOTSOCK:
-
 
329
            throw new SocketException("The argument sockfd is not a socket.");
-
 
330
 
-
 
331
            case EOPNOTSUPP:
-
 
332
            throw new SocketException("The socket is not of a type that supports the listen() operation.");
-
 
333
 
-
 
334
            default:
-
 
335
            throw new SocketException("Unknow exception: " + itos(errno));
-
 
336
            break;
-
 
337
        }
-
 
338
    }
-
 
339
}
-
 
340
 
-
 
341
bool AsyncSocket::accept(AsyncSocket* newSocket)
-
 
342
{
-
 
343
    int addr_length = sizeof(myAddressStruct);
-
 
344
    int socket = ::accept(mySocket, (sockaddr*)&myAddressStruct, (socklen_t*)&addr_length);
-
 
345
 
-
 
346
    if (socket > 0)
-
 
347
    {
-
 
348
        newSocket->setSocket(socket);
-
 
349
        return true;
-
 
350
    }
-
 
351
 
-
 
352
    return false;
282
}
353
}
283
 
354
 
284
void AsyncSocket::connect()
355
void AsyncSocket::connect()
285
{
356
{
286
    SyslogStream &slog = SyslogStream::getInstance();
357
    SyslogStream &slog = SyslogStream::getInstance();
287
 
358
 
288
    close();
359
    create();
289
 
-
 
290
    slog << "Trying to connect...\n";
-
 
291
 
-
 
292
    mySocket = ::socket(AF_INET, SOCK_STREAM, 0);
-
 
293
 
360
 
294
    int on = 1;
361
    int on = 1;
295
    int status = setsockopt(mySocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on));
-
 
296
    if (status == -1)
-
 
297
    {
-
 
298
        throw new SocketException("Connect:Reuseaddress: " + itos(errno));
-
 
299
    }
-
 
300
 
-
 
301
    ///FIXME: Verify that this works
362
    ///FIXME: Verify that this works
302
    status = setsockopt(mySocket, SOL_SOCKET, SO_KEEPALIVE, (const char*)&on, sizeof(on));
363
    int status = setsockopt(mySocket, SOL_SOCKET, SO_KEEPALIVE, (const char*)&on, sizeof(on));
303
    if (status == -1)
364
    if (status == -1)
304
    {
365
    {
-
 
366
        close();
305
        throw new SocketException("Connect:Keepalive: " + itos(errno));
367
        throw new SocketException("Connect:Keepalive: " + itos(errno));
306
    }
368
    }
307
 
369
 
308
    ///FIXME: Verify that this works
370
    ///FIXME: Verify that this works
309
    status = setsockopt(mySocket, SOL_TCP, TCP_KEEPIDLE, (const char*)&on, sizeof(on));
371
    status = setsockopt(mySocket, SOL_TCP, TCP_KEEPIDLE, (const char*)&on, sizeof(on));
310
    if (status == -1)
372
    if (status == -1)
311
    {
373
    {
-
 
374
        close();
312
        throw new SocketException("Connect:Keepidle: " + itos(errno));
375
        throw new SocketException("Connect:Keepidle: " + itos(errno));
313
    }
376
    }
314
 
377
 
315
    memset(&myAddressStruct, 0, sizeof(myAddressStruct));
378
    memset(&myAddressStruct, 0, sizeof(myAddressStruct));
316
 
379
 
317
    myAddressStruct.sin_family = AF_INET;
380
    myAddressStruct.sin_family = AF_INET;
318
    myAddressStruct.sin_port = htons(myPort);
381
    myAddressStruct.sin_port = htons(myPort);
319
 
382
 
320
    struct hostent *hptr = gethostbyname(myAddress.c_str());
383
    struct hostent *hptr = gethostbyname(myAddress.c_str());
321
    if (hptr == NULL)
384
    if (hptr == NULL)
322
    {
385
    {
-
 
386
        close();
323
        throw new SocketException("Connect: Could not resolv ip address");
387
        throw new SocketException("Connect: Could not resolv ip address");
324
    }
388
    }
325
 
389
 
326
    memcpy(&myAddressStruct.sin_addr, hptr->h_addr, hptr->h_length);
390
    memcpy(&myAddressStruct.sin_addr, hptr->h_addr, hptr->h_length);
327
    /*
391
    /*
328
    status = inet_pton(AF_INET, myAddress.c_str(), &myAddressStruct.sin_addr);
392
    status = inet_pton(AF_INET, myAddress.c_str(), &myAddressStruct.sin_addr);
329
 
393
 
330
    if (status == -1)
394
    if (status == -1)
331
    {
395
    {
332
        if (errno == EAFNOSUPPORT)
396
        if (errno == EAFNOSUPPORT)
333
            throw new SocketException("Connect: EAFNOSUPPORT");
397
            throw new SocketException("Connect: EAFNOSUPPORT");
334
    }
398
    }
335
    */
399
    */
336
 
400
 
-
 
401
    slog << "Trying to connect...\n";
337
   
402
 
338
    status = ::connect(mySocket, (sockaddr*)&myAddressStruct, sizeof(myAddressStruct));
403
    status = ::connect(mySocket, (sockaddr*)&myAddressStruct, sizeof(myAddressStruct));
339
 
404
 
340
    if (status == -1)
405
    if (status == -1)
341
    {
406
    {
-
 
407
        close();
342
        switch (errno)
408
        switch (errno)
343
        {
409
        {
344
            case EACCES:
410
            case EACCES:
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).)");
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).)");
346
 
412
 
347
            case EPERM:
413
            case EPERM:
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.");
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.");
349
 
415
 
350
            case EADDRINUSE:
416
            case EADDRINUSE:
351
            throw new SocketException("Local address is already in use.");
417
            throw new SocketException("Local address is already in use.");
352
 
418
 
353
            case EAFNOSUPPORT:
419
            case EAFNOSUPPORT:
354
            throw new SocketException("The passed address didn't have the correct address family in its sa_family field.");
420
            throw new SocketException("The passed address didn't have the correct address family in its sa_family field.");
355
 
421
 
356
            case EAGAIN:
422
            case EAGAIN:
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.");
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.");
358
 
424
 
359
            case EALREADY:
425
            case EALREADY:
360
            throw new SocketException("The socket is non-blocking and a previous connection attempt has not yet been completed.");
426
            throw new SocketException("The socket is non-blocking and a previous connection attempt has not yet been completed.");
361
 
427
 
362
            case EBADF:
428
            case EBADF:
363
            throw new SocketException("The file descriptor is not a valid index in the descriptor table.");
429
            throw new SocketException("The file descriptor is not a valid index in the descriptor table.");
364
 
430
 
365
            case ECONNREFUSED:
431
            case ECONNREFUSED:
366
            throw new SocketException("No-one listening on the remote address.");
432
            throw new SocketException("No-one listening on the remote address.");
367
 
433
 
368
            case EFAULT:
434
            case EFAULT:
369
            throw new SocketException("The socket structure address is outside the user's address space.");
435
            throw new SocketException("The socket structure address is outside the user's address space.");
370
 
436
 
371
            case EINPROGRESS:
437
            case EINPROGRESS:
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).");
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).");
373
 
439
 
374
            case EINTR:
440
            case EINTR:
375
            throw new SocketException("The system call was interrupted by a signal that was caught; see signal(7).");
441
            throw new SocketException("The system call was interrupted by a signal that was caught; see signal(7).");
376
 
442
 
377
            case EISCONN:
443
            case EISCONN:
378
            throw new SocketException("The socket is already connected.");
444
            throw new SocketException("The socket is already connected.");
379
 
445
 
380
            case ENETUNREACH:
446
            case ENETUNREACH:
381
            throw new SocketException("Network is unreachable.");
447
            throw new SocketException("Network is unreachable.");
382
 
448
 
383
            case ENOTSOCK:
449
            case ENOTSOCK:
384
            throw new SocketException("The file descriptor is not associated with a socket.");
450
            throw new SocketException("The file descriptor is not associated with a socket.");
385
 
451
 
386
            case ETIMEDOUT:
452
            case ETIMEDOUT:
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.");
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.");
388
 
454
 
389
            default:
455
            default:
390
            throw new SocketException("Other errors may be generated by the underlying protocol modules. : " + itos(errno));
456
            throw new SocketException("Other errors may be generated by the underlying protocol modules. : " + itos(errno));
391
        }
457
        }
392
    }
458
    }
393
 
459
 
394
    struct sigaction saio;
460
    struct sigaction saio;
395
    saio.sa_handler = AsyncSocket::signalHandler;
461
    saio.sa_handler = AsyncSocket::signalHandler;
396
    sigemptyset(&saio.sa_mask);
462
    sigemptyset(&saio.sa_mask);
397
    saio.sa_flags = 0;
463
    saio.sa_flags = 0;
398
    saio.sa_restorer = NULL;
464
    saio.sa_restorer = NULL;
399
    sigaction(SIGIO, &saio, NULL);
465
    sigaction(SIGIO, &saio, NULL);
400
 
466
 
401
    fcntl(mySocket, F_SETOWN, getpid());
467
    fcntl(mySocket, F_SETOWN, getpid());
402
    int flags = fcntl(mySocket, F_GETFL);
468
    int flags = fcntl(mySocket, F_GETFL);
403
 
469
 
404
    if (flags < 0)
470
    if (flags < 0)
-
 
471
    {
-
 
472
        close();
405
        throw new SocketException("Async socket fcntl failed");
473
        throw new SocketException("Async socket fcntl failed");
-
 
474
    }
406
 
475
 
407
    fcntl(mySocket, F_SETFL, flags | O_NONBLOCK | FASYNC);
476
    fcntl(mySocket, F_SETFL, flags | O_NONBLOCK | FASYNC);
408
 
477
 
409
    myForceReconnect = false;
478
    myForceReconnect = false;
410
 
479
 
411
    slog << "Connection established.\n";
480
    slog << "Connection established.\n";
412
}
481
}
413
 
482
 
414
void AsyncSocket::close()
483
void AsyncSocket::close()
415
{
484
{
416
    if (mySocket != -1)
485
    if (mySocket != -1)
417
    {
486
    {
418
        ::close(mySocket);
487
        ::close(mySocket);
419
        mySocket = -1;
488
        mySocket = -1;
420
        setEvent(ASYNCSOCKET_EVENT_CLOSED);
489
        setEvent(ASYNCSOCKET_EVENT_CLOSED);
421
    }
490
    }
-
 
491
}
-
 
492
 
-
 
493
bool AsyncSocket::isConnected()
-
 
494
{
-
 
495
    return mySocket != -1;
422
}
496
}
423
 
497
 
424
void AsyncSocket::setReconnectTimeout(unsigned int timeout)
498
void AsyncSocket::setReconnectTimeout(unsigned int timeout)
425
{
499
{
426
    myReconnectTimeout = timeout;
500
    myReconnectTimeout = timeout;
427
}
501
}
428
 
502
 
429
void AsyncSocket::startEvent()
503
void AsyncSocket::startEvent()
430
{
504
{
431
    myEventSemaphore.lock();
505
    myEventSemaphore.lock();
432
}
506
}
433
 
507
 
434
int AsyncSocket::getEvent()
508
int AsyncSocket::getEvent()
435
{
509
{
436
    int event = myEvent;
510
    int event = myEvent;
437
    myEvent = ASYNCSOCKET_EVENT_NONE;
511
    myEvent = ASYNCSOCKET_EVENT_NONE;
438
    return event;
512
    return event;
439
}
513
}
440
 
514
 
441
void AsyncSocket::waitForEvent()
515
void AsyncSocket::waitForEvent()
442
{
516
{
443
    myEventSemaphore.wait();
517
    myEventSemaphore.wait();
444
}
518
}
445
 
519
 
446
void AsyncSocket::stopEvent()
520
void AsyncSocket::stopEvent()
447
{
521
{
448
    myEventSemaphore.unlock();
522
    myEventSemaphore.unlock();
-
 
523
}
-
 
524
 
-
 
525
void AsyncSocket::setAddress(string address, int port)
-
 
526
{
-
 
527
    myAddress = address;
-
 
528
    myPort = port;
449
}
529
}
450
 
530
 
451
void AsyncSocket::setAddress(string address, int port)
531
void AsyncSocket::setPort(int port)
452
{
532
{
453
    myAddress = address;
-
 
454
    myPort = port;
533
    myPort = port;
455
}
534
}
-
 
535
 
-
 
536
void AsyncSocket::setSocket(int socket)
-
 
537
{
-
 
538
    mySocket = socket;
-
 
539
}
-
 
540
 
-
 
541
int AsyncSocket::getSocket()
-
 
542
{
-
 
543
    return mySocket;
-
 
544
}
456
 
545
 
457
bool AsyncSocket::availableData()
546
bool AsyncSocket::availableData()
458
{
547
{
459
    return (myInQueue.size() > 0);
548
    return (myInQueue.size() > 0);
460
}
549
}
461
 
550
 
462
string AsyncSocket::getData()
551
string AsyncSocket::getData()
463
{
552
{
464
    return myInQueue.pop();
553
    return myInQueue.pop();
465
}
554
}
466
 
555
 
467
bool AsyncSocket::sendData(string data)
556
bool AsyncSocket::sendData(string data)
468
{
557
{
469
    myOutQueue.push(data);
558
    myOutQueue.push(data);
470
    mySemaphore.broadcast();
559
    mySemaphore.broadcast();
471
    return true;
560
    return true;
-
 
561
}
-
 
562
 
-
 
563
void AsyncSocket::sendDataDirect(string data)
-
 
564
{
-
 
565
    SyslogStream &slog = SyslogStream::getInstance();
-
 
566
 
-
 
567
    //slog << "Sending: " << data << "\n";
-
 
568
 
-
 
569
    int status = ::send(mySocket, data.c_str(), data.size(), 0);
-
 
570
 
-
 
571
    //slog << "Status: " << status << "\n";
-
 
572
 
-
 
573
    if (status == -1)
-
 
574
    {
-
 
575
        switch (errno)
-
 
576
        {
-
 
577
            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).)");
-
 
579
 
-
 
580
            case EAGAIN:
-
 
581
            //slog << "The socket is marked non-blocking and the requested operation would block.\n";
-
 
582
            break;
-
 
583
 
-
 
584
            case EBADF:
-
 
585
            throw new SocketException("An invalid descriptor was specified.");
-
 
586
 
-
 
587
            case ECONNRESET:
-
 
588
            throw new SocketException("Connection reset by peer.");
-
 
589
 
-
 
590
            case EDESTADDRREQ:
-
 
591
            throw new SocketException("The socket is not connection-mode, and no peer address is set.");
-
 
592
 
-
 
593
            case EFAULT:
-
 
594
            throw new SocketException("An invalid user space address was specified for an argument.");
-
 
595
 
-
 
596
            case EINTR:
-
 
597
            throw new SocketException("A signal occurred before any data was transmitted; see signal(7).");
-
 
598
 
-
 
599
            case EINVAL:
-
 
600
            throw new SocketException("1Invalid argument passed.");
-
 
601
 
-
 
602
            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.)");
-
 
604
 
-
 
605
            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.");
-
 
607
 
-
 
608
            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.)");
-
 
610
 
-
 
611
            case ENOMEM:
-
 
612
            throw new SocketException("No memory available.");
-
 
613
 
-
 
614
            case ENOTCONN:
-
 
615
            throw new SocketException("The socket is not connected, and no target has been given.");
-
 
616
 
-
 
617
            case ENOTSOCK:
-
 
618
            throw new SocketException("The argument s is not a socket.");
-
 
619
 
-
 
620
            case EOPNOTSUPP:
-
 
621
            throw new SocketException("Some bit in the flags argument is inappropriate for the socket type.");
-
 
622
 
-
 
623
            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.");
-
 
625
 
-
 
626
            default:
-
 
627
            slog << "Unknow exception: " + itos(errno) + "\n";
-
 
628
            break;
-
 
629
        }
-
 
630
    }
472
}
631
}
473
 
632
 
474
void AsyncSocket::setEvent(int event)
633
void AsyncSocket::setEvent(int event)
475
{
634
{
476
    myEventSemaphore.lock();
635
    myEventSemaphore.lock();
477
    myEvent = event;
636
    myEvent = event;
478
    myEventSemaphore.unlock();
637
    myEventSemaphore.unlock();
479
    myEventSemaphore.broadcast();
638
    myEventSemaphore.broadcast();
480
}
639
}
481
 
640
 
482
void AsyncSocket::forceReconnect()
641
void AsyncSocket::forceReconnect()
483
{
642
{
484
    myForceReconnect = true;
643
    myForceReconnect = true;
485
    mySemaphore.broadcast();
644
    mySemaphore.broadcast();
486
}
645
}
487
 
646
 
488
void AsyncSocket::signalHandler(int signum)
647
void AsyncSocket::signalHandler(int signum)
489
{
648
{
490
    //FIXME: We must know which socket is ready to read by using select... 
649
    //FIXME: We must know which socket is ready to read by using select... 
491
    //cout << "DEBUG: signalHandler signum: " << signum << endl;
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;
492
    mySemaphore.broadcast();
658
        iter->second->mySemaphore.broadcast();
-
 
659
    }
-
 
660
    mySocketsMutex.unlock();
-
 
661
   
493
}
662
}
494
 
663