diff options
Diffstat (limited to 'lib/avtp_pipeline/platform/Linux/avdecc_msg/openavb_avdecc_msg_server_osal.c')
-rw-r--r-- | lib/avtp_pipeline/platform/Linux/avdecc_msg/openavb_avdecc_msg_server_osal.c | 271 |
1 files changed, 271 insertions, 0 deletions
diff --git a/lib/avtp_pipeline/platform/Linux/avdecc_msg/openavb_avdecc_msg_server_osal.c b/lib/avtp_pipeline/platform/Linux/avdecc_msg/openavb_avdecc_msg_server_osal.c new file mode 100644 index 00000000..e73b9701 --- /dev/null +++ b/lib/avtp_pipeline/platform/Linux/avdecc_msg/openavb_avdecc_msg_server_osal.c @@ -0,0 +1,271 @@ +/************************************************************************************************************* +Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company +Copyright (c) 2016-2017, Harman International Industries, Incorporated +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. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "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 OWNER OR CONTRIBUTORS LISTED 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. + +Attributions: The inih library portion of the source code is licensed from +Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt. +Complete license and copyright information can be found at +https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175. +*************************************************************************************************************/ + +#ifndef OPENAVB_AVDECC_MSG_SERVER_OSAL_C +#define OPENAVB_AVDECC_MSG_SERVER_OSAL_C + +#define AVB_AVDECC_LISTEN_FDS 0 // first fds, was last MAX_AVB_STREAMS +#define SOCK_INVALID (-1) +#define POLL_FD_COUNT ((MAX_AVB_STREAMS) + 1) + +static int lsock = SOCK_INVALID; +static struct pollfd fds[POLL_FD_COUNT]; +static struct sockaddr_un serverAddr; + +static void socketClose(int h) +{ + AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG); + + if (h < 0 || h >= POLL_FD_COUNT) { + AVB_LOG_ERROR("Closing socket; invalid handle"); + } + else { + if (h != AVB_AVDECC_LISTEN_FDS) { + openavbAvdeccMsgSrvrCloseClientConnection(h); + } + close(fds[h].fd); + fds[h].fd = SOCK_INVALID; + fds[h].events = 0; + } + + AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG); +} + +static bool openavbAvdeccMsgSrvrSendToClient(int h, openavbAvdeccMessage_t *msg) +{ + AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG); + + if (h < 0 || h >= POLL_FD_COUNT) { + AVB_LOG_ERROR("Sending message; invalid handle"); + AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG); + return FALSE; + } + if (!msg) { + AVB_LOG_ERROR("Sending message; invalid argument passed"); + AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG); + return FALSE; + } + + int csock = fds[h].fd; + if (csock == SOCK_INVALID) { + AVB_LOG_ERROR("Socket closed unexpectedly"); + return FALSE; + } + + ssize_t nWrite = write(csock, msg, OPENAVB_AVDECC_MSG_LEN); + AVB_LOGF_VERBOSE("Sent message, len=%zu, nWrite=%zu", OPENAVB_AVDECC_MSG_LEN, nWrite); + if (nWrite < OPENAVB_AVDECC_MSG_LEN) { + if (nWrite < 0) { + AVB_LOGF_ERROR("Failed to write socket: %s", strerror(errno)); + } + else if (nWrite == 0) { + AVB_LOG_ERROR("Socket closed unexpectedly"); + } + else { + AVB_LOG_ERROR("Socket write too short"); + } + socketClose(h); + AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG); + return FALSE; + } + + AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG); + return TRUE; +} + +bool openavbAvdeccMsgServerOpen(void) +{ + AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG); + int i; + + // Perform the base initialization. + openavbAvdeccMsgInitialize(); + + for (i=0; i < POLL_FD_COUNT; i++) { + fds[i].fd = SOCK_INVALID; + fds[i].events = 0; + } + + lsock = socket(AF_UNIX, SOCK_STREAM, 0); + if (lsock < 0) { + AVB_LOGF_ERROR("Failed to open socket: %s", strerror(errno)); + goto error; + } + // serverAddr is file static + serverAddr.sun_family = AF_UNIX; + snprintf(serverAddr.sun_path, UNIX_PATH_MAX, AVB_AVDECC_MSG_UNIX_PATH); + + // try remove old socket + if (unlink(serverAddr.sun_path) == -1 && errno != ENOENT) { + AVB_LOGF_ERROR("Failed to remove %s: %s", serverAddr.sun_path, strerror(errno)); + } + + int rslt = bind(lsock, (struct sockaddr*)&serverAddr, sizeof(struct sockaddr_un)); + if (rslt != 0) { + AVB_LOGF_ERROR("Failed to create %s: %s", serverAddr.sun_path, strerror(errno)); + AVB_LOG_WARNING("** If AVDECC Msg process crashed, run the cleanup script **"); + goto error; + } + + rslt = listen(lsock, 5); + if (rslt != 0) { + AVB_LOGF_ERROR("Failed to listen on socket: %s", strerror(errno)); + goto error; + } + AVB_LOGF_DEBUG("Listening on socket: %s", serverAddr.sun_path); + + fds[AVB_AVDECC_LISTEN_FDS].fd = lsock; + fds[AVB_AVDECC_LISTEN_FDS].events = POLLIN; + + AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG); + return TRUE; + + error: + if (lsock >= 0) { + close(lsock); + lsock = -1; + } + AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG); + return FALSE; +} + +void openavbAvdeccMsgSrvrService(void) +{ + AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG); + struct sockaddr_un addrClient; + socklen_t lenAddr; + int i, j; + int csock; + + int nfds = POLL_FD_COUNT; + int pRet; + + AVB_LOG_VERBOSE("Waiting for event..."); + pRet = poll(fds, nfds, 1000); + + if (pRet == 0) { + AVB_LOG_VERBOSE("poll timeout"); + } + else if (pRet < 0) { + if (errno == EINTR) { + AVB_LOG_VERBOSE("Poll interrupted"); + } + else { + AVB_LOGF_ERROR("Poll error: %s", strerror(errno)); + } + } + else { + AVB_LOGF_VERBOSE("Poll returned %d events", pRet); + for (i=0; i<nfds; i++) { + if (fds[i].revents != 0) { + AVB_LOGF_VERBOSE("%d sock=%d, event=0x%x, revent=0x%x", i, fds[i].fd, fds[i].events, fds[i].revents); + + if (i == AVB_AVDECC_LISTEN_FDS) { + // listen sock - indicates new connection from client + lenAddr = sizeof(addrClient); + csock = accept(lsock, (struct sockaddr*)&addrClient, &lenAddr); + if (csock < 0) { + AVB_LOGF_ERROR("Failed to accept connection: %s", strerror(errno)); + } + else { + for (j = 0; j < POLL_FD_COUNT; j++) { + if (fds[j].fd == SOCK_INVALID) { + fds[j].fd = csock; + fds[j].events = POLLIN; + break; + } + } + if (j >= POLL_FD_COUNT) { + AVB_LOG_ERROR("Too many client connections"); + close(csock); + } + } + + AVB_LOG_INFO("New AVDECC Msg client connection detected"); + } + else { + csock = fds[i].fd; + openavbAvdeccMessage_t msgBuf; + memset(&msgBuf, 0, OPENAVB_AVDECC_MSG_LEN); + ssize_t nRead = read(csock, &msgBuf, OPENAVB_AVDECC_MSG_LEN); + AVB_LOGF_VERBOSE("Socket read h=%d,fd=%d: read=%zu, expect=%zu", i, csock, nRead, OPENAVB_AVDECC_MSG_LEN); + + if (nRead < OPENAVB_AVDECC_MSG_LEN) { + // sock closed + if (nRead == 0) { + AVB_LOGF_DEBUG("Socket closed, h=%d", i); + } + else if (nRead < 0) { + AVB_LOGF_ERROR("Socket read, h=%d: %s", i, strerror(errno)); + } + else { + AVB_LOGF_ERROR("Short read, h=%d", i); + } + socketClose(i); + } + else { + // got a message + if (!openavbAvdeccMsgSrvrReceiveFromClient(i, &msgBuf)) { + AVB_LOG_ERROR("Failed to handle message"); + socketClose(i); + } + } + } + } + } + } + AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG); +} + +void openavbAvdeccMsgServerClose(void) +{ + AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG); + int i; + for (i = 0; i < POLL_FD_COUNT; i++) { + if (fds[i].fd != SOCK_INVALID) { + socketClose(i); + } + } + if (lsock != SOCK_INVALID) { + close(lsock); + } + + if (unlink(serverAddr.sun_path) != 0) { + AVB_LOGF_ERROR("Failed to unlink %s: %s", serverAddr.sun_path, strerror(errno)); + } + + // Perform the base cleanup. + openavbAvdeccMsgCleanup(); + + AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG); +} + +#endif // OPENAVB_AVDECC_MSG_SERVER_OSAL_C |