/****************************************************************************** * This file is part of a software distribution, which is furnished under the * * terms of a license. Use of this software by any means is subject to this * * license and signifies the acceptance of the licensing terms stated * * therein. Please see the file LICENSE in the top-level directory of this * * software distribution for detailed copyright disclaimers and licensing * * terms. * ****************************************************************************** * Copryight (c) by Andreas S. Wetzel - All rights reserved. * ******************************************************************************/ /* $Id: network.c,v 1.2 2001/03/19 14:54:01 mickey Exp $ */ #include #include #include #include #include #include #if HAVE_SYS_UIO_H #include #endif #ifndef O_NONBLOCK #include #endif /*** Externals ***/ int uchannel = 0; extern VP vp; extern VCONN sconn; extern TMSTAT tmstat; extern char *prog_name; extern char nlstr[]; extern u_char is_handler; extern VIDENT *ident(void); extern VLOGINDAT *genvldat(void); extern void vquit(char *fmt, ...); extern void ring_my_bell(char *dat, size_t size); /*** Globals ***/ ULIST_ITEM *ulist_base; int ulist_cnt = 0; /*** Code ***/ /***************************************************************************** * Connect server at on port , requesting magicnumber . * * If the server asks for a password to be supplied send to the * * server to authenticate us. * * Connection data is placed in the buffer pointed to by * * -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * * Return values: * * -1 => Error has occured. See errno * * CONN_OK => Connection established * * CONN_E... => Error occured (see param.h) * *****************************************************************************/ int connect_server(VCONN *vcn, struct in_addr *addr, u_short cport, u_long magic, u_char *passwd) { u_char state; /* * Initialize VCONN structure */ BZERO(vcn, sizeof(VCONN)); /* * Connect to vchat server */ sprintf(vcn->host, "%s", iptoname(*addr)); vcn->saddr.sin_port = htons(cport); vcn->saddr.sin_family = AF_INET; vcn->saddr.sin_addr = *addr; if((vcn->fd = socket(PF_INET, SOCK_STREAM, 0)) == -1) return(-1); if(connect(vcn->fd, (struct sockaddr *)&vcn->saddr, sizeof(vcn->saddr)) < 0) { close(vcn->fd); return(-1); } /* * Get server identification packet */ if(read(vcn->fd, &vcn->vid, sizeof(VIDENT)) != sizeof(VIDENT)) { close(vcn->fd); return(-1); } vcn->vid.ident[VPIDENTSIZE] = '\0'; vcn->vid.magic = ntohl(vcn->vid.magic); vcn->vid.proto = ntohl(vcn->vid.proto); vcn->vid.type = ntohl(vcn->vid.type); /* * Check server magic number */ if(vcn->vid.magic != magic) { close(vcn->fd); return(CONN_EMAGIC); } /* * Check for server messages in VIDENT packet */ if(vcn->vid.type != CONN_OK) { close(vcn->fd); return((int)vcn->vid.type); } /* * Send out our identification */ if(write(vcn->fd, (void *)ident(), sizeof(VIDENT)) != sizeof(VIDENT)) { close(vcn->fd); return(-1); } /* * Await status */ if(read(vcn->fd, &state, 1) != 1) { close(vcn->fd); return(-1); } if(state != CONN_OK) { close(vcn->fd); return((int)state); } /* * Send client data structure */ if(write(vcn->fd, (void *)genvldat(), sizeof(VLOGINDAT)) != sizeof(VLOGINDAT)) { close(vcn->fd); return(-1); } /* * Await status */ if(read(vcn->fd, &state, 1) != 1) { close(vcn->fd); return(-1); } /* * Send password if authorization is required by the server */ if(state == CONN_AUTHREQ) { VPASSWD vpwd; BZERO(&vpwd, sizeof(VPASSWD)); if(passwd) strncpy(vpwd.passwd, passwd, VPPASSWDSIZE); if(write(vcn->fd, &vpwd, sizeof(VPASSWD)) != sizeof(VPASSWD)) { close(vcn->fd); return(-1); } /* * Await status */ if(read(vcn->fd, &state, 1) != 1) { close(vcn->fd); return(-1); } } /* * Set socket owner */ if(state == CONN_OK) { fcntl(vcn->fd, F_SETOWN, getpid()); } else { close(vcn->fd); } return((int)state); } void rcv_sv_msg(void) { static u_char rcvbuf[SVMSGBUF]; static u_char *rcvptr = (u_char *)&rcvbuf; u_char *dat; register int i; int amount; int segment; int arg; #ifndef O_NONBLOCK int on = 0xff; int off = 0; #endif VMSG *xsv; TMREPORT *tmr; ULIST_ITEM *u; /* * Keep vlock from modifying signal mask state */ is_handler = 1; /* * Set filedesc to nonblocking I/O */ #ifndef O_NONBLOCK ioctl(sconn.fd, FIONBIO, &on); #else arg = fcntl(sconn.fd, F_GETFL, 0); arg |= O_NONBLOCK; fcntl(sconn.fd, F_SETFL, arg); #endif /* * Read in any data waiting */ if((amount = read(sconn.fd, rcvptr, (sizeof(rcvbuf) - (rcvptr - &rcvbuf[0])))) > 0) { rcvptr += amount; } else if(!amount) { /*** Broken pipe ***/ vquit("GASP! Server connection has deceased -- exiting."); } else { switch(errno) { case EINTR: #if !(EWOULDBLOCK == EAGAIN) case EWOULDBLOCK: #endif case EAGAIN: break; default: vsleep(1,0); vquit("Error while reading from socket (%s) -- exiting.%s", strerror(errno), nlstr); break; } } /* * Reset nonblocking I/O on filedesc */ #ifndef O_NONBLOCK ioctl(sconn.fd, FIONBIO, &off); #else arg &= ~O_NONBLOCK; fcntl(sconn.fd, F_SETFL, arg); #endif /* * Process any completed command * packets waiting in the buffer */ xsv = (VMSG *)rcvbuf; amount = (rcvptr - rcvbuf); while(amount >= sizeof(VMSG) && amount >= (segment = (sizeof(VMSG) + ntohl(xsv->len)))) { dat = ((u_char *)xsv + sizeof(VMSG)); switch(ntohl(xsv->cmd)) { case RTCMP_ACK: timestamp(&tmstat.endmark); if(((RTCMP *)dat)->seq > 1) { ((RTCMP *)dat)->seq--; store_tm_value(diff_t(&((RTCMP *)dat)->stamp, &tmstat.endmark)); timestamp(&((RTCMP *)dat)->stamp); snd_serv(CMD_RTCMP, (char *)((RTCMP *)dat), sizeof(RTCMP)); } else { store_tm_value(diff_t(&((RTCMP *)dat)->stamp, &tmstat.endmark)); tmr = report_stat(); cprintf(chat, "\n* %d bytes from %s%s%s (%s%s%s) - round-trip-delay:", (sizeof(RTCMP) + sizeof(VMSG)), S_BOLD, inet_ntoa(vp.sv_ip), S_OFF, S_UL, sconn.host, S_OFF); cprintf(chat, "* (min/avg/max) %s%s%s / %s%s%s / %s%s%s", S_FG_YEL, pr_time(&tmr->_min), S_OFF, S_FG_CYN, pr_time(&tmr->_avg), S_OFF, S_FG_MAG, pr_time(&tmr->_max), S_OFF); clear_tm_stats(); } break; case SERV_MSG: cputnchars(dat, ntohl(xsv->len)); break; case SUBMIT_TOPIC: submit_topic(); break; case WAKEUP: ring_my_bell(dat, ntohl(xsv->len)); break; case NICK_ACK: BCOPY(&vp.tmpnick, vp.nick, sizeof(vp.nick)); alter_status(STAT_NICK, "%s ", vp.nick); vsleep(0,300000); update_status(0); break; case CHAN_ACK: alter_status(STAT_CHAN, "%d ", ntohl(*((signed long *)dat))); uchannel = ntohl(*((signed long *)dat)); vsleep(0,300000); update_status(0); break; case ULIST_CLEAR: if(ulist_base) free(ulist_base); ulist_base = NULL; ulist_cnt = 0; break; case ULIST_ADD: if(ulist_base) { if((u = (ULIST_ITEM *)realloc(ulist_base, sizeof(ULIST_ITEM) * (ulist_cnt + 1))) == NULL) { cprintf(chat, "* Memory reallocation error (%s%s%s)", S_FG_RED, strerror(errno), S_OFF); ulist_base = NULL; ulist_cnt = 0; break; } ulist_base = u; u = ulist_base + ulist_cnt; } else { if((u = (ULIST_ITEM *)malloc(sizeof(ULIST_ITEM))) == NULL) { cprintf(chat, "* Memory allocation error (%s%s%s)", S_FG_RED, strerror(errno), S_OFF); ulist_base = NULL; ulist_cnt = 0; break; } ulist_base = u; ulist_cnt = 0; } BZERO(u->nick, VPNICKSIZE + 1); BCOPY(dat, u->nick, (ntohl(xsv->len) <= VPNICKSIZE) ? ntohl(xsv->len) : VPNICKSIZE); ++ulist_cnt; break; case ULIST_REMOVE: { u_char lookup[VPNICKSIZE+1]; BZERO(lookup, sizeof(lookup)); BCOPY(dat, lookup, (ntohl(xsv->len) > VPNICKSIZE) ? VPNICKSIZE : ntohl(xsv->len)); for(i = 0; i < ulist_cnt; i++) { u = ulist_base + i; if(!strcmp(u->nick, lookup)) { if(i < (ulist_cnt - 1)) memmove((char *)u, (char *)u + sizeof(ULIST_ITEM), (ulist_cnt - (i + 1)) * sizeof(ULIST_ITEM)); if((u = realloc(ulist_base, (ulist_cnt - 1) * sizeof(ULIST_ITEM))) == NULL) { cprintf(chat, "* Memory reallocation error (%s%s%s)", S_FG_RED, strerror(errno), S_OFF); ulist_base = NULL; ulist_cnt = 0; } ulist_base = u; --ulist_cnt; break; } } } break; default: break; } amount -= segment; #if SUPPORT_ODD_ADDRS xsv = (VMSG *)((u_char *)xsv + segment); #else if(amount) memmove(rcvbuf, &rcvbuf[segment], amount); #endif } #if SUPPORT_ODD_ADDRS if((u_char *)xsv > rcvbuf) { if(amount) memmove(rcvbuf, xsv, amount); rcvptr = &rcvbuf[amount]; } #else rcvptr = &rcvbuf[amount]; #endif /* * Release vlock */ is_handler = 0; } void snd_serv(u_short cmd, char *data, size_t siz) { snd_conn(sconn.fd, cmd, data, siz); } void snd_conn(int fd, u_short cmd, char *data, size_t siz) { #if HAVE_SYS_UIO_H struct iovec iov[2]; VMSG svmsg; svmsg.cmd = htonl(cmd); iov[0].iov_base = (char *)&svmsg; iov[0].iov_len = sizeof(VMSG); if(data && siz) { svmsg.len = htonl(siz); iov[1].iov_base = data; iov[1].iov_len = siz; writev(fd, (struct iovec *)&iov, 2); } else { svmsg.len = htonl(0); writev(fd, (struct iovec *)&iov, 1); } #else u_char sndbuf[sizeof(VMSG) + siz]; VMSG *svmsg; char *datbuf; svmsg = (VMSG *)&sndbuf; datbuf = (char *)&sndbuf[sizeof(VMSG)]; svmsg->cmd = htonl(cmd); if(data && siz) { svmsg->len = htonl(siz); BCOPY(data, datbuf, siz); write(fd, (char *)&sndbuf, sizeof(VMSG) + siz); } else { svmsg->len = htonl(0); write(fd, (char *)&sndbuf, sizeof(VMSG)); } #endif } char *iptoname(struct in_addr ip) { #define SIZE 128 static char namebuf[1024]; static char *bufptr; static int index = 0; struct hostent *ht; if(++index > 7) index = 0; bufptr = (char *) &namebuf[(index * SIZE)]; if((ht = gethostbyaddr((char *)&ip, sizeof(ip), AF_INET)) == NULL) { sprintf(bufptr, "%s", inet_ntoa(ip)); } else { strcpy(bufptr, ht->h_name); } return(bufptr); }