📄 socket.c
字号:
/* Socket handling tests Copyright (C) 2002-2004, Joe Orton <joe@manyfish.co.uk> 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 2 of the License, 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.*//* This module can be compiled with -DSOCKET_SSL enabled, to run all * the tests over an SSL connection. */#include "config.h"#include <sys/types.h>#include <sys/socket.h> /* for AF_INET6 */#ifdef HAVE_STDLIB_H#include <stdlib.h>#endif#ifdef HAVE_STRING_H#include <string.h>#endif#include <time.h> /* for time() */#include "ne_socket.h"#include "ne_utils.h"#include "ne_alloc.h"#include "child.h"#include "tests.h"#include "utils.h"#ifdef SOCKET_SSL#include <openssl/err.h>#include <openssl/ssl.h>#include "ne_ssl.h"SSL_CTX *server_ctx;ne_ssl_context *client_ctx;#endifstatic ne_sock_addr *localhost;static char buffer[BUFSIZ];#if defined(AF_INET6) && defined(USE_GETADDRINFO)#define TEST_IPV6#endif/* tests for doing init/finish multiple times. */static int multi_init(void){ int res1 = ne_sock_init(), res2 = ne_sock_init(); ONV(res1 != res2, ("cached init result changed from %d to %d", res1, res2)); ne_sock_exit(); res1 = ne_sock_init(); ONV(res1 != res2, ("re-init after exit gave %d not %d", res1, res2)); res2 = ne_sock_init(); ONV(res1 != res2, ("second time, cached init result changed from %d to %d", res1, res2)); return OK;}static ne_socket *do_connect(ne_sock_addr *addr, unsigned int port){ ne_socket *sock = ne_sock_create(); const ne_inet_addr *ia; if (!sock) return NULL; for (ia = ne_addr_first(addr); ia; ia = ne_addr_next(addr)) { if (ne_sock_connect(sock, ia, port) == 0) return sock; } ne_sock_close(sock); return NULL;}#ifdef SOCKET_SSL/* FIXME: largely cut'n'pasted from ssl.c. */static int init_ssl(void){ char *server_key; ne_ssl_certificate *cert; /* take srcdir as argv[1]. */ if (test_argc > 1) { server_key = ne_concat(test_argv[1], "/server.key", NULL); } else { server_key = "server.key"; } ONN("sock_init failed.\n", ne_sock_init()); server_ctx = SSL_CTX_new(SSLv23_server_method()); ONN("SSL_CTX_new failed", server_ctx == NULL); ONN("failed to load private key", !SSL_CTX_use_PrivateKey_file(server_ctx, server_key, SSL_FILETYPE_PEM)); ONN("failed to load certificate", !SSL_CTX_use_certificate_file(server_ctx, "server.cert", SSL_FILETYPE_PEM)); client_ctx = ne_ssl_context_create(); ONN("SSL_CTX_new failed for client", client_ctx == NULL); cert = ne_ssl_cert_read("ca/cert.pem"); ONN("could not load ca/cert.pem", cert == NULL); ne_ssl_ctx_trustcert(client_ctx, cert); return OK;}#endifstatic int resolve(void){ char buf[256]; localhost = ne_addr_resolve("localhost", 0); ONV(ne_addr_result(localhost), ("could not resolve `localhost': %s", ne_addr_error(localhost, buf, sizeof buf))); /* and again for child.c */ return lookup_localhost();}static int serve_close(ne_socket *sock, void *ud){ return 0;}#ifdef SOCKET_SSLstruct serve_pair { server_fn fn; void *userdata;};static int wrap_serve(ne_socket *sock, void *ud){ struct serve_pair *pair = ud; int fd = ne_sock_fd(sock), ret; SSL *ssl = SSL_new(server_ctx); BIO *bio = BIO_new_socket(fd, BIO_NOCLOSE); ONN("SSL_new failed", ssl == NULL); SSL_set_bio(ssl, bio, bio);#define ERROR_SSL_STRING (ERR_reason_error_string(ERR_get_error())) NE_DEBUG(NE_DBG_SOCKET, "Doing SSL accept:\n"); ret = SSL_accept(ssl); if (ret != 1) { NE_DEBUG(NE_DBG_SOCKET, "SSL_accept failed: %s\n", ERROR_SSL_STRING); return 1; } NE_DEBUG(NE_DBG_SOCKET, "SSL accept okay.\n"); ne_sock_switch_ssl(sock, ssl); return pair->fn(sock, pair->userdata);}static int begin(ne_socket **sock, server_fn fn, void *ud){ struct serve_pair pair; pair.fn = fn; pair.userdata = ud; CALL(spawn_server(7777, wrap_serve, &pair)); *sock = do_connect(localhost, 7777); ONN("could not connect to localhost:7777", *sock == NULL); ONV(ne_sock_connect_ssl(*sock, client_ctx), ("SSL negotation failed: %s", ne_sock_error(*sock))); return OK;}#else/* non-SSL begin() function. */static int begin(ne_socket **sock, server_fn fn, void *ud){ CALL(spawn_server(7777, fn, ud)); *sock = do_connect(localhost, 7777); ONN("could not connect to localhost:7777", *sock == NULL); return OK;}#endifstatic int resolve_numeric(void){ ne_sock_addr *addr = ne_addr_resolve("127.0.0.1", 0); ONV(ne_addr_result(addr), ("failed to resolve 127.0.0.1: %s", ne_addr_error(addr, buffer, sizeof buffer))); ONN("ne_addr_first returned NULL", ne_addr_first(addr) == NULL); ONN("ne_iaddr_print didn't return buffer", ne_iaddr_print(ne_addr_first(addr), buffer, sizeof buffer) != buffer); ONV(strcmp(buffer, "127.0.0.1"), ("ntop gave `%s' not 127.0.0.1", buffer)); ne_addr_destroy(addr); return OK;}#if 0static int resolve_ipv6(void){ char err[256]; ne_sock_addr *addr = ne_addr_resolve("[::1]", 0); ONV(ne_addr_result(addr), ("could not resolve `[::1]': %s", ne_addr_error(addr, err, sizeof err))); ne_addr_destroy(addr); return OK;}#endifstatic const unsigned char raw_127[4] = "\x7f\0\0\01", /* 127.0.0.1 */raw6_nuls[16] = /* :: */ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";#ifdef TEST_IPV6static const unsigned char raw6_cafe[16] = /* feed::cafe */ "\xfe\xed\0\0\0\0\0\0\0\0\0\0\0\0\xca\xfe",raw6_babe[16] = /* cafe:babe:: */ "\xca\xfe\xba\xbe\0\0\0\0\0\0\0\0\0\0\0\0";#endifstatic int addr_make_v4(void){ ne_inet_addr *ia; char pr[50]; ia = ne_iaddr_make(ne_iaddr_ipv4, raw_127); ONN("ne_iaddr_make returned NULL", ia == NULL); ne_iaddr_print(ia, pr, sizeof pr); ONV(strcmp(pr, "127.0.0.1"), ("address was %s not 127.0.0.1", pr)); ne_iaddr_free(ia); return OK;}static int addr_make_v6(void){#ifdef TEST_IPV6 struct { const unsigned char *addr; const char *rep; } as[] = { { raw6_cafe, "feed::cafe" }, { raw6_babe, "cafe:babe::" }, { raw6_nuls, "::" }, { NULL, NULL } }; int n; for (n = 0; as[n].rep != NULL; n++) { ne_inet_addr *ia = ne_iaddr_make(ne_iaddr_ipv6, as[n].addr); char pr[128]; ONV(ia == NULL, ("could not make address for %d", n)); ne_iaddr_print(ia, pr, sizeof pr); ONV(strcmp(pr, as[n].rep), ("address %d was '%s' not '%s'", n, pr, as[n].rep)); ne_iaddr_free(ia); } return OK;#else /* should fail when lacking IPv6 support. */ ne_inet_addr *ia = ne_iaddr_make(ne_iaddr_ipv6, raw6_nuls); ONN("ne_iaddr_make did not return NULL", ia != NULL);#endif return OK;}static int addr_compare(void){ ne_inet_addr *ia1, *ia2; int ret; ia1 = ne_iaddr_make(ne_iaddr_ipv4, raw_127); ia2 = ne_iaddr_make(ne_iaddr_ipv4, raw_127); ONN("addr_make returned NULL", !ia1 || !ia2); ret = ne_iaddr_cmp(ia1, ia2); ONV(ret != 0, ("comparison of equal IPv4 addresses was %d", ret)); ne_iaddr_free(ia2); ia2 = ne_iaddr_make(ne_iaddr_ipv4, "abcd"); ret = ne_iaddr_cmp(ia1, ia2); ONN("comparison of unequal IPv4 addresses was zero", ret == 0); #ifdef TEST_IPV6 ne_iaddr_free(ia2); ia2 = ne_iaddr_make(ne_iaddr_ipv6, "feed::1"); ret = ne_iaddr_cmp(ia1, ia2); ONN("comparison of IPv4 and IPv6 addresses was zero", ret == 0); ne_iaddr_free(ia1); ia1 = ne_iaddr_make(ne_iaddr_ipv4, "feed::1"); ret = ne_iaddr_cmp(ia1, ia2); ONN("comparison of equal IPv6 addresses was zero", ret == 0);#endif ne_iaddr_free(ia1); ne_iaddr_free(ia2); return OK;}static int just_connect(void){ ne_socket *sock; CALL(begin(&sock, serve_close, NULL)); ne_sock_close(sock); return await_server();}/* Connect to an address crafted using ne_iaddr_make rather than from * the resolver. */static int addr_connect(void){ ne_socket *sock = ne_sock_create(); ne_inet_addr *ia; ia = ne_iaddr_make(ne_iaddr_ipv4, raw_127); ONN("ne_iaddr_make returned NULL", ia == NULL); CALL(spawn_server(7777, serve_close, NULL)); ONN("could not connect", ne_sock_connect(sock, ia, 7777)); ne_sock_close(sock); CALL(await_server()); ne_iaddr_free(ia); return OK;}/* Exect a read() to return EOF */static int expect_close(ne_socket *sock){ ssize_t n = ne_sock_read(sock, buffer, 1); ONV(n > 0, ("read got %" NE_FMT_SSIZE_T "bytes not closure", n)); ONV(n < 0 && n != NE_SOCK_CLOSED, ("read got error not closure: `%s'", ne_sock_error(sock))); return OK;}static int good_close(ne_socket *sock){ NE_DEBUG(NE_DBG_SOCKET, "Socket error was %s\n", ne_sock_error(sock)); ONN("close failed", ne_sock_close(sock)); return OK; }/* Finish a test, closing socket and rejoining child. If eof is non-zero, * expects to read EOF from the socket before closing. */static int finish(ne_socket *sock, int eof){ if (eof) CALL(expect_close(sock)); CALL(good_close(sock)); return await_server();}/* Exect a ne_sock_peek() to return EOF */static int expect_peek_close(ne_socket *sock){ ssize_t n = ne_sock_read(sock, buffer, 1); ONV(n != NE_SOCK_CLOSED, ("peek gave %" NE_FMT_SSIZE_T " not closure", n)); return OK;}/* Test that just does a connect then a close. */static int read_close(void){ ne_socket *sock; CALL(begin(&sock, serve_close, NULL)); CALL(expect_close(sock)); ONN("close failed", ne_sock_close(sock)); return await_server();}/* Test that just does a connect then a close (but gets the close via * ne_sock_peek). */static int peek_close(void){ ne_socket *sock; CALL(begin(&sock, serve_close, NULL)); CALL(expect_peek_close(sock)); ONN("close failed", ne_sock_close(sock)); return await_server();}/* Don't change this string. */#define STR "Hello, World."/* do a sock_peek() on sock for 'len' bytes, and expect 'str'. */static int peek_expect(ne_socket *sock, const char *str, size_t len){ ssize_t ret = ne_sock_peek(sock, buffer, len); ONV((ssize_t)len != ret, ("peek got %" NE_FMT_SSIZE_T " bytes not %" NE_FMT_SIZE_T, ret, len)); ONV(memcmp(str, buffer, len), ("peek mismatch: `%.*s' not `%.*s'", (int)len, buffer, (int)len, str)); return OK;}/* do a sock_read() on sock for 'len' bytes, and expect 'str'. */static int read_expect(ne_socket *sock, const char *str, size_t len){ ssize_t ret = ne_sock_read(sock, buffer, len); ONV((ssize_t)len != ret, ("peek got %" NE_FMT_SSIZE_T " bytes not %" NE_FMT_SIZE_T, ret, len)); ONV(memcmp(str, buffer, len), ("read mismatch: `%.*s' not `%.*s'", (int)len, buffer, (int)len, str)); return OK;}/* Declare a struct string */#define DECL(var,str) struct string var = { str, 0 }; var.len = strlen(str)/* Test a simple read. */static int single_read(void){ ne_socket *sock; DECL(hello, STR);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -