Skip to content

Commit 8f33c0f

Browse files
c1728p9geky
authored andcommitted
Add synchronization to the network socket API
Add mutexes to protect the network socket API. Also use semaphores to wait for read/write events. Also fix a typo in the comments for timeout.
1 parent 3d310c2 commit 8f33c0f

File tree

8 files changed

+309
-112
lines changed

8 files changed

+309
-112
lines changed

Socket.cpp

Lines changed: 72 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -19,109 +19,153 @@
1919
Socket::Socket()
2020
: _iface(0)
2121
, _socket(0)
22-
, _timeout(-1)
22+
, _timeout(osWaitForever)
2323
{
2424
}
2525

2626
Socket::~Socket()
2727
{
28-
if (_socket) {
29-
close();
30-
}
28+
// Underlying close is thread safe
29+
close();
3130
}
3231

3332
int Socket::open(NetworkStack *iface, nsapi_protocol_t proto)
3433
{
34+
_lock.lock();
35+
36+
if (_iface != NULL) {
37+
_lock.unlock();
38+
return NSAPI_ERROR_PARAMETER;
39+
}
3540
_iface = iface;
3641

3742
void *socket;
3843
int err = _iface->socket_open(&socket, proto);
3944
if (err) {
45+
_lock.unlock();
4046
return err;
4147
}
4248

4349
_socket = socket;
4450
_iface->socket_attach(_socket, &Socket::thunk, this);
4551

52+
_lock.unlock();
53+
4654
return 0;
4755
}
4856

4957
int Socket::close()
5058
{
51-
if (!_socket) {
52-
return 0;
59+
_lock.lock();
60+
61+
int ret = 0;
62+
if (_socket) {
63+
_iface->socket_attach(_socket, 0, 0);
64+
65+
void * socket = _socket;
66+
_socket = 0;
67+
ret = _iface->socket_close(socket);
5368
}
54-
55-
_iface->socket_attach(_socket, 0, 0);
56-
57-
void *volatile socket = _socket;
58-
_socket = 0;
59-
return _iface->socket_close(socket);
69+
70+
// Wakeup anything in a blocking operation
71+
// on this socket
72+
socket_event();
73+
74+
_lock.unlock();
75+
return ret;
6076
}
6177

6278
int Socket::bind(uint16_t port)
6379
{
80+
// Underlying bind is thread safe
6481
SocketAddress addr(0, port);
6582
return bind(addr);
6683
}
6784

6885
int Socket::bind(const char *address, uint16_t port)
6986
{
87+
// Underlying bind is thread safe
7088
SocketAddress addr(address, port);
7189
return bind(addr);
7290
}
7391

7492
int Socket::bind(const SocketAddress &address)
7593
{
76-
if (!_socket) {
77-
return NSAPI_ERROR_NO_SOCKET;
94+
_lock.lock();
95+
96+
int ret = NSAPI_ERROR_NO_SOCKET;
97+
if (_socket) {
98+
ret = _iface->socket_bind(_socket, address);
7899
}
79100

80-
return _iface->socket_bind(_socket, address);
101+
_lock.unlock();
102+
return ret;
81103
}
82104

83105
void Socket::set_blocking(bool blocking)
84106
{
107+
// Socket::set_timeout is thread safe
85108
set_timeout(blocking ? -1 : 0);
86109
}
87110

88111
void Socket::set_timeout(int timeout)
89112
{
90-
_timeout = timeout;
113+
_lock.lock();
114+
115+
if (timeout >= 0) {
116+
_timeout = (uint32_t)timeout;
117+
} else {
118+
_timeout = osWaitForever;
119+
}
120+
121+
_lock.unlock();
91122
}
92123

93124
int Socket::setsockopt(int level, int optname, const void *optval, unsigned optlen)
94125
{
95-
if (!_socket) {
96-
return NSAPI_ERROR_NO_SOCKET;
126+
_lock.lock();
127+
128+
int ret = NSAPI_ERROR_NO_SOCKET;
129+
if (_socket) {
130+
ret = _iface->setsockopt(_socket, level, optname, optval, optlen);
97131
}
98132

99-
return _iface->setsockopt(_socket, level, optname, optval, optlen);
133+
_lock.unlock();
134+
return ret;
100135
}
101136

102137
int Socket::getsockopt(int level, int optname, void *optval, unsigned *optlen)
103138
{
104-
if (!_socket) {
105-
return NSAPI_ERROR_NO_SOCKET;
139+
_lock.lock();
140+
141+
int ret = NSAPI_ERROR_NO_SOCKET;
142+
if (_socket) {
143+
ret = _iface->getsockopt(_socket, level, optname, optval, optlen);
106144
}
107145

108-
return _iface->getsockopt(_socket, level, optname, optval, optlen);
146+
_lock.unlock();
147+
return ret;
109148

110149
}
111150

112-
void Socket::wakeup()
151+
void Socket::attach(FunctionPointer callback)
113152
{
153+
_lock.lock();
154+
155+
_callback = callback;
156+
157+
_lock.unlock();
114158
}
115159

116160
void Socket::thunk(void *data)
117161
{
118162
Socket *self = (Socket *)data;
119-
if (self->_callback) {
120-
self->_callback();
121-
}
163+
self->socket_event();
122164
}
123165

124-
void Socket::attach(FunctionPointer callback)
166+
void Socket::socket_event(void)
125167
{
126-
_callback = callback;
168+
if (_callback) {
169+
_callback();
170+
}
127171
}

Socket.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include "SocketAddress.h"
2121
#include "NetworkStack.h"
22+
#include "Mutex.h"
2223

2324
/** Abstract socket class
2425
*/
@@ -97,10 +98,11 @@ class Socket {
9798
*
9899
* Initially all sockets have unbounded timeouts. NSAPI_ERROR_WOULD_BLOCK
99100
* is returned if a blocking operation takes longer than the specified
100-
* timeout. A timeout of -1 removes the timeout from the socket.
101+
* timeout. A timeout of 0 removes the timeout from the socket. A negative
102+
* value give the socket an unbounded timeout.
101103
*
102-
* set_timeout(-1) is equivalent to set_blocking(false)
103-
* set_timeout(0) is equivalent to set_blocking(true)
104+
* set_timeout(0) is equivalent to set_blocking(false)
105+
* set_timeout(-1) is equivalent to set_blocking(true)
104106
*
105107
* @param timeout Timeout in milliseconds
106108
*/
@@ -169,12 +171,13 @@ class Socket {
169171
int open(NetworkStack *iface, nsapi_protocol_t proto);
170172

171173
static void thunk(void *);
172-
static void wakeup();
174+
virtual void socket_event(void);
173175

174176
NetworkStack *_iface;
175177
void *_socket;
176-
int _timeout;
178+
uint32_t _timeout;
177179
FunctionPointer _callback;
180+
rtos::Mutex _lock;
178181
};
179182

180183
#endif

TCPServer.cpp

Lines changed: 48 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@
1717
#include "TCPServer.h"
1818
#include "Timer.h"
1919

20-
TCPServer::TCPServer()
20+
TCPServer::TCPServer(): _accept_sem(0)
2121
{
2222
}
2323

24-
TCPServer::TCPServer(NetworkStack *iface)
24+
TCPServer::TCPServer(NetworkStack *iface): _accept_sem(0)
2525
{
2626
open(iface);
2727
}
@@ -33,43 +33,69 @@ int TCPServer::open(NetworkStack *iface)
3333

3434
int TCPServer::listen(int backlog)
3535
{
36-
if (!_socket) {
37-
return NSAPI_ERROR_NO_SOCKET;
36+
_lock.lock();
37+
38+
int ret = NSAPI_ERROR_NO_SOCKET;
39+
if (_socket) {
40+
ret = _iface->socket_listen(_socket, backlog);
3841
}
3942

40-
return _iface->socket_listen(_socket, backlog);
43+
_lock.unlock();
44+
return ret;
4145
}
4246

4347
int TCPServer::accept(TCPSocket *connection)
4448
{
45-
mbed::Timer timer;
46-
timer.start();
47-
mbed::Timeout timeout;
48-
if (_timeout >= 0) {
49-
timeout.attach_us(&Socket::wakeup, _timeout * 1000);
50-
}
51-
52-
if (connection->_socket) {
53-
connection->close();
54-
}
49+
_lock.lock();
5550

51+
int ret = NSAPI_ERROR_NO_SOCKET;
5652
while (true) {
5753
if (!_socket) {
58-
return NSAPI_ERROR_NO_SOCKET;
54+
ret = NSAPI_ERROR_NO_SOCKET;
55+
break;
5956
}
6057

6158
void *socket;
62-
int err = _iface->socket_accept(&socket, _socket);
63-
if (!err) {
59+
ret = _iface->socket_accept(&socket, _socket);
60+
if (0 == ret) {
61+
connection->_lock.lock();
62+
63+
if (connection->_socket) {
64+
connection->close();
65+
}
66+
6467
connection->_iface = _iface;
6568
connection->_socket = socket;
69+
_iface->socket_attach(socket, &Socket::thunk, connection);
70+
71+
connection->_lock.unlock();
72+
break;
6673
}
6774

68-
if (err != NSAPI_ERROR_WOULD_BLOCK
69-
|| (_timeout >= 0 && timer.read_ms() >= _timeout)) {
70-
return err;
75+
if (NSAPI_ERROR_WOULD_BLOCK == ret) {
76+
int32_t count;
77+
78+
_lock.unlock();
79+
count = _accept_sem.wait(_timeout);
80+
_lock.lock();
81+
82+
if (count < 1) {
83+
ret = NSAPI_ERROR_WOULD_BLOCK;
84+
break;
85+
}
7186
}
87+
}
7288

73-
__WFI();
89+
_lock.unlock();
90+
return ret;
91+
}
92+
93+
void TCPServer::socket_event()
94+
{
95+
int32_t status = _accept_sem.wait(0);
96+
if (status <= 1) {
97+
_accept_sem.release();
7498
}
99+
100+
Socket::socket_event();
75101
}

TCPServer.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "Socket.h"
2121
#include "TCPSocket.h"
2222
#include "NetworkStack.h"
23+
#include "Semaphore.h"
2324

2425
/** TCP socket server
2526
*/
@@ -74,6 +75,9 @@ class TCPServer : public Socket {
7475
* @return 0 on success, negative error code on failure
7576
*/
7677
int accept(TCPSocket *connection);
78+
protected:
79+
virtual void socket_event(void);
80+
rtos::Semaphore _accept_sem;
7781
};
7882

7983
#endif

0 commit comments

Comments
 (0)