Blame Esm/ib/src/cs/cs_sockwrap.c

Packit 857059
/* BEGIN_ICS_COPYRIGHT5 ****************************************
Packit 857059
Packit 857059
Copyright (c) 2015-2017, Intel Corporation
Packit 857059
Packit 857059
Redistribution and use in source and binary forms, with or without
Packit 857059
modification, are permitted provided that the following conditions are met:
Packit 857059
Packit 857059
    * Redistributions of source code must retain the above copyright notice,
Packit 857059
      this list of conditions and the following disclaimer.
Packit 857059
    * Redistributions in binary form must reproduce the above copyright
Packit 857059
      notice, this list of conditions and the following disclaimer in the
Packit 857059
      documentation and/or other materials provided with the distribution.
Packit 857059
    * Neither the name of Intel Corporation nor the names of its contributors
Packit 857059
      may be used to endorse or promote products derived from this software
Packit 857059
      without specific prior written permission.
Packit 857059
Packit 857059
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
Packit 857059
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
Packit 857059
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
Packit 857059
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
Packit 857059
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
Packit 857059
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
Packit 857059
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
Packit 857059
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
Packit 857059
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
Packit 857059
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit 857059
Packit 857059
 * ** END_ICS_COPYRIGHT5   ****************************************/
Packit 857059
Packit 857059
/*******************************************************************************
Packit 857059
 * @file cs_sockwrap.c
Packit 857059
 *
Packit 857059
 * @brief
Packit 857059
 * This file contains some socket creation routines for server and client
Packit 857059
 * AF_UNIX type sockets.
Packit 857059
 * The routines are supposed to be used on both Unix and Vxworks but the
Packit 857059
 * structure of the socket addresss strings passed to the routines differs
Packit 857059
 * between the operating systems.
Packit 857059
 * In UNIX the structure of the strings is supposed to be generally of the
Packit 857059
 * form "/var/tmp/<unique file name>" and in VXWORKS the string should
Packit 857059
 * take the form "/comp/socket/0xNumber" where 0xNumber is a string
Packit 857059
 * representation of a 16 bit number is hexadecimal form.
Packit 857059
 *******************************************************************************
Packit 857059
 */
Packit 857059
Packit 857059
#include <stdlib.h>
Packit 857059
#include <sys/socket.h>
Packit 857059
#include <sys/un.h>
Packit 857059
#include <sys/stat.h>
Packit 857059
#include "cs_sockwrap.h"
Packit 857059
#include <fcntl.h>
Packit 857059
#include "cs_g.h"
Packit 857059
#include <errno.h>
Packit 857059
#include <string.h>
Packit 857059
Packit 857059
#define QLEN	10
Packit 857059
Packit 857059
Packit 857059
#define	CLI_PERM	S_IRWXU			/* rwx for user only */
Packit 857059
Packit 857059
#define MAXWAIT  30
Packit 857059
Packit 857059
Packit 857059
/*
Packit 857059
 * @brief
Packit 857059
 *
Packit 857059
 * cs_local_comm_init --
Packit 857059
 *
Packit 857059
 * This function takes a string as an argument and creates a AF_UNIX
Packit 857059
 * socket with the string supplied to it as the address in the socket
Packit 857059
 * structure.
Packit 857059
 * This routine is to be called by a program that needs a server socket.
Packit 857059
 *
Packit 857059
 * @param[in] name	pointer to unique socket address string
Packit 857059
 *
Packit 857059
 * @return *  socket descriptor on sucess or (-1) on failure
Packit 857059
 *
Packit 857059
 * NOTE: For VxWorks socket support, please refer to the WindRiver Network Stack
Packit 857059
 * Programmer's Guide 6.9 (Section 5.3 - Working with Local Domain Sockets)
Packit 857059
 *
Packit 857059
 */
Packit 857059
int
Packit 857059
cs_local_comm_init(const char *name)
Packit 857059
{
Packit 857059
	int			fd;
Packit 857059
	int			len;
Packit 857059
	int			err;
Packit 857059
	struct sockaddr_un	un;
Packit 857059
Packit 857059
	if (strlen(name) >= (sizeof(un.sun_path) )) {
Packit 857059
		errno = ENAMETOOLONG;
Packit 857059
		return(-1);
Packit 857059
	}
Packit 857059
Packit 857059
	/* create a UNIX domain stream socket */
Packit 857059
#ifdef __LINUX__
Packit 857059
	if ((fd = socket(AF_UNIX, SOCK_SEQPACKET, 0)) < 0) {
Packit 857059
#else
Packit 857059
	if ((fd = socket(AF_LOCAL, SOCK_SEQPACKET, 0)) < 0) {
Packit 857059
#endif
Packit 857059
		return(fd);
Packit 857059
	}
Packit 857059
Packit 857059
	unlink(name);	/* in case it already exists */
Packit 857059
Packit 857059
	/* fill in socket address structure */
Packit 857059
	memset(&un, 0, sizeof(un));
Packit 857059
	snprintf(un.sun_path, sizeof(un.sun_path), "%s", name);
Packit 857059
Packit 857059
#ifdef __LINUX__
Packit 857059
	un.sun_family = AF_UNIX;
Packit 857059
	len = offsetof(struct sockaddr_un, sun_path) + strlen(name);
Packit 857059
#else
Packit 857059
	un.sun_family = AF_LOCAL;
Packit 857059
	len = sizeof(struct sockaddr_un);
Packit 857059
	un.sun_len = len;
Packit 857059
#endif
Packit 857059
Packit 857059
	/* bind the name */
Packit 857059
	if (bind(fd, (struct sockaddr *)&un, len) < 0) {
Packit 857059
		goto errout;
Packit 857059
	}
Packit 857059
Packit 857059
	if (listen(fd, QLEN) < 0) {	/* tell kernel we're a server */
Packit 857059
		goto errout;
Packit 857059
	}
Packit 857059
	return(fd);
Packit 857059
Packit 857059
errout:
Packit 857059
	err = errno;
Packit 857059
	close(fd);
Packit 857059
	errno = err;
Packit 857059
	return(-1);
Packit 857059
}
Packit 857059
Packit 857059
Packit 857059
/*
Packit 857059
 * @brief
Packit 857059
 *
Packit 857059
 * cs_local_comm_accept --
Packit 857059
 *
Packit 857059
 * This function takes a socket descriptor as an argument and waits for
Packit 857059
 * a client connectio to arrive on it. It accepts the new connection
Packit 857059
 * checks for to see if the connection is via a socket and whether it
Packit 857059
 * is writeable and returns with the new socket descriptor if everything
Packit 857059
 * is successful
Packit 857059
 *
Packit 857059
 * @param[in] listenfd	socket to listen for a connection on
Packit 857059
 *
Packit 857059
 * @return    socket descriptor on sucess or (-1) on failure
Packit 857059
 *
Packit 857059
 */
Packit 857059
int
Packit 857059
cs_local_comm_accept(int listenfd)
Packit 857059
{
Packit 857059
	int				clifd;
Packit 857059
	socklen_t			len;
Packit 857059
	struct sockaddr_un		un;
Packit 857059
	char				*name;
Packit 857059
#ifdef __LINUX__
Packit 857059
	int err;
Packit 857059
	struct stat			statbuf;
Packit 857059
#endif
Packit 857059
Packit 857059
	/* allocate enough space for longest name plus terminating null */
Packit 857059
	if ((name = malloc(sizeof(un.sun_path) + 1)) == NULL)
Packit 857059
		assert(name);
Packit 857059
	len = sizeof(un);
Packit 857059
	if ((clifd = accept(listenfd, (struct sockaddr *)&un, &len)) < 0) {
Packit 857059
		free(name);
Packit 857059
		return (clifd);
Packit 857059
	}
Packit 857059
Packit 857059
	len -= offsetof(struct sockaddr_un, sun_path); /* len of pathname */
Packit 857059
	StringCopy(name, un.sun_path, len);
Packit 857059
Packit 857059
#ifdef __LINUX__
Packit 857059
	if (stat(name, &statbuf) < 0) {
Packit 857059
		goto errout;
Packit 857059
	}
Packit 857059
Packit 857059
	/* check path to make sure its a socket and writable */
Packit 857059
	if (S_ISSOCK(statbuf.st_mode) == 0) {
Packit 857059
		errno = ENOTSOCK;	/* not a socket */
Packit 857059
		goto errout;
Packit 857059
	}
Packit 857059
Packit 857059
	if ((statbuf.st_mode & (S_IRWXG | S_IRWXO)) ||
Packit 857059
		(statbuf.st_mode & S_IRWXU) != S_IRWXU) {
Packit 857059
		  errno = EPERM;
Packit 857059
		  goto errout;
Packit 857059
	}
Packit 857059
#endif
Packit 857059
Packit 857059
	unlink(name);
Packit 857059
	free(name);
Packit 857059
	return(clifd);
Packit 857059
Packit 857059
#ifdef __LINUX__
Packit 857059
errout:
Packit 857059
	err = errno;
Packit 857059
	close(clifd);
Packit 857059
	free(name);
Packit 857059
	errno = err;
Packit 857059
	return(-1);
Packit 857059
#endif
Packit 857059
}
Packit 857059
Packit 857059
Packit 857059
Packit 857059
Packit 857059
/*
Packit 857059
 * @brief
Packit 857059
 *
Packit 857059
 * cs_local_comm_connect --
Packit 857059
 *
Packit 857059
 * This function takes two string arguments which
Packit 857059
 * are AF_UNIX socket addresses creates a new socket
Packit 857059
 * and connects to a specified server socket.
Packit 857059
 *
Packit 857059
 * @param[in] srvaddr   Server socket address string
Packit 857059
 * @param[in] claddr    Client socket address string
Packit 857059
 *
Packit 857059
 * @return    socket descriptor on sucess or (-1) on failure
Packit 857059
 *
Packit 857059
 * NOTE: For VxWorks socket support, please refer to the WindRiver Network Stack
Packit 857059
 * Programmer's Guide 6.9 (Section 5.3 - Working with Local Domain Sockets)
Packit 857059
 *
Packit 857059
 */
Packit 857059
int
Packit 857059
cs_local_comm_connect(const char *srvaddr, const char *claddr)
Packit 857059
{
Packit 857059
	int			fd, len, err;
Packit 857059
	struct sockaddr_un	un, sun;
Packit 857059
	int			do_unlink = 0;
Packit 857059
Packit 857059
	if ((strlen(srvaddr) >= (sizeof(un.sun_path)) ||
Packit 857059
	     (strlen(claddr) >= sizeof(un.sun_path)))) {
Packit 857059
		errno = ENAMETOOLONG;
Packit 857059
		return(-1);
Packit 857059
	}
Packit 857059
Packit 857059
	/* create a UNIX domain stream socket */
Packit 857059
#ifdef __LINUX__
Packit 857059
	if ((fd = socket(AF_UNIX, SOCK_SEQPACKET, 0)) < 0) {
Packit 857059
#else
Packit 857059
	if ((fd = socket(AF_LOCAL, SOCK_SEQPACKET, 0)) < 0) {
Packit 857059
#endif
Packit 857059
		return(-1);
Packit 857059
	}
Packit 857059
Packit 857059
	/* fill socket address structure with our address */
Packit 857059
	memset(&un, 0, sizeof(un));
Packit 857059
	StringCopy(un.sun_path, claddr, sizeof(un.sun_path));
Packit 857059
Packit 857059
#ifdef __LINUX__
Packit 857059
	un.sun_family = AF_UNIX;
Packit 857059
	len = offsetof(struct sockaddr_un, sun_path) + strlen(un.sun_path);
Packit 857059
	unlink(un.sun_path);		/* in case it already exists */
Packit 857059
#else
Packit 857059
	un.sun_family = AF_LOCAL;
Packit 857059
	len = sizeof(struct sockaddr_un);
Packit 857059
	un.sun_len = len;
Packit 857059
#endif
Packit 857059
Packit 857059
	if (bind(fd, (struct sockaddr *)&un, len) < 0) {
Packit 857059
		goto errout;
Packit 857059
	}
Packit 857059
Packit 857059
#ifdef __LINUX__
Packit 857059
	if (chmod(un.sun_path, CLI_PERM) < 0) {
Packit 857059
		do_unlink = 1;
Packit 857059
		goto errout;
Packit 857059
	}
Packit 857059
#endif
Packit 857059
Packit 857059
	/* fill socket address structure with server's address */
Packit 857059
	memset(&sun, 0, sizeof(sun));
Packit 857059
	StringCopy(sun.sun_path, srvaddr, sizeof(un.sun_path));
Packit 857059
Packit 857059
#ifdef __LINUX__
Packit 857059
	sun.sun_family = AF_UNIX;
Packit 857059
	len = offsetof(struct sockaddr_un, sun_path) + strlen(srvaddr);
Packit 857059
#else
Packit 857059
	sun.sun_family = AF_LOCAL;
Packit 857059
	len = sizeof(struct sockaddr_un);
Packit 857059
	sun.sun_len = len;
Packit 857059
#endif
Packit 857059
	if (connect(fd, (struct sockaddr *)&sun, len) < 0) {
Packit 857059
		do_unlink = 1;
Packit 857059
		goto errout;
Packit 857059
	}
Packit 857059
	return(fd);
Packit 857059
Packit 857059
errout:
Packit 857059
	err = errno;
Packit 857059
	close(fd);
Packit 857059
	if (do_unlink)
Packit 857059
		unlink(un.sun_path);
Packit 857059
	errno = err;
Packit 857059
	return(-1);
Packit 857059
}
Packit 857059
Packit 857059
/**
Packit 857059
 * @brief
Packit 857059
 * cs_comm_connect --
Packit 857059
 *
Packit 857059
 * This function creates a socket with characteristics of the type requested
Packit 857059
 * and then connects to the specified channel using that socket. An explicit
Packit 857059
 * bind by the client is not done as the connect will bind a default address.
Packit 857059
 * If the connection fails because of an unready or a busy server it retries
Packit 857059
 * the connection in an exponential  form.
Packit 857059
 *
Packit 857059
 * @param[in]  domain   Socket domain
Packit 857059
 * @param[in]  type     Socket type
Packit 857059
 * @param[in]  protocol Usually 0
Packit 857059
 * @param[in]  srv_addr     sockaddr structure of server
Packit 857059
 * @param[in]  srv_len      len of server sockaddr
Packit 857059
 *
Packit 857059
 *
Packit 857059
 * @return   socket fd is successful, -1 if not
Packit 857059
 */
Packit 857059
static int
Packit 857059
cs_comm_connect(int domain, int type, int protocol,
Packit 857059
		const struct sockaddr *srv_addr, socklen_t srv_len)
Packit 857059
{
Packit 857059
	int wait = 0;
Packit 857059
	int fd = -1;
Packit 857059
Packit 857059
	if ((fd = socket(domain, type, protocol) <0)) {
Packit 857059
	    return (-1);
Packit 857059
	}
Packit 857059
Packit 857059
	while  (wait++ < MAXWAIT) {
Packit 857059
		if (connect(fd, srv_addr, srv_len) == 0) {
Packit 857059
			return (fd);
Packit 857059
		}else {
Packit 857059
			if (errno != ETIMEDOUT &&
Packit 857059
			    errno != ECONNREFUSED) {
Packit 857059
				goto exit_func;
Packit 857059
			}
Packit 857059
		}
Packit 857059
Packit 857059
		sleep(MAXWAIT - wait);
Packit 857059
	}
Packit 857059
exit_func:
Packit 857059
	close(fd);
Packit 857059
	return (-1);
Packit 857059
Packit 857059
}
Packit 857059
Packit 857059
/**
Packit 857059
 * @brief
Packit 857059
 * cs_tcp_comm_connect --
Packit 857059
 *
Packit 857059
 * This function initiates a tcp connect stream connection.
Packit 857059
 * Used for demo purposes at this point.
Packit 857059
 *
Packit 857059
 * @param[in]  srv_addr     sockaddr structure of server
Packit 857059
 * @param[in]  srv_len      len of server sockaddr
Packit 857059
 *
Packit 857059
 * @return   socket fd is successful, -1 if not
Packit 857059
 */
Packit 857059
int
Packit 857059
cs_tcp_comm_connect(const struct sockaddr *srv_addr, socklen_t srv_len)
Packit 857059
{
Packit 857059
	return (cs_comm_connect(AF_INET, SOCK_STREAM, 0, srv_addr, srv_len));
Packit 857059
}
Packit 857059
Packit 857059
/**
Packit 857059
 * @brief
Packit 857059
 * cs_udp_comm_connect --
Packit 857059
 *
Packit 857059
 * This function initiates a udp connect stream connection.
Packit 857059
 * Used for demo purposes at this point.
Packit 857059
 *
Packit 857059
 * @param[in]  srv_addr     sockaddr structure of server
Packit 857059
 * @param[in]  srv_len      len of server sockaddr
Packit 857059
 *
Packit 857059
 * @return   socket fd is successful, -1 if not
Packit 857059
 */
Packit 857059
int
Packit 857059
cs_udp_comm_connect(const struct sockaddr *srv_addr, socklen_t srv_len)
Packit 857059
{
Packit 857059
	return (cs_comm_connect(AF_INET, SOCK_DGRAM, 0, srv_addr, srv_len));
Packit 857059
}
Packit 857059
Packit 857059
/**
Packit 857059
 * @brief
Packit 857059
 *
Packit 857059
 * cs_set_fd_non_block --
Packit 857059
 *
Packit 857059
 * This function sets the fd passed in to non-blocking.
Packit 857059
 *
Packit 857059
 * @params[in]  fd  file descriptor
Packit 857059
 *
Packit 857059
 * @return	1 on success, (-1) on failure
Packit 857059
 *
Packit 857059
 */
Packit 857059
int
Packit 857059
cs_set_fd_non_block(int fd)
Packit 857059
{
Packit 857059
	/* TBD on vxworks */
Packit 857059
#ifdef __LINUX__
Packit 857059
	int options;
Packit 857059
Packit 857059
	if ((options = fcntl(fd, F_GETFL)) < 0) {
Packit 857059
		IB_LOG_ERROR_FMT(__func__, "fcntl get Error %s\n",
Packit 857059
						strerror(errno));
Packit 857059
		return (-1);
Packit 857059
	}
Packit 857059
Packit 857059
	options |= O_NONBLOCK;
Packit 857059
Packit 857059
	if (fcntl(fd, F_SETFL, options) < 0) {
Packit 857059
		IB_LOG_ERROR_FMT(__func__, "fcntl set Error %s\n",
Packit 857059
						strerror(errno));
Packit 857059
		return (-1);
Packit 857059
	}
Packit 857059
#endif
Packit 857059
Packit 857059
	return (1);
Packit 857059
}
Packit 857059
Packit 857059