[posix] add UART flush and clean up (#5312)

This commit mainly implements the otPlatUartFlush().
- fix code because MSG_NOSIGNAL is not a macro.
- set SO_NOSIGPIPE once.
This commit is contained in:
Yakun Xu
2020-08-01 09:41:58 -07:00
committed by GitHub
parent f0f924a747
commit 114a0e7dc7
3 changed files with 183 additions and 47 deletions
+2 -2
View File
@@ -173,8 +173,8 @@ jobs:
expects:
runs-on: ubuntu-18.04
env:
CFLAGS: -DCLI_COAP_SECURE_USE_COAP_DEFAULT_HANDLER=1
CXXFLAGS: -DCLI_COAP_SECURE_USE_COAP_DEFAULT_HANDLER=1
CFLAGS: -DCLI_COAP_SECURE_USE_COAP_DEFAULT_HANDLER=1 -DOPENTHREAD_CONFIG_MLE_MAX_CHILDREN=15
CXXFLAGS: -DCLI_COAP_SECURE_USE_COAP_DEFAULT_HANDLER=1 -DOPENTHREAD_CONFIG_MLE_MAX_CHILDREN=15
steps:
- uses: actions/checkout@v2
- name: Bootstrap
+103 -45
View File
@@ -162,11 +162,6 @@ exit:
return error;
}
otError otPlatUartFlush(void)
{
return OT_ERROR_NOT_IMPLEMENTED;
}
void platformUartUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, fd_set *aErrorFdSet, int *aMaxFd)
{
VerifyOrExit(sEnabled, OT_NOOP);
@@ -236,6 +231,19 @@ static void InitializeSessionSocket(void)
VerifyOrExit((rval = fcntl(sSessionSocket, F_SETFD, rval)) != -1, OT_NOOP);
#ifndef __linux__
// some platforms (macOS, Solaris) don't have MSG_NOSIGNAL
// SOME of those (macOS, but NOT Solaris) support SO_NOSIGPIPE
// if we have SO_NOSIGPIPE, then set it. Otherwise, we're going
// to simply ignore it.
#if defined(SO_NOSIGPIPE)
rval = 1;
VerifyOrExit((rval = setsockopt(sSessionSocket, SOL_SOCKET, SO_NOSIGPIPE, &rval, sizeof(rval)) != -1, OT_NOOP));
#else
#warning "no support for MSG_NOSIGNAL or SO_NOSIGPIPE"
#endif
#endif // __linux__
exit:
if (rval == -1)
{
@@ -249,6 +257,47 @@ exit:
}
#endif
static otError UartWrite(int aFd)
{
otError error = OT_ERROR_NONE;
ssize_t rval;
VerifyOrExit(sWriteLength > 0, error = OT_ERROR_INVALID_STATE);
#if OPENTHREAD_POSIX_CONFIG_DAEMON_ENABLE && defined(__linux__)
if (aFd == sSessionSocket)
{
// Don't die on SIGPIPE
rval = send(aFd, sWriteBuffer, sWriteLength, MSG_NOSIGNAL);
}
else
#endif // OPENTHREAD_POSIX_CONFIG_DAEMON_ENABLE && defined(__linux__)
{
rval = write(aFd, sWriteBuffer, sWriteLength);
}
if (rval < 0)
{
#if OPENTHREAD_POSIX_CONFIG_DAEMON_ENABLE
otLogWarnPlat("UART write: %s", strerror(errno));
if (aFd == sSessionSocket)
{
close(sSessionSocket);
sSessionSocket = -1;
}
ExitNow();
#else
DieNow(OT_EXIT_ERROR_ERRNO);
#endif
}
sWriteBuffer += rval;
sWriteLength -= static_cast<uint16_t>(rval);
exit:
return error;
}
void platformUartProcess(const fd_set *aReadFdSet, const fd_set *aWriteFdSet, const fd_set *aErrorFdSet)
{
ssize_t rval;
@@ -328,48 +377,11 @@ void platformUartProcess(const fd_set *aReadFdSet, const fd_set *aWriteFdSet, co
fd = STDOUT_FILENO;
#endif
if ((sWriteLength > 0) && (FD_ISSET(fd, aWriteFdSet)))
if ((FD_ISSET(fd, aWriteFdSet)))
{
#if OPENTHREAD_POSIX_CONFIG_DAEMON_ENABLE
// Don't die on SIGPIPE
#if !defined(MSG_NOSIGNAL)
// some platforms (mac OS, Solaris) don't have MSG_NOSIGNAL
// SOME of those (mac OS, but NOT Solaris) support SO_NOSIGPIPE
// if we have SO_NOSIGPIPE, then set it. otherwise, we're going
// to simply ignore it.
#if defined(SO_NOSIGPIPE)
int err;
int flag;
otError error = UartWrite(fd);
flag = 1;
err = setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &flag, sizeof(flag));
VerifyOrDie(err == 0, OT_EXIT_ERROR_ERRNO);
#else
#warning "no support for MSG_NOSIGNAL or SO_NOSIGPIPE"
#endif
#define MSG_NOSIGNAL 0
#endif // !defined(MSG_NOSIGNAL)
rval = send(fd, sWriteBuffer, sWriteLength, MSG_NOSIGNAL);
#else
rval = write(fd, sWriteBuffer, sWriteLength);
#endif // OPENTHREAD_POSIX_CONFIG_DAEMON_ENABLE
if (rval < 0)
{
#if OPENTHREAD_POSIX_CONFIG_DAEMON_ENABLE
perror("UART write");
close(sSessionSocket);
sSessionSocket = -1;
ExitNow();
#else
DieNowWithMessage("UART write", OT_EXIT_ERROR_ERRNO);
#endif
}
VerifyOrExit(rval > 0, OT_NOOP);
sWriteBuffer += (uint16_t)rval;
sWriteLength -= (uint16_t)rval;
VerifyOrExit(error == OT_ERROR_NONE, otLogWarnPlat("UART write: %s", otThreadErrorToString(error)));
if (sWriteLength == 0)
{
@@ -380,3 +392,49 @@ void platformUartProcess(const fd_set *aReadFdSet, const fd_set *aWriteFdSet, co
exit:
return;
}
otError otPlatUartFlush(void)
{
otError error = OT_ERROR_NONE;
while (sWriteLength > 0)
{
int fd =
#if OPENTHREAD_POSIX_CONFIG_DAEMON_ENABLE
sSessionSocket != -1 ? sSessionSocket :
#endif
STDOUT_FILENO;
int rval;
fd_set writeFdSet;
FD_ZERO(&writeFdSet);
FD_SET(fd, &writeFdSet);
rval = select(fd + 1, nullptr, &writeFdSet, nullptr, nullptr);
assert(rval != 0);
if (rval > 0)
{
assert(FD_ISSET(fd, &writeFdSet));
SuccessOrExit(error = UartWrite(fd));
}
else if (errno != EINTR)
{
#if OPENTHREAD_POSIX_CONFIG_DAEMON_ENABLE
if (sSessionSocket == fd)
{
close(sSessionSocket);
sSessionSocket = -1;
}
else
#endif
{
DieNow(OT_EXIT_ERROR_ERRNO);
}
}
}
exit:
return error;
}
+78
View File
@@ -0,0 +1,78 @@
#!/usr/bin/expect -f
#
# Copyright (c) 2020, The OpenThread Authors.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. Neither the name of the copyright holder nor the
# names of its contributors may be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
source "tests/scripts/expect/_common.exp"
set max_node 15
set spawn_ids(1) [spawn_node 1]
set spawn_id $spawn_ids(1)
expect_after {
timeout { exit 1 }
}
send "panid 0xface\n"
expect "Done"
send "ifconfig up\n"
expect "Done"
send "thread start\n"
expect "Done"
wait_for "state" "leader"
expect "Done"
for {set i 2} {$i <= $max_node} {incr i} {
set spawn_ids($i) [spawn_node $i]
set spawn_id $spawn_ids($i)
expect_after {
timeout { exit 1 }
}
send "mode rs\n"
expect "Done"
send "panid 0xface\n"
expect "Done"
send "ifconfig up\n"
expect "Done"
send "thread start\n"
expect "Done"
wait_for "state" "child"
expect "Done"
}
set spawn_id $spawn_ids(1)
expect_after {
timeout { exit 1 }
}
send "child table\n"
expect "Done"
for {set i 1} {$i <= $max_node} {incr i} {
set spawn_id $spawn_ids($i)
expect_after {
timeout { exit 1 }
}
dispose
}