Skip to content

Commit d9069f5

Browse files
committed
app: Add AT#XLISTEN and AT#XACCEPT
Add AT#XLISTEN and AT#XACCEPT for TCP server functionality. Signed-off-by: Markus Lassila <markus.lassila@nordicsemi.no>
1 parent 86dc1bb commit d9069f5

5 files changed

Lines changed: 849 additions & 52 deletions

File tree

app/src/sm_at_socket.c

Lines changed: 172 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,11 @@ static struct sm_socket {
8585
int family; /* Socket address family */
8686
int fd; /* Socket descriptor. */
8787
uint16_t cid; /* PDP Context ID, 0: primary; 1~10: secondary */
88+
uint16_t local_port; /* Explicitly bound local port. */
8889
int send_flags; /* Send flags */
8990
bool send_cb_set: 1; /* Send callback set */
9091
bool connected: 1; /* Connected flag. */
92+
bool listen: 1; /* Listen flag for TCP server sockets. */
9193
struct sm_async_poll async_poll; /* Async poll info. */
9294
struct sm_send_ntf send_ntf; /* Send notification info. */
9395
} socks[SM_MAX_SOCKET_COUNT];
@@ -122,9 +124,11 @@ static void init_socket(struct sm_socket *socket)
122124
socket->family = NRF_AF_UNSPEC;
123125
socket->fd = INVALID_SOCKET;
124126
socket->cid = 0;
127+
socket->local_port = 0;
125128
socket->send_flags = 0;
126129
socket->send_cb_set = false;
127130
socket->connected = false;
131+
socket->listen = false;
128132
socket->send_ntf = (struct sm_send_ntf){0};
129133
socket->async_poll = (struct sm_async_poll){0};
130134
}
@@ -222,6 +226,10 @@ static void auto_reception(struct sm_socket *sock)
222226
if (sock == NULL) {
223227
return;
224228
}
229+
if (sock->listen) {
230+
return;
231+
}
232+
225233
if (sock->connected || sock->type == NRF_SOCK_RAW) {
226234
err = do_recv(sock, 0, NRF_MSG_DONTWAIT,
227235
sock->async_poll.adr_hex ? AT_SOCKET_MODE_HEX
@@ -510,10 +518,6 @@ static int do_socket_open(struct sm_socket *sock)
510518
ret = nrf_socket(sock->family, NRF_SOCK_DGRAM, NRF_IPPROTO_UDP);
511519
proto = NRF_IPPROTO_UDP;
512520
} else if (sock->type == NRF_SOCK_RAW) {
513-
if (sock->role != NRF_SO_SEC_ROLE_CLIENT) {
514-
LOG_ERR("Raw socket: Role must be client");
515-
return -EINVAL;
516-
}
517521
ret = nrf_socket(sock->family, NRF_SOCK_RAW, NRF_IPPROTO_RAW);
518522
proto = NRF_IPPROTO_IP;
519523
} else {
@@ -612,18 +616,6 @@ static int do_secure_socket_open(struct sm_socket *sock, int peer_verify)
612616
ret = -errno;
613617
goto error;
614618
}
615-
/* Set up (D)TLS server role if applicable */
616-
if (sock->role == AT_SOCKET_ROLE_SERVER) {
617-
int tls_role = NRF_SO_SEC_ROLE_SERVER;
618-
619-
ret = nrf_setsockopt(sock->fd, NRF_SOL_SECURE, NRF_SO_SEC_ROLE, &tls_role,
620-
sizeof(int));
621-
if (ret) {
622-
LOG_ERR("nrf_setsockopt(%d) error: %d", NRF_SO_SEC_ROLE, -errno);
623-
ret = -errno;
624-
goto error;
625-
}
626-
}
627619

628620
rsp_send("\r\n#XSSOCKET: %d,%d,%d\r\n", sock->fd, sock->type, proto);
629621

@@ -702,6 +694,10 @@ static int at_sockopt_to_sockopt(enum at_sockopt at_option, int *level, int *opt
702694
*level = NRF_SOL_SOCKET;
703695
*option = NRF_SO_RAI;
704696
break;
697+
case AT_SO_TCP_SRV_SESSTIMEO:
698+
*level = NRF_IPPROTO_TCP;
699+
*option = NRF_SO_TCP_SRV_SESSTIMEO;
700+
break;
705701

706702
default:
707703
LOG_WRN("Unsupported option: %d", at_option);
@@ -879,7 +875,7 @@ static int sec_sockopt_get(struct sm_socket *sock, enum at_sec_sockopt at_option
879875
return ret;
880876
}
881877

882-
int bind_to_local_addr(struct sm_socket *sock, uint16_t port)
878+
static int bind_to_local_addr(struct sm_socket *sock, uint16_t port)
883879
{
884880
int ret;
885881

@@ -938,6 +934,7 @@ int bind_to_local_addr(struct sm_socket *sock, uint16_t port)
938934
return -EINVAL;
939935
}
940936

937+
sock->local_port = port;
941938
return 0;
942939
}
943940

@@ -1158,7 +1155,7 @@ static int do_recvfrom(struct sm_socket *sock, int timeout, int flags,
11581155
{
11591156
int ret;
11601157
struct net_sockaddr remote;
1161-
net_socklen_t addrlen = sizeof(struct nrf_sockaddr);
1158+
net_socklen_t addrlen = sizeof(struct net_sockaddr);
11621159
struct timeval tmo = {.tv_sec = timeout};
11631160

11641161
ret = nrf_setsockopt(sock->fd, NRF_SOL_SOCKET, NRF_SO_RCVTIMEO, &tmo, sizeof(tmo));
@@ -1339,15 +1336,6 @@ STATIC int handle_at_secure_socket(enum at_parser_cmd_type cmd_type,
13391336
if (err) {
13401337
goto error;
13411338
}
1342-
/** Peer verification level for TLS connection.
1343-
* - 0 - none
1344-
* - 1 - optional
1345-
* - 2 - required
1346-
* If not set, socket will use defaults (none for servers,
1347-
* required for clients)
1348-
*/
1349-
uint16_t peer_verify;
1350-
13511339
err = at_parser_num_get(parser, 2, &sock->type);
13521340
if (err) {
13531341
goto error;
@@ -1356,19 +1344,14 @@ STATIC int handle_at_secure_socket(enum at_parser_cmd_type cmd_type,
13561344
if (err) {
13571345
goto error;
13581346
}
1359-
if (sock->role == AT_SOCKET_ROLE_SERVER) {
1360-
peer_verify = ZSOCK_TLS_PEER_VERIFY_NONE;
1361-
} else if (sock->role == AT_SOCKET_ROLE_CLIENT) {
1362-
peer_verify = ZSOCK_TLS_PEER_VERIFY_REQUIRED;
1363-
} else {
1364-
err = -EINVAL;
1365-
goto error;
1366-
}
13671347
sock->sec_tag = SEC_TAG_TLS_INVALID;
13681348
err = at_parser_num_get(parser, 4, &sock->sec_tag);
13691349
if (err) {
13701350
goto error;
13711351
}
1352+
1353+
uint16_t peer_verify = ZSOCK_TLS_PEER_VERIFY_REQUIRED;
1354+
13721355
if (param_count > 5) {
13731356
err = at_parser_num_get(parser, 5, &peer_verify);
13741357
if (err) {
@@ -1649,10 +1632,6 @@ STATIC int handle_at_connect(enum at_parser_cmd_type cmd_type, struct at_parser
16491632
if (sock == NULL) {
16501633
return -EINVAL;
16511634
}
1652-
if (sock->role != AT_SOCKET_ROLE_CLIENT) {
1653-
LOG_ERR("Invalid role");
1654-
return -EOPNOTSUPP;
1655-
}
16561635
err = util_string_get(parser, 2, url, &size);
16571636
if (err) {
16581637
return err;
@@ -1957,6 +1936,160 @@ STATIC int handle_at_recvfrom(enum at_parser_cmd_type cmd_type, struct at_parser
19571936
return err;
19581937
}
19591938

1939+
static int do_listen(struct sm_socket *sock)
1940+
{
1941+
int ret;
1942+
1943+
if (sock->type != NRF_SOCK_STREAM || sock->local_port == 0 ||
1944+
sock->sec_tag != SEC_TAG_TLS_INVALID) {
1945+
return -EOPNOTSUPP;
1946+
}
1947+
1948+
/* Set the socket to non-blocking mode, so accept() won't block. */
1949+
ret = nrf_fcntl(sock->fd, NRF_F_SETFL, NRF_O_NONBLOCK);
1950+
if (ret) {
1951+
LOG_ERR("nrf_fcntl() failed: %d", -errno);
1952+
return -errno;
1953+
}
1954+
1955+
/* nRF modem ignores the backlog parameter. Backlog in modem is fixed to 2. */
1956+
ret = nrf_listen(sock->fd, 2);
1957+
if (ret) {
1958+
LOG_ERR("nrf_listen() failed: %d", -errno);
1959+
return -errno;
1960+
}
1961+
1962+
sock->listen = true;
1963+
1964+
return 0;
1965+
}
1966+
1967+
SM_AT_CMD_CUSTOM(xlisten, "AT#XLISTEN", handle_at_listen);
1968+
STATIC int handle_at_listen(enum at_parser_cmd_type cmd_type, struct at_parser *parser, uint32_t)
1969+
{
1970+
int err = -EINVAL;
1971+
int fd;
1972+
1973+
struct sm_socket *sock = NULL;
1974+
1975+
switch (cmd_type) {
1976+
case AT_PARSER_CMD_TYPE_SET:
1977+
err = at_parser_num_get(parser, 1, &fd);
1978+
if (err) {
1979+
return err;
1980+
}
1981+
sock = find_socket(fd);
1982+
if (sock == NULL) {
1983+
return -EINVAL;
1984+
}
1985+
err = do_listen(sock);
1986+
break;
1987+
1988+
case AT_PARSER_CMD_TYPE_READ:
1989+
for (int i = 0; i < SM_MAX_SOCKET_COUNT; i++) {
1990+
if (socks[i].fd != INVALID_SOCKET && socks[i].listen) {
1991+
rsp_send("\r\n#XLISTEN: %d,%d,%d\r\n", socks[i].fd, socks[i].cid,
1992+
socks[i].local_port);
1993+
}
1994+
}
1995+
err = 0;
1996+
break;
1997+
1998+
case AT_PARSER_CMD_TYPE_TEST:
1999+
rsp_send("\r\n#XLISTEN: <handle>\r\n");
2000+
err = 0;
2001+
break;
2002+
2003+
default:
2004+
break;
2005+
}
2006+
2007+
return err;
2008+
}
2009+
2010+
static int do_accept(struct sm_socket *sock)
2011+
{
2012+
int ret;
2013+
struct net_sockaddr remote;
2014+
net_socklen_t addrlen = sizeof(struct net_sockaddr);
2015+
char peer_addr[NRF_INET6_ADDRSTRLEN] = {0};
2016+
uint16_t peer_port = 0;
2017+
2018+
if (sock->type != NRF_SOCK_STREAM || !sock->listen) {
2019+
return -EOPNOTSUPP;
2020+
}
2021+
2022+
ret = nrf_accept(sock->fd, (struct nrf_sockaddr *)&remote, (nrf_socklen_t *)&addrlen);
2023+
if (ret < 0) {
2024+
LOG_ERR("nrf_accept() failed: %d", -errno);
2025+
return -errno;
2026+
}
2027+
2028+
struct sm_socket *new_sock = find_avail_socket();
2029+
if (new_sock == NULL) {
2030+
LOG_ERR("Max socket count reached, closing accepted socket");
2031+
nrf_close(ret);
2032+
return -EINVAL;
2033+
}
2034+
init_socket(new_sock);
2035+
new_sock->fd = ret;
2036+
new_sock->family = remote.sa_family;
2037+
new_sock->type = NRF_SOCK_STREAM;
2038+
new_sock->role = AT_SOCKET_ROLE_CLIENT;
2039+
new_sock->cid = sock->cid;
2040+
new_sock->connected = true;
2041+
2042+
util_get_peer_addr(&remote, peer_addr, &peer_port);
2043+
rsp_send("\r\n#XACCEPT: %d,%d,\"%s\",%d\r\n", new_sock->fd, new_sock->cid, peer_addr,
2044+
peer_port);
2045+
2046+
/* Update poll events for xapoll and automatic data reception */
2047+
new_sock->async_poll.adr_flags = poll_ctx.adr_flags;
2048+
new_sock->async_poll.adr_hex = poll_ctx.adr_hex;
2049+
new_sock->async_poll.xapoll_events_requested = poll_ctx.xapoll_events_requested;
2050+
update_poll_events(new_sock,
2051+
NRF_POLLIN | NRF_POLLOUT | NRF_POLLERR | NRF_POLLHUP | NRF_POLLNVAL,
2052+
true);
2053+
2054+
/* Restore POLLIN for listening socket. */
2055+
update_poll_events(sock, NRF_POLLIN, true);
2056+
2057+
return 0;
2058+
}
2059+
2060+
SM_AT_CMD_CUSTOM(xaccept, "AT#XACCEPT", handle_at_accept);
2061+
STATIC int handle_at_accept(enum at_parser_cmd_type cmd_type, struct at_parser *parser, uint32_t)
2062+
{
2063+
int err = -EINVAL;
2064+
int fd;
2065+
2066+
struct sm_socket *sock = NULL;
2067+
2068+
switch (cmd_type) {
2069+
case AT_PARSER_CMD_TYPE_SET:
2070+
err = at_parser_num_get(parser, 1, &fd);
2071+
if (err) {
2072+
return err;
2073+
}
2074+
sock = find_socket(fd);
2075+
if (sock == NULL) {
2076+
return -EINVAL;
2077+
}
2078+
err = do_accept(sock);
2079+
break;
2080+
2081+
case AT_PARSER_CMD_TYPE_TEST:
2082+
rsp_send("\r\n#XACCEPT: <handle>\r\n");
2083+
err = 0;
2084+
break;
2085+
2086+
default:
2087+
break;
2088+
}
2089+
2090+
return err;
2091+
}
2092+
19602093
SM_AT_CMD_CUSTOM(xgetaddrinfo, "AT#XGETADDRINFO", handle_at_getaddrinfo);
19612094
STATIC int handle_at_getaddrinfo(enum at_parser_cmd_type cmd_type, struct at_parser *parser,
19622095
uint32_t param_count)

app/src/sm_sockopt.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ enum at_sockopt {
2424
AT_SO_IP_ECHO_REPLY = 31,
2525
AT_SO_IPV6_ECHO_REPLY = 32,
2626
AT_SO_BINDTOPDN = 40,
27+
AT_SO_TCP_SRV_SESSTIMEO = 55,
2728
AT_SO_RAI = 61,
2829
AT_SO_IPV6_DELAYED_ADDR_REFRESH = 62,
2930
};

0 commit comments

Comments
 (0)