#ident "@(#)network.c 1.6"
/*
* network.c -- handles stuff dealing with connecting and name resolving
*
* Written by Jeremy Nelson in 1995
* See the COPYRIGHT file or do /help ircii copyright
*/
#define SET_SOURCE_SOCKET
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "irc.h"
#include "ircaux.h"
#include "vars.h"
#ifdef HAVE_SYS_UN_H
#include <sys/un.h>
#endif
/*
* connect_by_number: Wheeeee. Yet another monster function i get to fix
* for the sake of it being inadequate for extension.
*
* we now take four arguments:
*
* - hostname - name of the host (pathname) to connect to (if applicable)
* - portnum - port number to connect to or listen on (0 if you dont care)
* - service - 0 - set up a listening socket
* 1 - set up a connecting socket
* - protocol - 0 - use the TCP protocol
* 1 - use the UDP protocol
*
*
* Returns:
* Non-negative number -- new file descriptor ready for use
* -1 -- could not open a new file descriptor or
* an illegal value for the protocol was specified
* -2 -- call to bind() failed
* -3 -- call to listen() failed.
* -4 -- call to connect() failed
* -5 -- call to getsockname() failed
* -6 -- the name of the host could not be resolved
* -7 -- illegal or unsupported request
*
*
* Credit: I couldnt have put this together without the help of BSD4.4-lite
* User Supplimentary Document #20 (Inter-process Communications tutorial)
*/
int connect_by_number(char *hostn, unsigned short *portnum, int service, int protocol, int nonblocking)
{
int fd = -1;
int is_unix = (hostn && *hostn == '/');
int sock_type, proto_type;
sock_type = (is_unix) ? AF_UNIX : AF_INET;
proto_type = (protocol == PROTOCOL_TCP) ? SOCK_STREAM : SOCK_DGRAM;
if ((fd = socket(sock_type, proto_type, 0)) < 0)
return -1;
set_socket_options(fd);
/* Unix domain server */
#ifdef HAVE_SYS_UN_H
if (is_unix) {
struct sockaddr_un name;
memset(&name, 0, sizeof(struct sockaddr_un));
name.sun_family = AF_UNIX;
strcpy(name.sun_path, hostn);
#ifdef HAVE_SUN_LEN
#ifdef SUN_LEN
name.sun_len = SUN_LEN(&name);
#else
name.sun_len = strlen(hostn) + 1;
#endif
#endif
if (is_unix && (service == SERVICE_SERVER)) {
if (bind(fd, (struct sockaddr *) &name, strlen(name.sun_path) + 2))
return close(fd), -2;
if (protocol == PROTOCOL_TCP)
if (listen(fd, 4) < 0)
return close(fd), -3;
}
/* Unix domain client */
else if (service == SERVICE_CLIENT) {
alarm(get_int_var(CONNECT_TIMEOUT_VAR));
if (connect(fd, (struct sockaddr *) &name, strlen(name.sun_path) + 2) < 0) {
alarm(0);
return close(fd), -4;
}
alarm(0);
}
} else
#endif
/* Inet domain server */
if (!is_unix && (service == SERVICE_SERVER)) {
socklen_t length;
struct sockaddr_in name;
memset(&name, 0, sizeof(struct sockaddr_in));
name.sin_family = AF_INET;
name.sin_addr.s_addr = htonl(INADDR_ANY);
name.sin_port = htons(*portnum);
if (bind(fd, (struct sockaddr *) &name, sizeof(name)))
return close(fd), -2;
length = sizeof(name);
if (getsockname(fd, (struct sockaddr *) &name, &length))
return close(fd), -5;
*portnum = ntohs(name.sin_port);
if (protocol == PROTOCOL_TCP)
if (listen(fd, 4) < 0)
return close(fd), -3;
if (nonblocking && set_non_blocking(fd) < 0)
return close(fd), -4;
}
/* Inet domain client */
else if (!is_unix && (service == SERVICE_CLIENT)) {
struct sockaddr_in server;
struct hostent *hp;
#if 0
/*
* Doing this bind is bad news unless you are sure that
* the hostname is valid. This is not true for me at home,
* since i dynamic-ip it.
*/
if (LocalHostName) {
struct sockaddr_in localaddr;
memset(&localaddr, 0, sizeof(struct sockaddr_in));
localaddr.sin_family = AF_INET;
localaddr.sin_addr = LocalHostAddr;
localaddr.sin_port = 0;
if (bind(fd, (struct sockaddr *) &localaddr, sizeof(localaddr)))
return close(fd), -2;
}
#endif
memset(&server, 0, sizeof(struct sockaddr_in));
if (!(hp = resolv(hostn)))
return close(fd), -6;
memcpy(&(server.sin_addr), hp->h_addr, hp->h_length);
server.sin_family = AF_INET;
server.sin_port = htons(*portnum);
if (nonblocking && set_non_blocking(fd) < 0)
return close(fd), -4;
alarm(get_int_var(CONNECT_TIMEOUT_VAR));
if (connect(fd, (struct sockaddr *) &server, sizeof(server)) < 0) {
alarm(0);
if (errno != EINPROGRESS && !nonblocking)
return close(fd), -4;
}
alarm(0);
}
/* error */
else
return close(fd), -7;
return fd;
}
extern struct hostent *resolv(const char *stuff)
{
struct hostent *hep;
if ((hep = lookup_host(stuff)) == NULL)
hep = lookup_ip(stuff);
return hep;
}
extern struct hostent *lookup_host(const char *host)
{
struct hostent *hep;
alarm(1);
hep = gethostbyname(host);
alarm(0);
return hep;
}
extern char *host_to_ip(const char *host)
{
struct hostent *hep = lookup_host(host);
static char ip[256];
return (hep ? sprintf(ip, "%u.%u.%u.%u", hep->h_addr[0] & 0xff,
hep->h_addr[1] & 0xff, hep->h_addr[2] & 0xff, hep->h_addr[3] & 0xff), ip : empty_str);
}
extern struct hostent *lookup_ip(const char *ip)
{
int b1 = 0, b2 = 0, b3 = 0, b4 = 0;
char foo[4];
struct hostent *hep;
sscanf(ip, "%d.%d.%d.%d", &b1, &b2, &b3, &b4);
foo[0] = b1;
foo[1] = b2;
foo[2] = b3;
foo[3] = b4;
alarm(1);
hep = gethostbyaddr(foo, 4, AF_INET);
alarm(0);
return hep;
}
extern char *ip_to_host(const char *ip)
{
struct hostent *hep = lookup_ip(ip);
static char host[128];
return (hep ? strcpy(host, hep->h_name) : empty_str);
}
extern char *one_to_another(const char *what)
{
if (!isdigit(what[strlen(what) - 1]))
return host_to_ip(what);
else
return ip_to_host(what);
}
int set_non_blocking(int fd)
{
int res, nonb = 0;
#if defined(O_NONBLOCK)
nonb |= O_NONBLOCK;
#else
#if defined(O_NDELAY)
nonb |= O_NDELAY;
#else
res = 1;
if (ioctl(fd, FIONBIO, &res) < 0)
return -1;
#endif
#endif
#if defined(O_NONBLOCK) || defined(O_NDELAY)
if ((res = fcntl(fd, F_GETFL, 0)) == -1)
return -1;
else if (fcntl(fd, F_SETFL, res | nonb) == -1)
return -1;
#endif
return 0;
}
int set_blocking(int fd)
{
int res, nonb = 0;
#if defined(O_NONBLOCK)
nonb |= O_NONBLOCK;
#else
#if defined(O_NDELAY)
nonb |= O_NDELAY;
#else
res = 0;
if (ioctl(fd, FIONBIO, &res) < 0)
return -1;
#endif
#endif
#if defined(O_NONBLOCK) || defined(O_NDELAY)
if ((res = fcntl(fd, F_GETFL, 0)) == -1)
return -1;
else if (fcntl(fd, F_SETFL, res & ~nonb) == -1)
return -1;
#endif
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1