/*
* sockets - open a socket connection and read/write to nntp server
*
* Copyright (C) 1992/93/94 Stephen Hebditch <steveh@tqmcomms.co.uk>.
* All rights reserved. TQM Communications, BCM Box 225, London, WC1N 3XX.
*
* See README for more information and disclaimers
*
* Obtain the current time from the remote server in standard unix time
* format for use with the next NEWNEWS. If the client is unable to
* connect to the time server, then local time is used instead.
*
* $Id: sockets.c,v 1.9 1995/01/10 13:09:21 root Exp $
*
* $Log: sockets.c,v $
* Revision 1.9 1995/01/10 13:09:21 root
* Moved includes from slurp.h.
* Added additional parameter to tcp_open() to specify port number
* if required.
* Moved in do_authinfo() and do_mode_reader() from slurp.c.
* General tidying-up.
*
* Revision 1.7 1993/06/23 10:15:37 root
* Replaced bzero/bcopy definitions with ANSI memcpy and memset.
* Duplicate fd before using fdopen separately on each fd for read
* and write, fixing long-standing stdio memory problems.
*
* Revision 1.6 1993/04/22 18:25:16 root
* If NOBUFFOUT defined then turn off stdio buffering for the
* output stream to the server to get round problem with SVR3s.
*
* Revision 1.5 1993/03/01 18:00:18 root
* Use ferror to detect erros, not return code.
*
* Revision 1.4 1993/02/14 16:22:42 root
* No longer have get_server return a return code. Makes this module
* no longer compatible with nntp 1.6 client library, but there ya go...
* Changed error detection in put_server for no other reason than to
* be consistent with elsewhere.
*
* Revision 1.3 1992/12/15
* Removed unnecessary close() in close_server.
* Syslog log level for connected message changed to LOG_INFO.
*
* Revision 1.1 1992/12/04
* Print line before it is sent to server when debugging is on.
*
* Revision 1.0 1992/11/29
* Adapted from nntpxfer-e code.
* Incorporate code to set up a tcp connection, plus cleaned up the
* existing code.
*/
#include "conf.h"
/* POSIX headers */
#undef _POSIX_SOURCE
#include <sys/types.h>
#include <errno.h>
#include <limits.h>
#include <setjmp.h>
#include <signal.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef NOUNISTD
#include <unistd.h>
#endif
/* IP headers */
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/* Local headers */
#include "nntp.h"
#include "slurp.h"
#include "syslog.h"
/* Fixes */
#ifndef INADDR_NONE
#define INADDR_NONE 0xffffffff
#endif
/* File-scope variables */
static struct sockaddr_in serv_addr;
static struct servent serv_info;
static struct hostent host_info;
static jmp_buf env_alrm;
static FILE *server_rd_fp;
static FILE *server_wr_fp;
/*
* tcp_open - Open a tcp connection to 'host' for service 'service',
* returning a file descriptor for the socket.
*/
int
tcp_open (const char *host, const char *service, const int portno)
{
int on = 1;
int sockfd;
struct hostent *hp;
struct servent *sp;
unsigned long inaddr;
(void) memset (&serv_addr, 0, sizeof (serv_addr));
serv_addr.sin_family = AF_INET;
/* Get service information if required*/
if (portno == 0)
{
if ((sp = getservbyname (service, "tcp")) == NULL)
{
log_ret ("tcp_open: unknown service %s/tcp", service);
return (-1);
}
serv_info = *sp;
serv_addr.sin_port = sp -> s_port;
}
else
{
serv_addr.sin_port = htons (portno);
}
/* Try to convert host name as dotted decimal */
if ((inaddr = inet_addr (host)) != INADDR_NONE)
{
(void) memcpy (&serv_addr.sin_addr, &inaddr, sizeof (inaddr));
host_info.h_name = NULL;
}
/* If that failed, then look up the host name */
else
{
if ((hp = gethostbyname (host)) == NULL)
{
log_ret ("tcp_open: host name error: %s", host);
return (-1);
}
host_info = *hp;
(void) memcpy (&serv_addr.sin_addr, hp -> h_addr, hp -> h_length);
}
if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) < 0)
{
log_ret ("tcp_open: can't create TCP socket");
return (-1);
}
if (connect (sockfd, (struct sockaddr *) &serv_addr,
sizeof (serv_addr)) < 0)
{
log_ret ("tcp_open: can't connect to server %s", host);
(void) close (sockfd);
return (-1);
}
if (setsockopt (sockfd, SOL_SOCKET, SO_KEEPALIVE,
(char *) &on, sizeof (on)) < 0)
log_ret ("tcp_open: can't set KEEPALIVE on socket");
return (sockfd);
}
/*
* server_init - Open a connection to the NNTP server. Returns -1 if an
* error occurs, otherwise the server's initial response code.
*/
int
server_init (const char *hostname, const int portno)
{
char line [NNTP_STRLEN];
int server_rd_fd;
int server_wr_fd;
/* First try and make the connection */
if ((server_rd_fd = tcp_open (hostname, "nntp", portno)) < 0)
return (-1);
server_wr_fd = dup (server_rd_fd);
/* Now fdopen to enable buffering of data */
if ((server_rd_fp = fdopen (server_rd_fd, "r")) == NULL)
{
log_ret ("server_init: can't fdopen socket for reading");
return (-1);
}
if ((server_wr_fp = fdopen (server_wr_fd, "w")) == NULL)
{
log_ret ("server_init: can't fdopen socket for writing");
return (-1);
}
/* Inform everyone that we're there */
#ifdef SYSLOG
if (!debug_flag)
syslog (LOG_INFO, "Connected to nntp server at %s", hostname);
else
#endif
(void) fprintf (stderr, "Connected to nntp server at %s\n", hostname);
/* Get the greeting herald */
get_server (line, sizeof (line));
if (debug_flag)
(void) fprintf (stderr, "-> %s\n", line);
/* Return the banner code */
return (atoi (line));
}
/*
* close_server - Close down the NNTP server connection, sending a
* QUIT message to the server then closing the socket.
*/
void
close_server (void)
{
char line [NNTP_STRLEN];
if (debug_flag)
(void) fprintf (stderr, "<- QUIT\n");
put_server ("QUIT");
get_server (line, sizeof (line));
if (debug_flag)
(void) fprintf (stderr, "-> %s\n", line);
(void) fclose (server_rd_fp);
(void) fclose (server_wr_fp);
}
/*
* sig_alrm - Signal handler for socket read timeout
*/
static void
sig_alrm (int signo)
{
longjmp (env_alrm, 1);
}
/*
* get_server - Read a line up to CRLF from the socket into a buffer.
* Will timeout after TIMEOUT seconds if nothing is read from the socket.
*/
void
get_server (char *line, const int size)
{
int esave;
char *pos;
/* Set up an alarm to handle socket timeout */
if (setjmp (env_alrm))
{
(void) alarm (0); /* Reset alarm clock */
(void) signal (SIGALRM, SIG_DFL);
errno = EPIPE;
log_sys ("get_server: read error on server socket");
}
(void) signal (SIGALRM, sig_alrm);
(void) alarm (TIMEOUT);
/* Read line */
(void) fgets (line, size, server_rd_fp);
/* Reset the alarm */
esave = errno;
(void) alarm (0);
(void) signal (SIGALRM, SIG_DFL);
errno = esave;
/* Report any error */
if (ferror (server_rd_fp))
log_sys ("get_server: read error on server socket");
/* Kill the CRLF */
if ((pos = strchr (line, '\r')) != NULL)
*pos = '\0';
if ((pos = strchr (line, '\n')) != NULL)
*pos = '\0';
}
/*
* put_server - write a line from a string to a socket
*/
void
put_server (const char *line)
{
(void) fprintf (server_wr_fp, "%s\r\n", line);
if (ferror (server_wr_fp))
log_sys ("put_server: write error on server socket");
(void) fflush (server_wr_fp);
}
/*
* do_authinfo - Check in the authinfo username and password with the
* server.
*/
void
do_authinfo (const char *username, const char *password)
{
char line [NNTP_STRLEN];
/* Send the username to the server */
(void) sprintf (line, "AUTHINFO USER %s", username);
if (debug_flag)
(void) fprintf (stderr, "<- %s\n", line);
put_server (line);
/* Get the response and check it's okay */
get_server (line, sizeof (line));
if (debug_flag)
(void) fprintf (stderr, "-> %s\n", line);
if (atoi (line) != NEED_AUTHDATA)
{
log_msg ("do_authinfo: NNTP protocol error: got '%s'", line);
exit (4);
}
/* Send the password to the server */
(void) sprintf (line, "AUTHINFO PASS %s", password);
if (debug_flag)
(void) fprintf (stderr, "<- %s\n", line);
put_server (line);
/* Get the response and check it's okay */
get_server (line, sizeof (line));
if (debug_flag)
(void) fprintf (stderr, "-> %s\n", line);
if (atoi (line) != OK_AUTH)
{
log_msg ("do_authinfo: NNTP protocol error: got '%s'", line);
exit (4);
}
}
/*
* do_mode_reader - Send mode reader command to INN to switch to nnrpd
* so we can do a NEWNEWS.
*/
void
do_mode_reader (void)
{
char line [NNTP_STRLEN];
/* Send the command to the server */
if (debug_flag)
(void) fprintf (stderr, "<- MODE READER\n");
put_server ("MODE READER");
/* Get the response and check it's okay */
get_server (line, sizeof (line));
if (debug_flag)
(void) fprintf (stderr, "-> %s\n", line);
switch (atoi (line))
{
case OK_CANPOST :
case OK_NOPOST :
break;
default :
log_msg ("do_mode_reader: NNTP protocol error: got '%s'", line);
exit (4);
}
}
/* END-OF-FILE */
syntax highlighted by Code2HTML, v. 0.9.1