/* $Header: /pjproject-0.3/pjlib/src/pjlib-test/sock.c 4 10/29/05 11:51a Bennylp $ */ | |
/* $Log: /pjproject-0.3/pjlib/src/pjlib-test/sock.c $ | |
* | |
* 4 10/29/05 11:51a Bennylp | |
* Version 0.3-pre2. | |
* | |
* 3 14/10/05 11:31 Bennylp | |
* Fixed bug when TCP data is received in chunks. | |
* | |
* 2 10/14/05 12:26a Bennylp | |
* Finished error code framework, some fixes in ioqueue, etc. Pretty | |
* major. | |
* | |
* 1 9/21/05 1:38p Bennylp | |
* Renamed from *.cpp | |
* | |
* 2 9/17/05 10:37a Bennylp | |
* Major reorganization towards version 0.3. | |
* | |
* 1 9/15/05 8:41p Bennylp | |
*/ | |
#include <pjlib.h> | |
#include "test.h" | |
/** | |
* \page page_pjlib_sock_test Test: Socket | |
* | |
* This file provides implementation of \b sock_test(). It tests the | |
* various aspects of the socket API. | |
* | |
* \section sock_test_scope_sec Scope of the Test | |
* | |
* The scope of the test: | |
* - verify the validity of the address structs. | |
* - verify that address manipulation API works. | |
* - simple socket creation and destruction. | |
* - simple socket send/recv and sendto/recvfrom. | |
* - UDP connect() | |
* - send/recv big data. | |
* - all for both UDP and TCP. | |
* | |
* The APIs tested in this test: | |
* - pj_inet_aton() | |
* - pj_inet_ntoa() | |
* - pj_gethostname() | |
* - pj_sock_socket() | |
* - pj_sock_close() | |
* - pj_sock_send() | |
* - pj_sock_sendto() | |
* - pj_sock_recv() | |
* - pj_sock_recvfrom() | |
* - pj_sock_bind() | |
* - pj_sock_connect() | |
* - pj_sock_listen() | |
* - pj_sock_accept() | |
* | |
* | |
* This file is <b>pjlib-test/sock.c</b> | |
* | |
* \include pjlib-test/sock.c | |
*/ | |
#if INCLUDE_SOCK_TEST | |
#define UDP_PORT 51234 | |
#define TCP_PORT (UDP_PORT+10) | |
#define BIG_DATA_LEN 9000 | |
static char bigdata[BIG_DATA_LEN]; | |
static char bigbuffer[BIG_DATA_LEN]; | |
static int format_test(void) | |
{ | |
pj_str_t s = pj_str("127.0.0.1"); | |
char *p; | |
pj_in_addr addr; | |
const pj_str_t *hostname; | |
PJ_LOG(3,("test", "...format_test()")); | |
/* pj_inet_aton() */ | |
if (pj_inet_aton(&s, &addr) != 1) | |
return -10; | |
/* Check the result. */ | |
p = (char*)&addr; | |
if (p[0]!=127 || p[1]!=0 || p[2]!=0 || p[3]!=1) | |
return -15; | |
/* pj_inet_ntoa() */ | |
p = pj_inet_ntoa(addr); | |
if (!p) | |
return -20; | |
if (pj_strcmp2(&s, p) != 0) | |
return -30; | |
/* pj_gethostname() */ | |
hostname = pj_gethostname(); | |
if (!hostname || !hostname->ptr || !hostname->slen) | |
return -40; | |
/* pj_gethostaddr() */ | |
return 0; | |
} | |
static int simple_sock_test(void) | |
{ | |
int types[2]; | |
pj_sock_t sock; | |
int i; | |
pj_status_t rc = PJ_SUCCESS; | |
types[0] = PJ_SOCK_STREAM; | |
types[1] = PJ_SOCK_DGRAM; | |
PJ_LOG(3,("test", "...simple_sock_test()")); | |
for (i=0; i<sizeof(types)/sizeof(types[0]); ++i) { | |
rc = pj_sock_socket(PJ_AF_INET, types[i], 0, &sock); | |
if (rc != PJ_SUCCESS) { | |
app_perror("...error: unable to create socket type %d", rc); | |
break; | |
} else { | |
rc = pj_sock_close(sock); | |
if (rc != 0) { | |
app_perror("...error: close socket", rc); | |
break; | |
} | |
} | |
} | |
return rc; | |
} | |
static int send_recv_test(int sock_type, | |
pj_sock_t ss, pj_sock_t cs, | |
pj_sockaddr_in *dstaddr, pj_sockaddr_in *srcaddr, | |
int addrlen) | |
{ | |
enum { DATA_LEN = 16 }; | |
char senddata[DATA_LEN+4], recvdata[DATA_LEN+4]; | |
pj_ssize_t sent, received, total_received; | |
pj_status_t rc; | |
TRACE_(("test", "....create_random_string()")); | |
pj_create_random_string(senddata, DATA_LEN); | |
senddata[DATA_LEN-1] = '\0'; | |
/* | |
* Test send/recv small data. | |
*/ | |
TRACE_(("test", "....sendto()")); | |
if (dstaddr) { | |
sent = DATA_LEN; | |
rc = pj_sock_sendto(cs, senddata, &sent, 0, dstaddr, addrlen); | |
if (rc != PJ_SUCCESS || sent != DATA_LEN) { | |
app_perror("...sendto error", rc); | |
rc = -140; goto on_error; | |
} | |
} else { | |
sent = DATA_LEN; | |
rc = pj_sock_send(cs, senddata, &sent, 0); | |
if (rc != PJ_SUCCESS || sent != DATA_LEN) { | |
app_perror("...send error", rc); | |
rc = -145; goto on_error; | |
} | |
} | |
TRACE_(("test", "....recv()")); | |
if (srcaddr) { | |
pj_sockaddr_in addr; | |
int srclen = sizeof(addr); | |
pj_memset(&addr, 0, sizeof(addr)); | |
received = DATA_LEN; | |
rc = pj_sock_recvfrom(ss, recvdata, &received, 0, &addr, &srclen); | |
if (rc != PJ_SUCCESS || received != DATA_LEN) { | |
app_perror("...recvfrom error", rc); | |
rc = -150; goto on_error; | |
} | |
if (srclen != addrlen) | |
return -151; | |
if (pj_memcmp(&addr, srcaddr, srclen) != 0) { | |
char srcaddr_str[32], addr_str[32]; | |
strcpy(srcaddr_str, pj_inet_ntoa(srcaddr->sin_addr)); | |
strcpy(addr_str, pj_inet_ntoa(addr.sin_addr)); | |
PJ_LOG(3,("test", "...error: src address mismatch (original=%s, " | |
"recvfrom addr=%s)", | |
srcaddr_str, addr_str)); | |
return -152; | |
} | |
} else { | |
/* Repeat recv() until all data is received. | |
* This applies only for non-UDP of course, since for UDP | |
* we would expect all data to be received in one packet. | |
*/ | |
total_received = 0; | |
do { | |
received = DATA_LEN-total_received; | |
rc = pj_sock_recv(ss, recvdata+total_received, &received, 0); | |
if (rc != PJ_SUCCESS) { | |
app_perror("...recv error", rc); | |
rc = -155; goto on_error; | |
} | |
if (received <= 0) { | |
PJ_LOG(3,("", "...error: socket has closed! (received=%d)", | |
received)); | |
rc = -156; goto on_error; | |
} | |
if (received != DATA_LEN-total_received) { | |
if (sock_type != PJ_SOCK_STREAM) { | |
PJ_LOG(3,("", "...error: expecting %u bytes, got %u bytes", | |
DATA_LEN-total_received, received)); | |
rc = -157; goto on_error; | |
} | |
} | |
total_received += received; | |
} while (total_received < DATA_LEN); | |
} | |
TRACE_(("test", "....memcmp()")); | |
if (pj_memcmp(senddata, recvdata, DATA_LEN) != 0) { | |
PJ_LOG(3,("","...error: received data mismatch " | |
"(got:'%s' expecting:'%s'", | |
recvdata, senddata)); | |
rc = -160; goto on_error; | |
} | |
/* | |
* Test send/recv big data. | |
*/ | |
TRACE_(("test", "....sendto()")); | |
if (dstaddr) { | |
sent = BIG_DATA_LEN; | |
rc = pj_sock_sendto(cs, bigdata, &sent, 0, dstaddr, addrlen); | |
if (rc != PJ_SUCCESS || sent != BIG_DATA_LEN) { | |
app_perror("...sendto error", rc); | |
rc = -161; goto on_error; | |
} | |
} else { | |
sent = BIG_DATA_LEN; | |
rc = pj_sock_send(cs, bigdata, &sent, 0); | |
if (rc != PJ_SUCCESS || sent != BIG_DATA_LEN) { | |
app_perror("...send error", rc); | |
rc = -165; goto on_error; | |
} | |
} | |
TRACE_(("test", "....recv()")); | |
/* Repeat recv() until all data is received. | |
* This applies only for non-UDP of course, since for UDP | |
* we would expect all data to be received in one packet. | |
*/ | |
total_received = 0; | |
do { | |
received = BIG_DATA_LEN-total_received; | |
rc = pj_sock_recv(ss, bigbuffer+total_received, &received, 0); | |
if (rc != PJ_SUCCESS) { | |
app_perror("...recv error", rc); | |
rc = -170; goto on_error; | |
} | |
if (received <= 0) { | |
PJ_LOG(3,("", "...error: socket has closed! (received=%d)", | |
received)); | |
rc = -173; goto on_error; | |
} | |
if (received != BIG_DATA_LEN-total_received) { | |
if (sock_type != PJ_SOCK_STREAM) { | |
PJ_LOG(3,("", "...error: expecting %u bytes, got %u bytes", | |
BIG_DATA_LEN-total_received, received)); | |
rc = -176; goto on_error; | |
} | |
} | |
total_received += received; | |
} while (total_received < BIG_DATA_LEN); | |
TRACE_(("test", "....memcmp()")); | |
if (pj_memcmp(bigdata, bigbuffer, BIG_DATA_LEN) != 0) { | |
PJ_LOG(3,("", "...error: received data has been altered!")); | |
rc = -180; goto on_error; | |
} | |
rc = 0; | |
on_error: | |
return rc; | |
} | |
static int udp_test(void) | |
{ | |
pj_sock_t cs = PJ_INVALID_SOCKET, ss = PJ_INVALID_SOCKET; | |
pj_sockaddr_in dstaddr, srcaddr; | |
pj_str_t s; | |
pj_status_t rc = 0, retval; | |
PJ_LOG(3,("test", "...udp_test()")); | |
rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &ss); | |
if (rc != 0) { | |
app_perror("...error: unable to create socket", rc); | |
return -100; | |
} | |
rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &cs); | |
if (rc != 0) | |
return -110; | |
/* Bind server socket. */ | |
pj_memset(&dstaddr, 0, sizeof(dstaddr)); | |
dstaddr.sin_family = PJ_AF_INET; | |
dstaddr.sin_port = pj_htons(UDP_PORT); | |
dstaddr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1")); | |
if ((rc=pj_sock_bind(ss, &dstaddr, sizeof(dstaddr))) != 0) { | |
app_perror("...bind error", rc); | |
rc = -120; goto on_error; | |
} | |
/* Bind client socket. */ | |
pj_memset(&srcaddr, 0, sizeof(srcaddr)); | |
srcaddr.sin_family = PJ_AF_INET; | |
srcaddr.sin_port = pj_htons(UDP_PORT-1); | |
srcaddr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1")); | |
if ((rc=pj_sock_bind(cs, &srcaddr, sizeof(srcaddr))) != 0) { | |
app_perror("...bind error", rc); | |
rc = -121; goto on_error; | |
} | |
/* Test send/recv, with sendto */ | |
rc = send_recv_test(PJ_SOCK_DGRAM, ss, cs, &dstaddr, NULL, | |
sizeof(dstaddr)); | |
if (rc != 0) | |
goto on_error; | |
/* Test send/recv, with sendto and recvfrom */ | |
rc = send_recv_test(PJ_SOCK_DGRAM, ss, cs, &dstaddr, | |
&srcaddr, sizeof(dstaddr)); | |
if (rc != 0) | |
goto on_error; | |
/* connect() the sockets. */ | |
rc = pj_sock_connect(cs, &dstaddr, sizeof(dstaddr)); | |
if (rc != 0) { | |
app_perror("...connect() error", rc); | |
rc = -122; goto on_error; | |
} | |
/* Test send/recv with send() */ | |
rc = send_recv_test(PJ_SOCK_DGRAM, ss, cs, NULL, NULL, 0); | |
if (rc != 0) | |
goto on_error; | |
/* Test send/recv with send() and recvfrom */ | |
rc = send_recv_test(PJ_SOCK_DGRAM, ss, cs, NULL, &srcaddr, | |
sizeof(srcaddr)); | |
if (rc != 0) | |
goto on_error; | |
on_error: | |
retval = rc; | |
if (cs != PJ_INVALID_SOCKET) { | |
rc = pj_sock_close(cs); | |
if (rc != PJ_SUCCESS) { | |
app_perror("...error in closing socket", rc); | |
return -1000; | |
} | |
} | |
if (ss != PJ_INVALID_SOCKET) { | |
rc = pj_sock_close(ss); | |
if (rc != PJ_SUCCESS) { | |
app_perror("...error in closing socket", rc); | |
return -1010; | |
} | |
} | |
return retval; | |
} | |
static int tcp_test(void) | |
{ | |
pj_sock_t cs, ss; | |
pj_status_t rc = 0, retval; | |
PJ_LOG(3,("test", "...tcp_test()")); | |
rc = app_socketpair(PJ_AF_INET, PJ_SOCK_STREAM, 0, &ss, &cs); | |
if (rc != PJ_SUCCESS) { | |
app_perror("...error: app_socketpair():", rc); | |
return -2000; | |
} | |
/* Test send/recv with send() and recv() */ | |
retval = send_recv_test(PJ_SOCK_STREAM, ss, cs, NULL, NULL, 0); | |
rc = pj_sock_close(cs); | |
if (rc != PJ_SUCCESS) { | |
app_perror("...error in closing socket", rc); | |
return -2000; | |
} | |
rc = pj_sock_close(ss); | |
if (rc != PJ_SUCCESS) { | |
app_perror("...error in closing socket", rc); | |
return -2010; | |
} | |
return retval; | |
} | |
static int ioctl_test(void) | |
{ | |
return 0; | |
} | |
int sock_test() | |
{ | |
int rc; | |
pj_create_random_string(bigdata, BIG_DATA_LEN); | |
rc = format_test(); | |
if (rc != 0) | |
return rc; | |
rc = simple_sock_test(); | |
if (rc != 0) | |
return rc; | |
rc = ioctl_test(); | |
if (rc != 0) | |
return rc; | |
rc = udp_test(); | |
if (rc != 0) | |
return rc; | |
rc = tcp_test(); | |
if (rc != 0) | |
return rc; | |
return 0; | |
} | |
#else | |
/* To prevent warning about "translation unit is empty" | |
* when this test is disabled. | |
*/ | |
int dummy_sock_test; | |
#endif /* INCLUDE_SOCK_TEST */ | |