/* netio/fget_netio_handle.c. Generated from netio_handle.c.in by configure. */
/*
** Copyright 1998-2004 University of Illinois Board of Trustees
** Copyright 1998-2004 Mark D. Roth
** All rights reserved.
**
** fget_netio_handle.c - code to initialize a NETIO handle
**
** Mark D. Roth <roth@feep.net>
*/
#include <fget_netio_internal.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include <fcntl.h>
#ifdef STDC_HEADERS
# include <stdlib.h>
# include <string.h>
# include <stdarg.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
const int netio_is_thread_safe =
#if defined(HAVE_GETHOSTBYNAME_R) && defined(HAVE_GETSERVBYNAME_R)
1;
#else
0;
#endif
int
fget_netio_service_port(char *service)
{
struct servent *sp;
#ifdef HAVE_GETSERVBYNAME_R
struct servent sent;
char buf[10240];
#endif
#ifdef HAVE_GETSERVBYNAME_R
if (getservbyname_r(service, "tcp", &sent, buf, sizeof(buf), &sp) == 0
&& sp != NULL)
#else /* ! HAVE_GETSERVBYNAME_R */
if ((sp = getservbyname(service, "tcp")) != NULL)
#endif /* HAVE_GETSERVBYNAME_R */
return sp->s_port;
return -1;
}
/*
** netio_new() - open a connection to hostname
*/
int
fget_netio_vnew(NETIO **niop, size_t size, char *hostname,
time_t timeout, unsigned short flags, va_list args)
{
struct sockaddr_in addr;
socklen_t addrlen = sizeof(addr);
int i, host_idx, sock_flags;
char *cp;
struct hostent *hp;
#ifdef HAVE_GETHOSTBYNAME_R
struct hostent hent;
int h_errno_r;
char buf[10240];
#endif
#ifdef DEBUG
printf("==> fget_netio_new(niop=0x%lx, size=%lu, "
"timeout=%lu, hostname=\"%s\", flags=%hu, ...)\n",
niop, (unsigned long)size, (unsigned long)timeout,
hostname, flags);
#endif
/*
** allocate and initialize new NETIO handle
*/
*niop = (NETIO *)calloc(1, sizeof(NETIO));
if (*niop == NULL)
return -1;
/* initialize socket to -1 */
(*niop)->n_fd = -1;
/* initialize buffer */
(*niop)->n_buf = (char *)calloc(1, size);
if ((*niop)->n_buf == NULL)
goto connect_error;
(*niop)->n_writep = (*niop)->n_buf;
(*niop)->n_bufsize = size;
/* save the host we're trying to connect to */
strlcpy((*niop)->n_host, hostname, sizeof((*niop)->n_host));
/* initialize options */
fget_netio_init_options(*niop);
fget_netio_vset_options(*niop, args);
/*
** initialize address structure
*/
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
/*
** determine port to connect to
*/
if ((cp = strchr(hostname, ':')) != NULL)
{
/*
** caller supplied explicit port number or service name
*/
*cp++ = '\0';
if (strspn(cp, "0123456789") == strlen(cp))
{
/* all numeric - it's a literal port number */
addr.sin_port = htons(atoi(cp));
}
else
{
/* non-numeric - it's a service name */
i = fget_netio_service_port(cp);
if (i == -1)
{
errno = EINVAL;
goto connect_error;
}
addr.sin_port = i;
}
}
else
{
/*
** no explicit port specified
** fall back to application defaults
*/
/* first, try default service name */
if ((*niop)->n_default_service != NULL)
{
i = fget_netio_service_port((*niop)->n_default_service);
if (i != -1)
addr.sin_port = i;
}
/* if that didn't work, try default port */
if (addr.sin_port == 0
&& (*niop)->n_default_port != 0)
{
addr.sin_port = htons((*niop)->n_default_port);
}
}
/*
** look up hostname
*/
#ifdef HAVE_GETHOSTBYNAME_R
if (gethostbyname_r(hostname, &hent, buf, sizeof(buf),
&hp, &h_errno_r) != 0
|| hp == NULL)
#else /* ! HAVE_GETHOSTBYNAME_R */
hp = gethostbyname(hostname);
if (hp == NULL)
#endif /* HAVE_GETHOSTBYNAME_R */
{
errno = EINVAL;
goto connect_error;
}
for (host_idx = 0; hp->h_addr_list[host_idx] != NULL; host_idx++)
{
memcpy(&(addr.sin_addr.s_addr), hp->h_addr_list[host_idx],
hp->h_length);
(*niop)->n_fd = socket(AF_INET, SOCK_STREAM, 0);
if ((*niop)->n_fd == -1)
{
#ifdef DEBUG
fprintf(stderr, "niop_connect(): socket(): %s\n",
strerror(errno));
#endif
goto connect_error;
}
/*
** make socket non-blocking so that the
** connect() timeout will work below
*/
sock_flags = fcntl((*niop)->n_fd, F_GETFL);
if (sock_flags == -1)
goto connect_error;
BIT_SET(sock_flags, O_NONBLOCK);
if (fcntl((*niop)->n_fd, F_SETFL, sock_flags) == -1)
goto connect_error;
if (connect((*niop)->n_fd, (struct sockaddr *)&addr,
addrlen) == -1)
{
#ifdef DEBUG
fprintf(stderr, "niop_connect(): connect(): %s\n",
strerror(errno));
#endif
if (errno == EINPROGRESS)
{
i = fget_netio_wait(*niop, 1,
timeout);
if (i == -1)
goto connect_error;
if (i == 0)
break;
/* if (i == 1), fall through */
errno = ETIMEDOUT;
}
if (BIT_ISSET(flags, NETIO_CONNECT_DNS_RR))
{
close((*niop)->n_fd);
(*niop)->n_fd = -1;
continue;
}
goto connect_error;
}
break;
}
/* failed on all IP addresses */
if ((*niop)->n_fd == -1)
goto connect_error;
/* socket no longer needs to be non-blocking */
BIT_CLEAR(sock_flags, O_NONBLOCK);
if (fcntl((*niop)->n_fd, F_SETFL, sock_flags) == -1)
goto connect_error;
return 0;
connect_error:
if (*niop != NULL)
{
fget_netio_free(*niop);
*niop = NULL;
}
return -1;
}
int
fget_netio_new(NETIO **niop, size_t size, char *hostname,
time_t timeout, unsigned short flags, ...)
{
va_list args;
int retval;
va_start(args, flags);
retval = fget_netio_vnew(niop, size, hostname,
timeout, flags, args);
va_end(args);
return retval;
}
char *
fget_netio_get_host(NETIO *nio)
{
return nio->n_host;
}
int
fget_netio_fd(NETIO *nio)
{
return nio->n_fd;
}
int
fget_netio_local_addr(NETIO *nio,
struct sockaddr *addr, socklen_t *addrlen,
char *buf, size_t buflen)
{
struct sockaddr_in tmp_addr;
socklen_t tmp_addr_len;
if (addr == NULL)
{
tmp_addr_len = sizeof(tmp_addr);
addr = (struct sockaddr *)&tmp_addr;
addrlen = &tmp_addr_len;
}
if (getsockname(nio->n_fd, addr, addrlen) == -1)
return -1;
if (buf != NULL)
{
snprintf(buf, buflen, "%s:%d",
inet_ntoa(((struct sockaddr_in *)addr)->sin_addr),
ntohl(((struct sockaddr_in *)addr)->sin_port));
}
return 0;
}
int
fget_netio_remote_addr(NETIO *nio,
struct sockaddr *addr, socklen_t *addrlen,
char *buf, size_t buflen)
{
struct sockaddr_in tmp_addr;
socklen_t tmp_addr_len;
if (addr == NULL)
{
tmp_addr_len = sizeof(tmp_addr);
addr = (struct sockaddr *)&tmp_addr;
addrlen = &tmp_addr_len;
}
if (getpeername(nio->n_fd, addr, addrlen) == -1)
return -1;
if (buf != NULL)
{
snprintf(buf, buflen, "%s:%d",
inet_ntoa(((struct sockaddr_in *)addr)->sin_addr),
ntohl(((struct sockaddr_in *)addr)->sin_port));
}
return 0;
}
int
fget_netio_free(NETIO *nio)
{
if (nio->n_fd != -1)
{
/*
** ignore return value of shutdown(), since
** it's just a formality anyway
**
** (there are unconfirmed reports that shutdown() fails
** on some platforms when called on a listen() socket)
*/
shutdown(nio->n_fd, SHUT_RDWR);
if (close(nio->n_fd) == -1)
return -1;
nio->n_fd = -1;
}
if (nio->n_buf != NULL)
free(nio->n_buf);
if (nio->n_default_service != NULL)
free(nio->n_default_service);
free(nio);
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1