Skip to content

Commit 0da0f16

Browse files
TCPSocket accept refactored to close cleanly and icetea test added
Private constructor called in TCPSocket accept, when creating a new Socket. Close() method calls moved "up" to InternetSocket. InternetSocket::close() returns proper error code when no socket available. Add TcpSocket::accept icetea tests. Deleting sockets moved to teardown.
1 parent 140f3e2 commit 0da0f16

File tree

12 files changed

+215
-73
lines changed

12 files changed

+215
-73
lines changed

TEST_APPS/device/socket_app/cmd_socket.cpp

Lines changed: 52 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,8 @@ class SInfo {
9595
enum SocketType {
9696
TCP_CLIENT,
9797
TCP_SERVER,
98-
UDP
98+
UDP,
99+
OTHER
99100
};
100101
SInfo(TCPSocket *sock):
101102
_id(id_count++),
@@ -151,6 +152,24 @@ class SInfo {
151152
{
152153
assert(sock);
153154
}
155+
SInfo(Socket* sock, bool delete_on_exit=true):
156+
_id(id_count++),
157+
_sock(sock),
158+
_type(SInfo::OTHER),
159+
_blocking(true),
160+
_dataLen(0),
161+
_maxRecvLen(0),
162+
_repeatBufferFill(1),
163+
_receivedTotal(0),
164+
_receiverThread(NULL),
165+
_receiveBuffer(NULL),
166+
_senderThreadId(NULL),
167+
_receiverThreadId(NULL),
168+
_packetSizes(NULL),
169+
_check_pattern(false)
170+
{
171+
MBED_ASSERT(sock);
172+
}
154173
~SInfo()
155174
{
156175
this->_sock->sigio(Callback<void()>());
@@ -1109,40 +1128,48 @@ static int cmd_socket(int argc, char *argv[])
11091128
}
11101129

11111130
/*
1112-
* Commands for TCPServer
1131+
* Commands for TCPServer and TCPSocket
11131132
* listen, accept
11141133
*/
1115-
if ((COMMAND_IS("listen") || COMMAND_IS("accept")) && info->type() != SInfo::TCP_SERVER) {
1116-
cmd_printf("Not TCPServer\r\n");
1117-
return CMDLINE_RETCODE_FAIL;
1118-
}
11191134
if (COMMAND_IS("listen")) {
11201135
int32_t backlog;
11211136
if (cmd_parameter_int(argc, argv, "listen", &backlog)) {
1122-
return handle_nsapi_error("TCPServer::listen()", static_cast<TCPServer &>(info->socket()).listen(backlog));
1137+
return handle_nsapi_error("Socket::listen()", info->socket().listen(backlog));
11231138
} else {
1124-
return handle_nsapi_error("TCPServer::listen()", static_cast<TCPServer &>(info->socket()).listen());
1139+
return handle_nsapi_error("Socket::listen()", info->socket().listen());
11251140
}
11261141

11271142
} else if (COMMAND_IS("accept")) {
1128-
SocketAddress addr;
1129-
int32_t id;
1130-
if (!cmd_parameter_int(argc, argv, "accept", &id)) {
1131-
cmd_printf("Need new socket id\r\n");
1132-
return CMDLINE_RETCODE_INVALID_PARAMETERS;
1133-
}
1134-
SInfo *new_info = get_sinfo(id);
1135-
if (!new_info) {
1136-
cmd_printf("Invalid socket id\r\n");
1137-
return CMDLINE_RETCODE_FAIL;
1138-
}
1139-
TCPSocket *new_sock = static_cast<TCPSocket *>(&new_info->socket());
1140-
nsapi_error_t ret = static_cast<TCPServer &>(info->socket()).accept(new_sock, &addr);
1141-
if (ret == NSAPI_ERROR_OK) {
1142-
cmd_printf("TCPServer::accept() new socket sid: %d connection from %s port %d\r\n",
1143-
new_info->id(), addr.get_ip_address(), addr.get_port());
1143+
nsapi_error_t ret;
1144+
if (info->type() != SInfo::TCP_SERVER) {
1145+
Socket *new_sock = info->socket().accept(&ret);
1146+
if (ret == NSAPI_ERROR_OK) {
1147+
SInfo *new_info = new SInfo(new_sock);
1148+
m_sockets.push_back(new_info);
1149+
cmd_printf("Socket::accept() new socket sid: %d\r\n", new_info->id());
1150+
}
1151+
return handle_nsapi_error("Socket::accept()", ret);
1152+
} else { // Old TCPServer API
1153+
int32_t id;
1154+
SocketAddress addr;
1155+
1156+
if (!cmd_parameter_int(argc, argv, "accept", &id)) {
1157+
cmd_printf("Need new socket id\r\n");
1158+
return CMDLINE_RETCODE_INVALID_PARAMETERS;
1159+
}
1160+
SInfo *new_info = get_sinfo(id);
1161+
if (!new_info) {
1162+
cmd_printf("Invalid socket id\r\n");
1163+
return CMDLINE_RETCODE_FAIL;
1164+
}
1165+
TCPSocket *new_sock = static_cast<TCPSocket*>(&new_info->socket());
1166+
nsapi_error_t ret = static_cast<TCPServer&>(info->socket()).accept(new_sock, &addr);
1167+
if (ret == NSAPI_ERROR_OK) {
1168+
cmd_printf("TCPServer::accept() new socket sid: %d connection from %s port %d\r\n",
1169+
new_info->id(), addr.get_ip_address(), addr.get_port());
1170+
}
1171+
return handle_nsapi_error("TCPServer::accept()", ret);
11441172
}
1145-
return handle_nsapi_error("TCPServer::accept()", ret);
11461173
}
11471174
return CMDLINE_RETCODE_INVALID_PARAMETERS;
11481175
}

TEST_APPS/testcases/netsocket/SOCKET_BIND_PORT.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,15 @@ def setup(self):
4343

4444
def socket_bind_port(self, socket_type):
4545
response = self.command("dut1", "socket new " + socket_type)
46-
socket_id = int(response.parsed['socket_id'])
46+
self.socket_id = int(response.parsed['socket_id'])
4747

48-
self.command("dut1", "socket " + str(socket_id) + " open")
48+
self.command("dut1", "socket " + str(self.socket_id) + " open")
4949

50-
self.command("dut1", "socket " + str(socket_id) + " bind port 1024")
51-
52-
self.command("dut1", "socket " + str(socket_id) + " delete")
50+
self.command("dut1", "socket " + str(self.socket_id) + " bind port 1024")
5351

5452
def teardown(self):
53+
self.command("dut1", "socket " + str(self.socket_id) + " delete")
54+
5555
self.command("dut1", "ifdown")
5656

5757

TEST_APPS/testcases/netsocket/TCPSERVER_ACCEPT.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -62,15 +62,15 @@ def case(self):
6262
self.used_port = 2000
6363

6464
response = self.command("dut1", "socket new TCPServer")
65-
server_base_socket_id = int(response.parsed['socket_id'])
65+
self.server_base_socket_id = int(response.parsed['socket_id'])
6666

67-
self.command("dut1", "socket " + str(server_base_socket_id) + " open")
68-
self.command("dut1", "socket " + str(server_base_socket_id) + " bind port " + str(self.used_port))
69-
self.command("dut1", "socket " + str(server_base_socket_id) + " listen")
67+
self.command("dut1", "socket " + str(self.server_base_socket_id) + " open")
68+
self.command("dut1", "socket " + str(self.server_base_socket_id) + " bind port " + str(self.used_port))
69+
self.command("dut1", "socket " + str(self.server_base_socket_id) + " listen")
7070

7171
response = self.command("dut1", "socket new TCPSocket")
72-
server_socket_id = int(response.parsed['socket_id'])
73-
self.command("dut1", "socket " + str(server_socket_id) + " open")
72+
self.server_socket_id = int(response.parsed['socket_id'])
73+
self.command("dut1", "socket " + str(self.server_socket_id) + " open")
7474

7575
response = self.command("dut2", "socket new TCPSocket")
7676
zero = response.timedelta
@@ -81,7 +81,7 @@ def case(self):
8181
t.start()
8282

8383
wait = 5
84-
response = self.command("dut1", "socket " + str(server_base_socket_id) + " accept " + str(server_socket_id))
84+
response = self.command("dut1", "socket " + str(self.server_base_socket_id) + " accept " + str(self.server_socket_id))
8585
response.verify_response_duration(expected=wait, zero=zero, threshold_percent=10, break_in_fail=True)
8686
socket_id = int(response.parsed['socket_id'])
8787

@@ -94,10 +94,10 @@ def case(self):
9494
if data != "hello":
9595
raise TestStepFail("Received data doesn't match the sent data")
9696

97-
self.command("dut1", "socket " + str(server_socket_id) + " delete")
98-
self.command("dut1", "socket " + str(server_base_socket_id) + " delete")
99-
self.command("dut2", "socket " + str(self.client_socket_id) + " delete")
100-
10197
def teardown(self):
98+
self.command("dut1", "socket " + str(self.server_socket_id) + " delete")
99+
self.command("dut1", "socket " + str(self.server_base_socket_id) + " delete")
100+
self.command("dut2", "socket " + str(self.client_socket_id) + " delete")
101+
102102
interfaceDown(self, ["dut1"])
103103
interfaceDown(self, ["dut2"])
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
"""
2+
Copyright 2018 ARM Limited
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.
14+
"""
15+
16+
import threading
17+
import time
18+
19+
from icetea_lib.bench import Bench
20+
from interface import interfaceUp, interfaceDown
21+
#from mbed_clitest.tools import test_case
22+
#from mbed_clitest.TestStepError import SkippedTestcaseException
23+
from icetea_lib.TestStepError import TestStepFail
24+
25+
class Testcase(Bench):
26+
def __init__(self):
27+
Bench.__init__(self,
28+
name="TCPSOCKET_ACCEPT",
29+
title = "TCPSOCKET_ACCEPT",
30+
purpose = "Test that TCPSocket::bind(), TCPSocket::listen() and TCPSocket::accept() works",
31+
status = "released",
32+
component= ["mbed-os", "netsocket"],
33+
type="smoke",
34+
subtype="socket",
35+
requirements={
36+
"duts": {
37+
'*': { #requirements for all nodes
38+
"count":2,
39+
"type": "hardware",
40+
"application": {
41+
"name": "TEST_APPS-device-socket_app"
42+
}
43+
},
44+
"1": {"nick": "dut1"},
45+
"2": {"nick": "dut2"}
46+
}
47+
}
48+
)
49+
50+
def setup(self):
51+
interface = interfaceUp(self, ["dut1"])
52+
self.server_ip = interface["dut1"]["ip"]
53+
interface = interfaceUp(self, ["dut2"])
54+
self.client_ip = interface["dut2"]["ip"]
55+
56+
def clientThread(self):
57+
self.logger.info("Starting")
58+
time.sleep(5) #wait accept from server
59+
self.command("dut2", "socket " + str(self.client_socket_id) + " open")
60+
self.command("dut2", "socket " + str(self.client_socket_id) + " connect " + str(self.server_ip) + " " + str(self.used_port))
61+
62+
63+
def case(self):
64+
self.used_port = 2000
65+
66+
response = self.command("dut1", "socket new TCPSocket")
67+
self.server_base_socket_id = int(response.parsed['socket_id'])
68+
69+
self.command("dut1", "socket " + str(self.server_base_socket_id) + " open")
70+
response = self.command("dut1", "socket " + str(self.server_base_socket_id) + " bind port " + str(self.used_port), report_cmd_fail = False)
71+
if response.retcode == -1:
72+
if (response.verify_trace("NSAPI_ERROR_UNSUPPORTED", break_in_fail = False)):
73+
raise SkippedTestcaseException("UNSUPPORTED")
74+
else:
75+
TestStepFail("Bind port failed")
76+
self.command("dut1", "socket " + str(self.server_base_socket_id) + " listen")
77+
78+
response = self.command("dut2", "socket new TCPSocket")
79+
self.client_socket_id = int(response.parsed['socket_id'])
80+
81+
#Create a thread which calls client connect()
82+
t = threading.Thread(name='clientThread', target=self.clientThread)
83+
t.start()
84+
85+
response = self.command("dut1", "socket " + str(self.server_base_socket_id) + " accept")
86+
87+
t.join()
88+
self.accept_socket_id = int(response.parsed['socket_id'])
89+
if response.timedelta < 5.0: # Check that socket accept call blocks
90+
raise TestStepFail("Longer response time expected")
91+
92+
self.command("dut1", "socket " + str(self.accept_socket_id) + " send hello")
93+
94+
response = self.command("dut2", "socket " + str(self.client_socket_id) + " recv 5")
95+
data = response.parsed['data'].replace(":","")
96+
97+
if data != "hello":
98+
raise TestStepFail("Received data doesn't match the sent data")
99+
100+
def teardown(self):
101+
response = self.command("dut2", "socket " + str(self.client_socket_id) + " delete")
102+
response = self.command("dut1", "socket " + str(self.server_base_socket_id) + " delete")
103+
response = self.command("dut1", "socket " + str(self.accept_socket_id) + " close")
104+
105+
interfaceDown(self, ["dut1"])
106+
interfaceDown(self, ["dut2"])

TEST_APPS/testcases/netsocket/TCPSOCKET_ECHOTEST_BURST_SHORT.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,31 +48,30 @@ def setup(self):
4848

4949
def case(self):
5050
response = self.command("dut1", "socket new TCPSocket")
51-
socket_id = int(response.parsed['socket_id'])
51+
self.socket_id = int(response.parsed['socket_id'])
5252

53-
self.command("dut1", "socket " + str(socket_id) + " open")
54-
self.command("dut1", "socket " + str(socket_id) + " connect echo.mbedcloudtesting.com 7")
53+
self.command("dut1", "socket " + str(self.socket_id) + " open")
54+
self.command("dut1", "socket " + str(self.socket_id) + " connect echo.mbedcloudtesting.com 7")
5555

5656
for i in range(2):
5757
sentData = ""
5858
for size in (100, 200, 300, 120, 500):
5959
packet = Randomize.random_string(max_len=size, min_len=size, chars=string.ascii_uppercase)
6060
sentData += packet
61-
response = self.command("dut1", "socket " + str(socket_id) + " send " + str(packet))
61+
response = self.command("dut1", "socket " + str(self.socket_id) + " send " + str(packet))
6262
response.verify_trace("TCPSocket::send() returned: " + str(size))
6363

6464
received = 0
6565
data = ""
6666
totalSize = 1220
6767
while received < totalSize:
68-
response = self.command("dut1", "socket " + str(socket_id) + " recv " + str(totalSize))
68+
response = self.command("dut1", "socket " + str(self.socket_id) + " recv " + str(totalSize))
6969
data += response.parsed['data'].replace(":", "")
7070
received += int(response.parsed['received_bytes'])
7171

7272
if data != sentData:
7373
raise TestStepFail("Received data doesn't match the sent data")
7474

75-
self.command("dut1", "socket " + str(socket_id) + " delete")
76-
7775
def teardown(self):
76+
self.command("dut1", "socket " + str(self.socket_id) + " delete")
7877
self.command("dut1", "ifdown")

UNITTESTS/features/netsocket/InternetSocket/test_InternetSocket.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ TEST_F(TestInternetSocket, close)
151151
TEST_F(TestInternetSocket, close_no_open)
152152
{
153153
stack.return_value = NSAPI_ERROR_OK;
154-
EXPECT_EQ(socket->close(), NSAPI_ERROR_OK);
154+
EXPECT_EQ(socket->close(), NSAPI_ERROR_NO_SOCKET);
155155
}
156156

157157
TEST_F(TestInternetSocket, close_during_read)

features/netsocket/InternetSocket.cpp

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ InternetSocket::InternetSocket()
2626
{
2727
}
2828

29+
InternetSocket::~InternetSocket()
30+
{
31+
close();
32+
}
33+
2934
nsapi_error_t InternetSocket::open(NetworkStack *stack)
3035
{
3136
_lock.lock();
@@ -56,17 +61,16 @@ nsapi_error_t InternetSocket::close()
5661
_lock.lock();
5762

5863
nsapi_error_t ret = NSAPI_ERROR_OK;
59-
if (!_stack) {
60-
return ret;
64+
if (!_socket) {
65+
return NSAPI_ERROR_NO_SOCKET;
6166
}
6267

63-
if (_socket) {
64-
_stack->socket_attach(_socket, 0, 0);
65-
nsapi_socket_t socket = _socket;
66-
_socket = 0;
67-
ret = _stack->socket_close(socket);
68-
}
69-
_stack = 0;
68+
// Just in case - tell the stack not to callback any more, then remove this socket.
69+
_stack->socket_attach(_socket, 0, 0);
70+
nsapi_socket_t socket = _socket;
71+
_socket = 0;
72+
ret = _stack->socket_close(socket);
73+
_stack = 0; // Invalidate the stack pointer - otherwise open() fails.
7074

7175
// Wakeup anything in a blocking operation
7276
// on this socket
@@ -81,7 +85,7 @@ nsapi_error_t InternetSocket::close()
8185

8286
_lock.unlock();
8387

84-
// When allocated by accept() call, will self desctruct on close();
88+
// When allocated by accept() call, will destroy itself on close();
8589
if (_factory_allocated) {
8690
delete this;
8791
}

features/netsocket/InternetSocket.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class InternetSocket : public Socket {
3636
*
3737
* Closes socket if the socket is still open
3838
*/
39-
virtual ~InternetSocket() {}
39+
virtual ~InternetSocket();
4040

4141
/** Opens a socket
4242
*

features/netsocket/TCPServer.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ TCPServer::TCPServer()
2424

2525
TCPServer::~TCPServer()
2626
{
27-
close();
2827
}
2928

3029
nsapi_error_t TCPServer::accept(TCPSocket *connection, SocketAddress *address)

0 commit comments

Comments
 (0)