Skip to content

Commit b15e2c2

Browse files
committed
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 c8fc4df commit b15e2c2

File tree

8 files changed

+309
-112
lines changed

8 files changed

+309
-112
lines changed

net/NetworkSocketAPI/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
}

net/NetworkSocketAPI/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

net/NetworkSocketAPI/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
}

net/NetworkSocketAPI/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)