/* * Unreal Internet Relay Chat Daemon, src/socket.c * Copyright (C) 1990 Jarkko Oikarinen and * University of Oulu, Computing Center * * 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "struct.h" #include "common.h" #include "sys.h" #include "h.h" #include #include "inet.h" #ifndef _WIN32 extern int errno; /* ...seems that errno.h doesn't define this everywhere */ #endif #include #ifndef _WIN32 #include #endif #ifdef DEBUGMODE int writecalls = 0, writeb[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; #endif /* ** deliver_it ** Attempt to send a sequence of bytes to the connection. ** Returns ** ** < 0 Some fatal error occurred, (but not EWOULDBLOCK). ** This return is a request to close the socket and ** clean up the link. ** ** >= 0 No real error occurred, returns the number of ** bytes actually transferred. EWOULDBLOCK and other ** possibly similar conditions should be mapped to ** zero return. Upper level routine will have to ** decide what to do with those unwritten bytes... ** ** *NOTE* alarm calls have been preserved, so this should ** work equally well whether blocking or non-blocking ** mode is used... ** ** *NOTE* I nuked 'em. At the load of current ircd servers ** you can't run with stuff that blocks. And we don't. */ int deliver_it(aClient *cptr, char *str, int len) { int retval; aClient *acpt = cptr->listener; #ifdef DEBUGMODE writecalls++; #endif #ifdef VMS retval = netwrite(cptr->fd, str, len); #else if (IsDead(cptr) || (!IsServer(cptr) && !IsPerson(cptr) && !IsHandshake(cptr) #ifdef USE_SSL && !IsSSLHandshake(cptr) #endif && !IsUnknown(cptr))) { str[len] = '\0'; sendto_ops ("* * * DEBUG ERROR * * * !!! Calling deliver_it() for %s, status %d %s, with message: %s", cptr->name, cptr->status, IsDead(cptr) ? "DEAD" : "", str); return -1; } #ifdef USE_SSL if (cptr->flags & FLAGS_SSL) retval = ircd_SSL_write(cptr, str, len); else #endif retval = send(cptr->fd, str, len, 0); /* ** Convert WOULDBLOCK to a return of "0 bytes moved". This ** should occur only if socket was non-blocking. Note, that ** all is Ok, if the 'write' just returns '0' instead of an ** error and errno=EWOULDBLOCK. ** ** ...now, would this work on VMS too? --msa */ # ifndef _WIN32 if (retval < 0 && (errno == EWOULDBLOCK || errno == EAGAIN || errno == ENOBUFS)) # else if (retval < 0 && (WSAGetLastError() == WSAEWOULDBLOCK || WSAGetLastError() == WSAENOBUFS)) # endif { retval = 0; SetBlocked(cptr); } else if (retval > 0) { ClearBlocked(cptr); } #endif #ifdef DEBUGMODE if (retval < 0) { writeb[0]++; Debug((DEBUG_ERROR, "write error (%s) to %s", STRERROR(ERRNO), cptr->name)); } else if (retval == 0) writeb[1]++; else if (retval < 16) writeb[2]++; else if (retval < 32) writeb[3]++; else if (retval < 64) writeb[4]++; else if (retval < 128) writeb[5]++; else if (retval < 256) writeb[6]++; else if (retval < 512) writeb[7]++; else if (retval < 1024) writeb[8]++; else writeb[9]++; #endif if (retval > 0) { cptr->sendB += retval; me.sendB += retval; if (cptr->sendB > 1023) { cptr->sendK += (cptr->sendB >> 10); cptr->sendB &= 0x03ff; /* 2^10 = 1024, 3ff = 1023 */ } if (acpt != &me) { acpt->sendB += retval; if (acpt->sendB > 1023) { acpt->sendK += (acpt->sendB >> 10); acpt->sendB &= 0x03ff; } } if (me.sendB > 1023) { me.sendK += (me.sendB >> 10); me.sendB &= 0x03ff; } } return (retval); } char *Inet_si2pB(struct SOCKADDR_IN *sin, char *buf, int sz) { #ifdef INET6 u_char *cp; /* Hack to rerepresent ::ffff:x.x.x.x as x.x.x.x */ cp = (u_char *)sin->SIN_ADDR.s6_addr; if (cp[0] == 0 && cp[1] == 0 && cp[2] == 0 && cp[3] == 0 && cp[4] == 0 && cp[5] == 0 && cp[6] == 0 && cp[7] == 0 && cp[8] == 0 && cp[9] == 0 && cp[10] == 0xff && cp[11] == 0xff) { (void)ircsprintf(buf, "%u.%u.%u.%u", (u_int)(cp[12]), (u_int)(cp[13]), (u_int)(cp[14]), (u_int)(cp[15])); return (buf); } else return ((char *)inetntop(AFINET, &sin->SIN_ADDR.s6_addr, buf, sz)); #else return ((char *)inet_ntoa(sin->SIN_ADDR)); #endif } char *Inet_si2p(struct SOCKADDR_IN *sin) { static char buf[256]; return (Inet_si2pB(sin, buf, sizeof(buf))); } /* May return NULL if inet_ntop() fails. */ char *Inet_ia2p(struct IN_ADDR *ia) { #ifndef INET6 return ((char *)inet_ntoa(*ia)); #else /* Hack to make proper addresses */ static char buf[256]; u_char *cp; cp = (u_char *)((struct IN_ADDR *)ia)->s6_addr; if (cp[0] == 0 && cp[1] == 0 && cp[2] == 0 && cp[3] == 0 && cp[4] == 0 && cp[5] == 0 && cp[6] == 0 && cp[7] == 0 && cp[8] == 0 && cp[9] == 0 && cp[10] == 0xff && cp[11] == 0xff) { (void)ircsprintf(buf, "%u.%u.%u.%u", (u_int)(cp[12]), (u_int)(cp[13]), (u_int)(cp[14]), (u_int)(cp[15])); return (buf); } else return((char *)inet_ntop(AFINET, ia, buf, sizeof(buf))); #endif } char *Inet_ia2pNB(struct IN_ADDR *ia, int compressed) { #ifndef INET6 return ((char *)inet_ntoa(*ia)); #else static char buf[256]; if (compressed) return ((char *)inet_ntop(AFINET, ia, buf, sizeof(buf))); else return ((char *)inetntop(AFINET, ia, buf, sizeof(buf))); #endif }