[posix-app] add daemon mode (#3463)

This commit adds the daemon mode for POSIX CLI app. The daemon simply
receive UART input from a unix socket connection.
This commit is contained in:
Yakun Xu
2019-02-01 22:05:59 -08:00
committed by Jonathan Hui
parent e68e86317e
commit 69aa5c4f04
9 changed files with 457 additions and 40 deletions
+32
View File
@@ -470,6 +470,38 @@ AC_SUBST(OPENTHREAD_ENABLE_POSIX_APP)
AM_CONDITIONAL([OPENTHREAD_ENABLE_POSIX_APP], [test "${enable_posix_app}" = "yes"])
AC_DEFINE_UNQUOTED([OPENTHREAD_ENABLE_POSIX_APP], [${OPENTHREAD_ENABLE_POSIX_APP}], [Define to 1 to build posix application.])
#
# POSIX Daemon
#
AC_MSG_CHECKING([whether to build POSIX applicaton in daemon mode])
AC_ARG_ENABLE(posix-app-daemon,
[AS_HELP_STRING([--enable-posix-app-daemon], [Build POSIX application in daemon mode@<:@default=no@:>@.])],
[
case "${enableval}" in
no|yes)
enable_posix_app_daemon=${enableval}
;;
*)
AC_MSG_ERROR([Invalid value ${enable_posix_app} for --enable-posix-app-daemon])
;;
esac
],
[enable_posix_app_daemon=no])
if test "$enable_posix_app_daemon" = "yes"; then
OPENTHREAD_ENABLE_POSIX_APP_DAEMON=1
else
OPENTHREAD_ENABLE_POSIX_APP_DAEMON=0
fi
AC_MSG_RESULT(${enable_posix_app_daemon})
AC_SUBST(OPENTHREAD_ENABLE_POSIX_APP_DAEMON)
AM_CONDITIONAL([OPENTHREAD_ENABLE_POSIX_APP_DAEMON], [test "${enable_posix_app_daemon}" = "yes"])
AC_DEFINE_UNQUOTED([OPENTHREAD_ENABLE_POSIX_APP_DAEMON], [${OPENTHREAD_ENABLE_POSIX_APP_DAEMON}], [Define to 1 to build posix application in daemon mode.])
#
# FTD Library
#
+5
View File
@@ -44,6 +44,7 @@ COMMISSIONER ?= 1
CHANNEL_MANAGER ?= 1
CHANNEL_MONITOR ?= 1
CHILD_SUPERVISION ?= 1
DAEMON ?= 0
DHCP6_CLIENT ?= 1
DHCP6_SERVER ?= 1
DIAGNOSTIC ?= 1
@@ -76,6 +77,10 @@ configure_OPTIONS = \
# Platform specific switches
ifeq (${DAEMON},1)
configure_OPTIONS += --enable-posix-app-daemon
endif
ifneq ($(DEBUG),1)
COMMONCFLAGS += \
-O2 \
+45 -6
View File
@@ -77,12 +77,6 @@ bin_PROGRAMS = \
$(NULL)
if OPENTHREAD_ENABLE_EXECUTABLE
if OPENTHREAD_ENABLE_NCP
bin_PROGRAMS += \
ot-ncp \
$(NULL)
endif
ot_ncp_CPPFLAGS = \
$(CPPFLAGS_COMMON) \
-DOPENTHREAD_POSIX_APP=1 \
@@ -108,11 +102,56 @@ ot_ncp_LIBTOOLFLAGS = \
$(LIBTOOLFLAGS_COMMON) \
$(NULL)
if OPENTHREAD_ENABLE_POSIX_APP_DAEMON
bin_PROGRAMS += \
ot-ctl \
ot-daemon \
$(NULL)
else # OPENTHREAD_ENABLE_POSIX_APP_DAEMON
if OPENTHREAD_ENABLE_CLI
bin_PROGRAMS += \
ot-cli \
$(NULL)
endif
if OPENTHREAD_ENABLE_NCP
bin_PROGRAMS += \
ot-ncp \
$(NULL)
endif
endif # OPENTHREAD_ENABLE_POSIX_APP_DAEMON
ot_ctl_SOURCES = \
client.c \
$(NULL)
ot_ctl_CPPFLAGS = \
$(CPPFLAGS_COMMON) \
$(NULL)
ot_daemon_CPPFLAGS = \
$(CPPFLAGS_COMMON) \
-DOPENTHREAD_POSIX_APP=2 \
$(NULL)
ot_daemon_SOURCES = \
main.c \
$(NULL)
ot_daemon_LDADD = \
$(top_builddir)/src/cli/libopenthread-cli-ftd.a \
$(top_builddir)/src/core/libopenthread-ftd.a \
$(LDADD_COMMON) \
$(top_builddir)/src/core/libopenthread-ftd.a \
$(LDADD_COMMON) \
$(NULL)
ot_daemon_LDFLAGS = \
$(LDFLAGS_COMMON) \
$(NULL)
ot_daemon_LIBTOOLFLAGS = \
$(LIBTOOLFLAGS_COMMON) \
$(NULL)
ot_cli_CPPFLAGS = \
$(CPPFLAGS_COMMON) \
+17
View File
@@ -105,3 +105,20 @@ sudo wpantund -s 'system:./output/posix/x86_64-unknown-linux-gnu/bin/ot-ncp /dev
# CC2538
sudo wpantund -s 'system:./output/posix/x86_64-unknown-linux-gnu/bin/ot-ncp /dev/ttyUSB0 115200'
```
Daemon Mode Support
-------------------
OpenThread Posix Daemon mode uses a unix socket as input and output, so that OpenThread core can run as a service. And a client
can communicate with it by connecting to the socket. The protocol is OpenThread CLI.
```
# build daemon mode core stack for POSIX
make -f src/posix/Makefile-posix DAEMON=1
# Daemon with simulation
./output/posix/x86_64-unknown-linux-gnu/bin/ot-daemon ./output/x86_64-unknown-linux-gnu/bin/ot-ncp-radio 1
# Daemon with real device
./output/posix/x86_64-unknown-linux-gnu/bin/ot-daemon /dev/ttyACM0 115200
# Built-in controller
./output/posix/x86_64-unknown-linux-gnu/bin/ot-ctl
```
+126
View File
@@ -0,0 +1,126 @@
/*
* Copyright (c) 2019, 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.
*/
#include "openthread-core-config.h"
#include <openthread/platform/toolchain.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include "code_utils.h"
#include "platform-posix.h"
int main(int argc, char *argv[])
{
OT_UNUSED_VARIABLE(argc);
OT_UNUSED_VARIABLE(argv);
int ret;
int session = -1;
session = socket(AF_UNIX, SOCK_STREAM, 0);
otEXPECT_ACTION(session != -1, perror("socket"); ret = OT_EXIT_FAILURE);
{
struct sockaddr_un sockname;
memset(&sockname, 0, sizeof(struct sockaddr_un));
sockname.sun_family = AF_UNIX;
strncpy(sockname.sun_path, OPENTHREAD_POSIX_APP_SOCKET_NAME, sizeof(sockname.sun_path) - 1);
ret = connect(session, (const struct sockaddr *)&sockname, sizeof(struct sockaddr_un));
if (ret == -1)
{
fprintf(stderr, "OpenThread daemon is not running.\n");
otEXIT_NOW(ret = OT_EXIT_FAILURE);
}
}
while (1)
{
char buffer[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE];
fd_set readFdSet;
int maxFd = STDIN_FILENO;
FD_ZERO(&readFdSet);
FD_SET(STDIN_FILENO, &readFdSet);
FD_SET(session, &readFdSet);
maxFd = session > maxFd ? session : maxFd;
ret = select(maxFd + 1, &readFdSet, NULL, NULL, NULL);
otEXPECT_ACTION(ret != -1, perror("select"); ret = OT_EXIT_FAILURE);
if (ret == 0)
{
otEXIT_NOW(ret = OT_EXIT_SUCCESS);
}
if (FD_ISSET(STDIN_FILENO, &readFdSet))
{
otEXPECT_ACTION(fgets(buffer, sizeof(buffer), stdin) != NULL, ret = OT_EXIT_FAILURE);
ret = (int)write(session, buffer, strlen(buffer));
otEXPECT_ACTION(ret != -1, perror("write"); ret = OT_EXIT_FAILURE);
}
if (FD_ISSET(session, &readFdSet))
{
ret = (int)read(session, buffer, sizeof(buffer));
otEXPECT_ACTION(ret != -1, perror("read"); ret = OT_EXIT_FAILURE);
if (ret == 0)
{
// daemon closed session
otEXIT_NOW(ret = OT_EXIT_FAILURE);
}
else
{
buffer[ret] = 0;
printf("%s", buffer);
fflush(stdout);
}
}
}
exit:
if (session != -1)
{
close(session);
}
return ret;
}
+1 -1
View File
@@ -34,7 +34,7 @@
#ifndef POSIX_APP_HDLC_INTERFACE_HPP_
#define POSIX_APP_HDLC_INTERFACE_HPP_
#include "platform-posix.h"
#include "platform-config.h"
#include "hdlc.hpp"
+53
View File
@@ -0,0 +1,53 @@
/*
* Copyright (c) 2019, 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.
*/
/**
* @file
* @brief
* This file includes the POSIX platform-specific configurations.
*/
/**
* @def OPENTHREAD_CONFIG_POSIX_APP_ENABLE_PTY_DEVICE
*
* Define as 1 to enable PTY device support in POSIX app.
*
*/
#ifndef OPENTHREAD_CONFIG_POSIX_APP_ENABLE_PTY_DEVICE
#define OPENTHREAD_CONFIG_POSIX_APP_ENABLE_PTY_DEVICE 1
#endif
/**
* @def OPENTHREAD_POSIX_APP_SOCKET_BASENAME
*
* Define socket basename used by POSIX app daemon.
*
*/
#ifndef OPENTHREAD_POSIX_APP_SOCKET_BASENAME
#define OPENTHREAD_POSIX_APP_SOCKET_BASENAME "/tmp/openthread"
#endif
+4 -6
View File
@@ -40,15 +40,13 @@
#include <openthread/instance.h>
#include "platform-config.h"
/**
* @def OPENTHREAD_CONFIG_POSIX_APP_ENABLE_PTY_DEVICE
*
* Define as 1 to enable PTY device support in POSIX app.
* This is the socket name used by daemon mode.
*
*/
#ifndef OPENTHREAD_CONFIG_POSIX_APP_ENABLE_PTY_DEVICE
#define OPENTHREAD_CONFIG_POSIX_APP_ENABLE_PTY_DEVICE 1
#endif
#define OPENTHREAD_POSIX_APP_SOCKET_NAME OPENTHREAD_POSIX_APP_SOCKET_BASENAME ".sock"
#ifdef __cplusplus
extern "C" {
+174 -27
View File
@@ -29,6 +29,16 @@
#include "openthread-core-config.h"
#include "platform-posix.h"
#if OPENTHREAD_ENABLE_POSIX_APP_DAEMON
#include <assert.h>
#include <fcntl.h>
#include <signal.h>
#include <string.h>
#include <sys/file.h>
#include <sys/socket.h>
#include <sys/un.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@@ -37,9 +47,16 @@
#include "code_utils.h"
static uint8_t sReceiveBuffer[128];
static const uint8_t *sWriteBuffer;
static uint16_t sWriteLength;
#define OPENTHREAD_POSIX_APP_SOCKET_LOCK OPENTHREAD_POSIX_APP_SOCKET_BASENAME ".lock"
#if OPENTHREAD_ENABLE_POSIX_APP_DAEMON
static int sUartSocket = -1;
static int sUartLock = -1;
static int sSessionSocket = -1;
#endif
static const uint8_t *sWriteBuffer = NULL;
static uint16_t sWriteLength = 0;
void platformUartRestore(void)
{
@@ -47,12 +64,86 @@ void platformUartRestore(void)
otError otPlatUartEnable(void)
{
return OT_ERROR_NONE;
otError error = OT_ERROR_NONE;
#if OPENTHREAD_ENABLE_POSIX_APP_DAEMON
struct sockaddr_un sockname;
int ret;
sUartSocket = socket(AF_UNIX, SOCK_STREAM, 0);
if (sUartSocket == -1)
{
perror("socket");
exit(OT_EXIT_FAILURE);
}
sUartLock = open(OPENTHREAD_POSIX_APP_SOCKET_LOCK, O_CREAT | O_RDONLY, 0600);
if (sUartLock == -1)
{
perror("open");
exit(OT_EXIT_FAILURE);
}
if (flock(sUartLock, LOCK_EX | LOCK_NB) == -1)
{
perror("flock");
exit(OT_EXIT_FAILURE);
}
memset(&sockname, 0, sizeof(struct sockaddr_un));
(void)unlink(OPENTHREAD_POSIX_APP_SOCKET_NAME);
sockname.sun_family = AF_UNIX;
assert(sizeof(OPENTHREAD_POSIX_APP_SOCKET_NAME) < sizeof(sockname.sun_path), "socket name too long");
strncpy(sockname.sun_path, OPENTHREAD_POSIX_APP_SOCKET_NAME, sizeof(sockname.sun_path) - 1);
ret = bind(sUartSocket, (const struct sockaddr *)&sockname, sizeof(struct sockaddr_un));
if (ret == -1)
{
perror("bind");
exit(OT_EXIT_FAILURE);
}
//
// only accept 1 connection.
//
ret = listen(sUartSocket, 1);
if (ret == -1)
{
perror("listen");
exit(OT_EXIT_FAILURE);
}
#endif // OPENTHREAD_ENABLE_POSIX_APP_DAEMON
return error;
}
otError otPlatUartDisable(void)
{
return OT_ERROR_NONE;
otError error = OT_ERROR_NONE;
#if OPENTHREAD_ENABLE_POSIX_APP_DAEMON
if (sSessionSocket != -1)
{
close(sSessionSocket);
sSessionSocket = -1;
}
if (sUartSocket != -1)
{
close(sUartSocket);
sUartSocket = -1;
}
if (sUartLock != -1)
{
close(sUartLock);
sUartLock = -1;
}
#endif // OPENTHREAD_ENABLE_POSIX_APP_DAEMON
return error;
}
otError otPlatUartSend(const uint8_t *aBuf, uint16_t aBufLength)
@@ -72,31 +163,42 @@ void platformUartUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, fd_set *aE
{
if (aReadFdSet != NULL)
{
FD_SET(STDIN_FILENO, aReadFdSet);
#if OPENTHREAD_ENABLE_POSIX_APP_DAEMON
int fd = (sSessionSocket == -1 ? sUartSocket : sSessionSocket);
#else
int fd = STDIN_FILENO;
#endif
FD_SET(fd, aReadFdSet);
if (aErrorFdSet != NULL)
{
FD_SET(STDIN_FILENO, aErrorFdSet);
FD_SET(fd, aErrorFdSet);
}
if (aMaxFd != NULL && *aMaxFd < STDIN_FILENO)
if (aMaxFd != NULL && *aMaxFd < fd)
{
*aMaxFd = STDIN_FILENO;
*aMaxFd = fd;
}
}
if ((aWriteFdSet != NULL) && (sWriteLength > 0))
{
FD_SET(STDOUT_FILENO, aWriteFdSet);
#if OPENTHREAD_ENABLE_POSIX_APP_DAEMON
int fd = (sSessionSocket == -1 ? sUartSocket : sSessionSocket);
#else
int fd = STDOUT_FILENO;
#endif
FD_SET(fd, aWriteFdSet);
if (aErrorFdSet != NULL)
{
FD_SET(STDOUT_FILENO, aErrorFdSet);
FD_SET(fd, aErrorFdSet);
}
if (aMaxFd != NULL && *aMaxFd < STDOUT_FILENO)
if (aMaxFd != NULL && *aMaxFd < fd)
{
*aMaxFd = STDOUT_FILENO;
*aMaxFd = fd;
}
}
}
@@ -104,7 +206,31 @@ void platformUartUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, fd_set *aE
void platformUartProcess(const fd_set *aReadFdSet, const fd_set *aWriteFdSet, const fd_set *aErrorFdSet)
{
ssize_t rval;
int fd;
#if OPENTHREAD_ENABLE_POSIX_APP_DAEMON
if (FD_ISSET(sUartSocket, aErrorFdSet))
{
perror("socket error");
exit(OT_EXIT_FAILURE);
}
else if (FD_ISSET(sUartSocket, aReadFdSet))
{
sSessionSocket = accept(sUartSocket, NULL, NULL);
}
otEXPECT(sSessionSocket != -1);
if (FD_ISSET(sSessionSocket, aErrorFdSet))
{
close(sSessionSocket);
sSessionSocket = -1;
}
otEXPECT(sSessionSocket != -1);
fd = sSessionSocket;
#else // OPENTHREAD_ENABLE_POSIX_APP_DAEMON
if (FD_ISSET(STDIN_FILENO, aErrorFdSet))
{
perror("stdin");
@@ -117,36 +243,54 @@ void platformUartProcess(const fd_set *aReadFdSet, const fd_set *aWriteFdSet, co
exit(OT_EXIT_FAILURE);
}
if (FD_ISSET(STDIN_FILENO, aReadFdSet))
fd = STDIN_FILENO;
#endif // OPENTHREAD_ENABLE_POSIX_APP_DAEMON
if (FD_ISSET(fd, aReadFdSet))
{
rval = read(STDIN_FILENO, sReceiveBuffer, sizeof(sReceiveBuffer));
uint8_t buffer[256];
rval = read(fd, buffer, sizeof(buffer));
if (rval > 0)
{
otPlatUartReceived(sReceiveBuffer, (uint16_t)rval);
otPlatUartReceived(buffer, (uint16_t)rval);
}
else if (rval < 0)
else if (rval <= 0)
{
perror("UART read");
#if OPENTHREAD_ENABLE_POSIX_APP_DAEMON
close(sSessionSocket);
sSessionSocket = -1;
otEXIT_NOW();
#else
exit(OT_EXIT_FAILURE);
}
else
{
fprintf(stderr, "UART ended\r\n");
exit(OT_EXIT_SUCCESS);
#endif
}
}
if ((sWriteLength > 0) && (FD_ISSET(STDOUT_FILENO, aWriteFdSet)))
{
rval = write(STDOUT_FILENO, sWriteBuffer, sWriteLength);
#if !OPENTHREAD_ENABLE_POSIX_APP_DAEMON
fd = STDOUT_FILENO;
#endif
if (rval <= 0)
if ((sWriteLength > 0) && (FD_ISSET(fd, aWriteFdSet)))
{
rval = write(fd, sWriteBuffer, sWriteLength);
if (rval < 0)
{
perror("UART write");
#if OPENTHREAD_ENABLE_POSIX_APP_DAEMON
close(sSessionSocket);
sSessionSocket = -1;
otEXIT_NOW();
#else
exit(OT_EXIT_FAILURE);
#endif
}
otEXPECT(rval > 0);
sWriteBuffer += (uint16_t)rval;
sWriteLength -= (uint16_t)rval;
@@ -155,4 +299,7 @@ void platformUartProcess(const fd_set *aReadFdSet, const fd_set *aWriteFdSet, co
otPlatUartSendDone();
}
}
exit:
return;
}