📄 ne_socket.c
字号:
ne_snprintf(sock->error, sizeof sock->error, _("SSL error: %s"), ERR_reason_error_string(err)); } break; default: ne_snprintf(sock->error, sizeof sock->error, _("SSL error: %s"), ERR_reason_error_string(ERR_get_error())); break; } return ret;}/* Work around OpenSSL's use of 'int' rather than 'size_t', to prevent * accidentally passing a negative number, etc. */#define CAST2INT(n) (((n) > INT_MAX) ? INT_MAX : (n))static ssize_t read_ossl(ne_socket *sock, char *buffer, size_t len){ int ret; ret = readable_ossl(sock, sock->rdtimeout); if (ret) return ret; ret = SSL_read(sock->ssl.ssl, buffer, CAST2INT(len)); if (ret <= 0) ret = error_ossl(sock, ret); return ret;}static ssize_t write_ossl(ne_socket *sock, const char *data, size_t len){ int ret, ilen = CAST2INT(len); ret = SSL_write(sock->ssl.ssl, data, ilen); /* ssl.h says SSL_MODE_ENABLE_PARTIAL_WRITE must be enabled to * have SSL_write return < length... so, SSL_write should never * return < length. */ if (ret != ilen) return error_ossl(sock, ret); return 0;}static const struct iofns iofns_ossl = { read_ossl, write_ossl, readable_ossl};#endif /* NEON_SSL */int ne_sock_fullwrite(ne_socket *sock, const char *data, size_t len){ return sock->ops->write(sock, data, len);}ssize_t ne_sock_readline(ne_socket *sock, char *buf, size_t buflen){ char *lf; size_t len; if ((lf = memchr(sock->bufpos, '\n', sock->bufavail)) == NULL && sock->bufavail < RDBUFSIZ) { /* The buffered data does not contain a complete line: move it * to the beginning of the buffer. */ if (sock->bufavail) memmove(sock->buffer, sock->bufpos, sock->bufavail); sock->bufpos = sock->buffer; /* Loop filling the buffer whilst no newline is found in the data * buffered so far, and there is still buffer space available */ do { /* Read more data onto end of buffer. */ ssize_t ret = sock->ops->read(sock, sock->buffer + sock->bufavail, RDBUFSIZ - sock->bufavail); if (ret < 0) return ret; sock->bufavail += ret; } while ((lf = memchr(sock->buffer, '\n', sock->bufavail)) == NULL && sock->bufavail < RDBUFSIZ); } if (lf) len = lf - sock->bufpos + 1; else len = buflen; /* fall into "line too long" error... */ if ((len + 1) > buflen) { set_error(sock, _("Line too long")); return NE_SOCK_ERROR; } memcpy(buf, sock->bufpos, len); buf[len] = '\0'; /* consume the line from buffer: */ sock->bufavail -= len; sock->bufpos += len; return len;}ssize_t ne_sock_fullread(ne_socket *sock, char *buffer, size_t buflen) { ssize_t len; while (buflen > 0) { len = ne_sock_read(sock, buffer, buflen); if (len < 0) return len; buflen -= len; buffer += len; } return 0;}#ifndef INADDR_NONE#define INADDR_NONE ((unsigned long) -1)#endif#if !defined(USE_GETADDRINFO) && !defined(HAVE_DECL_H_ERRNO) && !defined(WIN32)/* Ancient versions of netdb.h don't export h_errno. */extern int h_errno;#endif/* This implemementation does not attempt to support IPv6 using * gethostbyname2 et al. */ne_sock_addr *ne_addr_resolve(const char *hostname, int flags){ ne_sock_addr *addr = ne_calloc(sizeof *addr);#ifdef USE_GETADDRINFO struct addrinfo hints = {0}; char *pnt; hints.ai_socktype = SOCK_STREAM; if (hostname[0] == '[' && ((pnt = strchr(hostname, ']')) != NULL)) { char *hn = ne_strdup(hostname + 1); hn[pnt - hostname - 1] = '\0';#ifdef AI_NUMERICHOST /* added in the RFC2553 API */ hints.ai_flags = AI_NUMERICHOST;#endif hints.ai_family = AF_INET6; addr->errnum = getaddrinfo(hn, NULL, &hints, &addr->result); ne_free(hn); } else {#ifdef USE_GAI_ADDRCONFIG /* added in the RFC3493 API */ hints.ai_flags = AI_ADDRCONFIG; hints.ai_family = AF_UNSPEC; addr->errnum = getaddrinfo(hostname, NULL, &hints, &addr->result);#else hints.ai_family = ipv6_disabled ? AF_INET : AF_UNSPEC; addr->errnum = getaddrinfo(hostname, NULL, &hints, &addr->result);#endif }#else /* Use gethostbyname() */ unsigned long laddr; struct hostent *hp; laddr = inet_addr(hostname); if (laddr == INADDR_NONE) { hp = gethostbyname(hostname); if (hp == NULL) {#ifdef WIN32 addr->errnum = WSAGetLastError();#else addr->errnum = h_errno;#endif } else if (hp->h_length != sizeof(struct in_addr)) { /* fail gracefully if somebody set RES_USE_INET6 */ addr->errnum = NO_RECOVERY; } else { size_t n; /* count addresses */ for (n = 0; hp->h_addr_list[n] != NULL; n++) /* noop */; addr->count = n; addr->addrs = ne_malloc(n * sizeof *addr->addrs); for (n = 0; n < addr->count; n++) memcpy(&addr->addrs[n], hp->h_addr_list[n], hp->h_length); } } else { addr->addrs = ne_malloc(sizeof *addr->addrs); addr->count = 1; memcpy(addr->addrs, &laddr, sizeof *addr->addrs); }#endif return addr;}int ne_addr_result(const ne_sock_addr *addr){ return addr->errnum;}const ne_inet_addr *ne_addr_first(ne_sock_addr *addr){#ifdef USE_GETADDRINFO addr->cursor = addr->result->ai_next; return addr->result;#else addr->cursor = 0; return &addr->addrs[0];#endif}const ne_inet_addr *ne_addr_next(ne_sock_addr *addr){#ifdef USE_GETADDRINFO struct addrinfo *ret = addr->cursor; if (addr->cursor) addr->cursor = addr->cursor->ai_next;#else struct in_addr *ret; if (++addr->cursor < addr->count) ret = &addr->addrs[addr->cursor]; else ret = NULL;#endif return ret;}char *ne_addr_error(const ne_sock_addr *addr, char *buf, size_t bufsiz){#ifdef WIN32 print_error(addr->errnum, buf, bufsiz);#else const char *err;#ifdef USE_GETADDRINFO /* override horrible generic "Name or service not known" error. */ if (addr->errnum == EAI_NONAME) err = _("Host not found"); else err = gai_strerror(addr->errnum);#elif defined(HAVE_HSTRERROR) err = hstrerror(addr->errnum);#else err = _("Host not found");#endif ne_strnzcpy(buf, err, bufsiz);#endif /* WIN32 */ return buf;}char *ne_iaddr_print(const ne_inet_addr *ia, char *buf, size_t bufsiz){#ifdef USE_GETADDRINFO /* implies inet_ntop */ const char *ret;#ifdef AF_INET6 if (ia->ai_family == AF_INET6) { struct sockaddr_in6 *in6 = SACAST(in6, ia->ai_addr); ret = inet_ntop(AF_INET6, &in6->sin6_addr, buf, bufsiz); } else#endif if (ia->ai_family == AF_INET) { struct sockaddr_in *in = SACAST(in, ia->ai_addr); ret = inet_ntop(AF_INET, &in->sin_addr, buf, bufsiz); } else ret = NULL; if (ret == NULL) ne_strnzcpy(buf, "[IP address]", bufsiz);#else ne_strnzcpy(buf, inet_ntoa(*ia), bufsiz);#endif return buf;}void ne_addr_destroy(ne_sock_addr *addr){#ifdef USE_GETADDRINFO if (addr->result) freeaddrinfo(addr->result);#else if (addr->addrs) ne_free(addr->addrs);#endif ne_free(addr);}/* Connect socket 'fd' to address 'addr' on given 'port': */static int raw_connect(int fd, const ne_inet_addr *addr, unsigned int port){#ifdef USE_GETADDRINFO#ifdef AF_INET6 /* fill in the _family field for AIX 4.3, which forgets to do so. */ if (addr->ai_family == AF_INET6) { struct sockaddr_in6 in6; memcpy(&in6, addr->ai_addr, sizeof in6); in6.sin6_port = port; in6.sin6_family = AF_INET6; return connect(fd, (struct sockaddr *)&in6, sizeof in6); } else#endif if (addr->ai_family == AF_INET) { struct sockaddr_in in; memcpy(&in, addr->ai_addr, sizeof in); in.sin_port = port; in.sin_family = AF_INET; return connect(fd, (struct sockaddr *)&in, sizeof in); } else { errno = EINVAL; return -1; }#else struct sockaddr_in sa = {0}; sa.sin_family = AF_INET; sa.sin_port = port; sa.sin_addr = *addr; return connect(fd, (struct sockaddr *)&sa, sizeof sa);#endif}ne_socket *ne_sock_create(void){ ne_socket *sock = ne_calloc(sizeof *sock); sock->rdtimeout = SOCKET_READ_TIMEOUT; sock->bufpos = sock->buffer; sock->ops = &iofns_raw; sock->fd = -1; return sock;}int ne_sock_connect(ne_socket *sock, const ne_inet_addr *addr, unsigned int port){ int fd;#ifdef USE_GETADDRINFO /* use SOCK_STREAM rather than ai_socktype: some getaddrinfo * implementations do not set ai_socktype, e.g. RHL6.2. */ fd = socket(addr->ai_family, SOCK_STREAM, addr->ai_protocol);#else fd = socket(AF_INET, SOCK_STREAM, 0);#endif if (fd < 0) { set_strerror(sock, ne_errno); return -1; } #if defined(TCP_NODELAY) && defined(HAVE_SETSOCKOPT) && defined(IPPROTO_TCP) { /* Disable the Nagle algorithm; better to add write buffering * instead of doing this. */ int flag = 1; setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof flag); }#endif if (raw_connect(fd, addr, ntohs(port))) { set_strerror(sock, ne_errno); ne_close(fd); return -1; } sock->fd = fd; return 0;}ne_inet_addr *ne_iaddr_make(ne_iaddr_type type, const unsigned char *raw){ ne_inet_addr *ia;#if !defined(AF_INET6) || !defined(USE_GETADDRINFO) /* fail if IPv6 address is given if IPv6 is not supported. */ if (type == ne_iaddr_ipv6) return NULL;#endif ia = ne_calloc(sizeof *ia);#ifdef USE_GETADDRINFO /* ai_protocol and ai_socktype aren't used by raw_connect so * ignore them here. (for now) */ if (type == ne_iaddr_ipv4) { struct sockaddr_in *in4 = ne_calloc(sizeof *in4); ia->ai_family = AF_INET; ia->ai_addr = (struct sockaddr *)in4; ia->ai_addrlen = sizeof *in4; in4->sin_family = AF_INET; memcpy(&in4->sin_addr.s_addr, raw, sizeof in4->sin_addr.s_addr); }#ifdef AF_INET6 else { struct sockaddr_in6 *in6 = ne_calloc(sizeof *in6); ia->ai_family = AF_INET6; ia->ai_addr = (struct sockaddr *)in6; ia->ai_addrlen = sizeof *in6; in6->sin6_family = AF_INET6; memcpy(&in6->sin6_addr, raw, sizeof in6->sin6_addr.s6_addr); }#endif#else /* !USE_GETADDRINFO */ memcpy(&ia->s_addr, raw, sizeof ia->s_addr);#endif return ia;}int ne_iaddr_cmp(const ne_inet_addr *i1, const ne_inet_addr *i2){#ifdef USE_GETADDRINFO if (i1->ai_family != i2->ai_family) return i2->ai_family - i1->ai_family; if (i1->ai_family == AF_INET) { struct sockaddr_in *in1 = SACAST(in, i1->ai_addr), *in2 = SACAST(in, i2->ai_addr); return memcmp(&in1->sin_addr.s_addr, &in2->sin_addr.s_addr, sizeof in1->sin_addr.s_addr); } else if (i1->ai_family == AF_INET6) { struct sockaddr_in6 *in1 = SACAST(in6, i1->ai_addr), *in2 = SACAST(in6, i2->ai_addr); return memcmp(in1->sin6_addr.s6_addr, in2->sin6_addr.s6_addr, sizeof in1->sin6_addr.s6_addr); } else return -1;#else return memcmp(&i1->s_addr, &i2->s_addr, sizeof i1->s_addr);#endif}void ne_iaddr_free(ne_inet_addr *addr){#ifdef USE_GETADDRINFO ne_free(addr->ai_addr);#endif ne_free(addr);}int ne_sock_accept(ne_socket *sock, int listener) { int fd = accept(listener, NULL, NULL); if (fd < 0) return -1; sock->fd = fd; return 0;}int ne_sock_fd(const ne_socket *sock){ return sock->fd;}void ne_sock_read_timeout(ne_socket *sock, int timeout){ sock->rdtimeout = timeout;}#ifdef NEON_SSLvoid ne_sock_switch_ssl(ne_socket *sock, void *ssl){ sock->ssl.ssl = ssl; sock->ops = &iofns_ossl;}int ne_sock_connect_ssl(ne_socket *sock, ne_ssl_context *ctx){ SSL *ssl; int ret; if (seed_ssl_prng()) { set_error(sock, _("SSL disabled due to lack of entropy")); return NE_SOCK_ERROR; } sock->ssl.ssl = ssl = SSL_new(ctx->ctx); if (!ssl) { set_error(sock, _("Could not create SSL structure")); return NE_SOCK_ERROR; } SSL_set_app_data(ssl, ctx); SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); SSL_set_fd(ssl, sock->fd); sock->ops = &iofns_ossl; if (ctx->sess) SSL_set_session(ssl, ctx->sess); ret = SSL_connect(ssl); if (ret != 1) { error_ossl(sock, ret); SSL_free(ssl); sock->ssl.ssl = NULL; return NE_SOCK_ERROR; } return 0;}ne_ssl_socket *ne_sock_sslsock(ne_socket *sock){ return &sock->ssl;}#endifconst char *ne_sock_error(const ne_socket *sock){ return sock->error;}/* Closes given ne_socket */int ne_sock_close(ne_socket *sock){ int ret;#ifdef NEON_SSL if (sock->ssl.ssl) { SSL_shutdown(sock->ssl.ssl); SSL_free(sock->ssl.ssl); }#endif if (sock->fd < 0) ret = 0; else ret = ne_close(sock->fd); ne_free(sock); return ret;}/* Returns HOST byte order port of given name */int ne_service_lookup(const char *name){ struct servent *ent; ent = getservbyname(name, "tcp"); if (ent) return ntohs(ent->s_port); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -