Skip to content

Commit 439d758

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 fb20dbe commit 439d758

File tree

2 files changed

+411
-1
lines changed

2 files changed

+411
-1
lines changed

app/src/sm_at_socket.c

Lines changed: 161 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,11 @@ static struct sm_socket {
8383
int family; /* Socket address family */
8484
int fd; /* Socket descriptor. */
8585
uint16_t cid; /* PDP Context ID, 0: primary; 1~10: secondary */
86+
uint16_t local_port; /* Explicitly bound local port. */
8687
int send_flags; /* Send flags */
8788
bool send_cb_set: 1; /* Send callback set */
8889
bool connected: 1; /* Connected flag. */
90+
bool listen: 1; /* Listen flag for TCP server sockets. */
8991
struct sm_async_poll async_poll; /* Async poll info. */
9092
struct sm_send_ntf send_ntf; /* Send notification info. */
9193
} socks[SM_MAX_SOCKET_COUNT];
@@ -120,9 +122,11 @@ static void init_socket(struct sm_socket *socket)
120122
socket->family = AF_UNSPEC;
121123
socket->fd = INVALID_SOCKET;
122124
socket->cid = 0;
125+
socket->local_port = 0;
123126
socket->send_flags = 0;
124127
socket->send_cb_set = false;
125128
socket->connected = false;
129+
socket->listen = false;
126130
socket->send_ntf = (struct sm_send_ntf){0};
127131
socket->async_poll = (struct sm_async_poll){0};
128132
}
@@ -877,7 +881,7 @@ static int sec_sockopt_get(struct sm_socket *sock, enum at_sec_sockopt at_option
877881
return ret;
878882
}
879883

880-
int bind_to_local_addr(struct sm_socket *sock, uint16_t port)
884+
static int bind_to_local_addr(struct sm_socket *sock, uint16_t port)
881885
{
882886
int ret;
883887

@@ -936,6 +940,7 @@ int bind_to_local_addr(struct sm_socket *sock, uint16_t port)
936940
return -EINVAL;
937941
}
938942

943+
sock->local_port = port;
939944
return 0;
940945
}
941946

@@ -1955,6 +1960,161 @@ STATIC int handle_at_recvfrom(enum at_parser_cmd_type cmd_type, struct at_parser
19551960
return err;
19561961
}
19571962

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

0 commit comments

Comments
 (0)