/*
- * $Id: usockfd.c,v 1.3 2005-05-03 14:55:11 didg Exp $
+ * $Id: usockfd.c,v 1.6 2009-11-05 14:38:07 franklahm Exp $
*
* Copyright (C) Joerg Lenneis 2003
* All Rights Reserved. See COPYING.
#include <atalk/logger.h>
#include "usockfd.h"
+#include <sys/select.h>
int usockfd_create(char *usock_fn, mode_t mode, int backlog)
{
return -1;
}
+#ifdef chmod
+#undef chmod
+#endif
if (chmod(usock_fn, mode) < 0) {
LOG(log_error, logtype_cnid, "error changing permissions for %s: %s",
usock_fn, strerror(errno));
}
/* ---------------
- create a tcp socket (should share dsi stuff)
-*/
-int tsockfd_create(char *host, u_int16_t ipport, int backlog)
+ * create a tcp socket
+ */
+int tsockfd_create(char *host, char *port, int backlog)
{
- int sockfd;
- struct sockaddr_in server;
- struct hostent *hp;
- int port;
-
- hp=gethostbyname(host);
- if (!hp) {
- unsigned long int addr=inet_addr(host);
- if (addr!= (unsigned)-1)
- hp=gethostbyaddr((char*)addr,sizeof(addr),AF_INET);
-
- if (!hp) {
- LOG(log_error, logtype_cnid, "gethostbyaddr %s: %s", host, strerror(errno));
- return -1;
- }
- }
- memcpy((char*)&server.sin_addr,(char*)hp->h_addr,sizeof(server.sin_addr));
+ int sockfd, flag, ret;
+ struct addrinfo hints, *servinfo, *p;
- if ((sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
- LOG(log_error, logtype_cnid, "error in socket call: %s", strerror(errno));
- return -1;
+ /* Prepare hint for getaddrinfo */
+ memset(&hints, 0, sizeof hints);
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+
+ if ((ret = getaddrinfo(host, port, &hints, &servinfo)) != 0) {
+ LOG(log_error, logtype_default, "tsockfd_create: getaddrinfo: %s\n", gai_strerror(ret));
+ return 0;
}
-
- port = htons(ipport);
-
- server.sin_family = AF_INET;
- server.sin_port = port;
+ /* create a socket */
+ /* loop through all the results and bind to the first we can */
+ for (p = servinfo; p != NULL; p = p->ai_next) {
+ if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
+ LOG(log_info, logtype_default, "tsockfd_create: socket: %s", strerror(errno));
+ continue;
+ }
+
+ /*
+ * Set some socket options:
+ * SO_REUSEADDR deals w/ quick close/opens
+ * TCP_NODELAY diables Nagle
+ */
#ifdef SO_REUSEADDR
- port = 1;
- setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &port, sizeof(port));
-#endif /* SO_REUSEADDR */
+ flag = 1;
+ setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag));
+#endif
-#ifdef USE_TCP_NODELAY
+#ifdef USE_TCP_NODELAY
#ifndef SOL_TCP
#define SOL_TCP IPPROTO_TCP
-#endif /* ! SOL_TCP */
- port = 1;
- setsockopt(sockfd, SOL_TCP, TCP_NODELAY, &port, sizeof(port));
+#endif
+ flag = 1;
+ setsockopt(sockfd, SOL_TCP, TCP_NODELAY, &flag, sizeof(flag));
#endif /* USE_TCP_NODELAY */
+
+ if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
+ close(sockfd);
+ LOG(log_info, logtype_default, "tsockfd_create: bind: %s\n", strerror(errno));
+ continue;
+ }
- if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0) {
- LOG(log_error, logtype_cnid, "error binding to socket for %s: %s",
- host, strerror(errno));
- return -1;
+ if (listen(sockfd, backlog) < 0) {
+ close(sockfd);
+ LOG(log_info, logtype_default, "tsockfd_create: listen: %s\n", strerror(errno));
+ continue;
+ }
+
+ /* We got a socket */
+ break;
}
- if (listen(sockfd, backlog) < 0) {
- LOG(log_error, logtype_cnid, "error in listen for %s: %s",
- host, strerror(errno));
+ if (p == NULL) {
+ LOG(log_error, logtype_default, "tsockfd_create: no suitable network config %s:%s", host, port);
+ freeaddrinfo(servinfo);
return -1;
}
+ freeaddrinfo(servinfo);
return sockfd;
}
/* --------------------- */
-int usockfd_check(int sockfd, unsigned long ndelay)
+int usockfd_check(int sockfd, const sigset_t *sigset)
{
int fd;
socklen_t size;
fd_set readfds;
- struct timeval tv;
int ret;
+ struct timeval tv;
FD_ZERO(&readfds);
FD_SET(sockfd, &readfds);
- tv.tv_usec = ndelay % 1000000;
- tv.tv_sec = ndelay / 1000000;
- if ((ret = select(sockfd + 1, &readfds, NULL, NULL, &tv)) < 0) {
+ if ((ret = pselect(sockfd + 1, &readfds, NULL, NULL, NULL, sigset)) < 0) {
if (errno == EINTR)
return 0;
LOG(log_error, logtype_cnid, "error in select: %s",
strerror(errno));
return -1;
}
+ tv.tv_sec = 5;
+ tv.tv_usec = 0;
+ if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
+ LOG(log_error, logtype_cnid, "set SO_RCVTIMEO: %s", strerror(errno));
+ close(fd);
+ return -1;
+ }
return fd;
} else
return 0;