We may just free some TCP connections before monitor stopped, e.g.
sacrificie a TCP conn in `tcp_alloc` will just call `tcp_free` and reuse
the connection. But we noticed that the TCP monitor is not released in
`tcp_free` because it is mounted on `conn->connevents` instead of
`conn->sconn.list` while `tcp_free` only release the latter.
Signed-off-by: Zhe Weng <wengzhe@xiaomi.com>
with nonblocking sockets, POLLOUT is returned when the application
calls poll even if the send buffer is full
Signed-off-by: zhanghongyu <zhanghongyu@xiaomi.com>
Normally, `SO_ERROR` for disconn events will be set by `tcp_poll_eventhandler`, but when the socket is closed before poll, we should also set the `SO_ERROR`.
On Linux, `tcp_poll` returns `EPOLLERR` event when `sk->sk_err` has value but doesn't let `poll` fail (doesn't set `errno`). https://github.com/torvalds/linux/blob/v6.5/net/ipv4/tcp.c#L594-L596
Note: `sk->sk_err` can be get by socket option `SO_ERROR` on Linux, so `POLLERR` will always be together with `SO_ERROR`.
Common libs like curl may try to read `SO_ERROR` on `POLLERR`.
Signed-off-by: Zhe Weng <wengzhe@xiaomi.com>
Summary
The following compilation error occurs after configuring CONFIG_DEBUG_OPTLEVEL="-O3"
CC: local/local_fifo.c In file included from local/local_fifo.c:25:
In function 'local_format_name',
inlined from 'local_cs_name' at local/local_fifo.c:101:3,
inlined from 'local_create_fifos' at local/local_fifo.c:431:3:
local/local_fifo.c:84:16: error: '%x' directive output may be truncated writing between 1 and 8 bytes into a region of size between 5 and 112 [-Werror=format-truncation=]
84 | CONFIG_NET_LOCAL_VFS_PATH "/%s%s%" PRIx32,
| ^~~~~~~~~~~~~~~~~~~~~~~~~
Signed-off-by: wangming9 <wangming9@xiaomi.com>
conn->sendsize is used in rpmsg_socket_ept_cb() and
rpmsg_socket_connect_internal(), the connected event may be missed
as stated below:
1. in rpmsg_socket_connect_internal(), judge conn->sendsize == 0
and prepare to wait sendsem;
2. interrupt by rptun thread, rpmsg_socket_ept_cb() is called to
update conn->sendsize and post the sendsem, but the no one wait
rx sem yet, so not post (see rpmsg_socket_post());
3. return to rpmsg_socket_connect_internal() to wait the sendsem, but
has miss the connected event.
So add recvlock in rpmsg_socket_connect_internal() also.
Signed-off-by: Bowen Wang <wangbowen6@xiaomi.com>
After the sack is enabled and the ofosegs has gap, tcp cannot update the
tx_unacked, so the peer received packets are retransmitted after the
timer timeout.
So update tx_unacked first.
Signed-off-by: zhanghongyu <zhanghongyu@xiaomi.com>
Non-blocking sockets are almost never in the connected state when app try to
get result of connect success through poll, to avoid confusion because of
this error print, so downgrade the print level to warning.
Signed-off-by: zhanghongyu <zhanghongyu@xiaomi.com>
refer to https://man7.org/linux/man-pages/man7/ip.7.html
IP_MULTICAST_IF (since Linux 1.2)
Set the local device for a multicast socket. The argument
for setsockopt(2) is an ip_mreqn or (since Linux 3.5)
ip_mreq structure similar to IP_ADD_MEMBERSHIP, or an
in_addr structure. (The kernel determines which structure
is being passed based on the size passed in optlen.) For
getsockopt(2), the argument is an in_addr structure.
refer to https://man7.org/linux/man-pages/man7/ipv6.7.html
IPV6_MULTICAST_IF
Set the device for outgoing multicast packets on the
socket. This is allowed only for SOCK_DGRAM and SOCK_RAW
socket. The argument is a pointer to an interface index
(see netdevice(7)) in an integer.
testcase1:
TEST_IMPL(udp_multicast_interface) {
/* TODO(gengjiawen): Fix test on QEMU. */
RETURN_SKIP("Test does not currently work in QEMU");
int r;
uv_udp_send_t req;
uv_buf_t buf;
struct sockaddr_in addr;
struct sockaddr_in baddr;
close_cb_called = 0;
sv_send_cb_called = 0;
ASSERT(0 == uv_ip4_addr("239.255.0.1", TEST_PORT, &addr));
r = uv_udp_init(uv_default_loop(), &server);
ASSERT(r == 0);
ASSERT(0 == uv_ip4_addr("0.0.0.0", 0, &baddr));
r = uv_udp_bind(&server, (const struct sockaddr*)&baddr, 0);
ASSERT(r == 0);
r = uv_udp_set_multicast_interface(&server, "0.0.0.0");
ASSERT(r == 0);
/* server sends "PING" */
buf = uv_buf_init("PING", 4);
r = uv_udp_send(&req,
&server,
&buf,
1,
(const struct sockaddr*)&addr,
sv_send_cb);
ASSERT(r == 0);
ASSERT(close_cb_called == 0);
ASSERT(sv_send_cb_called == 0);
/* run the loop till all events are processed */
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
ASSERT(sv_send_cb_called == 1);
ASSERT(close_cb_called == 1);
ASSERT(client.send_queue_size == 0);
ASSERT(server.send_queue_size == 0);
MAKE_VALGRIND_HAPPY();
return 0;
}
testcase2:
TEST_IMPL(udp_multicast_interface6) {
/* TODO(gengjiawen): Fix test on QEMU. */
RETURN_SKIP("Test does not currently work in QEMU");
int r;
uv_udp_send_t req;
uv_buf_t buf;
struct sockaddr_in6 addr;
struct sockaddr_in6 baddr;
if (!can_ipv6())
RETURN_SKIP("IPv6 not supported");
close_cb_called = 0;
sv_send_cb_called = 0;
ASSERT(0 == uv_ip6_addr("::1", TEST_PORT, &addr));
r = uv_udp_init(uv_default_loop(), &server);
ASSERT(r == 0);
ASSERT(0 == uv_ip6_addr("::", 0, &baddr));
r = uv_udp_bind(&server, (const struct sockaddr*)&baddr, 0);
ASSERT(r == 0);
r = uv_udp_set_multicast_interface(&server, "::1%lo0");
r = uv_udp_set_multicast_interface(&server, NULL);
ASSERT(r == 0);
/* server sends "PING" */
buf = uv_buf_init("PING", 4);
r = uv_udp_send(&req,
&server,
&buf,
1,
(const struct sockaddr*)&addr,
sv_send_cb);
ASSERT(r == 0);
ASSERT(close_cb_called == 0);
ASSERT(sv_send_cb_called == 0);
/* run the loop till all events are processed */
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
ASSERT(sv_send_cb_called == 1);
ASSERT(close_cb_called == 1);
MAKE_VALGRIND_HAPPY();
return 0;
}
Signed-off-by: wangchen <wangchen41@xiaomi.com>
Using the macro places the buffers into .data section which means they
will consume the full buffer size of flash / read only memory as well.
Place the buffers into .bss to avoid this case.
Use PRIx64 which defines the width correctly regardless or architecture.
Fixes build error:
rpmsg/rpmsg_sockif.c:610:57: error: format '%llx' expects argument of type 'long long unsigned int', but argument 4 has type 'uint64_t' {aka 'long unsigned int'} [-Werror=format=]
610 | snprintf(conn->nameid, sizeof(conn->nameid), ":%llx", g_rpmsg_id++);
| ~~~^ ~~~~~~~~~~~~
| | |
| | uint64_t {aka long unsigned int}
| long long unsigned int
| %lx
- Fix `ip6_map_ipv4addr` and `ip6_get_ipv4addr` macro to work under
different endianness.
- Use `iob_reserve` instead of `iob_trimhead` in `udp_datahandler`.
- Because we may set `sockaddr_in6` into IPv4 header, which causes
`offset` become negative. `iob_reserve` can hold this case while
`iob_trimhead` cannot.
- Select IPv4 domain in send case.
Signed-off-by: Zhe Weng <wengzhe@xiaomi.com>
When do poll operation and the tcp connection state is TCP_ALLOCATED, eventset(POLLERR|POLLHUP) is return, causing the libuv poll_multiple_handles to fail.
Verification: Use the libuv test case ` uv_run_tests poll_multiple_handles`.
Signed-off-by: liqinhui <liqinhui@xiaomi.com>
Some programs use EAGAIN to determine whether all data has been read,
so cancel the error print when the error code is EAGAIN.
Signed-off-by: zhanghongyu <zhanghongyu@xiaomi.com>
Example of /proc/PID/group/fd in this case:
FD OFLAGS TYPE POS PATH
17 67 9 0 socket:[domain 16, type 2, proto 0]
Signed-off-by: Zhe Weng <wengzhe@xiaomi.com>
Verification:
Write a packet, the length is bigger than CONFIG_DEV_FIFO_SIZE.
The return value should be -1, and the errno is EMSGSIZE.
Signed-off-by: liqinhui <liqinhui@xiaomi.com>
Verifiction:
Write a bigger packet and read the packet using a smaller buffer.
The return length of reading should be the length of smaller buffer.
Signed-off-by: liqinhui <liqinhui@xiaomi.com>
The error log is as follows:
tcp/tcp_send_buffered.c:376:57: runtime error: member access within misaligned
address 0x10075942 for type 'struct tcp_sack_s', which requires 4 byte alignment
Signed-off-by: liqinhui <liqinhui@xiaomi.com>