/* * Copyright (c) 2013-2016, Wind River Systems, Inc. * * 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 Wind River Systems 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 "guest_unix.h" #include #include #include #include #include #include #include #include "guest_limits.h" #include "guest_types.h" #include "guest_debug.h" #include "guest_selobj.h" GuestUnixConnectCallbackT _callback = NULL; // **************************************************************************** // Guest Unix - Connect // ==================== GuestErrorT guest_unix_connect( int s, char* address ) { struct sockaddr_un remote; int len, result; memset(&remote, 0, sizeof(remote)); remote.sun_family = AF_UNIX; len = sizeof(remote.sun_family); len += snprintf(remote.sun_path, sizeof(remote.sun_path), "%s", address); result = connect(s, (struct sockaddr*) &remote, sizeof(remote)); if (0 > result) { DPRINTFE("Failed to connect to %s, error=%s.", address, strerror(errno)); return GUEST_FAILED; } return GUEST_OKAY; } // **************************************************************************** // **************************************************************************** // Guest Unix - Dispatch Connection // ================================ static void guest_unix_dispatch_connection( int s ) { int sock; struct sockaddr_un remote; socklen_t len; int result; memset(&remote, 0, sizeof(remote)); len = sizeof(remote); result = accept(s, (struct sockaddr*) &remote, &len); if (0 > result) { DPRINTFE("Failed to accept on socket, error=%s.", strerror(errno)); return; } sock = result; result = fcntl(sock, F_SETFD, FD_CLOEXEC); if (0 > result) { DPRINTFE("Failed to set to close on exec, error=%s.", strerror(errno)); close(sock); return; } result = fcntl(sock, F_GETFL); if (0 > result) { DPRINTFE("Failed to get socket options, error=%s.", strerror(errno)); close(sock); return; } result = fcntl(sock, F_SETFL, result | O_NONBLOCK); if (0 > result) { DPRINTFE("Failed to set socket options, error=%s.", strerror(errno)); close(sock); return; } if (NULL == _callback) close(sock); _callback(sock, remote.sun_path); } // **************************************************************************** // **************************************************************************** // Guest Unix - Listen // =================== GuestErrorT guest_unix_listen( int s, char* address, GuestUnixConnectCallbackT callback ) { struct sockaddr_un local; int len, result; GuestSelObjCallbacksT callbacks; GuestErrorT error; memset(&local, 0, sizeof(local)); local.sun_family = AF_UNIX; len = sizeof(local.sun_family); len += snprintf(local.sun_path, sizeof(local.sun_path), "%s", address); unlink(address); result = bind(s, (struct sockaddr*) &local, len); if (0 > result) { DPRINTFE("Failed to bind socket to address %s, error=%s.", address, strerror(errno)); return GUEST_FAILED; } result = listen(s, GUEST_MAX_CONNECTIONS); if (0 > result) { DPRINTFE("Failed to listen on %s, error=%s.", address, strerror(errno)); return GUEST_FAILED; } memset(&callbacks, 0, sizeof(callbacks)); callbacks.read_callback = guest_unix_dispatch_connection; error = guest_selobj_register(s, &callbacks); if (GUEST_OKAY != error) { DPRINTFE("Failed to register selection object, error=%s.", guest_error_str(error)); return error; } _callback = callback; return GUEST_OKAY; } // **************************************************************************** // **************************************************************************** // Guest Unix - Send // ================= GuestErrorT guest_unix_send( int s, void* msg, int msg_size ) { int result; result = write(s, msg, msg_size); if (0 > result) { DPRINTFE("Failed to write to socket, error=%s.", strerror(errno)); return GUEST_FAILED; } return GUEST_OKAY; } // **************************************************************************** // **************************************************************************** // Guest Unix - Receive // ==================== GuestErrorT guest_unix_receive( int s, void* msg_buf, int msg_buf_size, int* msg_size ) { int result; result = read(s, msg_buf, msg_buf_size); if (0 > result) { if (EINTR == errno) { DPRINTFD("Interrupted on socket read, error=%s.", strerror(errno)); return GUEST_INTERRUPTED; } else if (ECONNRESET == errno) { DPRINTFD("Peer connection reset, error=%s.", strerror(errno)); *msg_size = 0; return GUEST_OKAY; } else { DPRINTFE("Failed to read from socket, error=%s.", strerror(errno)); return GUEST_FAILED; } } else if (0 == result) { DPRINTFD("No message received from socket."); *msg_size = 0; return GUEST_OKAY; } else { DPRINTFV("Received message, msg_size=%i.", result); *msg_size = result; } return GUEST_OKAY; } // **************************************************************************** // **************************************************************************** // Guest Unix - Open // ================= GuestErrorT guest_unix_open( int* s ) { int sock; int reuse_addr = 1; struct sockaddr_un local; int result; *s = -1; memset(&local, 0, sizeof(local)); sock = socket(AF_UNIX, SOCK_STREAM, 0); if (0 > sock) { DPRINTFE("Failed to open socket, error=%s.", strerror(errno)); return GUEST_FAILED; } result = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr)); if (0 > result) { DPRINTFE("Failed to set socket option (REUSEADDR), error=%s.", strerror(errno)); close(sock); return GUEST_FAILED; } result = fcntl(sock, F_SETFD, FD_CLOEXEC); if (0 > result) { DPRINTFE("Failed to set to close on exec, error=%s.", strerror(errno)); close(sock); return GUEST_FAILED; } result = fcntl(sock, F_GETFL); if (0 > result) { DPRINTFE("Failed to get socket options, error=%s.", strerror(errno)); close(sock); return GUEST_FAILED; } result = fcntl(sock, F_SETFL, result | O_NONBLOCK); if (0 > result) { DPRINTFE("Failed to set socket options, error=%s.", strerror(errno)); close(sock); return GUEST_FAILED; } *s = sock; return GUEST_OKAY; } // **************************************************************************** // **************************************************************************** // Guest Unix - Close // ================== GuestErrorT guest_unix_close( int s ) { GuestErrorT error; if (0 <= s) { error = guest_selobj_deregister(s); if (GUEST_OKAY != error) { DPRINTFE("Failed to deregister selection object, error=%s.", guest_error_str(error)); } close(s); } return GUEST_OKAY; } // **************************************************************************** // **************************************************************************** // Guest Unix - Initialize // ======================= GuestErrorT guest_unix_initialize( void ) { _callback = NULL; return GUEST_OKAY; } // **************************************************************************** // **************************************************************************** // Guest Unix - Finalize // ===================== GuestErrorT guest_unix_finalize( void ) { _callback = NULL; return GUEST_OKAY; } // ****************************************************************************