/* $Revision: 6119 $
**
** Open a connection to a remote NNTP server.
*/
#include "config.h"
#include "clibrary.h"
#include "portable/socket.h"
#include <errno.h>
#include <netdb.h>
#ifdef HAVE_UNIX_DOMAIN_SOCKETS
# include <sys/un.h>
#endif
#include "inn/innconf.h"
#include "libinn.h"
#include "nntp.h"
#include "paths.h"
/*
** Open a connection to an NNTP server and create stdio FILE's for talking
** to it. Return -1 on error.
*/
int NNTPconnect(char *host, int port, FILE **FromServerp, FILE **ToServerp, char *errbuff)
{
char mybuff[NNTP_STRLEN + 2];
char *buff;
int i = -1;
int j;
int oerrno;
FILE *F;
#ifdef HAVE_INET6
struct addrinfo hints, *ressave, *addr;
char portbuf[16];
struct sockaddr_storage client;
#else
char **ap;
char *dest;
char *fakelist[2];
char *p;
struct hostent *hp;
struct hostent fakehp;
struct in_addr quadaddr;
struct sockaddr_in server, client;
#endif
buff = errbuff ? errbuff : mybuff;
*buff = '\0';
#ifdef HAVE_INET6
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
sprintf(portbuf, "%d", port);
if (getaddrinfo(host, portbuf, &hints, &addr) != 0)
return -1;
for (ressave = addr; addr; addr = addr->ai_next) {
if ((i = socket(addr->ai_family, addr->ai_socktype,
addr->ai_protocol)) < 0)
continue; /* ignore */
/* bind the local (source) address, if requested */
memset(&client, 0, sizeof client);
if (addr->ai_family == AF_INET && innconf->sourceaddress) {
if (inet_pton(AF_INET, innconf->sourceaddress,
&((struct sockaddr_in *)&client)->sin_addr) < 1) {
addr = NULL;
break;
}
((struct sockaddr_in *)&client)->sin_family = AF_INET;
#ifdef HAVE_SOCKADDR_LEN
((struct sockaddr_in *)&client)->sin_len = sizeof( struct sockaddr_in );
#endif
}
if (addr->ai_family == AF_INET6 && innconf->sourceaddress6) {
if (inet_pton(AF_INET6, innconf->sourceaddress6,
&((struct sockaddr_in6 *)&client)->sin6_addr) < 1) {
addr = NULL;
break;
}
((struct sockaddr_in6 *)&client)->sin6_family = AF_INET6;
#ifdef HAVE_SOCKADDR_LEN
((struct sockaddr_in6 *)&client)->sin6_len = sizeof( struct sockaddr_in6 );
#endif
}
if (client.ss_family != 0) {
if (bind(i, (struct sockaddr *)&client, addr->ai_addrlen) < 0) {
addr = NULL;
break;
}
}
/* we are ready, try to connect */
if (connect(i, addr->ai_addr, addr->ai_addrlen) == 0)
break; /* success */
oerrno = errno;
close(i);
errno = oerrno;
}
freeaddrinfo(ressave);
if (addr == NULL) {
/* all connect(2) calls failed or some other error has occurred */
oerrno = errno;
close(i);
errno = oerrno;
return -1;
}
{
#else /* HAVE_INET6 */
if (inet_aton(host, &quadaddr)) {
/* Host was specified as a dotted-quad internet address. Fill in
* the parts of the hostent struct that we need. */
fakehp.h_length = sizeof quadaddr;
fakehp.h_addrtype = AF_INET;
hp = &fakehp;
fakelist[0] = (char *)&quadaddr;
fakelist[1] = NULL;
ap = fakelist;
}
else if ((hp = gethostbyname(host)) != NULL)
ap = hp->h_addr_list;
else
/* Not a host name. */
return -1;
/* Set up the socket address. */
memset(&server, 0, sizeof server);
server.sin_family = hp->h_addrtype;
#ifdef HAVE_SOCKADDR_LEN
server.sin_len = sizeof( struct sockaddr_in );
#endif
server.sin_port = htons(port);
/* Source IP address to which we bind. */
memset(&client, 0, sizeof client);
client.sin_family = AF_INET;
#ifdef HAVE_SOCKADDR_LEN
client.sin_len = sizeof( struct sockaddr_in );
#endif
if (innconf->sourceaddress) {
if (!inet_aton(innconf->sourceaddress, &client.sin_addr))
return -1;
} else
client.sin_addr.s_addr = htonl(INADDR_ANY);
/* Loop through the address list, trying to connect. */
for (; ap && *ap; ap++) {
/* Make a socket and try to connect. */
if ((i = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0)
break;
/* Bind to the source address we want. */
if (bind(i, (struct sockaddr *)&client, sizeof client) < 0) {
oerrno = errno;
close(i);
errno = oerrno;
continue;
}
/* Copy the address via inline memcpy:
* memcpy(&server.sin_addr, *ap, hp->h_length); */
p = (char *)*ap;
for (dest = (char *)&server.sin_addr, j = hp->h_length; --j >= 0; )
*dest++ = *p++;
if (connect(i, (struct sockaddr *)&server, sizeof server) < 0) {
oerrno = errno;
close(i);
errno = oerrno;
continue;
}
#endif /* HAVE_INET6 */
/* Connected -- now make sure we can post. */
if ((F = fdopen(i, "r")) == NULL) {
oerrno = errno;
close(i);
errno = oerrno;
return -1;
}
if (fgets(buff, sizeof mybuff, F) == NULL) {
oerrno = errno;
fclose(F);
errno = oerrno;
return -1;
}
j = atoi(buff);
if (j != NNTP_POSTOK_VAL && j != NNTP_NOPOSTOK_VAL) {
fclose(F);
/* This seems like a reasonable error code to use... */
errno = EPERM;
return -1;
}
*FromServerp = F;
if ((*ToServerp = fdopen(dup(i), "w")) == NULL) {
oerrno = errno;
fclose(F);
errno = oerrno;
return -1;
}
return 0;
}
return -1;
}
int NNTPremoteopen(int port, FILE **FromServerp, FILE **ToServerp, char *errbuff)
{
char *p;
if ((p = innconf->server) == NULL) {
if (errbuff)
strcpy(errbuff, "What server?");
return -1;
}
return NNTPconnect(p, port, FromServerp, ToServerp, errbuff);
}
syntax highlighted by Code2HTML, v. 0.9.1