/* * 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 * 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; }