⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ne_socket.c

📁 linux subdivision ying gai ke yi le ba
💻 C
📖 第 1 页 / 共 2 页
字号:
/*    socket handling routines   Copyright (C) 1998-2004, Joe Orton <joe@manyfish.co.uk>,    Copyright (C) 1999-2000 Tommi Komulainen <Tommi.Komulainen@iki.fi>   This library is free software; you can redistribute it and/or   modify it under the terms of the GNU Library General Public   License as published by the Free Software Foundation; either   version 2 of the License, or (at your option) any later version.      This library 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   Library General Public License for more details.   You should have received a copy of the GNU Library General Public   License along with this library; if not, write to the Free   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,   MA 02111-1307, USA*//*  portions were originally under GPL in Mutt, http://www.mutt.org/  Relicensed under LGPL for neon, http://www.webdav.org/neon/*/#include "config.h"#ifdef __hpux/* pick up hstrerror */#define _XOPEN_SOURCE_EXTENDED 1/* don't use the broken getaddrinfo shipped in HP-UX 11.11 */#ifdef USE_GETADDRINFO#undef USE_GETADDRINFO#endif#endif#include <sys/types.h>#ifdef HAVE_SYS_TIME_H#include <sys/time.h>#endif#include <sys/stat.h>#ifdef HAVE_SYS_SELECT_H#include <sys/select.h>#endif#ifdef HAVE_SYS_SOCKET_H#include <sys/socket.h>#endif#ifdef HAVE_NETINET_IN_H#include <netinet/in.h>#endif#ifdef HAVE_NETINET_TCP_H#include <netinet/tcp.h>#endif#ifdef HAVE_ARPA_INET_H#include <arpa/inet.h>#endif#ifdef HAVE_NETDB_H#include <netdb.h>#endif#ifdef WIN32#include <winsock2.h>#include <stddef.h>#endif#if defined(NEON_SSL) && defined(HAVE_LIMITS_H)#include <limits.h> /* for INT_MAX */#endif#ifdef HAVE_STRING_H#include <string.h>#endif#ifdef HAVE_STRINGS_H#include <strings.h>#endif #ifdef HAVE_UNISTD_H#include <unistd.h>#endif#ifdef HAVE_SIGNAL_H#include <signal.h>#endif#ifdef HAVE_ERRNO_H#include <errno.h>#endif#ifdef HAVE_STDLIB_H#include <stdlib.h>#endif#ifdef HAVE_SOCKS_H#include <socks.h>#endif#ifdef NEON_SSL#include <openssl/ssl.h>#include <openssl/err.h>#include <openssl/pkcs12.h> /* for PKCS12_PBE_add */#include <openssl/rand.h>#include "ne_privssl.h"#endif#include "ne_i18n.h"#include "ne_utils.h"#include "ne_string.h"#define NE_INET_ADDR_DEFINED/* A slightly ugly hack: change the ne_inet_addr definition to be the * real address type used.  The API only exposes ne_inet_addr as a * pointer to an opaque object, so this should be well-defined * behaviour.  It avoids the hassle of a real wrapper ne_inet_addr * structure, or losing type-safety by using void *. */#ifdef USE_GETADDRINFOtypedef struct addrinfo ne_inet_addr;/* To avoid doing AAAA queries unless absolutely necessary, either use * AI_ADDRCONFIG where available, or a run-time check for working IPv6 * support; the latter is only known to work on Linux. */#if !defined(USE_GAI_ADDRCONFIG) && defined(__linux__)#define USE_CHECK_IPV6#endif#elsetypedef struct in_addr ne_inet_addr;#endif#include "ne_socket.h"#include "ne_alloc.h"#if defined(__BEOS__) && !defined(BONE_VERSION)/* pre-BONE */#define ne_write(a,b,c) send(a,b,c,0)#define ne_read(a,b,c) recv(a,b,c,0)#define ne_close(s) closesocket(s)#define ne_errno errno#elif defined(WIN32)#define ne_write(a,b,c) send(a,b,c,0)#define ne_read(a,b,c) recv(a,b,c,0)#define ne_close(s) closesocket(s)#define ne_errno WSAGetLastError()#else /* really Unix! */#define ne_write(a,b,c) write(a,b,c)#define ne_read(a,b,c) read(a,b,c)#define ne_close(s) close(s)#define ne_errno errno#endif#ifdef WIN32#define NE_ISRESET(e) ((e) == WSAECONNABORTED || (e) == WSAETIMEDOUT || \                       (e) == WSAECONNRESET || (e) == WSAENETRESET)#define NE_ISCLOSED(e) ((e) == WSAESHUTDOWN || (e) == WSAENOTCONN)#define NE_ISINTR(e) (0)#else /* Unix */#define NE_ISRESET(e) ((e) == ECONNRESET)#define NE_ISCLOSED(e) ((e) == EPIPE)#define NE_ISINTR(e) ((e) == EINTR)#endif/* Socket read timeout */#define SOCKET_READ_TIMEOUT 120/* Critical I/O functions on a socket: useful abstraction for easily * handling SSL I/O alongside raw socket I/O. */struct iofns {    /* Read up to 'len' bytes into 'buf' from socket.  Return <0 on     * error or EOF, or >0; number of bytes read. */    ssize_t (*read)(ne_socket *s, char *buf, size_t len);    /* Write exactly 'len' bytes from 'buf' to socket.  Return zero on     * success, <0 on error. */    ssize_t (*write)(ne_socket *s, const char *buf, size_t len);    /* Wait up to 'n' seconds for socket to become readable.  Returns     * 0 when readable, otherwise NE_SOCK_TIMEOUT or NE_SOCK_ERROR. */    int (*readable)(ne_socket *s, int n);};struct ne_socket_s {    int fd;    char error[200];    void *progress_ud;    int rdtimeout; /* read timeout. */    const struct iofns *ops;#ifdef NEON_SSL    ne_ssl_socket ssl;#endif    /* The read buffer: ->buffer stores byte which have been read; as     * these are consumed and passed back to the caller, bufpos     * advances through ->buffer.  ->bufavail gives the number of     * bytes which remain to be consumed in ->buffer (from ->bufpos),     * and is hence always <= RDBUFSIZ. */#define RDBUFSIZ 4096    char buffer[RDBUFSIZ];    char *bufpos;    size_t bufavail;};/* ne_sock_addr represents an Internet address. */struct ne_sock_addr_s {#ifdef USE_GETADDRINFO    struct addrinfo *result, *cursor;#else    struct in_addr *addrs;    size_t cursor, count;#endif    int errnum;};/* set_error: set socket error string to 'str'. */#define set_error(s, str) ne_strnzcpy((s)->error, (str), sizeof (s)->error)/* set_strerror: set socket error to system error string for 'errnum' */#ifdef WIN32/* Print system error message to given buffer. */static void print_error(int errnum, char *buffer, size_t buflen){    if (FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM                       | FORMAT_MESSAGE_IGNORE_INSERTS,                       NULL, (DWORD) errnum, 0,                        buffer, buflen, NULL) == 0)        ne_snprintf(buffer, buflen, "Socket error %d", errnum);}#define set_strerror(s, e) print_error((e), (s)->error, sizeof (s)->error)#else /* not WIN32 */#define set_strerror(s, e) ne_strerror((e), (s)->error, sizeof (s)->error)#endif#ifdef NEON_SSL/* Initialize SSL library. */static void init_ssl(void){    SSL_load_error_strings();    SSL_library_init();    PKCS12_PBE_add();  /* ### not sure why this is needed. */}/* Seed the SSL PRNG, if necessary; returns non-zero on failure. */static int seed_ssl_prng(void){    /* Check whether the PRNG has already been seeded. */    if (RAND_status() == 1)	return 0;#ifdef EGD_PATH    NE_DEBUG(NE_DBG_SOCKET, "Seeding PRNG from " EGD_PATH "...\n");    if (RAND_egd(EGD_PATH) != -1)	return 0;#elif defined(ENABLE_EGD)    {	static const char *paths[] = { "/var/run/egd-pool", "/dev/egd-pool",				       "/etc/egd-pool", "/etc/entropy" };	size_t n;	for (n = 0; n < sizeof(paths) / sizeof(char *); n++) {	    NE_DEBUG(NE_DBG_SOCKET, "Seeding PRNG from %s...\n", paths[n]);	    if (RAND_egd(paths[n]) != -1)		return 0;	}    }#endif /* EGD_PATH */    NE_DEBUG(NE_DBG_SOCKET, "No entropy source found; could not seed PRNG.\n");    return -1;}#endif /* NEON_SSL */#ifdef USE_CHECK_IPV6static int ipv6_disabled = 0;/* On Linux kernels, IPv6 is typically built as a loadable module, and * socket(AF_INET6, ...) will fail if this module is not loaded, so * the slow AAAA lookups can be avoided for this common case. */static void init_ipv6(void){    int fd = socket(AF_INET6, SOCK_STREAM, 0);        if (fd < 0)        ipv6_disabled = 1;    else        close(fd);}#else#define ipv6_disabled (0)#endifstatic int init_result = 0;int ne_sock_init(void){#ifdef WIN32    WORD wVersionRequested;    WSADATA wsaData;    int err;#endif    if (init_result > 0) 	return 0;    else if (init_result < 0)	return -1;#ifdef WIN32        wVersionRequested = MAKEWORD(2, 2);        err = WSAStartup(wVersionRequested, &wsaData);    if (err != 0) {	init_result = -1;	return -1;    }#endif#ifdef NEON_SOCKS    SOCKSinit("neon");#endif#if defined(HAVE_SIGNAL) && defined(SIGPIPE)    (void) signal(SIGPIPE, SIG_IGN);#endif#ifdef USE_CHECK_IPV6    init_ipv6();#endif#ifdef NEON_SSL    init_ssl();#endif    init_result = 1;    return 0;}void ne_sock_exit(void){#ifdef WIN32    WSACleanup();#endif    init_result = 0;}int ne_sock_block(ne_socket *sock, int n){    if (sock->bufavail)	return 0;    return sock->ops->readable(sock, n);}/* Cast address object AD to type 'sockaddr_TY' */ #define SACAST(ty, ad) ((struct sockaddr_##ty *)(ad))#define SOCK_ERR(x) do { ssize_t _sock_err = (x); \if (_sock_err < 0) return _sock_err; } while(0)ssize_t ne_sock_read(ne_socket *sock, char *buffer, size_t buflen){    ssize_t bytes;#if 0    NE_DEBUG(NE_DBG_SOCKET, "buf: at %d, %d avail [%s]\n", 	     sock->bufpos - sock->buffer, sock->bufavail, sock->bufpos);#endif    if (sock->bufavail > 0) {	/* Deliver buffered data. */	if (buflen > sock->bufavail)	    buflen = sock->bufavail;	memcpy(buffer, sock->bufpos, buflen);	sock->bufpos += buflen;	sock->bufavail -= buflen;	return buflen;    } else if (buflen >= sizeof sock->buffer) {	/* No need for read buffer. */	return sock->ops->read(sock, buffer, buflen);    } else {	/* Fill read buffer. */	bytes = sock->ops->read(sock, sock->buffer, sizeof sock->buffer);	if (bytes <= 0)	    return bytes;	if (buflen > (size_t)bytes)	    buflen = bytes;	memcpy(buffer, sock->buffer, buflen);	sock->bufpos = sock->buffer + buflen;	sock->bufavail = bytes - buflen;	return buflen;     }}ssize_t ne_sock_peek(ne_socket *sock, char *buffer, size_t buflen){    ssize_t bytes;        if (sock->bufavail) {	/* just return buffered data. */	bytes = sock->bufavail;    } else {	/* fill the buffer. */	bytes = sock->ops->read(sock, sock->buffer, sizeof sock->buffer);	if (bytes <= 0)	    return bytes;	sock->bufpos = sock->buffer;	sock->bufavail = bytes;    }    if (buflen > (size_t)bytes)	buflen = bytes;    memcpy(buffer, sock->bufpos, buflen);    return buflen;}/* Await data on raw fd in socket. */static int readable_raw(ne_socket *sock, int secs){    int fdno = sock->fd, ret;    fd_set rdfds;    struct timeval timeout, *tvp = (secs >= 0 ? &timeout : NULL);    /* Init the fd set */    FD_ZERO(&rdfds);    do {	FD_SET(fdno, &rdfds);	if (tvp) {	    tvp->tv_sec = secs;	    tvp->tv_usec = 0;	}	ret = select(fdno + 1, &rdfds, NULL, NULL, tvp);    } while (ret < 0 && NE_ISINTR(ne_errno));    if (ret < 0) {	set_strerror(sock, ne_errno);	return NE_SOCK_ERROR;    }    return (ret == 0) ? NE_SOCK_TIMEOUT : 0;}static ssize_t read_raw(ne_socket *sock, char *buffer, size_t len){    ssize_t ret;        ret = readable_raw(sock, sock->rdtimeout);    if (ret) return ret;    do {	ret = ne_read(sock->fd, buffer, len);    } while (ret == -1 && NE_ISINTR(ne_errno));    if (ret == 0) {	set_error(sock, _("Connection closed"));	ret = NE_SOCK_CLOSED;    } else if (ret < 0) {	int errnum = ne_errno;	ret = NE_ISRESET(errnum) ? NE_SOCK_RESET : NE_SOCK_ERROR;	set_strerror(sock, errnum);    }    return ret;}#define MAP_ERR(e) (NE_ISCLOSED(e) ? NE_SOCK_CLOSED : \                    (NE_ISRESET(e) ? NE_SOCK_RESET : NE_SOCK_ERROR))static ssize_t write_raw(ne_socket *sock, const char *data, size_t length) {    ssize_t wrote;        do {	wrote = ne_write(sock->fd, data, length);        if (wrote > 0) {            data += wrote;            length -= wrote;        }    } while ((wrote > 0 || NE_ISINTR(ne_errno)) && length > 0);    if (wrote < 0) {	int errnum = ne_errno;	set_strerror(sock, errnum);	return MAP_ERR(errnum);    }    return 0;}static const struct iofns iofns_raw = { read_raw, write_raw, readable_raw };#ifdef NEON_SSL/* OpenSSL I/O function implementations. */static int readable_ossl(ne_socket *sock, int secs){    /* If there is buffered SSL data, then don't block on the socket.     * FIXME: make sure that SSL_read *really* won't block if     * SSL_pending returns non-zero.  Possibly need to do     * SSL_read(ssl, buf, SSL_pending(ssl)) */    if (SSL_pending(sock->ssl.ssl))	return 0;    return readable_raw(sock, secs);}/* SSL error handling, according to SSL_get_error(3). */static int error_ossl(ne_socket *sock, int sret){    int err = SSL_get_error(sock->ssl.ssl, sret), ret = NE_SOCK_ERROR;        switch (err) {    case SSL_ERROR_ZERO_RETURN:	ret = NE_SOCK_CLOSED;	set_error(sock, _("Connection closed"));	break;    case SSL_ERROR_SYSCALL:	err = ERR_get_error();	if (err == 0) {	    if (sret == 0) {		/* EOF without close_notify, possible truncation */		set_error(sock, _("Secure connection truncated"));		ret = NE_SOCK_TRUNC;	    } else {		/* Other socket error. */		err = ne_errno;		set_strerror(sock, err);		ret = MAP_ERR(err);	    }	} else {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -