Subversion Repositories HomeAutomation

Rev

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

Rev 983 Rev 984
Line 27... Line 27...
27
{
27
{
28
    myId = socketCount++;
28
    myId = socketCount++;
29
    mySocket = -1;
29
    mySocket = -1;
30
    myReconnectTimeout = 0;
30
    myReconnectTimeout = 0;
31
    myForceReconnect = false;
31
    myForceReconnect = false;
32
 
-
 
33
    Thread<AsyncSocket>();
-
 
34
}
32
}
35
 
33
 
36
AsyncSocket::~AsyncSocket()
34
AsyncSocket::~AsyncSocket()
37
{
35
{
38
    if (mySocket != -1)
-
 
39
    {
-
 
40
        ::close(mySocket);
-
 
41
    }
-
 
42
 
-
 
43
    stop();
36
    stop();
-
 
37
    silentClose();
44
}
38
}
45
 
39
 
46
void AsyncSocket::run()
40
void AsyncSocket::run()
47
{
41
{
48
    SyslogStream &slog = SyslogStream::getInstance();
42
    // If connection is already up then we should not connect again
49
 
-
 
50
    if (!isConnected())
43
    if (!isConnected())
51
    {
44
    {
-
 
45
        // If we have choosen to not use automatic reconnect do not start reconnect loop
52
        if (myReconnectTimeout == 0)
46
        if (myReconnectTimeout == 0)
53
        {
47
        {
-
 
48
            // Connect to somewhere
54
            connect();
49
            connect();
55
        }
50
        }
56
        else
51
        else
57
        {
52
        {
-
 
53
            // Start the reconnect loop
-
 
54
            reconnectLoop();
-
 
55
        }
-
 
56
    }
-
 
57
 
-
 
58
    bool loop = true;
-
 
59
    try
-
 
60
    {
-
 
61
        while (loop)
-
 
62
        {
-
 
63
            // If we have triggered a forced reconnect do it here
-
 
64
            if (myForceReconnect)
-
 
65
            {
-
 
66
                myForceReconnect = false;
58
            reconnectLoop();
67
                reconnectLoop();
59
        }
68
            }
-
 
69
 
-
 
70
            // Receive data
-
 
71
            loop = receiveData();
-
 
72
        }
-
 
73
    }
-
 
74
    catch (SocketException *e)
-
 
75
    {
-
 
76
        // Something bad happend and we can not continue
-
 
77
        eventAdd(SocketEvent::TYPE_CONNECTION_DIED, e->getDescription());
60
    }
78
    }
61
 
79
 
-
 
80
    // Clean up socket if we would want to restart
-
 
81
    silentClose();
-
 
82
}
-
 
83
 
-
 
84
bool AsyncSocket::receiveData()
-
 
85
{
62
    char buf[MAXBUFFER + 1];
86
    char buffer[MAXBUFFER + 1];
63
    string data;
87
    memset(buffer, 0, MAXBUFFER + 1);
-
 
88
 
64
    int status;
89
    int status = ::recv(mySocket, buffer, MAXBUFFER, 0);
65
 
90
 
66
    bool loop = true;
91
    if (status == -1)
67
    try
-
 
68
    {
-
 
69
        while (loop)
-
 
70
        {
92
    {
71
            if (myForceReconnect)
-
 
72
            {
-
 
73
                reconnectLoop();
-
 
74
            }
-
 
75
 
-
 
76
            memset(buf, 0, MAXBUFFER + 1);
-
 
77
            status = ::recv(mySocket, buf, MAXBUFFER, 0);
-
 
78
 
-
 
79
            if (status == -1)
-
 
80
            {
-
 
81
                switch (errno)
93
        switch (errno)
82
                {
94
        {
83
                    case EAGAIN:
95
            case EAGAIN:
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.");
96
            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.");
85
                    break;
-
 
86
 
97
 
87
                    case EBADF:
98
            case EBADF:
88
                    throw new SocketException("The argument s is an invalid descriptor.");
99
            throw new SocketException("The argument s is an invalid descriptor.");
89
 
100
 
90
                    case ECONNREFUSED:
101
            case ECONNREFUSED:
91
                    throw new SocketException("A remote host refused to allow the network connection (typically because it is not running the requested service).");
102
            throw new SocketException("A remote host refused to allow the network connection (typically because it is not running the requested service).");
92
 
103
 
93
                    case EFAULT:
104
            case EFAULT:
94
                    throw new SocketException("The receive buffer pointer(s) point outside the process's address space.");
105
            throw new SocketException("The receive buffer pointer(s) point outside the process's address space.");
95
 
106
 
96
                    case EINTR:
107
            case EINTR:
97
                    throw new SocketException("The receive was interrupted by delivery of a signal before any data were available; see signal(7).");
108
            throw new SocketException("The receive was interrupted by delivery of a signal before any data were available; see signal(7).");
98
 
109
 
99
                    case EINVAL:
110
            case EINVAL:
100
                    throw new SocketException("Invalid argument passed.");
111
            throw new SocketException("Invalid argument passed.");
101
                    break;
-
 
102
 
112
 
103
                    case ENOMEM:
113
            case ENOMEM:
104
                    throw new SocketException("Could not allocate memory for recvmsg().");
114
            throw new SocketException("Could not allocate memory for recvmsg().");
105
 
115
 
106
                    case ENOTCONN:
116
            case ENOTCONN:
Line 108... Line 118...
108
 
118
 
109
                    case ENOTSOCK:
119
            case ENOTSOCK:
110
                    throw new SocketException("The argument s does not refer to a socket.");
120
            throw new SocketException("The argument s does not refer to a socket.");
111
 
121
 
112
                    case ECONNRESET:
122
            case ECONNRESET:
113
                    setEvent(ASYNCSOCKET_EVENT_RESET);
123
            eventAdd(SocketEvent::TYPE_CONNECTION_RESET);
-
 
124
 
-
 
125
            // If we have automatic reconnect we want to start it now
114
                    if (myReconnectTimeout > 0)
126
            if (myReconnectTimeout == 0)
115
                    {
127
            {
116
                        reconnectLoop();
128
                reconnectLoop();
117
                    }
129
            }
118
                    else
130
            else
119
                    {
131
            {
-
 
132
                // Otherwise we would like to end the main loop
120
                        loop = false;
133
                return false;
121
                    }
134
            }
122
                    break;
135
            break;
123
 
136
 
124
                    default:
137
            default:
125
                    throw new SocketException("Unknow exception: " + itos(errno));
138
            throw new SocketException("Unknow exception: " + itos(errno));
126
                    break;
139
            break;
127
                }
140
        }
128
            }
141
    }
129
            else if (status == 0)
142
    else if (status == 0)
130
            {
143
    {
-
 
144
        // Remote host have done a normal shutdown
131
                setEvent(ASYNCSOCKET_EVENT_CLOSED);
145
        eventAdd(SocketEvent::TYPE_CONNECTION_CLOSED);
-
 
146
 
132
                if (myReconnectTimeout > 0)
147
        if (myReconnectTimeout > 0)
133
                {
148
        {
134
                    reconnectLoop();
149
            reconnectLoop();
135
                }
150
        }
136
                else
151
        else
137
                {
152
        {
138
                    loop = false;
153
            return false;
139
                }
154
        }
140
            }
155
    }
141
            else if (status > 0)
156
    else if (status > 0)
142
            {
157
    {
143
                data = buf;
158
        // We have received data
-
 
159
        eventAdd(SocketEvent::TYPE_DATA, buffer);
144
 
160
    }
145
                //slog << "Received: " + data + "\n";
-
 
146
 
161
 
147
                myInQueue.push(data);
162
    return true;
148
                setEvent(ASYNCSOCKET_EVENT_DATA);
-
 
149
            }
163
}
150
        }
164
 
-
 
165
void AsyncSocket::silentClose()
151
    }
166
{
152
    catch (SocketException *e)
167
    if (mySocket != -1)
153
    {
168
    {
154
        slog << "Exception: " + e->getDescription() + "\n";
169
        ::close(mySocket);
155
        setEvent(ASYNCSOCKET_EVENT_DIED);
170
        mySocket = -1;
-
 
171
    }
156
    }
172
}
157
 
173
 
-
 
174
void AsyncSocket::close()
-
 
175
{
158
    close();
176
    silentClose();
-
 
177
    eventAdd(SocketEvent::TYPE_CONNECTION_CLOSED);
159
}
178
}
160
 
179
 
161
void AsyncSocket::reconnectLoop()
180
void AsyncSocket::reconnectLoop()
162
{
181
{
163
    SyslogStream &slog = SyslogStream::getInstance();
-
 
164
 
-
 
165
    while (1)
182
    while (true)
166
    {
183
    {
167
        try
184
        try
168
        {
185
        {
169
            connect();
186
            connect();
170
            break;
187
            return;
171
        }
188
        }
172
        catch (SocketException *e)
189
        catch (SocketException *e)
173
        {
190
        {
174
            setEvent(ASYNCSOCKET_EVENT_CONNECT_FAILED);
191
            eventAdd(SocketEvent::TYPE_CONNECTION_FAILED, e->getDescription());
175
            setEvent(ASYNCSOCKET_EVENT_WAITING_TO_RECONNECT);
192
            eventAdd(SocketEvent::TYPE_WAITING_RECONNECT);
176
            slog << "Could not connect: " + e->getDescription() + "\n";//FIXME: Remove these
-
 
177
            slog << "Will try again in " + itos(myReconnectTimeout) + " seconds\n";
-
 
178
            sleep(myReconnectTimeout);
193
            sleep(myReconnectTimeout);
179
        }
194
        }
180
    }
195
    }
181
}
196
}
182
 
197
 
183
void AsyncSocket::create()
198
void AsyncSocket::create()
184
{
199
{
185
    close();
200
    silentClose();
186
 
201
 
187
    mySocket = ::socket(AF_INET, SOCK_STREAM, 0);
202
    mySocket = ::socket(AF_INET, SOCK_STREAM, 0);
188
 
203
 
189
    int on = 1;
204
    int on = 1;
190
    int status = setsockopt(mySocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on));
205
    int status = setsockopt(mySocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on));
191
    if (status == -1)
206
    if (status == -1)
192
    {
207
    {
193
        close();
208
        silentClose();
194
        throw new SocketException("Create:Reuseaddress: " + itos(errno));
209
        throw new SocketException("Create:Reuseaddress: " + itos(errno));
195
    }
210
    }
196
}
211
}
197
 
212
 
198
void AsyncSocket::startListen()
213
void AsyncSocket::startListen()
199
{
214
{
200
    create();
215
    create();
201
 
216
 
202
    myAddressStruct.sin_family = AF_INET;
217
    myAddressStruct.sin_family = AF_INET;
Line 205... Line 220...
205
 
220
 
206
    int status = ::bind(mySocket, (struct sockaddr *)&myAddressStruct, sizeof(myAddressStruct));
221
    int status = ::bind(mySocket, (struct sockaddr *)&myAddressStruct, sizeof(myAddressStruct));
207
 
222
 
208
    if (status == -1)
223
    if (status == -1)
209
    {
224
    {
210
        close();
225
        silentClose();
211
        switch (errno)
226
        switch (errno)
212
        {
227
        {
213
            case EACCES:
228
            case EACCES:
214
            throw new SocketException("The address is protected, and the user is not the superuser.");
229
            throw new SocketException("The address is protected, and the user is not the superuser.");
215
 
230
 
Line 263... Line 278...
263
 
278
 
264
    status = ::listen(mySocket, MAXCONNECTIONS);
279
    status = ::listen(mySocket, MAXCONNECTIONS);
265
 
280
 
266
    if (status == -1)
281
    if (status == -1)
267
    {
282
    {
268
        close();
283
        silentClose();
269
        switch (errno)
284
        switch (errno)
270
        {
285
        {
271
            case EADDRINUSE:
286
            case EADDRINUSE:
272
            throw new SocketException("Another socket is already listening on the same port.");
287
            throw new SocketException("Another socket is already listening on the same port.");
273
 
288
 
Line 301... Line 316...
301
    return false;
316
    return false;
302
}
317
}
303
 
318
 
304
void AsyncSocket::connect()
319
void AsyncSocket::connect()
305
{
320
{
306
    SyslogStream &slog = SyslogStream::getInstance();
321
    eventAdd(SocketEvent::TYPE_CONNECTING);
307
 
322
 
308
    create();
323
    create();
309
 
324
 
310
    memset(&myAddressStruct, 0, sizeof(myAddressStruct));
325
    memset(&myAddressStruct, 0, sizeof(myAddressStruct));
311
 
326
 
312
    myAddressStruct.sin_family = AF_INET;
327
    myAddressStruct.sin_family = AF_INET;
313
    myAddressStruct.sin_port = htons(myPort);
328
    myAddressStruct.sin_port = htons(myPort);
314
 
-
 
315
    //slog << "Trying to resolv " + myAddress + "\n";
-
 
316
 
329
 
317
    struct hostent *hptr = gethostbyname(myAddress.c_str());
330
    struct hostent *hptr = gethostbyname(myAddress.c_str());
318
    if (hptr == NULL)
331
    if (hptr == NULL)
319
    {
332
    {
320
        close();
333
        silentClose();
321
        throw new SocketException("Connect: Could not resolv ip address");
334
        throw new SocketException("Connect: Could not resolv ip address");
322
    }
335
    }
323
 
-
 
324
   
336
 
325
    memcpy(&myAddressStruct.sin_addr, hptr->h_addr, hptr->h_length);
337
    memcpy(&myAddressStruct.sin_addr, hptr->h_addr, hptr->h_length);
326
 
338
 
327
    int status = ::connect(mySocket, (sockaddr*)&myAddressStruct, sizeof(myAddressStruct));
339
    int status = ::connect(mySocket, (sockaddr*)&myAddressStruct, sizeof(myAddressStruct));
328
 
340
 
329
    if (status == -1)
341
    if (status == -1)
330
    {
342
    {
331
        close();
343
        silentClose();
332
        switch (errno)
344
        switch (errno)
333
        {
345
        {
334
            case EACCES:
346
            case EACCES:
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).)");
347
            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).)");
336
 
348
 
Line 379... Line 391...
379
            default:
391
            default:
380
            throw new SocketException("Other errors may be generated by the underlying protocol modules. : " + itos(errno));
392
            throw new SocketException("Other errors may be generated by the underlying protocol modules. : " + itos(errno));
381
        }
393
        }
382
    }
394
    }
383
 
395
 
384
    myForceReconnect = false;
-
 
385
 
-
 
386
    setEvent(ASYNCSOCKET_EVENT_CONNECTED);
396
    eventAdd(SocketEvent::TYPE_CONNECTED);
387
}
-
 
388
 
-
 
389
void AsyncSocket::close()
-
 
390
{
-
 
391
    if (mySocket != -1)
-
 
392
    {
-
 
393
        ::close(mySocket);
-
 
394
        mySocket = -1;
-
 
395
        setEvent(ASYNCSOCKET_EVENT_CLOSED);
-
 
396
    }
-
 
397
}
-
 
398
 
-
 
399
bool AsyncSocket::isConnected()
-
 
400
{
-
 
401
    return mySocket != -1;
-
 
402
}
-
 
403
 
-
 
404
void AsyncSocket::setReconnectTimeout(unsigned int timeout)
-
 
405
{
-
 
406
    myReconnectTimeout = timeout;
-
 
407
}
-
 
408
 
-
 
409
void AsyncSocket::startEvent()
-
 
410
{
-
 
411
    myEventSemaphore.lock();
-
 
412
}
-
 
413
 
-
 
414
bool AsyncSocket::availableEvent()
-
 
415
{
-
 
416
    return (myEventQueue.size() > 0);
-
 
417
}
-
 
418
 
-
 
419
int AsyncSocket::getEvent()
-
 
420
{
-
 
421
    return myEventQueue.pop();
-
 
422
}
-
 
423
 
-
 
424
void AsyncSocket::waitForEvent()
-
 
425
{
-
 
426
    myEventSemaphore.wait();
-
 
427
}
-
 
428
 
-
 
429
void AsyncSocket::stopEvent()
-
 
430
{
-
 
431
    myEventSemaphore.unlock();
-
 
432
}
-
 
433
 
-
 
434
void AsyncSocket::setAddress(string address, int port)
-
 
435
{
-
 
436
    myAddress = address;
-
 
437
    myPort = port;
-
 
438
}
-
 
439
 
-
 
440
void AsyncSocket::setPort(int port)
-
 
441
{
-
 
442
    myPort = port;
-
 
443
}
-
 
444
 
-
 
445
void AsyncSocket::setSocket(int socket)
-
 
446
{
-
 
447
    mySocket = socket;
-
 
448
}
-
 
449
 
-
 
450
int AsyncSocket::getSocket()
-
 
451
{
-
 
452
    return mySocket;
-
 
453
}
-
 
454
 
-
 
455
bool AsyncSocket::availableData()
-
 
456
{
-
 
457
    return (myInQueue.size() > 0);
-
 
458
}
-
 
459
 
-
 
460
string AsyncSocket::getData()
-
 
461
{
-
 
462
    return myInQueue.pop();
-
 
463
}
397
}
464
 
398
 
465
bool AsyncSocket::sendData(string data)
399
void AsyncSocket::sendData(string data)
466
{
-
 
467
    //cout << "SendData on " + myAddress + ":" + itos(myPort) + ".\n";
-
 
468
    sendDataDirect(data);
-
 
469
    //myOutQueue.push(data);
-
 
470
    //mySemaphore.broadcast();
-
 
471
    return true;
-
 
472
}
-
 
473
 
-
 
474
void AsyncSocket::sendDataDirect(string data)
-
 
475
{
400
{
476
    SyslogStream &slog = SyslogStream::getInstance();
-
 
477
 
-
 
478
    //slog << "Sending: " << data << "\n";
-
 
479
 
-
 
480
    int status = ::send(mySocket, data.c_str(), data.size(), 0);
401
    int status = ::send(mySocket, data.c_str(), data.size(), 0);
481
 
402
 
482
    //slog << "Status: " << status << "\n";
-
 
483
 
-
 
484
    try
-
 
485
    {
-
 
486
        if (status == -1)
403
    if (status == -1)
487
        {
404
    {
488
            switch (errno)
405
        switch (errno)
489
            {
406
        {
490
                case EACCES:
407
            case EACCES:
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).)");
408
            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).)");
492
 
409
 
493
                case EAGAIN:
410
            case EAGAIN:
494
                //slog << "The socket is marked non-blocking and the requested operation would block.\n";
411
            throw new SocketException("The socket is marked non-blocking and the requested operation would block.");
495
                break;
-
 
496
 
412
 
497
                case EBADF:
413
            case EBADF:
498
                throw new SocketException("An invalid descriptor was specified.");
414
            throw new SocketException("An invalid descriptor was specified.");
499
 
415
 
500
                case ECONNRESET:
416
            case ECONNRESET:
Line 535... Line 451...
535
 
451
 
536
                case EPIPE:
452
            case EPIPE:
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.");
453
            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.");
538
 
454
 
539
                default:
455
            default:
540
                slog << "Unknow exception: " + itos(errno) + "\n";
456
            throw new SocketException("Unknow exception: " + itos(errno));
541
                break;
-
 
542
            }
-
 
543
        }
457
        }
544
    }
-
 
545
    catch (SocketException *e)
-
 
546
    {
-
 
547
        slog << "sendDataDirect: Exception: " + e->getDescription() + "\n";
-
 
548
    }
-
 
549
}
-
 
550
 
-
 
551
void AsyncSocket::setEvent(int event)
-
 
552
{
-
 
553
    myEventQueue.push(event);
-
 
554
    myEventSemaphore.broadcast();
-
 
555
}
458
    }
-
 
459
}
556
 
460
 
557
void AsyncSocket::forceReconnect()
461
void AsyncSocket::eventAdd(unsigned int eventType)
558
{
462
{
559
    ///FIXME: Threadsafe?
-
 
560
    myForceReconnect = true;
463
    eventAdd(eventType, "");
561
}
464
}
562
 
465
 
-
 
466
void AsyncSocket::eventAdd(unsigned int eventType, string eventData)
-
 
467
{
-
 
468
    SocketEvent socketEvent(eventType, eventData);
-
 
469
    myEventQueue.push(socketEvent);
-
 
470
    myEventSemaphore.broadcast();
-
 
471
}