/*
* ircio.c: A quaint little program to make irc life PING free
*
* Written By Michael Sandrof
*
* Copyright (c) 1990 Michael Sandrof.
* Copyright (c) 1991, 1992 Troy Rollo.
* Copyright (c) 1992-2004 Matthew R. Green.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "irc.h"
IRCII_RCSID("@(#)$eterna: ircio.c,v 2.24 2004/01/06 06:06:35 mrg Exp $");
#include "defs.h"
#include <sys/types.h>
#include <stdio.h>
#ifdef HAVE_SYS_SELECT_H
# include <sys/select.h>
#endif /* HAVE_SYS_SELECT_H */
#if defined(HAVE_UNISTD_H) && !defined(pyr) && !defined(_SEQUENT_)
# include <unistd.h>
#endif /* HAVE_UNISTD_H && !pyr && !_SEQUENT_ */
#include <sys/file.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <signal.h>
#ifdef TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#else
# ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif /* HAVE_SYS_TIME_H */
#endif /* TIME_WITH_SYS_TIME */
#include "newio.h"
/* machines we don't want to use <unistd.h> on 'cause its broken */
#if defined(pyr) || defined(_SEQUENT_)
# undef HAVE_UNISTD_H
#endif /* pyr || _SEQUENT_ */
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif /* HAVE_UNISTD_H */
#ifdef HAVE_SYS_UN_H
#include <sys/un.h>
static int connect_to_unix(char *);
#endif /* HAVE_SYS_UN_H */
#undef NON_BLOCKING
void new_free(char **);
char *new_malloc(size_t);
static int connect_by_number(char *, char *);
int main(int, char *[], char *[]);
char *
new_malloc(size)
size_t size;
{
char *ptr;
if ((ptr = (char *) malloc(size)) == (char *) 0)
{
printf("-1 0\n");
exit(1);
}
return (ptr);
}
/*
* new_free: Why do this? Why not? Saves me a bit of trouble here and
* there
*/
void
new_free(ptr)
char **ptr;
{
if (*ptr)
{
free(*ptr);
*ptr = 0;
}
}
/*
* Connect_By_Number Performs a connecting to socket 'service' on host
* 'host'. Host can be a hostname or ip-address. If 'host' is null, the
* local host is assumed. The parameter full_hostname will, on return,
* contain the expanded hostname (if possible). Note that full_hostname is a
* pointer to a char *, and is allocated by connect_by_numbers()
*
* Errors:
*
* -1 get service failed
*
* -2 get host failed
*
* -3 socket call failed
*
* -4 connect call failed
*/
static int
connect_by_number(service, host)
char *service;
char *host;
{
int s = -1, err;
char buf[256];
struct addrinfo hints, *res = 0, *res0 = 0;
if (host == (char *) 0)
{
gethostname(buf, sizeof(buf));
host = buf;
}
memset(&hints, 0, sizeof hints);
hints.ai_flags = 0;
hints.ai_protocol = 0;
hints.ai_addrlen = 0;
hints.ai_canonname = NULL;
hints.ai_addr = NULL;
hints.ai_next = NULL;
hints.ai_socktype = SOCK_STREAM;
hints.ai_family = AF_UNSPEC;
err = getaddrinfo(host, service, &hints, &res0);
if (err != 0)
return -2;
for (res = res0; res; res = res->ai_next)
{
err = 0;
if ((s = socket(res->ai_family, res->ai_socktype,
res->ai_protocol)) < 0)
continue;
set_socket_options(s);
err = connect(s, res->ai_addr, res->ai_addrlen);
if (err == 0)
break;
close(s);
}
freeaddrinfo(res0);
if (err)
return -4;
return (s);
}
/*
* ircio: This little program connects to the server (given as arg 1) on
* the given port (given as arg 2). It then accepts input from stdin and
* sends it to that server. Likewise, it reads stuff sent from the server and
* sends it to stdout. Simple? Yes, it is. But wait! There's more! It
* also intercepts server PINGs and automatically responds to them. This
* frees up the process that starts ircio (such as IRCII) to pause without
* fear of being pooted off the net.
*
* Future enhancements: No-blocking io. It will either discard or dynamically
* buffer anything that would block.
*/
int
main(argc, argv, envp)
int argc;
char *argv[];
char *envp[];
{
int des;
fd_set rd;
int done = 0,
c;
char *ptr,
lbuf[BUFSIZ + 1],
pong[BUFSIZ + 1];
#ifdef NON_BLOCKING
char block_buffer[BUFSIZ + 1];
fd_set *wd_ptr = (fd_set *) 0,
wd;
int wrote;
#endif /* NON_BLOCKING */
if (argc < 3)
exit(1);
#ifdef SOCKS
SOCKSinit(*argv);
#endif /* SOCKS */
#ifdef HAVE_SYS_UN_H
if (*argv[1] == '/')
des = connect_to_unix(argv[1]);
else
#endif /* HAVE_SYS_UN_H */
des = connect_by_number(argv[2], argv[1]);
if (des < 0)
exit(des);
fflush(stdout);
(void) MY_SIGNAL(SIGTERM, (sigfunc *) SIG_IGN, 0);
(void) MY_SIGNAL(SIGSEGV, (sigfunc *) SIG_IGN, 0);
(void) MY_SIGNAL(SIGPIPE, (sigfunc *) SIG_IGN, 0);
#ifdef SIGWINCH
(void) MY_SIGNAL(SIGWINCH, (sigfunc *) SIG_IGN, 0);
#endif /* SIGWINCH */
#ifdef SIGBUS
(void) MY_SIGNAL(SIGBUS, (sigfunc *) SIG_IGN, 0);
#endif /* SIGBUS */
#ifdef NON_BLOCKING
if (fcntl(1, F_SETFL, FNDELAY))
exit(1);
#endif /* NON_BLOCKING */
while (!done)
{
fflush(stderr);
FD_ZERO(&rd);
FD_SET(0, &rd);
FD_SET(des, &rd);
#ifdef NON_BLOCKING
if (wd_ptr)
{
FD_ZERO(wd_ptr);
FD_SET(1, wd_ptr);
}
switch (new_select(&rd, wd_ptr, NULL))
{
#else
switch (new_select(&rd, (fd_set *) 0, NULL))
{
#endif /* NON_BLOCKING */
case -1:
case 0:
break;
default:
#ifdef NON_BLOCKING
if (wd_ptr)
{
if (FD_ISSET(1, wd_ptr))
{
c = strlen(block_buffer);
if ((wrote = write(1, block_buffer,
c)) == -1)
{
wd_ptr = &wd;
}
else if (wrote < c)
{
strcpy(block_buffer,
&(block_buffer[wrote]));
wd_ptr = &wd;
}
else
wd_ptr = (fd_set *) 0;
}
}
#endif /* NON_BLOCKING */
if (FD_ISSET(0, &rd))
{
if (0 != (c = dgets(UP(lbuf), BUFSIZ, 0,
(u_char *) 0)))
write(des, lbuf, (size_t)c);
else
done = 1;
}
if (FD_ISSET(des, &rd))
{
if (0 != (c = dgets(UP(lbuf), BUFSIZ, des,
(u_char *) 0)))
{
if (strncmp(lbuf, "PING ", 5) == 0)
{
if ((ptr = (char *)
index(lbuf, ' ')) != NULL)
{
snprintf(pong, sizeof pong, "PONG user@host %s\n", ptr + 1);
write(des, pong, strlen(pong));
}
}
else
{
#ifdef NON_BLOCKING
if ((wrote = write(1, lbuf,
(size_t)c)) == -1)
wd_ptr = &wd;
else if (wrote < c)
{
strcpy(block_buffer,
&(lbuf[wrote]));
wd_ptr = &wd;
}
#else
write(1, lbuf, (size_t)c);
#endif /* NON_BLOCKING */
}
}
else
done = 1;
}
}
}
return 0;
}
#ifdef HAVE_SYS_UN_H
/*
* Connect to a UNIX domain socket. Only works for servers.
* submitted by Avalon for use with server 2.7.2 and beyond.
*/
static int
connect_to_unix(path)
char *path;
{
struct sockaddr_un un;
int sock;
sock = socket(AF_UNIX, SOCK_STREAM, 0);
un.sun_family = AF_UNIX;
strcpy(un.sun_path, path);
if (connect(sock, (struct sockaddr *)&un, (int)strlen(path)+2) == -1)
{
new_close(sock);
return -1;
}
return sock;
}
#endif /* HAVE_SYS_UN_H */
syntax highlighted by Code2HTML, v. 0.9.1