504 lines
11 KiB
C
504 lines
11 KiB
C
/*
|
|
* Socket wrapper functions.
|
|
* These could all go into separate files, so only the ones needed cause
|
|
* the corresponding function to be added to the executable. If sockets
|
|
* are a library (SVR4) this might make a difference (?), but if sockets
|
|
* are in the kernel (BSD) it doesn't matter.
|
|
*
|
|
* These wrapper functions also use the same prototypes as POSIX.1g,
|
|
* which might differ from many implementations (i.e., POSIX.1g specifies
|
|
* the fourth argument to getsockopt() as "void *", not "char *").
|
|
*
|
|
* If your system's headers are not correct [i.e., the Solaris 2.5
|
|
* <sys/socket.h> omits the "const" from the second argument to both
|
|
* bind() and connect()], you'll get warnings of the form:
|
|
*warning: passing arg 2 of `bind' discards `const' from pointer target type
|
|
*warning: passing arg 2 of `connect' discards `const' from pointer target type
|
|
*/
|
|
|
|
#include "unp.h"
|
|
|
|
int
|
|
Accept(int fd, struct sockaddr *sa, socklen_t *salenptr)
|
|
{
|
|
int n;
|
|
|
|
again:
|
|
if ( (n = accept(fd, sa, salenptr)) < 0) {
|
|
#ifdef EPROTO
|
|
if (errno == EPROTO || errno == ECONNABORTED)
|
|
#else
|
|
if (errno == ECONNABORTED)
|
|
#endif
|
|
goto again;
|
|
else
|
|
err_sys("accept error");
|
|
}
|
|
return(n);
|
|
}
|
|
|
|
void
|
|
Bind(int fd, const struct sockaddr *sa, socklen_t salen)
|
|
{
|
|
if (bind(fd, sa, salen) < 0)
|
|
err_sys("bind error");
|
|
}
|
|
|
|
void
|
|
Connect(int fd, const struct sockaddr *sa, socklen_t salen)
|
|
{
|
|
if (connect(fd, sa, salen) < 0)
|
|
err_sys("connect error");
|
|
}
|
|
|
|
void
|
|
Getpeername(int fd, struct sockaddr *sa, socklen_t *salenptr)
|
|
{
|
|
if (getpeername(fd, sa, salenptr) < 0)
|
|
err_sys("getpeername error");
|
|
}
|
|
|
|
void
|
|
Getsockname(int fd, struct sockaddr *sa, socklen_t *salenptr)
|
|
{
|
|
if (getsockname(fd, sa, salenptr) < 0)
|
|
err_sys("getsockname error");
|
|
}
|
|
|
|
void
|
|
Getsockopt(int fd, int level, int optname, void *optval, socklen_t *optlenptr)
|
|
{
|
|
if (getsockopt(fd, level, optname, optval, optlenptr) < 0)
|
|
err_sys("getsockopt error");
|
|
}
|
|
|
|
#ifdef HAVE_INET6_RTH_INIT
|
|
int
|
|
Inet6_rth_space(int type, int segments)
|
|
{
|
|
int ret;
|
|
|
|
ret = inet6_rth_space(type, segments);
|
|
if (ret < 0)
|
|
err_quit("inet6_rth_space error");
|
|
|
|
return ret;
|
|
}
|
|
|
|
void *
|
|
Inet6_rth_init(void *rthbuf, socklen_t rthlen, int type, int segments)
|
|
{
|
|
void *ret;
|
|
|
|
ret = inet6_rth_init(rthbuf, rthlen, type, segments);
|
|
if (ret == NULL)
|
|
err_quit("inet6_rth_init error");
|
|
|
|
return ret;
|
|
}
|
|
|
|
void
|
|
Inet6_rth_add(void *rthbuf, const struct in6_addr *addr)
|
|
{
|
|
if (inet6_rth_add(rthbuf, addr) < 0)
|
|
err_quit("inet6_rth_add error");
|
|
}
|
|
|
|
void
|
|
Inet6_rth_reverse(const void *in, void *out)
|
|
{
|
|
if (inet6_rth_reverse(in, out) < 0)
|
|
err_quit("inet6_rth_reverse error");
|
|
}
|
|
|
|
int
|
|
Inet6_rth_segments(const void *rthbuf)
|
|
{
|
|
int ret;
|
|
|
|
ret = inet6_rth_segments(rthbuf);
|
|
if (ret < 0)
|
|
err_quit("inet6_rth_segments error");
|
|
|
|
return ret;
|
|
}
|
|
|
|
struct in6_addr *
|
|
Inet6_rth_getaddr(const void *rthbuf, int idx)
|
|
{
|
|
struct in6_addr *ret;
|
|
|
|
ret = inet6_rth_getaddr(rthbuf, idx);
|
|
if (ret == NULL)
|
|
err_quit("inet6_rth_getaddr error");
|
|
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
#ifdef HAVE_KQUEUE
|
|
int
|
|
Kqueue(void)
|
|
{
|
|
int ret;
|
|
|
|
if ((ret = kqueue()) < 0)
|
|
err_sys("kqueue error");
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
Kevent(int kq, const struct kevent *changelist, int nchanges,
|
|
struct kevent *eventlist, int nevents, const struct timespec *timeout)
|
|
{
|
|
int ret;
|
|
|
|
if ((ret = kevent(kq, changelist, nchanges,
|
|
eventlist, nevents, timeout)) < 0)
|
|
err_sys("kevent error");
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
|
|
/* include Listen */
|
|
void
|
|
Listen(int fd, int backlog)
|
|
{
|
|
char *ptr;
|
|
|
|
/*4can override 2nd argument with environment variable */
|
|
if ( (ptr = getenv("LISTENQ")) != NULL)
|
|
backlog = atoi(ptr);
|
|
|
|
if (listen(fd, backlog) < 0)
|
|
err_sys("listen error");
|
|
}
|
|
/* end Listen */
|
|
|
|
#ifdef HAVE_POLL
|
|
int
|
|
Poll(struct pollfd *fdarray, unsigned long nfds, int timeout)
|
|
{
|
|
int n;
|
|
|
|
if ( (n = poll(fdarray, nfds, timeout)) < 0)
|
|
err_sys("poll error");
|
|
|
|
return(n);
|
|
}
|
|
#endif
|
|
|
|
ssize_t
|
|
Recv(int fd, void *ptr, size_t nbytes, int flags)
|
|
{
|
|
ssize_t n;
|
|
|
|
if ( (n = recv(fd, ptr, nbytes, flags)) < 0)
|
|
err_sys("recv error");
|
|
return(n);
|
|
}
|
|
|
|
ssize_t
|
|
Recvfrom(int fd, void *ptr, size_t nbytes, int flags,
|
|
struct sockaddr *sa, socklen_t *salenptr)
|
|
{
|
|
ssize_t n;
|
|
|
|
if ( (n = recvfrom(fd, ptr, nbytes, flags, sa, salenptr)) < 0)
|
|
err_msg("recvfrom error");
|
|
return(n);
|
|
}
|
|
|
|
ssize_t
|
|
Recvmsg(int fd, struct msghdr *msg, int flags)
|
|
{
|
|
ssize_t n;
|
|
|
|
if ( (n = recvmsg(fd, msg, flags)) < 0)
|
|
err_sys("recvmsg error");
|
|
return(n);
|
|
}
|
|
|
|
int
|
|
Select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
|
|
struct timeval *timeout)
|
|
{
|
|
int n;
|
|
|
|
if ( (n = select(nfds, readfds, writefds, exceptfds, timeout)) < 0)
|
|
err_sys("select error");
|
|
return(n); /* can return 0 on timeout */
|
|
}
|
|
|
|
void
|
|
Send(int fd, const void *ptr, size_t nbytes, int flags)
|
|
{
|
|
if (send(fd, ptr, nbytes, flags) != (ssize_t)nbytes)
|
|
err_sys("send error");
|
|
}
|
|
|
|
void
|
|
Sendto(int fd, const void *ptr, size_t nbytes, int flags,
|
|
const struct sockaddr *sa, socklen_t salen)
|
|
{
|
|
if (sendto(fd, ptr, nbytes, flags, sa, salen) != (ssize_t)nbytes)
|
|
err_sys("sendto error");
|
|
}
|
|
|
|
void
|
|
Sendmsg(int fd, const struct msghdr *msg, int flags)
|
|
{
|
|
unsigned int i;
|
|
ssize_t nbytes;
|
|
|
|
nbytes = 0; /* must first figure out what return value should be */
|
|
for (i = 0; i < msg->msg_iovlen; i++)
|
|
nbytes += msg->msg_iov[i].iov_len;
|
|
|
|
if (sendmsg(fd, msg, flags) != nbytes)
|
|
err_sys("sendmsg error");
|
|
}
|
|
|
|
void
|
|
Setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen)
|
|
{
|
|
if (setsockopt(fd, level, optname, optval, optlen) < 0)
|
|
err_sys("setsockopt error");
|
|
}
|
|
|
|
void
|
|
Shutdown(int fd, int how)
|
|
{
|
|
if (shutdown(fd, how) < 0)
|
|
err_sys("shutdown error");
|
|
}
|
|
|
|
int
|
|
Sockatmark(int fd)
|
|
{
|
|
int n;
|
|
|
|
if ( (n = sockatmark(fd)) < 0)
|
|
err_sys("sockatmark error");
|
|
return(n);
|
|
}
|
|
|
|
/* include Socket */
|
|
int
|
|
Socket(int family, int type, int protocol)
|
|
{
|
|
int n;
|
|
|
|
if ( (n = socket(family, type, protocol)) < 0)
|
|
err_sys("socket error");
|
|
return(n);
|
|
}
|
|
/* end Socket */
|
|
|
|
void
|
|
Socketpair(int family, int type, int protocol, int *fd)
|
|
{
|
|
int n;
|
|
|
|
if ( (n = socketpair(family, type, protocol, fd)) < 0)
|
|
err_sys("socketpair error");
|
|
}
|
|
|
|
ssize_t /* Write "n" bytes to a descriptor. */
|
|
writen(int fd, const void *vptr, size_t n)
|
|
{
|
|
size_t nleft;
|
|
ssize_t nwritten;
|
|
const char *ptr;
|
|
|
|
ptr = vptr;
|
|
nleft = n;
|
|
while (nleft > 0) {
|
|
if ( (nwritten = write(fd, ptr, nleft)) <= 0) {
|
|
if (nwritten < 0 && errno == EINTR)
|
|
nwritten = 0; /* and call write() again */
|
|
else
|
|
return(-1); /* error */
|
|
}
|
|
|
|
nleft -= nwritten;
|
|
ptr += nwritten;
|
|
}
|
|
return(n);
|
|
}
|
|
/* end writen */
|
|
|
|
void
|
|
Writen(int fd, void *ptr, size_t nbytes)
|
|
{
|
|
if ( writen(fd, ptr, nbytes) != nbytes)
|
|
err_sys("writen error");
|
|
}
|
|
|
|
ssize_t /* Read "n" bytes from a descriptor. */
|
|
readn(int fd, void *vptr, size_t n)
|
|
{
|
|
size_t nleft;
|
|
ssize_t nread;
|
|
char *ptr;
|
|
|
|
ptr = vptr;
|
|
nleft = n;
|
|
while (nleft > 0) {
|
|
if ( (nread = read(fd, ptr, nleft)) < 0) {
|
|
if (errno == EINTR)
|
|
nread = 0; /* and call read() again */
|
|
else
|
|
return(-1);
|
|
} else if (nread == 0)
|
|
break; /* EOF */
|
|
|
|
nleft -= nread;
|
|
ptr += nread;
|
|
}
|
|
return(n - nleft); /* return >= 0 */
|
|
}
|
|
/* end readn */
|
|
|
|
ssize_t
|
|
Readn(int fd, void *ptr, size_t nbytes)
|
|
{
|
|
ssize_t n;
|
|
|
|
if ( (n = readn(fd, ptr, nbytes)) < 0)
|
|
err_sys("readn error");
|
|
return(n);
|
|
}
|
|
|
|
int
|
|
tcp_connect(const char *host, const char *serv)
|
|
{
|
|
int sockfd, n;
|
|
struct addrinfo hints, *res, *ressave;
|
|
|
|
bzero(&hints, sizeof(struct addrinfo));
|
|
hints.ai_family = AF_UNSPEC;
|
|
hints.ai_socktype = SOCK_STREAM;
|
|
|
|
if ( (n = getaddrinfo(host, serv, &hints, &res)) != 0)
|
|
err_quit("tcp_connect error for %s, %s: %s",
|
|
host, serv, gai_strerror(n));
|
|
ressave = res;
|
|
|
|
do {
|
|
sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
|
|
if (sockfd < 0)
|
|
continue; /* ignore this one */
|
|
|
|
if (connect(sockfd, res->ai_addr, res->ai_addrlen) == 0)
|
|
break; /* success */
|
|
|
|
Close(sockfd); /* ignore this one */
|
|
} while ( (res = res->ai_next) != NULL);
|
|
|
|
if (res == NULL) /* errno set from final connect() */
|
|
err_sys("tcp_connect error for %s, %s", host, serv);
|
|
|
|
freeaddrinfo(ressave);
|
|
|
|
return(sockfd);
|
|
}
|
|
/* end tcp_connect */
|
|
|
|
/*
|
|
* We place the wrapper function here, not in wraplib.c, because some
|
|
* XTI programs need to include wraplib.c, and it also defines
|
|
* a Tcp_connect() function.
|
|
*/
|
|
|
|
int
|
|
Tcp_connect(const char *host, const char *serv)
|
|
{
|
|
return(tcp_connect(host, serv));
|
|
}
|
|
|
|
int ConnectWait(int sockfd, struct sockaddr *saddr, int addrsize, int sec)
|
|
{
|
|
int newSockStat;
|
|
int orgSockStat;
|
|
int res, n;
|
|
fd_set rset, wset;
|
|
struct timeval tval;
|
|
|
|
int error = 0;
|
|
int esize;
|
|
|
|
if ( (newSockStat = fcntl(sockfd, F_GETFL, NULL)) < 0 )
|
|
{
|
|
perror("F_GETFL error");
|
|
return -1;
|
|
}
|
|
|
|
orgSockStat = newSockStat;
|
|
newSockStat |= O_NONBLOCK;
|
|
|
|
// Non blocking 상태로 만든다.
|
|
if(fcntl(sockfd, F_SETFL, newSockStat) < 0)
|
|
{
|
|
perror("F_SETLF error");
|
|
return -1;
|
|
}
|
|
|
|
// 연결을 기다린다.
|
|
// Non blocking 상태이므로 바로 리턴한다.
|
|
if((res = connect(sockfd, saddr, addrsize)) < 0)
|
|
{
|
|
if (errno != EINPROGRESS)
|
|
return -1;
|
|
}
|
|
|
|
fprintf(stderr, "Waiting RES : %d\n", res);
|
|
// 즉시 연결이 성공했을 경우 소켓을 원래 상태로 되돌리고 리턴한다.
|
|
if (res == 0)
|
|
{
|
|
fprintf(stderr, "Waiting Connect Success\n");
|
|
fcntl(sockfd, F_SETFL, orgSockStat);
|
|
return 1;
|
|
}
|
|
|
|
|
|
FD_ZERO(&rset);
|
|
FD_SET(sockfd, &rset);
|
|
wset = rset;
|
|
|
|
|
|
tval.tv_sec = sec;
|
|
tval.tv_usec = 0;
|
|
|
|
if ( (n = select(sockfd, &rset, &wset, NULL, &tval)) == 0)
|
|
{
|
|
// timeout
|
|
errno = ETIMEDOUT;
|
|
return -1;
|
|
}
|
|
|
|
// 읽거나 쓴 데이터가 있는지 검사한다.
|
|
if (FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset) )
|
|
{
|
|
fprintf(stderr, "Read data\n");
|
|
esize = sizeof(int);
|
|
if ((n = getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, (socklen_t *)&esize)) < 0)
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
perror("Socket Not Set");
|
|
return -1;
|
|
}
|
|
|
|
fcntl(sockfd, F_SETFL, orgSockStat);
|
|
if(error)
|
|
{
|
|
errno = error;
|
|
perror("Socket");
|
|
return -1;
|
|
}
|
|
return 1;
|
|
}
|