| /*****************************************************************************\ |
| * slurm_protocol_socket_implementation.c - slurm communications interfaces |
| * based upon sockets. |
| * $Id$ |
| ***************************************************************************** |
| * 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 |
| */ |