Subversion Repositories HomeAutomation

Rev

Rev 969 | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | SVN | RSS feed

Rev 969 Rev 974
Line 25... Line 25...
25
 
25
 
26
AsyncSocket::AsyncSocket()
26
AsyncSocket::AsyncSocket()
27
{
27
{
28
    mySocket = -1;
28
    mySocket = -1;
29
    myReconnectTimeout = 10;
29
    myReconnectTimeout = 10;
-
 
30
    myForceReconnect = false;
30
 
31
 
31
    Thread<AsyncSocket>();
32
    Thread<AsyncSocket>();
32
}
33
}
33
 
34
 
34
AsyncSocket::~AsyncSocket()
35
AsyncSocket::~AsyncSocket()
Line 49... Line 50...
49
    reconnectLoop();
50
    reconnectLoop();
50
 
51
 
51
    char buf[MAXBUFFER + 1];
52
    char buf[MAXBUFFER + 1];
52
    string data;
53
    string data;
53
    int status;
54
    int status;
-
 
55
    int rc;
-
 
56
    int timeSince = time(NULL) + 10;
54
 
57
   
55
    AsyncSocket::mySemaphore.lock();
58
    AsyncSocket::mySemaphore.lock();
56
 
59
 
57
    try
60
    try
58
    {
61
    {
59
        while (1)
62
        while (1)
60
        {
63
        {
61
            mySemaphore.wait();
64
            rc = mySemaphore.wait(5);
-
 
65
 
-
 
66
            if (myForceReconnect)
-
 
67
            {
-
 
68
                slog << "Disconnected from server.\n";
-
 
69
                reconnectLoop();
-
 
70
                timeSince = time(NULL) + 10;
-
 
71
                continue;
-
 
72
            }
62
 
73
 
63
            //cout << "Socket awoken...\n";
74
            //cout << "Socket awoken...\n";
64
 
75
           
-
 
76
            if (rc == ETIMEDOUT)
-
 
77
            {
-
 
78
                /* Socket timed out, this means we have not received anything in some time
-
 
79
                and we should check the connection */
-
 
80
 
-
 
81
                setEvent(ASYNCSOCKET_EVENT_INACTIVITY);
-
 
82
                timeSince = time(NULL);
-
 
83
            }
-
 
84
            else
-
 
85
            {
65
            while (myOutQueue.size() > 0)
86
                while (myOutQueue.size() > 0)
66
            {
87
                {
67
                data = myOutQueue.pop();
88
                    data = myOutQueue.pop();
68
 
89
 
69
                //slog << "Sending: " << data << "\n";
90
                    //slog << "Sending: " << data << "\n";
70
 
91
 
71
                status = ::send(mySocket, data.c_str(), data.size(), 0);
92
                    status = ::send(mySocket, data.c_str(), data.size(), 0);
-
 
93
 
-
 
94
                    //slog << "Status: " << status << "\n";
72
 
95
 
73
                if (status == -1)
96
                    if (status == -1)
74
                {
97
                    {
75
                    switch (errno)
98
                        switch (errno)
76
                    {
99
                        {
Line 78... Line 101...
78
                        throw new SocketException("(For  Unix  domain sockets, which are identified by pathname) Write permission is denied on the destination socket file, or search permission is denied for one of the directories the path prefix.  (See path_resolution(7).)");
101
                            throw new SocketException("(For  Unix  domain sockets, which are identified by pathname) Write permission is denied on the destination socket file, or search permission is denied for one of the directories the path prefix.  (See path_resolution(7).)");
79
 
102
 
80
                        case EAGAIN:
103
                            case EAGAIN:
81
                        //slog << "The socket is marked non-blocking and the requested operation would block.\n";
104
                            //slog << "The socket is marked non-blocking and the requested operation would block.\n";
82
                        break;
105
                            break;
83
 
106
 
84
                        case EBADF:
107
                            case EBADF:
85
                        throw new SocketException("An invalid descriptor was specified.");
108
                            throw new SocketException("An invalid descriptor was specified.");
86
 
109
 
87
                        case ECONNRESET:
110
                            case ECONNRESET:
88
                        throw new SocketException("Connection reset by peer.");
111
                            throw new SocketException("Connection reset by peer.");
Line 93... Line 116...
93
                        case EFAULT:
116
                            case EFAULT:
94
                        throw new SocketException("An invalid user space address was specified for an argument.");
117
                            throw new SocketException("An invalid user space address was specified for an argument.");
95
 
118
 
96
                        case EINTR:
119
                            case EINTR:
97
                        throw new SocketException("A signal occurred before any data was transmitted; see signal(7).");
120
                            throw new SocketException("A signal occurred before any data was transmitted; see signal(7).");
98
 
121
 
99
                        case EINVAL:
122
                            case EINVAL:
100
                        throw new SocketException("Invalid argument passed.");
123
                            throw new SocketException("1Invalid argument passed.");
101
 
124
 
102
                        case EISCONN:
125
                            case EISCONN:
103
                        throw new SocketException("The connection-mode socket was connected already but a recipient was specified. (Now either this error is returned, or the recipient specification is ignored.)");
126
                            throw new SocketException("The connection-mode socket was connected already but a recipient was specified. (Now either this error is returned, or the recipient specification is ignored.)");
104
 
127
 
105
                        case EMSGSIZE:
128
                            case EMSGSIZE:
106
                        throw new SocketException("The socket type requires that message be sent atomically, and the size of the message to be sent made this impossible.");
129
                            throw new SocketException("The socket type requires that message be sent atomically, and the size of the message to be sent made this impossible.");
107
 
130
 
108
                        case ENOBUFS:
131
                            case ENOBUFS:
109
                        throw new SocketException("The output queue for a network interface was full.  This generally indicates that the interface has stopped sending, but may be caused by transient congestion.  (Normally, this does not occur in Linux.  Packets are just silently dropped when a device queue overflows.)");
132
                            throw new SocketException("The output queue for a network interface was full.  This generally indicates that the interface has stopped sending, but may be caused by transient congestion.  (Normally, this does not occur in Linux.  Packets are just silently dropped when a device queue overflows.)");
110
 
133
 
111
                        case ENOMEM:
134
                            case ENOMEM:
112
                        throw new SocketException("No memory available.");
135
                            throw new SocketException("No memory available.");
113
 
136
 
114
                        case ENOTCONN:
137
                            case ENOTCONN:
115
                        throw new SocketException("The socket is not connected, and no target has been given.");
138
                            throw new SocketException("The socket is not connected, and no target has been given.");
116
 
139
 
117
                        case ENOTSOCK:
140
                            case ENOTSOCK:
118
                        throw new SocketException("The argument s is not a socket.");
141
                            throw new SocketException("The argument s is not a socket.");
Line 123... Line 146...
123
                        case EPIPE:
146
                            case EPIPE:
124
                        throw new SocketException("The  local end has been shut down on a connection oriented socket. In this case the process will also receive a SIGPIPE unless MSG_NOSIGNAL is set.");
147
                            throw new SocketException("The  local end has been shut down on a connection oriented socket. In this case the process will also receive a SIGPIPE unless MSG_NOSIGNAL is set.");
125
 
148
 
126
                        default:
149
                            default:
127
                        slog << "Unknow exception: " << errno << "\n";
150
                            slog << "Unknow exception: " << errno << "\n";
128
                        break;
151
                            break;
129
                    }
152
                        }
130
                }
153
                    }
131
            }
154
                }
132
 
155
 
133
            memset(buf, 0, MAXBUFFER + 1);
156
                memset(buf, 0, MAXBUFFER + 1);
134
 
157
 
135
            status = ::recv(mySocket, buf, MAXBUFFER, 0);
158
                status = ::recv(mySocket, buf, MAXBUFFER, 0);
-
 
159
 
-
 
160
                //slog << "Receiving: " << buf << "\n";
136
 
161
 
137
            if (status == -1)
162
                if (status == -1)
138
            {
163
                {
139
                switch (errno)
164
                    switch (errno)
140
                {
165
                    {
141
                    case EAGAIN:
166
                        case EAGAIN:
142
                    //slog << "The socket is marked non-blocking and the receive operation would block, or a receive timeout had been set and the timeout expired before data was received.\n";
167
                        //slog << "The socket is marked non-blocking and the receive operation would block, or a receive timeout had been set and the timeout expired before data was received.\n";
143
                    break;
168
                        break;
144
 
169
 
145
                    case EBADF:
170
                        case EBADF:
146
                    throw new SocketException("The argument s is an invalid descriptor.");
171
                        throw new SocketException("The argument s is an invalid descriptor.");
147
 
172
 
148
                    case ECONNREFUSED:
173
                        case ECONNREFUSED:
149
                    throw new SocketException("A remote host refused to allow the network connection (typically because it is not running the requested service).");
174
                        throw new SocketException("A remote host refused to allow the network connection (typically because it is not running the requested service).");
150
 
175
 
151
                    case EFAULT:
176
                        case EFAULT:
152
                    throw new SocketException("The receive buffer pointer(s) point outside the process's address space.");
177
                        throw new SocketException("The receive buffer pointer(s) point outside the process's address space.");
153
 
178
 
154
                    case EINTR:
179
                        case EINTR:
155
                    throw new SocketException("The receive was interrupted by delivery of a signal before any data were available; see signal(7).");
180
                        throw new SocketException("The receive was interrupted by delivery of a signal before any data were available; see signal(7).");
156
 
181
 
157
                    case EINVAL:
182
                        case EINVAL:
158
                    throw new SocketException("Invalid argument passed.");
183
                        //throw new SocketException("2Invalid argument passed.");
-
 
184
                        slog << "Disconnected from server.\n";
-
 
185
                        reconnectLoop();
-
 
186
                        break;
159
 
187
 
160
                    case ENOMEM:
188
                        case ENOMEM:
161
                    throw new SocketException("Could not allocate memory for recvmsg().");
189
                        throw new SocketException("Could not allocate memory for recvmsg().");
162
 
190
 
163
                    case ENOTCONN:
191
                        case ENOTCONN:
164
                    throw new SocketException("The socket is associated with a connection-oriented protocol and has not been connected (see connect(2) and  accept(2)).");
192
                        throw new SocketException("The socket is associated with a connection-oriented protocol and has not been connected (see connect(2) and  accept(2)).");
165
 
193
 
166
                    case ENOTSOCK:
194
                        case ENOTSOCK:
167
                    throw new SocketException("The argument s does not refer to a socket.");
195
                        throw new SocketException("The argument s does not refer to a socket.");
168
 
196
 
169
                    default:
197
                        default:
170
                    slog << "Unknow exception: " << errno << "\n";
198
                        slog << "Unknow exception: " << errno << "\n";
171
                    break;
199
                        break;
172
                }
200
                    }
173
            }
201
                }
174
            else if (status == 0)
202
                else if (status == 0)
175
            {
203
                {
176
                slog << "Disconnected from server.\n";
204
                    slog << "Disconnected from server.\n";
177
                reconnectLoop();
205
                    reconnectLoop();
178
            }
206
                }
179
            else if (status > 0)
207
                else if (status > 0)
180
            {
208
                {
181
                data = buf;
209
                    data = buf;
182
 
210
 
183
                myInQueue.push(data);
211
                    myInQueue.push(data);
184
 
212
 
185
                setEvent(ASYNCSOCKET_EVENT_DATA);
213
                    setEvent(ASYNCSOCKET_EVENT_DATA);
-
 
214
                   
-
 
215
                    timeSince = time(NULL);
-
 
216
                }
-
 
217
               
-
 
218
                if (timeSince + 10 < time(NULL))
-
 
219
                {
-
 
220
                    setEvent(ASYNCSOCKET_EVENT_INACTIVITY);
-
 
221
                    timeSince = time(NULL);
-
 
222
                }
186
            }
223
            }
187
        }
224
        }
188
    }
225
    }
189
    catch (SocketException *e)
226
    catch (SocketException *e)
190
    {
227
    {
191
        slog << "Exception: " << e->getDescription() << "\n";
228
        slog << "Exception: " << e->getDescription() << "\n";
192
        mySemaphore.unlock();
229
        mySemaphore.unlock();
193
        setEvent(ASYNCSOCKET_EVENT_DIED);
230
        setEvent(ASYNCSOCKET_EVENT_DIED);
194
        stop();
231
        stop();
195
    }
232
    }
196
 
233
 
197
    close();
234
    close();
198
 
235
 
199
    mySemaphore.unlock();
236
    mySemaphore.unlock();
200
}
237
}
201
 
238
 
202
void AsyncSocket::reconnectLoop()
239
void AsyncSocket::reconnectLoop()
203
{
240
{
204
    SyslogStream &slog = SyslogStream::getInstance();
241
    SyslogStream &slog = SyslogStream::getInstance();
205
 
242
 
206
    while (1)
243
    while (1)
207
    {
244
    {
208
        try
245
        try
209
        {
246
        {
210
            slog << "Trying to connect...\n";
247
            slog << "Trying to connect...\n";
211
            connect();
248
            connect();
212
            slog << "Connection established.\n";
249
            slog << "Connection established.\n";
Line 220... Line 257...
220
        }
257
        }
221
    }
258
    }
222
}
259
}
223
 
260
 
224
void AsyncSocket::connect()
261
void AsyncSocket::connect()
225
{
262
{
226
    if (mySocket != -1)
263
    if (mySocket != -1)
227
    {
264
    {
228
        ::close(mySocket);
265
        ::close(mySocket);
229
        mySocket = -1;
266
        mySocket = -1;
230
    }
267
    }
231
   
268
   
232
    mySocket = ::socket(AF_INET, SOCK_STREAM, 0);
269
    mySocket = ::socket(AF_INET, SOCK_STREAM, 0);
233
 
270
 
234
    // TIME_WAIT - argh
-
 
235
    int on = 1;
271
    int on = 1;
236
    int status = setsockopt(mySocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on));
272
    int status = setsockopt(mySocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on));
237
    if (status == -1)
273
    if (status == -1)
238
    {
274
    {
-
 
275
        throw new SocketException("Connect:Reuseaddress: " + itos(errno));
-
 
276
    }
-
 
277
 
-
 
278
    ///FIXME: Verify that this works
-
 
279
    status = setsockopt(mySocket, SOL_SOCKET, SO_KEEPALIVE, (const char*)&on, sizeof(on));
-
 
280
    if (status == -1)
-
 
281
    {
-
 
282
        throw new SocketException("Connect:Keepalive: " + itos(errno));
-
 
283
    }
-
 
284
 
-
 
285
    ///FIXME: Verify that this works
-
 
286
    status = setsockopt(mySocket, SOL_TCP, TCP_KEEPIDLE, (const char*)&on, sizeof(on));
-
 
287
    if (status == -1)
-
 
288
    {
239
        throw new SocketException("Connect: " + itos(errno));
289
        throw new SocketException("Connect:Keepidle: " + itos(errno));
240
    }
290
    }
241
 
291
 
242
    memset(&myAddressStruct, 0, sizeof(myAddressStruct));
292
    memset(&myAddressStruct, 0, sizeof(myAddressStruct));
243
 
293
 
244
    myAddressStruct.sin_family = AF_INET;
294
    myAddressStruct.sin_family = AF_INET;
Line 320... Line 370...
320
 
370
 
321
    if (flags < 0)
371
    if (flags < 0)
322
        throw new SocketException("Async socket fcntl failed");
372
        throw new SocketException("Async socket fcntl failed");
323
 
373
 
324
    fcntl(mySocket, F_SETFL, flags | O_NONBLOCK | FASYNC);
374
    fcntl(mySocket, F_SETFL, flags | O_NONBLOCK | FASYNC);
-
 
375
 
-
 
376
    myForceReconnect = false;
325
}
377
}
326
 
378
 
327
void AsyncSocket::close()
379
void AsyncSocket::close()
328
{
380
{
329
    if (mySocket != -1)
381
    if (mySocket != -1)
330
    {
382
    {
331
        ::close(mySocket);
383
        ::close(mySocket);
332
        mySocket = -1;
384
        mySocket = -1;
333
        setEvent(ASYNCSOCKET_EVENT_CLOSED);
385
        setEvent(ASYNCSOCKET_EVENT_CLOSED);
334
    }
386
    }
335
}
387
}
336
 
388
 
337
void AsyncSocket::setReconnectTimeout(unsigned int timeout)
389
void AsyncSocket::setReconnectTimeout(unsigned int timeout)
338
{
390
{
339
    myReconnectTimeout = timeout;
391
    myReconnectTimeout = timeout;
340
}
392
}
341
 
393
 
342
void AsyncSocket::startEvent()
394
void AsyncSocket::startEvent()
343
{
395
{
Line 347... Line 399...
347
int AsyncSocket::getEvent()
399
int AsyncSocket::getEvent()
348
{
400
{
349
    int event = myEvent;
401
    int event = myEvent;
350
    myEvent = ASYNCSOCKET_EVENT_NONE;
402
    myEvent = ASYNCSOCKET_EVENT_NONE;
351
    return event;
403
    return event;
352
}
404
}
353
 
405
 
354
void AsyncSocket::waitForEvent()
406
void AsyncSocket::waitForEvent()
355
{
407
{
356
    myEventSemaphore.wait();
408
    myEventSemaphore.wait();
357
}
409
}
358
 
410
 
359
void AsyncSocket::stopEvent()
411
void AsyncSocket::stopEvent()
360
{
412
{
361
    myEventSemaphore.unlock();
413
    myEventSemaphore.unlock();
362
}
414
}
363
 
415
 
364
void AsyncSocket::setAddress(string address, int port)
416
void AsyncSocket::setAddress(string address, int port)
365
{
417
{
366
    myAddress = address;
418
    myAddress = address;
367
    myPort = port;
419
    myPort = port;
Line 388... Line 440...
388
{
440
{
389
    myEventSemaphore.lock();
441
    myEventSemaphore.lock();
390
    myEvent = event;
442
    myEvent = event;
391
    myEventSemaphore.unlock();
443
    myEventSemaphore.unlock();
392
    myEventSemaphore.broadcast();
444
    myEventSemaphore.broadcast();
-
 
445
}
-
 
446
 
-
 
447
void AsyncSocket::forceReconnect()
-
 
448
{
-
 
449
    myForceReconnect = true;
-
 
450
    mySemaphore.broadcast();
393
}
451
}
394
 
452
 
395
void AsyncSocket::signalHandler(int signum)
453
void AsyncSocket::signalHandler(int signum)
396
{
454
{
-
 
455
    //FIXME: We must know which socket is ready to read by using select... 
397
    //cout << "DEBUG: signalHandler signum: " << signum << endl;
456
    //cout << "DEBUG: signalHandler signum: " << signum << endl;
398
    mySemaphore.broadcast();
457
    mySemaphore.broadcast();
399
}
458
}