sockutil.c

Go to the documentation of this file.
00001 /* Socket utility routines.
00002  *
00003  * (C) 2003-2007 Anope Team
00004  * Contact us at info@anope.org
00005  *
00006  * Please read COPYING and README for further details.
00007  *
00008  * Based on the original code of Epona by Lara.
00009  * Based on the original code of Services by Andy Church. 
00010  * 
00011  * $Id: sockutil.c 1265 2007-08-26 15:33:06Z geniusdex $ 
00012  *
00013  */
00014 
00015 #include "services.h"
00016 
00017 /*************************************************************************/
00018 
00019 static char read_netbuf[NET_BUFSIZE];
00020 static char *read_curpos = read_netbuf; /* Next byte to return */
00021 static char *read_bufend = read_netbuf; /* Next position for data from socket */
00022 static char *const read_buftop = read_netbuf + NET_BUFSIZE;
00023 int32 total_read = 0;
00024 static char write_netbuf[NET_BUFSIZE];
00025 static char *write_curpos = write_netbuf;       /* Next byte to write to socket */
00026 static char *write_bufend = write_netbuf;       /* Next position for data to socket */
00027 static char *const write_buftop = write_netbuf + NET_BUFSIZE;
00028 static int write_fd = -1;
00029 int32 total_written;
00030 static int lastchar = EOF;
00031 
00032 /*************************************************************************/
00033 
00038 int32 read_buffer_len()
00039 {
00040     if (read_bufend >= read_curpos) {
00041         return read_bufend - read_curpos;
00042     } else {
00043         return (read_bufend + NET_BUFSIZE) - read_curpos;
00044     }
00045 }
00046 
00047 /*************************************************************************/
00048 
00056 static int buffered_read(ano_socket_t fd, char *buf, int len)
00057 {
00058     int nread, left = len;
00059     fd_set fds;
00060     struct timeval tv = { 0, 0 };
00061     int errno_save = ano_sockgeterr();
00062 
00063     if (fd < 0) {
00064         ano_sockseterr(SOCKERR_EBADF);
00065         return -1;
00066     }
00067     while (left > 0) {
00068         struct timeval *tvptr = (read_bufend == read_curpos ? NULL : &tv);
00069         FD_ZERO(&fds);
00070         FD_SET(fd, &fds);
00071         while (read_bufend != read_curpos - 1
00072                && !(read_curpos == read_netbuf
00073                     && read_bufend == read_buftop - 1)
00074                && select(fd + 1, &fds, 0, 0, tvptr) == 1) {
00075             int maxread;
00076             tvptr = &tv;        /* don't wait next time */
00077             if (read_bufend < read_curpos)      /* wrapped around? */
00078                 maxread = (read_curpos - 1) - read_bufend;
00079             else if (read_curpos == read_netbuf)
00080                 maxread = read_buftop - read_bufend - 1;
00081             else
00082                 maxread = read_buftop - read_bufend;
00083             nread = ano_sockread(fd, read_bufend, maxread);
00084             errno_save = ano_sockgeterr();
00085             if (debug >= 3)
00086                 alog("debug: buffered_read wanted %d, got %d", maxread,
00087                      nread);
00088             if (nread <= 0)
00089                 break;
00090             read_bufend += nread;
00091             if (read_bufend == read_buftop)
00092                 read_bufend = read_netbuf;
00093         }
00094         if (read_curpos == read_bufend) /* No more data on socket */
00095             break;
00096         /* See if we can gobble up the rest of the buffer. */
00097         if (read_curpos + left >= read_buftop && read_bufend < read_curpos) {
00098             nread = read_buftop - read_curpos;
00099             memcpy(buf, read_curpos, nread);
00100             buf += nread;
00101             left -= nread;
00102             read_curpos = read_netbuf;
00103         }
00104         /* Now everything we need is in a single chunk at read_curpos. */
00105         if (read_bufend > read_curpos && read_bufend - read_curpos < left)
00106             nread = read_bufend - read_curpos;
00107         else
00108             nread = left;
00109         if (nread) {
00110             memcpy(buf, read_curpos, nread);
00111             buf += nread;
00112             left -= nread;
00113             read_curpos += nread;
00114         }
00115     }
00116     total_read += len - left;
00117     if (debug >= 4) {
00118         alog("debug: buffered_read(%d,%p,%d) returning %d",
00119              fd, buf, len, len - left);
00120     }
00121     ano_sockseterr(errno_save);
00122     return len - left;
00123 }
00124 
00125 /*************************************************************************/
00126 
00133 static int buffered_read_one(ano_socket_t fd)
00134 {
00135     int nread;
00136     fd_set fds;
00137     struct timeval tv = { 0, 0 };
00138     char c;
00139     struct timeval *tvptr = (read_bufend == read_curpos ? NULL : &tv);
00140     int errno_save = ano_sockgeterr();
00141 
00142     if (fd < 0) {
00143         ano_sockseterr(SOCKERR_EBADF);
00144         return -1;
00145     }
00146     FD_ZERO(&fds);
00147     FD_SET(fd, &fds);
00148     while (read_bufend != read_curpos - 1
00149            && !(read_curpos == read_netbuf
00150                 && read_bufend == read_buftop - 1)
00151            && select(fd + 1, &fds, 0, 0, tvptr) == 1) {
00152         int maxread;
00153         tvptr = &tv;            /* don't wait next time */
00154         if (read_bufend < read_curpos)  /* wrapped around? */
00155             maxread = (read_curpos - 1) - read_bufend;
00156         else if (read_curpos == read_netbuf)
00157             maxread = read_buftop - read_bufend - 1;
00158         else
00159             maxread = read_buftop - read_bufend;
00160         nread = ano_sockread(fd, read_bufend, maxread);
00161         errno_save = ano_sockgeterr();
00162         if (debug >= 3)
00163             alog("debug: buffered_read_one wanted %d, got %d", maxread,
00164                  nread);
00165         if (nread <= 0)
00166             break;
00167         read_bufend += nread;
00168         if (read_bufend == read_buftop)
00169             read_bufend = read_netbuf;
00170     }
00171     if (read_curpos == read_bufend) {   /* No more data on socket */
00172         if (debug >= 4)
00173             alog("debug: buffered_read_one(%d) returning %d", fd, EOF);
00174         ano_sockseterr(errno_save);
00175         return EOF;
00176     }
00177     c = *read_curpos++;
00178     if (read_curpos == read_buftop)
00179         read_curpos = read_netbuf;
00180     total_read++;
00181     if (debug >= 4)
00182         alog("debug: buffered_read_one(%d) returning %d", fd, c);
00183     return (int) c & 0xFF;
00184 }
00185 
00186 /*************************************************************************/
00187 
00192 int32 write_buffer_len()
00193 {
00194     if (write_bufend >= write_curpos) {
00195         return write_bufend - write_curpos;
00196     } else {
00197         return (write_bufend + NET_BUFSIZE) - write_curpos;
00198     }
00199 }
00200 
00201 /*************************************************************************/
00202 
00209 static int flush_write_buffer(int wait)
00210 {
00211     fd_set fds;
00212     struct timeval tv = { 0, 0 };
00213     int errno_save = ano_sockgeterr();
00214 
00215     if (write_bufend == write_curpos || write_fd == -1)
00216         return 0;
00217     FD_ZERO(&fds);
00218     FD_SET(write_fd, &fds);
00219     if (select(write_fd + 1, 0, &fds, 0, wait ? NULL : &tv) == 1) {
00220         int maxwrite, nwritten;
00221         if (write_curpos > write_bufend)        /* wrapped around? */
00222             maxwrite = write_buftop - write_curpos;
00223         else if (write_bufend == write_netbuf)
00224             maxwrite = write_buftop - write_curpos - 1;
00225         else
00226             maxwrite = write_bufend - write_curpos;
00227         nwritten = ano_sockwrite(write_fd, write_curpos, maxwrite);
00228         errno_save = ano_sockgeterr();
00229         if (debug >= 3)
00230             alog("debug: flush_write_buffer wanted %d, got %d", maxwrite,
00231                  nwritten);
00232         if (nwritten > 0) {
00233             write_curpos += nwritten;
00234             if (write_curpos == write_buftop)
00235                 write_curpos = write_netbuf;
00236             total_written += nwritten;
00237             return nwritten;
00238         }
00239     }
00240     ano_sockseterr(errno_save);
00241     return 0;
00242 }
00243 
00244 /*************************************************************************/
00245 
00253 static int buffered_write(ano_socket_t fd, char *buf, int len)
00254 {
00255     int nwritten, left = len;
00256     int errno_save = ano_sockgeterr();
00257 
00258     if (fd < 0) {
00259         errno = EBADF;
00260         return -1;
00261     }
00262     write_fd = fd;
00263 
00264     while (left > 0) {
00265 
00266         /* Don't try putting anything in the buffer if it's full. */
00267         if (write_curpos != write_bufend + 1 &&
00268             (write_curpos != write_netbuf
00269              || write_bufend != write_buftop - 1)) {
00270             /* See if we need to write up to the end of the buffer. */
00271             if (write_bufend + left >= write_buftop
00272                 && write_curpos <= write_bufend) {
00273                 nwritten = write_buftop - write_bufend;
00274                 memcpy(write_bufend, buf, nwritten);
00275                 buf += nwritten;
00276                 left -= nwritten;
00277                 write_bufend = write_netbuf;
00278             }
00279             /* Now we can copy a single chunk to write_bufend. */
00280             if (write_curpos > write_bufend
00281                 && write_curpos - write_bufend - 1 < left)
00282                 nwritten = write_curpos - write_bufend - 1;
00283             else
00284                 nwritten = left;
00285             if (nwritten) {
00286                 memcpy(write_bufend, buf, nwritten);
00287                 buf += nwritten;
00288                 left -= nwritten;
00289                 write_bufend += nwritten;
00290             }
00291         }
00292 
00293         /* Now write to the socket as much as we can. */
00294         if (write_curpos == write_bufend + 1 ||
00295             (write_curpos == write_netbuf
00296              && write_bufend == write_buftop - 1))
00297             flush_write_buffer(1);
00298         else
00299             flush_write_buffer(0);
00300         errno_save = errno;
00301         if (write_curpos == write_bufend + 1 ||
00302             (write_curpos == write_netbuf
00303              && write_bufend == write_buftop - 1)) {
00304             /* Write failed on full buffer */
00305             break;
00306         }
00307     }
00308 
00309     if (debug >= 4) {
00310         alog("debug: buffered_write(%d,%p,%d) returning %d",
00311              fd, buf, len, len - left);
00312     }
00313     ano_sockseterr(errno_save);
00314     return len - left;
00315 }
00316 
00317 
00318 /*************************************************************************/
00319 
00328 #if 0
00329 static int buffered_write_one(int c, ano_socket_t fd)
00330 {
00331     struct timeval tv = { 0, 0 };
00332 
00333     if (fd < 0) {
00334         ano_sockseterr(SOCKERR_EBADF);
00335         return -1;
00336     }
00337     write_fd = fd;
00338 
00339     /* Try to flush the buffer if it's full. */
00340     if (write_curpos == write_bufend + 1 ||
00341         (write_curpos == write_netbuf
00342          && write_bufend == write_buftop - 1)) {
00343         flush_write_buffer(1);
00344         if (write_curpos == write_bufend + 1 ||
00345             (write_curpos == write_netbuf
00346              && write_bufend == write_buftop - 1)) {
00347             /* Write failed */
00348             if (debug >= 4)
00349                 alog("debug: buffered_write_one(%d) returning %d", fd,
00350                      EOF);
00351             return EOF;
00352         }
00353     }
00354 
00355     /* Write the character. */
00356     *write_bufend++ = c;
00357     if (write_bufend == write_buftop)
00358         write_bufend = write_netbuf;
00359 
00360     /* Move it to the socket if we can. */
00361     flush_write_buffer(0);
00362 
00363     if (debug >= 4)
00364         alog("debug: buffered_write_one(%d) returning %d", fd, c);
00365     return (int) c & 0xFF;
00366 }
00367 #endif                          /* 0 */
00368 
00369 /*************************************************************************/
00370 
00376 int sgetc(ano_socket_t s)
00377 {
00378     int c;
00379 
00380     if (lastchar != EOF) {
00381         c = lastchar;
00382         lastchar = EOF;
00383         return c;
00384     }
00385     return buffered_read_one(s);
00386 }
00387 
00388 /*************************************************************************/
00389 
00396 int sungetc(int c, int s)
00397 {
00398     return lastchar = c;
00399 }
00400 
00401 /*************************************************************************/
00402 
00411 char *sgets(char *buf, int len, ano_socket_t s)
00412 {
00413     int c = 0;
00414     struct timeval tv;
00415     fd_set fds;
00416     char *ptr = buf;
00417 
00418     flush_write_buffer(0);
00419 
00420     if (len == 0)
00421         return NULL;
00422     FD_SET(s, &fds);
00423     tv.tv_sec = ReadTimeout;
00424     tv.tv_usec = 0;
00425     while (read_buffer_len() == 0 &&
00426            (c = select(s + 1, &fds, NULL, NULL, &tv)) < 0) {
00427         if (ano_sockgeterr() != EINTR)
00428             break;
00429         flush_write_buffer(0);
00430     }
00431     if (read_buffer_len() == 0 && c == 0)
00432         return (char *) -1;
00433     c = sgetc(s);
00434     while (--len && (*ptr++ = c) != '\n' && (c = sgetc(s)) >= 0);
00435     if (c < 0)
00436         return NULL;
00437     *ptr = 0;
00438     return buf;
00439 }
00440 
00441 /*************************************************************************/
00442 
00451 char *sgets2(char *buf, int len, ano_socket_t s)
00452 {
00453     char *str = sgets(buf, len, s);
00454 
00455     if (!str || str == (char *) -1)
00456         return str;
00457     str = buf + strlen(buf) - 1;
00458     if (*str == '\n')
00459         *str-- = 0;
00460     if (*str == '\r')
00461         *str = 0;
00462     return buf;
00463 }
00464 
00465 /*************************************************************************/
00466 
00475 int sread(ano_socket_t s, char *buf, int len)
00476 {
00477     return buffered_read(s, buf, len);
00478 }
00479 
00480 /*************************************************************************/
00481 
00488 int sputs(char *str, ano_socket_t s)
00489 {
00490     return buffered_write(s, str, strlen(str));
00491 }
00492 
00493 /*************************************************************************/
00494 
00502 int sockprintf(ano_socket_t s, char *fmt, ...)
00503 {
00504     va_list args;
00505     char buf[16384];            /* Really huge, to try and avoid truncation */
00506     int value;
00507 
00508     va_start(args, fmt);
00509     value = buffered_write(s, buf, vsnprintf(buf, sizeof(buf), fmt, args));
00510     va_end(args);
00511     return value;
00512 }
00513 
00514 /*************************************************************************/
00515 
00516 #if !HAVE_GETHOSTBYNAME
00517 
00524 static char *pack_ip(const char *ipaddr)
00525 {
00526     static char ipbuf[4];
00527     int tmp[4], i;
00528 
00529     if (sscanf(ipaddr, "%d.%d.%d.%d", &tmp[0], &tmp[1], &tmp[2], &tmp[3])
00530         != 4)
00531         return NULL;
00532     for (i = 0; i < 4; i++) {
00533         if (tmp[i] < 0 || tmp[i] > 255)
00534             return NULL;
00535         ipbuf[i] = tmp[i];
00536     }
00537     return ipbuf;
00538 }
00539 
00540 #endif
00541 
00542 /*************************************************************************/
00543 
00553 int conn(const char *host, int port, const char *lhost, int lport)
00554 {
00555 #if HAVE_GETHOSTBYNAME
00556     struct hostent *hp;
00557 #else
00558     char *addr;
00559 #endif
00560     struct sockaddr_in sa, lsa;
00561     ano_socket_t sock;
00562 
00563     memset(&lsa, 0, sizeof(lsa));
00564     if (lhost) {
00565 #if HAVE_GETHOSTBYNAME
00566         if ((hp = gethostbyname(lhost)) != NULL) {
00567             memcpy((char *) &lsa.sin_addr, hp->h_addr, hp->h_length);
00568             lsa.sin_family = hp->h_addrtype;
00569 #else
00570         if (addr = pack_ip(lhost)) {
00571             memcpy((char *) &lsa.sin_addr, addr, 4);
00572             lsa.sin_family = AF_INET;
00573 #endif
00574         } else {
00575             lhost = NULL;
00576         }
00577     }
00578     if (lport)
00579         lsa.sin_port = htons((unsigned short) lport);
00580 
00581     memset(&sa, 0, sizeof(sa));
00582 #if HAVE_GETHOSTBYNAME
00583     if (!(hp = gethostbyname(host)))
00584         return -1;
00585     memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
00586     sa.sin_family = hp->h_addrtype;
00587 #else
00588     if (!(addr = pack_ip(host))) {
00589         alog("conn(): `%s' is not a valid IP address", host);
00590         ano_sockseterr(SOCKERR_EINVAL);
00591         return -1;
00592     }
00593     memcpy((char *) &sa.sin_addr, addr, 4);
00594     sa.sin_family = AF_INET;
00595 #endif
00596     sa.sin_port = htons((unsigned short) port);
00597 
00598     if ((sock = socket(sa.sin_family, SOCK_STREAM, 0)) < 0)
00599         return -1;
00600 
00601     if ((lhost || lport)
00602         && bind(sock, (struct sockaddr *) &lsa, sizeof(lsa)) < 0) {
00603         int errno_save = ano_sockgeterr();
00604         ano_sockclose(sock);
00605         ano_sockseterr(errno_save);
00606         return -1;
00607     }
00608 
00609     if (connect(sock, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
00610         int errno_save = ano_sockgeterr();
00611         ano_sockclose(sock);
00612         ano_sockseterr(errno_save);
00613         return -1;
00614     }
00615 
00616     return sock;
00617 }
00618 
00619 /*************************************************************************/
00620 
00626 void disconn(ano_socket_t s)
00627 {
00628     shutdown(s, 2);
00629     ano_sockclose(s);
00630 }
00631 
00632 /*************************************************************************/
00633 /* Windows support functions */
00634 
00635 #ifdef _WIN32
00636 /* Microsoft makes things nice and fun for us! */
00637 struct u_WSA_errors {
00638     int error_code;
00639     char *error_string;
00640 };
00641 
00642 /* Must be sorted ascending by error code */
00643 struct u_WSA_errors WSAErrors[] = {
00644     {WSAEINTR, "Interrupted system call"},
00645     {WSAEBADF, "Bad file number"},
00646     {WSAEACCES, "Permission denied"},
00647     {WSAEFAULT, "Bad address"},
00648     {WSAEINVAL, "Invalid argument"},
00649     {WSAEMFILE, "Too many open sockets"},
00650     {WSAEWOULDBLOCK, "Operation would block"},
00651     {WSAEINPROGRESS, "Operation now in progress"},
00652     {WSAEALREADY, "Operation already in progress"},
00653     {WSAENOTSOCK, "Socket operation on non-socket"},
00654     {WSAEDESTADDRREQ, "Destination address required"},
00655     {WSAEMSGSIZE, "Message too long"},
00656     {WSAEPROTOTYPE, "Protocol wrong type for socket"},
00657     {WSAENOPROTOOPT, "Bad protocol option"},
00658     {WSAEPROTONOSUPPORT, "Protocol not supported"},
00659     {WSAESOCKTNOSUPPORT, "Socket type not supported"},
00660     {WSAEOPNOTSUPP, "Operation not supported on socket"},
00661     {WSAEPFNOSUPPORT, "Protocol family not supported"},
00662     {WSAEAFNOSUPPORT, "Address family not supported"},
00663     {WSAEADDRINUSE, "Address already in use"},
00664     {WSAEADDRNOTAVAIL, "Can't assign requested address"},
00665     {WSAENETDOWN, "Network is down"},
00666     {WSAENETUNREACH, "Network is unreachable"},
00667     {WSAENETRESET, "Net connection reset"},
00668     {WSAECONNABORTED, "Software caused connection abort"},
00669     {WSAECONNRESET, "Connection reset by peer"},
00670     {WSAENOBUFS, "No buffer space available"},
00671     {WSAEISCONN, "Socket is already connected"},
00672     {WSAENOTCONN, "Socket is not connected"},
00673     {WSAESHUTDOWN, "Can't send after socket shutdown"},
00674     {WSAETOOMANYREFS, "Too many references, can't splice"},
00675     {WSAETIMEDOUT, "Connection timed out"},
00676     {WSAECONNREFUSED, "Connection refused"},
00677     {WSAELOOP, "Too many levels of symbolic links"},
00678     {WSAENAMETOOLONG, "File name too long"},
00679     {WSAEHOSTDOWN, "Host is down"},
00680     {WSAEHOSTUNREACH, "No route to host"},
00681     {WSAENOTEMPTY, "Directory not empty"},
00682     {WSAEPROCLIM, "Too many processes"},
00683     {WSAEUSERS, "Too many users"},
00684     {WSAEDQUOT, "Disc quota exceeded"},
00685     {WSAESTALE, "Stale NFS file handle"},
00686     {WSAEREMOTE, "Too many levels of remote in path"},
00687     {WSASYSNOTREADY, "Network subsystem is unavailable"},
00688     {WSAVERNOTSUPPORTED, "Winsock version not supported"},
00689     {WSANOTINITIALISED, "Winsock not yet initialized"},
00690     {WSAHOST_NOT_FOUND, "Host not found"},
00691     {WSATRY_AGAIN, "Non-authoritative host not found"},
00692     {WSANO_RECOVERY, "Non-recoverable errors"},
00693     {WSANO_DATA, "Valid name, no data record of requested type"},
00694     {WSAEDISCON, "Graceful disconnect in progress"},
00695 #ifdef WSASYSCALLFAILURE
00696     {WSASYSCALLFAILURE, "System call failure"},
00697 #endif
00698     {0, NULL}
00699 };
00700 
00701 char *ano_sockstrerror(int error)
00702 {
00703     static char unkerr[64];
00704     int start = 0;
00705     int stop = sizeof(WSAErrors) / sizeof(WSAErrors[0]) - 1;
00706     int mid;
00707 
00708     /* Microsoft decided not to use sequential numbers for the error codes,
00709      * so we can't just use the array index for the code. But, at least
00710      * use a binary search to make it as fast as possible. 
00711      */
00712     while (start <= stop) {
00713         mid = (start + stop) / 2;
00714         if (WSAErrors[mid].error_code > error)
00715             stop = mid - 1;
00716 
00717         else if (WSAErrors[mid].error_code < error)
00718             start = mid + 1;
00719         else
00720             return WSAErrors[mid].error_string;
00721     }
00722     sprintf(unkerr, "Unknown Error: %d", error);
00723     return unkerr;
00724 }
00725 
00726 int ano_socksetnonb(ano_socket_t fd)
00727 {
00728     u_long i = 1;
00729     return (!ioctlsocket(fd, FIONBIO, &i) ? -1 : 1);
00730 }
00731 #endif

Generated on Sun Dec 30 09:26:53 2007 for Anope by  doxygen 1.5.1-20070107