Logo Search packages:      
Sourcecode: slurm-llnl version File versions  Download package

slurm_protocol_socket_implementation.c

/*****************************************************************************\
 *  slurm_protocol_socket_implementation.c - slurm communications interfaces 
 *                                           based upon sockets.
 *  $Id: slurm_protocol_socket_implementation.c 12005 2007-08-14 17:20:11Z jette $
 *****************************************************************************
 *  Copyright (C) 2002-2006 The Regents of the University of California.
 *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
 *  Written by Kevin Tew <tew1@llnl.gov>, et. al.
 *  UCRL-CODE-226842.
 *  
 *  This file is part of SLURM, a resource management program.
 *  For details, see <http://www.llnl.gov/linux/slurm/>.
 *  
 *  SLURM is free software; you can redistribute it and/or modify it under
 *  the terms of the GNU General Public License as published by the Free
 *  Software Foundation; either version 2 of the License, or (at your option)
 *  any later version.
 *
 *  In addition, as a special exception, the copyright holders give permission 
 *  to link the code of portions of this program with the OpenSSL library under 
 *  certain conditions as described in each individual source file, and 
 *  distribute linked combinations including the two. You must obey the GNU 
 *  General Public License in all respects for all of the code used other than 
 *  OpenSSL. If you modify file(s) with this exception, you may extend this 
 *  exception to your version of the file(s), but you are not obligated to do 
 *  so. If you do not wish to do so, delete this exception statement from your
 *  version.  If you delete this exception statement from all source files in 
 *  the program, then also delete it here.
 *  
 *  SLURM is distributed in the hope that it will be useful, but WITHOUT ANY
 *  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 *  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 *  details.
 *  
 *  You should have received a copy of the GNU General Public License along
 *  with SLURM; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA.
\*****************************************************************************/

#if HAVE_CONFIG_H
#  include "config.h"
#endif

#define _USE_IRS 1      /* Required for AIX and hstrerror() */

#include <unistd.h>
#include <string.h>
#include <netdb.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/poll.h>
#include <sys/time.h>
#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <sys/param.h>
#include <slurm/slurm_errno.h>
#include <stdlib.h>

#if HAVE_SYS_SOCKET_H
#  include <sys/socket.h>
#else
#  if HAVE_SOCKET_H
#    include <socket.h>
#  endif
#endif

#include "src/common/slurm_protocol_api.h"
#include "src/common/slurm_protocol_interface.h"
#include "src/common/slurm_protocol_defs.h"
#include "src/common/log.h"
#include "src/common/fd.h"
#include "src/common/xsignal.h"
#include "src/common/xmalloc.h"
#include "src/common/util-net.h"

#define PORT_RETRIES    2
#define MIN_USER_PORT   (IPPORT_RESERVED + 1)
#define MAX_USER_PORT   0xffff
#define RANDOM_USER_PORT ((uint16_t) ((lrand48() % \
                (MAX_USER_PORT - MIN_USER_PORT + 1)) + MIN_USER_PORT))

/*
 *  Maximum message size. Messages larger than this value (in bytes)
 *  will not be received.
 */
#define MAX_MSG_SIZE     (16*1024*1024)

/****************************************************************
 * MIDDLE LAYER MSG FUNCTIONS
 ****************************************************************/

/* 
 * Return time in msec since "start time"
 */
static int _tot_wait (struct timeval *start_time)
{
        struct timeval end_time;
        int msec_delay;

        gettimeofday(&end_time, NULL);
        msec_delay =   (end_time.tv_sec  - start_time->tv_sec ) * 1000;
        msec_delay += ((end_time.tv_usec - start_time->tv_usec + 500) / 1000);
        return msec_delay;
}

slurm_fd _slurm_init_msg_engine ( slurm_addr * slurm_address )
{
        return _slurm_listen_stream ( slurm_address ) ;
}

slurm_fd _slurm_open_msg_conn ( slurm_addr * slurm_address )
{
        return _slurm_open_stream ( slurm_address, false ) ;
}

slurm_fd _slurm_accept_msg_conn (slurm_fd fd, slurm_addr *addr)
{
        return _slurm_accept_stream(fd, addr);
} 

/*
 * Pick a random port number to use. Use this if the system 
 * selected port can't connect. This may indicate that the 
 * port/address of both the client and server match a defunct 
 * socket record in TIME_WAIT state.
 */
static void _sock_bind_wild(int sockfd)
{
        int rc, retry;
        slurm_addr sin;
        static bool seeded = false;

        if (!seeded) {
                seeded = true;
                srand48((long int) (time(NULL) + getpid()));
        }

        memset(&sin, 0, sizeof(sin));
        sin.sin_family = AF_INET;
        sin.sin_addr.s_addr = htonl(INADDR_ANY);
        sin.sin_port = htons(RANDOM_USER_PORT);

        for (retry=0; retry < PORT_RETRIES ; retry++) {
                rc = bind(sockfd, (struct sockaddr *) &sin, sizeof(sin));
                if (rc >= 0)
                        break;
                sin.sin_port  = htons(RANDOM_USER_PORT);
        }
        return;
}
       
/* 
 * This would be a no-op in a message implementation
 */
int _slurm_close_accepted_conn (slurm_fd fd) 
{
        return _slurm_close (fd);
}

ssize_t _slurm_msg_recvfrom(slurm_fd fd, char **pbuf, size_t *lenp, 
                            uint32_t flags)
{
        return _slurm_msg_recvfrom_timeout(fd, pbuf, lenp, flags, 
                                (slurm_get_msg_timeout() * 1000));
}

ssize_t _slurm_msg_recvfrom_timeout(slurm_fd fd, char **pbuf, size_t *lenp, 
                                    uint32_t flags, int tmout)
{
        ssize_t  len;
        uint32_t msglen;

        len = _slurm_recv_timeout( fd, (char *)&msglen, 
                                   sizeof(msglen), 0, tmout );

        if (len < ((ssize_t) sizeof(msglen))) 
                return SLURM_ERROR;

        msglen = ntohl(msglen);
      
        if (msglen > MAX_MSG_SIZE) 
                slurm_seterrno_ret(SLURM_PROTOCOL_INSANE_MSG_LENGTH);

        /*
         *  Allocate memory on heap for message
         */
        *pbuf = xmalloc(msglen);

        if (_slurm_recv_timeout(fd, *pbuf, msglen, 0, tmout) != msglen) {
                xfree(*pbuf);
                *pbuf = NULL;
                return SLURM_ERROR;
        }

        *lenp = msglen;
        
        return (ssize_t) msglen;
}

ssize_t _slurm_msg_sendto(slurm_fd fd, char *buffer, size_t size, 
                          uint32_t flags)
{
        return _slurm_msg_sendto_timeout( fd, buffer, size, flags, 
                                (slurm_get_msg_timeout() * 1000));
}

ssize_t _slurm_msg_sendto_timeout(slurm_fd fd, char *buffer, size_t size, 
                                  uint32_t flags, int timeout)
{
        int   len;
        uint32_t usize;
        SigFunc *ohandler;

        /* 
         *  Ignore SIGPIPE so that send can return a error code if the 
         *    other side closes the socket 
         */
        ohandler = xsignal(SIGPIPE, SIG_IGN);

        usize = htonl(size);

      if ((len = _slurm_send_timeout( 
                        fd, (char *)&usize, sizeof(usize), 0, 
                        timeout)) < 0)
            goto done;

      if ((len = _slurm_send_timeout(fd, buffer, size, 0, timeout)) < 0)
            goto done;


     done:
        xsignal(SIGPIPE, ohandler);
        return len;
}

/* Send slurm message with timeout
 * RET message size (as specified in argument) or SLURM_ERROR on error */
int _slurm_send_timeout(slurm_fd fd, char *buf, size_t size, 
                        uint32_t flags, int timeout)
{
        int rc;
        int sent = 0;
        int fd_flags;
        struct pollfd ufds;
        struct timeval tstart;
        int timeleft = timeout;
      char temp[2];
        ufds.fd     = fd;
        ufds.events = POLLOUT;

        fd_flags = _slurm_fcntl(fd, F_GETFL);
        fd_set_nonblocking(fd);

        gettimeofday(&tstart, NULL);

        while (sent < size) {

                timeleft = timeout - _tot_wait(&tstart);
                if (timeleft <= 0) {
                  debug("_slurm_send_timeout at %d of %d, timeout",
                        sent, size);
                  slurm_seterrno(SLURM_PROTOCOL_SOCKET_IMPL_TIMEOUT);
                  sent = SLURM_ERROR;
                  goto done;
                }
                if ((rc = poll(&ufds, 1, timeleft)) <= 0) {
                  if ((rc == 0) || (errno == EINTR) || (errno == EAGAIN)) 
                        continue;
                  else {
                        debug("_slurm_send_timeout at %d of %d, "
                              "poll error: %s",
                              sent, size, strerror(errno));
                        slurm_seterrno(SLURM_COMMUNICATIONS_SEND_ERROR);
                        sent = SLURM_ERROR;
                        goto done;
                  }
                }

            /*
             * Check here to make sure the socket really is there.
             * If not then exit out and notify the sender.  This
             * is here since a write doesn't always tell you the
             * socket is gone, but getting 0 back from a
             * nonblocking read means just that. 
             */
            rc = _slurm_recv(fd, &temp, 1, flags);
            if (rc == 0) {
                  debug2("_slurm_send_timeout: Socket no longer there.");
                  slurm_seterrno(ENOTCONN);
                  sent = SLURM_ERROR;
                  goto done;              
            }

                rc = _slurm_send(fd, &buf[sent], (size - sent), flags);
                if (rc < 0) {
                  if (errno == EINTR)
                        continue;
                  else {
                        debug("_slurm_send_timeout at %d of %d, "
                              "send error: %s",
                              sent, size, strerror(errno));
                        slurm_seterrno(SLURM_COMMUNICATIONS_SEND_ERROR);
                        sent = SLURM_ERROR;
                        goto done;
                  }
                }
                if (rc == 0) {
                  debug("_slurm_send_timeout at %d of %d, "
                        "sent zero bytes", sent, size);
                        slurm_seterrno(SLURM_PROTOCOL_SOCKET_ZERO_BYTES_SENT);
                        sent = SLURM_ERROR;
                        goto done;
                }

                sent += rc;
        }

    done:
      /* Reset fd flags to prior state, preserve errno */
      if (fd_flags != SLURM_PROTOCOL_ERROR) {
            int slurm_err = slurm_get_errno();
            _slurm_fcntl(fd , F_SETFL , fd_flags);
            slurm_seterrno(slurm_err);
      }

        return sent;
        
}

/* Get slurm message with timeout
 * RET message size (as specified in argument) or SLURM_ERROR on error */
int _slurm_recv_timeout(slurm_fd fd, char *buffer, size_t size, 
                        uint32_t flags, int timeout )
{
        int rc;
        int recvlen = 0;
        int fd_flags;
        struct pollfd  ufds;
        struct timeval tstart;
      int timeleft = timeout;

        ufds.fd     = fd;
        ufds.events = POLLIN;

        fd_flags = _slurm_fcntl(fd, F_GETFL);
        fd_set_nonblocking(fd);

        gettimeofday(&tstart, NULL);

        while (recvlen < size) {

                timeleft = timeout - _tot_wait(&tstart);
                if (timeleft <= 0) {
                  debug("_slurm_recv_timeout at %d of %d, timeout",
                        recvlen, size);
                        slurm_seterrno(SLURM_PROTOCOL_SOCKET_IMPL_TIMEOUT);
                        recvlen = SLURM_ERROR;
                        goto done;
                }

                if ((rc = poll(&ufds, 1, timeleft)) <= 0) {
                        if ((errno == EINTR) || (errno == EAGAIN) || (rc == 0))
                                continue;
                        else {
                        debug("_slurm_recv_timeout at %d of %d, "
                              "poll error: %s",
                              recvlen, size, strerror(errno));
                        slurm_seterrno(
                              SLURM_COMMUNICATIONS_RECEIVE_ERROR);
                        recvlen = SLURM_ERROR; 
                        goto done;
                        }
                } 
                rc = _slurm_recv(fd, &buffer[recvlen], (size - recvlen), flags);
                if (rc < 0)  {
                        if (errno == EINTR)
                                continue;
                        else {
                        debug("_slurm_recv_timeout at %d of %d, "
                              "recv error: %s",
                              recvlen, size, strerror(errno));
                        slurm_seterrno(
                              SLURM_COMMUNICATIONS_RECEIVE_ERROR);
                        recvlen = SLURM_ERROR; 
                        goto done;
                        }
                }
                if (rc == 0) {
                  debug("_slurm_recv_timeout at %d of %d, "
                        "recv zero bytes", recvlen, size);
                  slurm_seterrno(SLURM_PROTOCOL_SOCKET_ZERO_BYTES_SENT);
                  recvlen = SLURM_ERROR;
                  goto done;
                }
                recvlen += rc;
        }


    done:
      /* Reset fd flags to prior state, preserve errno */
      if (fd_flags != SLURM_PROTOCOL_ERROR) {
            int slurm_err = slurm_get_errno();
            _slurm_fcntl(fd , F_SETFL , fd_flags);
            slurm_seterrno(slurm_err);
      }

        return recvlen;
}

int _slurm_shutdown_msg_engine ( slurm_fd open_fd )
{
        return _slurm_close ( open_fd ) ;
}

slurm_fd _slurm_listen_stream(slurm_addr *addr)
{
        int rc;
        slurm_fd fd;
        const int one = 1;
        const size_t sz1 = sizeof(one);

        if ((fd = _slurm_create_socket(SLURM_STREAM)) < 0) {
            error("Error creating slurm stream socket: %m");
                return fd;
        }

        rc = _slurm_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sz1);
        if (rc < 0) {
            error("setsockopt SO_REUSEADDR failed: %m");
                goto error; 
        }

        rc = _slurm_bind(fd, (struct sockaddr const *) addr, sizeof(*addr));
        if (rc < 0) {
            error("Error binding slurm stream socket: %m");
                goto error; 
        }

        if (_slurm_listen(fd, SLURM_PROTOCOL_DEFAULT_LISTEN_BACKLOG) < 0) {
            error( "Error listening on slurm stream socket: %m" ) ;
                rc = SLURM_ERROR;
                goto error; 
        }
        
        return fd;

    error:
      if ((_slurm_close_stream(fd) < 0) && (errno == EINTR))
            _slurm_close_stream(fd);      /* try again */
        return rc;
        
}

slurm_fd _slurm_accept_stream(slurm_fd fd, slurm_addr *addr)
{
        socklen_t len = sizeof(slurm_addr);
        return _slurm_accept(fd, (struct sockaddr *)addr, &len);
}

slurm_fd _slurm_open_stream(slurm_addr *addr, bool retry)
{
        int retry_cnt;
        slurm_fd fd;

        if ( (addr->sin_family == 0) || (addr->sin_port  == 0) ) 
                return SLURM_SOCKET_ERROR;

        for (retry_cnt=0; ; retry_cnt++) {
                int rc;
                if ((fd =_slurm_create_socket(SLURM_STREAM)) < 0) {
                  error("Error creating slurm stream socket: %m");
                        slurm_seterrno(errno);
                        return SLURM_SOCKET_ERROR;
                }

                if (retry_cnt) {
                        if (retry_cnt == 1)
                                debug3("Error connecting, picking new stream port");
                        _sock_bind_wild(fd);
                }

                rc = _slurm_connect(fd, (struct sockaddr const *)addr, sizeof(*addr));
                if (rc >= 0)                    /* success */
                        break;
                if ((errno != ECONNREFUSED) || 
                    (!retry) || (retry_cnt >= PORT_RETRIES)) {
                        slurm_seterrno(errno);
                        goto error;
                }

                if ((_slurm_close_stream(fd) < 0) && (errno == EINTR))
                        _slurm_close_stream(fd);        /* try again */
      }

        return fd;

    error:
        debug2("Error connecting slurm stream socket: %m");
      if ((_slurm_close_stream(fd) < 0) && (errno == EINTR))
            _slurm_close_stream(fd);      /* try again */
        return SLURM_SOCKET_ERROR;
}

int _slurm_get_stream_addr(slurm_fd fd, slurm_addr *addr )
{
        socklen_t size = sizeof(addr);
        return _slurm_getsockname(fd, (struct sockaddr *)addr, &size);
}

int _slurm_close_stream ( slurm_fd open_fd )
{
        return _slurm_close ( open_fd ) ;
}


int _slurm_set_stream_non_blocking(slurm_fd fd)
{
        fd_set_nonblocking(fd);
        return SLURM_SUCCESS;
}

int _slurm_set_stream_blocking(slurm_fd fd) 
{
        fd_set_blocking(fd);
        return SLURM_SUCCESS;
}

extern int _slurm_socket (int __domain, int __type, int __protocol)
{
        return socket ( __domain, __type, __protocol ) ;
}        

extern slurm_fd _slurm_create_socket ( slurm_socket_type_t type )
{
        switch ( type )
        {
                case SLURM_STREAM :
                        return _slurm_socket ( AF_INET, SOCK_STREAM, 
                                                IPPROTO_TCP) ;
                        break;
                case SLURM_MESSAGE :
                        return _slurm_socket ( AF_INET, SOCK_DGRAM, 
                                                IPPROTO_UDP ) ;
                        break;
                default :
                        return SLURM_SOCKET_ERROR;
        }
}

/* Create two new sockets, of type TYPE in domain DOMAIN and using
 * protocol PROTOCOL, which are connected to each other, and put file
 * descriptors for them in FDS[0] and FDS[1].  If PROTOCOL is zero,
 * one will be chosen automatically.  Returns 0 on success, -1 for errors.  */
extern int _slurm_socketpair (int __domain, int __type, 
                                int __protocol, int __fds[2])
{
        return SLURM_PROTOCOL_FUNCTION_NOT_IMPLEMENTED ;
}

/* Give the socket FD the local address ADDR (which is LEN bytes long).  */
extern int _slurm_bind (int __fd, struct sockaddr const * __addr, 
                                socklen_t __len)
{
        return bind ( __fd , __addr , __len ) ;
}

/* Put the local address of FD into *ADDR and its length in *LEN.  */
extern int _slurm_getsockname (int __fd, struct sockaddr * __addr, 
                                socklen_t *__restrict __len)
{
        return getsockname ( __fd , __addr , __len ) ;        
}

/* Open a connection on socket FD to peer at ADDR (which LEN bytes long).
 * For connectionless socket types, just set the default address to send to
 * and the only address from which to accept transmissions.
 * Return 0 on success, -1 for errors.  */
extern int _slurm_connect (int __fd, struct sockaddr const * __addr, 
                                socklen_t __len)
{
#if 0
      return connect ( __fd , __addr , __len ) ;
#else
      /* From "man connect": Note that for IP sockets the timeout
       * may be very long when syncookies are enabled on the server.
       *
       * Timeouts in excess of 3 minutes have been observed, resulting
       * in serious problems for slurmctld. Making the connect call 
       * non-blocking and polling seems to fix the problem. */
      int rc, flags, err;
      socklen_t len;
      struct pollfd ufds;

      flags = fcntl(__fd, F_GETFL);
      fcntl(__fd, F_SETFL, flags | O_NONBLOCK);

      err = 0;
      rc = connect(__fd , __addr , __len);
      if (rc < 0 && errno != EINPROGRESS)
            return -1;
      if (rc == 0)
            goto done;  /* connect completed immediately */

      ufds.fd = __fd;
      ufds.events = POLLIN | POLLOUT;
      ufds.revents = 0;

again:      rc = poll(&ufds, 1, 5000);
      if (rc == -1) {
            /* poll failed */
            if (errno == EINTR) {
                  /* NOTE: connect() is non-interruptible in Linux */
                  debug3("_slurm_connect poll failed: %m");
                  goto again;
            } else
                  error("_slurm_connect poll failed: %m");
            return -1;
      } else if (rc == 0) {
            /* poll timed out before any socket events */
            slurm_seterrno(ETIMEDOUT);
            debug2("_slurm_connect poll timeout: %m");
            return -1;
      } else {
            /* poll saw some event on the socket
             * We need to check if the connection succeeded by
             * using getsockopt.  The revent is not necessarily
             * POLLERR when the connection fails! */
            len = sizeof(err);
            if (getsockopt(__fd, SOL_SOCKET, SO_ERROR,
                         &err, &len) < 0)
                  return -1; /* solaris pending error */
      }

done:
      fcntl(__fd, F_SETFL, flags);

      /* NOTE: Connection refused is typically reported for
       * non-responsived nodes plus attempts to communicate
       * with terminated srun commands. */
      if (err) {
            slurm_seterrno(err);
            debug2("_slurm_connect failed: %m");
            slurm_seterrno(err);
            return -1;
      }

      return 0;
#endif
}

/* Put the address of the peer connected to socket FD into *ADDR
 * (which is *LEN bytes long), and its actual length into *LEN.  */
extern int _slurm_getpeername (int __fd, struct sockaddr * __addr, 
                                socklen_t *__restrict __len)
{
        return getpeername ( __fd , __addr , __len ) ;
}

/* Send N bytes of BUF to socket FD.  Returns the number sent or -1.  */
extern ssize_t _slurm_send (int __fd, __const void *__buf, size_t __n, 
                                int __flags)
{
        return send ( __fd , __buf , __n , __flags ) ;
}

/* Read N bytes into BUF from socket FD.
 * Returns the number read or -1 for errors.  */
extern ssize_t _slurm_recv (int __fd, void *__buf, size_t __n, int __flags)
{
        return recv ( __fd , __buf , __n , __flags ) ;
}

/* Send N bytes of BUF on socket FD to peer at address ADDR (which is
 * ADDR_LEN bytes long).  Returns the number sent, or -1 for errors.  */
extern ssize_t _slurm_sendto (int __fd, __const void *__buf, size_t __n, int __flags, struct sockaddr const * __addr, 
                                socklen_t __addr_len)
{
        return sendto ( __fd , __buf , __n , __flags , __addr, __addr_len) ;
}
/* Read N bytes into BUF through socket FD.
 * If ADDR is not NULL, fill in *ADDR_LEN bytes of it with tha address of
 * the sender, and store the actual size of the address in *ADDR_LEN.
 * Returns the number of bytes read or -1 for errors.  */
extern ssize_t _slurm_recvfrom (int __fd, void *__restrict __buf, 
                                size_t __n, int __flags, 
                                struct sockaddr * __addr, 
                                socklen_t *__restrict __addr_len)
{
        return recvfrom ( __fd , __buf , __n , __flags , __addr, __addr_len) ;
}

/* Send a msg described MESSAGE on socket FD.
 * Returns the number of bytes sent, or -1 for errors.  */
extern ssize_t _slurm_sendmsg (int __fd, __const struct msghdr *__msg, 
                                int __flags)
{
        return sendmsg ( __fd , __msg , __flags ) ;
}

/* Send a msg described MESSAGE on socket FD.
 * Returns the number of bytes read or -1 for errors.  */
extern ssize_t _slurm_recvmsg (int __fd, struct msghdr *__msg, int __flags)
{
        return recvmsg ( __fd , __msg , __flags );
}

/* Put the current value for socket FD's option OPTNAME at protocol level LEVEL
 * into OPTVAL (which is *OPTLEN bytes long), and set *OPTLEN to the value's
 * actual length.  Returns 0 on success, -1 for errors.  */
extern int _slurm_getsockopt (int __fd, int __level, int __optname, 
                                void *__restrict __optval, 
                                socklen_t *__restrict __optlen)
{
        return getsockopt ( __fd , __level , __optname , __optval , __optlen ) ;
}

/* Set socket FD's option OPTNAME at protocol level LEVEL
 * to *OPTVAL (which is OPTLEN bytes long).
 * Returns 0 on success, -1 for errors.  */
extern int _slurm_setsockopt (int __fd, int __level, int __optname, 
                                __const void *__optval, socklen_t __optlen)
{
        return setsockopt ( __fd , __level , __optname , __optval , __optlen ) ;
}


/* Prepare to accept connections on socket FD.
 * N connection requests will be queued before further requests are refused.
 * Returns 0 on success, -1 for errors.  */
extern int _slurm_listen (int __fd, int __n)
{
        return listen ( __fd , __n ) ;
}

/* Await a connection on socket FD.
 * When a connection arrives, open a new socket to communicate with it,
 * set *ADDR (which is *ADDR_LEN bytes long) to the address of the connecting
 * peer and *ADDR_LEN to the address's actual length, and return the
 * new socket's descriptor, or -1 for errors.  */
extern int _slurm_accept (int __fd, struct sockaddr * __addr, 
                                socklen_t *__restrict __addr_len)
{
        return accept ( __fd , __addr , __addr_len ) ;
}

/* Shut down all or part of the connection open on socket FD.
 * HOW determines what to shut down:
 * SHUT_RD   = No more receptions;
 * SHUT_WR   = No more transmissions;
 * SHUT_RDWR = No more receptions or transmissions.
 * Returns 0 on success, -1 for errors.  */
extern int _slurm_shutdown (int __fd, int __how)
{
        return shutdown ( __fd , __how );
}

extern int _slurm_close (int __fd )
{
        return close ( __fd ) ;
}

extern int _slurm_fcntl(int fd, int cmd, ... )
{
        int rc ;
        va_list va ;

        va_start ( va , cmd ) ;
        rc =_slurm_vfcntl ( fd , cmd , va ) ;
        va_end ( va ) ;
        return rc ;
}

extern int _slurm_vfcntl(int fd, int cmd, va_list va )
{
        long arg ;

        switch ( cmd )
        {
                case F_GETFL :
                        return fcntl ( fd , cmd ) ;
                        break ;
                case F_SETFL :
                        arg = va_arg ( va , long ) ;
                        return fcntl ( fd , cmd , arg) ;
                        break ;
                default :
                        return SLURM_PROTOCOL_ERROR ;
                        break ;
        }
}

/* sets the fields of a slurm_addr */
void _slurm_set_addr_uint (slurm_addr *addr, uint16_t port, uint32_t ipaddr)
{
        addr->sin_family      = AF_SLURM ;
        addr->sin_port        = htons(port);
        addr->sin_addr.s_addr = htonl(ipaddr);
}

/* resets the address field of a slurm_addr, port and family are unchanged */
void _reset_slurm_addr (slurm_addr *addr, slurm_addr new_addr)
{
        addr->sin_addr.s_addr = new_addr.sin_addr.s_addr;
}

void _slurm_set_addr_char (slurm_addr * addr, uint16_t port, char *host)
{
        struct hostent * he    = NULL;
        int              h_err = 0;
        char *           h_buf[4096];

        /* 
         * If NULL hostname passed in, we only update the port
         *   of addr
         */
        addr->sin_family = AF_SLURM;
        addr->sin_port   = htons(port);
        if (host == NULL)
                return;

        he = get_host_by_name(host, (void *)&h_buf, sizeof(h_buf), &h_err);

        if (he != NULL)
                memcpy (&addr->sin_addr.s_addr, he->h_addr, he->h_length);
        else {
                error("Unable to resolve \"%s\": %s", host, hstrerror(h_err));
                addr->sin_family = 0;
                addr->sin_port = 0;
        } 
        return;
}

void _slurm_get_addr (slurm_addr *addr, uint16_t *port, char *host, 
                      unsigned int buflen )
{
        struct hostent *he;
        char   h_buf[4096];
        int    h_err  = 0;
        char * s_addr = (char *) &addr->sin_addr.s_addr;
        int    len    = sizeof(addr->sin_addr.s_addr);

        he = get_host_by_addr( s_addr, len, AF_SLURM, 
                               (void *) &h_buf, sizeof(h_buf), &h_err );

        if (he != NULL) {
                *port = ntohs(addr->sin_port);
                strncpy(host, he->h_name, buflen);
        } else {
                error("Lookup failed: %s", host_strerror(h_err));
                *port = 0;
                strncpy(host, "", buflen);
        } 
        return;
}

void _slurm_print_slurm_addr ( slurm_addr * address, char *buf, size_t n )
{
        char addrbuf[INET_ADDRSTRLEN];
        inet_ntop(AF_INET, &address->sin_addr, addrbuf, INET_ADDRSTRLEN);
        /* warning: silently truncates */
        snprintf(buf, n, "%s:%d", addrbuf, ntohs(address->sin_port));
}
        
void _slurm_pack_slurm_addr(slurm_addr *addr, Buf buffer)
{
        pack32( ntohl( addr->sin_addr.s_addr ), buffer );
        pack16( ntohs( addr->sin_port ), buffer );
}

int _slurm_unpack_slurm_addr_no_alloc(slurm_addr *addr, Buf buffer)
{
        addr->sin_family = AF_SLURM ;
        safe_unpack32(&addr->sin_addr.s_addr, buffer);
        safe_unpack16(&addr->sin_port, buffer);

        addr->sin_addr.s_addr = htonl(addr->sin_addr.s_addr);
        addr->sin_port = htons(addr->sin_port);
        return SLURM_SUCCESS;

    unpack_error:
        return SLURM_ERROR;
}

/*
 * vi: tabstop=8 shiftwidth=8 expandtab
 */

Generated by  Doxygen 1.6.0   Back to index