Files
undernet-cservice/Sources/connect.c
2015-01-25 18:26:44 -06:00

697 lines
14 KiB
C

/* @(#)$Id: connect.c,v 1.12 1998/01/25 18:35:42 seks Exp $ */
/* Undernet Channel Service (X)
* Copyright (C) 1995-2002 Robin Thellend
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* The author can be contact by email at <csfeedback@robin.pfft.net>
*
* Please note that this software is unsupported and mostly
* obsolete. It was replaced by GNUworld/CMaster. See
* http://gnuworld.sourceforge.net/ for more information.
*/
#include "h.h"
#ifndef FD_ZERO
#define FD_ZERO(set) (((set)->fds_bits[0]) = 0)
#define FD_SET(s1, set) (((set)->fds_bits[0]) |= 1 << (s1))
#define FD_ISSET(s1, set) (((set)->fds_bits[0]) & (1 << (s1)))
#define FD_SETSIZE 30
#endif
int read_from_server(int);
int write_to_server(irc_socket *);
int connection(char *serv)
{
char buffer[200];
int portnum;
char *ptr;
struct sockaddr_in socketname;
#ifdef BINDADDR
struct sockaddr_in myname;
#endif
struct hostent *remote_host;
if ((ptr = strchr(serv, ':')) != NULL)
{
*(ptr++) = 0;
sscanf(ptr, "%d", &portnum);
#ifdef DEBUG
printf("Server: %s\nPort: %d\n", serv, portnum);
#endif
}
else
{
portnum = DEFAULT_PORTNUM;
}
sprintf(buffer, "CONNECTING TO %s ON PORT %d", serv, portnum);
log(buffer);
if (Irc.outbuf)
zap_buffer(&Irc.outbuf);
if (Irc.inbuf)
zap_buffer(&Irc.inbuf);
read_from_server(1); /* reset input buffer */
now = time(NULL);
/* open an inet socket */
if ((Irc.fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
#ifdef DEBUG
fprintf(stderr, "ERROR: Can't assign fd for socket, darn!\n");
#endif
log("ERROR ASSIGNING FD FOR SOCKET");
exit(1);
}
#ifdef BINDADDR
memset(&myname, 0, sizeof(myname));
myname.sin_family = AF_INET;
myname.sin_port = 0;
myname.sin_addr.s_addr = inet_addr(BINDADDR);
if (bind(Irc.fd, (struct sockaddr *)&myname, sizeof(myname)) < 0)
{
#ifdef DEBUG
fprintf(stderr, "ERROR: Can't bind local address %s\n", BINDADDR);
#endif
log("Can't bind local address");
log(BINDADDR);
exit(1);
}
#endif
/* make it non-blocking */
fcntl(Irc.fd, F_SETFL, O_NONBLOCK);
/* lookup host */
socketname.sin_family = AF_INET;
if ((remote_host = gethostbyname(serv)) == NULL)
{
#ifdef DEBUG
fprintf(stderr, "ERROR: Host %s is unknown, wtf?\n", serv);
#endif
log("ERROR: BULLSHIT HOST!");
exit(1);
}
memcpy((void *)&socketname.sin_addr, (void *)remote_host->h_addr, remote_host->h_length);
socketname.sin_port = htons(portnum);
/* connect socket */
if (connect(Irc.fd, (struct sockaddr *)&socketname, sizeof(socketname)) < 0
&& errno != EINPROGRESS)
{
close(Irc.fd);
Irc.fd = -1;
#ifdef DEBUG
printf("ERROR: connect() %d: %s\n", errno, strerror(errno));
#endif
log("ERROR: COULDN'T CONNECT");
return (1);
}
TSconnect = Irc.TS = now = time(NULL);
errno = 0;
return 0;
}
int wait_msg(void)
{
fd_set readfds, writefds;
struct timeval timeout;
static int pingflag = 0;
int maxfd = -1;
int to;
#ifdef DOHTTP
void http_log(char *fmt,...);
register http_socket *hsock, *hsocktmp;
register http_file_pipe *fpipe, *fpipetmp;
#endif
#ifdef UPGRADE
register misc_socket *msock, *msocktmp;
#endif
register dbquery **dq, *dqtmp;
register dbsync **ds, *dstmp;
/* initialize the fd_sets
*/
FD_ZERO(&readfds);
FD_ZERO(&writefds);
/* set timeout
*/
if (EventList != NULL)
{
to = EventList->time - now;
if (to < PING_FREQ)
timeout.tv_sec = (to > 0) ? to : 0;
else
timeout.tv_sec = PING_FREQ;
}
else
{
timeout.tv_sec = PING_FREQ;
}
timeout.tv_usec = 0;
/* Check the DBQuery list before the server fd because
* end_db_read() might writing something in the server's
* buffer.
*/
dq = &DBQuery;
while (*dq)
{
if ((*dq)->fd < 0)
{
dqtmp = *dq;
*dq = (*dq)->next;
end_db_read(dqtmp);
free(dqtmp);
}
else
{
if ((*dq)->fd > maxfd)
maxfd = (*dq)->fd;
FD_SET((*dq)->fd, &readfds);
dq = &(*dq)->next;
}
}
ds = &DBSync;
while (*ds)
{
if ((*ds)->fd < 0)
{
dstmp = *ds;
*ds = (*ds)->next;
end_db_sync(dstmp);
free(dstmp);
}
else
{
if ((*ds)->fd > maxfd)
maxfd = (*ds)->fd;
if ((*ds)->status == SYNC_PENDWRITE)
FD_SET((*ds)->fd, &writefds);
else
FD_SET((*ds)->fd, &readfds);
ds = &(*ds)->next;
}
}
/* check if the uplink's socket is ready for reading..
*/
FD_SET(Irc.fd, &readfds);
/* check if the uplink's socket is ready for writing only if
* we have something to write
*/
if (Irc.outbuf != NULL)
FD_SET(Irc.fd, &writefds);
if (Irc.fd > maxfd)
maxfd = Irc.fd;
#ifdef DOHTTP
fpipe = FilePipes;
while (fpipe != NULL)
{
if (fpipe->fd > maxfd)
maxfd = fpipe->fd;
FD_SET(fpipe->fd, &readfds);
fpipe = fpipe->next;
}
hsock = HttpList;
while (hsock != NULL)
{
if (hsock->fd < 0 || hsock->status == HTTP_ERROR)
{
hsock = hsock->next; /* am I an idiot or what? -Kev */
continue; /* you should see the logs from below! -Kev */
}
if (hsock->fd > maxfd)
maxfd = hsock->fd;
if (hsock->status != HTTP_LISTEN &&
hsock->status != HTTP_CHAT &&
hsock->since + 2 * HTTP_TIMEOUT < now)
{
http_log("ERROR: absolute timeout for fd %d (%d)",
hsock->fd, hsock->status);
close(hsock->fd);
hsock->fd = -1;
hsock->status = HTTP_ERROR;
}
if (hsock->status != HTTP_LISTEN &&
hsock->status != HTTP_CHAT &&
hsock->TS + HTTP_TIMEOUT < now)
{
close(hsock->fd);
hsock->fd = -1;
hsock->status = HTTP_ERROR;
}
if (hsock->status == HTTP_ENDING &&
hsock->outbuf == NULL)
{
close(hsock->fd);
hsock->fd = -1;
hsock->status = HTTP_ERROR;
}
if (hsock->status != HTTP_ERROR)
{
if (hsock->status != HTTP_ENDING &&
hsock->status != HTTP_PIPE)
FD_SET(hsock->fd, &readfds);
if (hsock->outbuf != NULL)
FD_SET(hsock->fd, &writefds);
}
hsock = hsock->next;
}
#endif
#ifdef UPGRADE
msock = MiscList;
while (msock != NULL)
{
if (msock->fd > maxfd)
maxfd = msock->fd;
if (msock->TS + MISC_TIMEOUT < now)
{
close(msock->fd);
msock->fd = -1;
msock->status = MISC_ERROR;
notice(msock->link, "connection timeout!");
}
if (msock->status != MISC_ERROR)
{
FD_SET(msock->fd, &readfds);
if (msock->outbuf != NULL)
FD_SET(msock->fd, &writefds);
}
msock = msock->next;
}
#endif
/* Wait till the socket is ready for reading
* and/or writing and/or a timeout
*/
if (select(maxfd + 1, &readfds, &writefds, NULL, &timeout) < 0)
{
log("ERROR: select()");
log((char *)sys_errlist[errno]);
return (-1);
}
now = time(NULL);
/* The uplink's socket is ready for reading... */
if (FD_ISSET(Irc.fd, &readfds))
{
if (read_from_server(0) < 0)
{
log("ERROR: in read_from_server()");
return (-1);
}
pingflag = 0;
Irc.TS = now;
}
/* The uplink's socket is ready for writing... */
if (FD_ISSET(Irc.fd, &writefds))
{
if (write_to_server(&Irc) < 0)
{
log("ERROR: in write_to_server()");
return (-1);
}
}
#ifdef DOHTTP
fpipe = FilePipes;
while (fpipe != NULL)
{
fpipetmp = fpipe;
fpipe = fpipe->next;
if (FD_ISSET(fpipetmp->fd, &readfds))
{
readfrom_file(fpipetmp);
}
}
hsock = HttpList;
while (hsock != NULL)
{
while (hsock != NULL && hsock->status == HTTP_ERROR)
{
hsocktmp = hsock;
hsock = hsock->next;
remove_httpsock(hsocktmp);
}
if (hsock == NULL)
break;
if (hsock->fd >= 0 && FD_ISSET(hsock->fd, &readfds))
{
if (hsock->status == HTTP_LISTEN)
{
http_accept(hsock->fd);
}
else
{
readfrom_http(hsock);
hsock->TS = now;
}
}
if (hsock->fd >= 0 && FD_ISSET(hsock->fd, &writefds))
{
if (flush_http_buffer(hsock) != -1)
hsock->TS = now;
if (hsock->status == HTTP_ENDING && hsock->outbuf == NULL)
{
close(hsock->fd);
hsock->fd = -1;
hsock->status = HTTP_ERROR;
}
}
hsock = hsock->next;
}
#endif
#ifdef UPGRADE
msocktmp = NULL;
msock = MiscList;
while (msock != NULL)
{
while (msock != NULL && msock->status == MISC_ERROR)
{
if (msocktmp == NULL)
{
MiscList = msock->next;
free(msock);
msock = MiscList;
}
else
{
msocktmp->next = msock->next;
free(msock);
msock = msocktmp->next;
}
}
if (msock == NULL)
break;
if (msock->fd >= 0 && FD_ISSET(msock->fd, &readfds))
{
readfrom_misc(msock);
msock->TS = now;
}
if (msock->fd >= 0 && FD_ISSET(msock->fd, &writefds))
{
if (flush_misc_buffer(msock) != -1)
msock->TS = now;
}
msocktmp = msock;
msock = msock->next;
}
#endif
dqtmp = DBQuery;
while (dqtmp)
{
if (FD_ISSET(dqtmp->fd, &readfds))
read_db(dqtmp);
dqtmp = dqtmp->next;
}
dstmp = DBSync;
while (dstmp)
{
if (FD_ISSET(dstmp->fd, &readfds) || FD_ISSET(dstmp->fd, &writefds))
db_sync_ready(dstmp);
dstmp = dstmp->next;
}
if (EventList != NULL && now >= EventList->time)
CheckEvent();
/* send a PING to the server if nothing is received within
* PING_FREQ seconds... if yet nothing arrives within 3 * PING_FREQ
* seconds it's a ping timeout and the connection should be closed
*/
if ((now - Irc.TS) >= (3 * PING_FREQ + 1))
{
log("Errr PING TIMEOUT");
#ifdef DEBUG
printf("Ping timeout..\n");
#endif
sendtoserv("ERROR :Connection timeout\n");
return (-1);
}
else if (pingflag == 0 && (now - Irc.TS) >= (PING_FREQ - 1))
{
sendtoserv("PING :");
sendtoserv(SERVERNAME);
sendtoserv("\n");
pingflag = 1;
}
if (DB_Save_Status != -1)
do_cold_sync_slice();
return 0;
}
void sendtoserv(char *msg)
{
#ifdef DEBUG
printf("#OUT#%s", msg);
#endif
CurrentSendQ = copy_to_buffer(&Irc.outbuf, msg, strlen(msg));
if (CurrentSendQ > MAX_SENDQ)
{
log("ERROR: Reached MAX_SENDQ!!!");
zap_buffer(&Irc.outbuf);
close(Irc.fd);
exit(-1);
}
}
void dumpbuff(void)
{
if (Irc.fd < 0)
return;
/* remove the O_NONBLOCK flag */
fcntl(Irc.fd, F_SETFL, 0);
write_to_server(&Irc);
if (Irc.fd >= 0)
/* reset the O_NONBLOCK flag */
fcntl(Irc.fd, F_SETFL, O_NONBLOCK);
}
int read_from_server(int reset)
{
static char inbuff[1025] = "";
static char source[SERVER_NAME_LENGTH] = "";
static char function[10] = "";
static char target[513] = "";
static char body[513] = "";
static int in_pos = 0;
static int in_offset = 0;
static int length = 0;
char *inchar;
int end;
#ifdef HISTORY
char buffer[600];
#endif
if (reset)
{
*inbuff = *source = *function = *target = *body = '\0';
in_pos = in_offset = length = 0;
return 0;
}
#ifdef DEBUG
printf("#IN#");
#endif
end = 1;
while (end > 0)
{
errno = 0;
if ((length = read(Irc.fd, inbuff, 1024)) <= 0)
{
if (errno == EWOULDBLOCK || errno == EAGAIN || length == 0)
{
end = 0;
}
else
{
end = -1;
in_pos = in_offset = 0;
*source = *function = *target = *body = '\0';
#ifdef DEBUG
printf("Read error.. not EWOULDBLOCK!\n");
#endif
}
return (end);
}
TTLREADBYTES += length;
inchar = inbuff;
while (length--)
{
#ifdef DEBUG
putchar(*inchar);
#endif
if (*inchar != '\n' && *inchar != '\r')
{
if (*inchar == ' ' && in_pos < 3)
{
switch (in_pos)
{
case 0:
source[in_offset] = '\0';
break;
case 1:
function[in_offset] = '\0';
break;
case 2:
target[in_offset] = '\0';
break;
default:
exit(1);
}
in_pos++;
in_offset = 0;
}
else
{
switch (in_pos)
{
case 0:
if (in_offset == 0 && *inchar != ':')
{
source[0] = '\0';
in_pos++;
function[in_offset++] = *inchar;
}
else
source[in_offset++] = *inchar;
break;
case 1:
function[in_offset++] = *inchar;
break;
case 2:
target[in_offset++] = *inchar;
break;
case 3:
body[in_offset++] = *inchar;
break;
default: /*shouldn't happen */
exit(1);
}
}
}
if (*inchar == '\n')
{
if (in_pos >= 3)
body[in_offset] = '\0';
else
{
body[0] = '\0';
switch (in_pos)
{
case 2:
target[in_offset] = '\0';
break;
case 1:
function[in_offset] = '\0';
break;
case 0:
source[in_offset] = '\0';
default:
break;
}
}
/* parse the received line */
#ifdef HISTORY
sprintf(buffer, "%s %s %s %s", source, function, target, body);
History(buffer);
#endif
proc(source, function, target, body);
in_pos = in_offset = end = 0;
*source = *function = *target = *body = '\0';
}
inchar++;
} /* while */
} /*while */
return 1;
}
int write_to_server(irc_socket * isock)
{
char buf[1024];
int length;
int count;
if (isock == NULL || isock->outbuf == NULL)
return -1;
while ((count = look_in_buffer(&isock->outbuf, buf, '\0', 1023)) > 0)
{
if ((length = write(isock->fd, buf, count)) <= 0)
{
if (errno == EWOULDBLOCK || errno == EAGAIN)
{
return 0;
}
else
{
close(isock->fd);
isock->fd = -1;
return -1;
}
}
else
{
TTLSENTBYTES += length;
CurrentSendQ -= length;
skip_char_in_buffer(&isock->outbuf, length);
}
}
return 0;
}