Subversion Repositories HomeAutomation

Rev

Rev 975 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | SVN | RSS feed

Rev 975 Rev 976
Line 18... Line 18...
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();
Line 45... Line 45...
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();
Line 145... Line 163...
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
 
177
 
160
                //slog << "Receiving: " << buf << "\n";
-
 
161
 
-
 
162
                if (status == -1)
178
                if (status == -1)
163
                {
179
                {
164
                    switch (errno)
180
                    switch (errno)
165
                    {
181
                    {
166
                        case EAGAIN:
182
                        case EAGAIN:
Line 176... Line 192...
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);
Line 223... Line 243...
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
    {
Line 368... Line 405...
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)