/* GLib testing framework examples and tests * * Copyright (C) 2008-2011 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General * Public License along with this library; if not, see <http://www.gnu.org/licenses/>. */#include<gio/gio.h>#ifdef G_OS_UNIX#include<errno.h>#include<sys/wait.h>#include<string.h>#include<stdlib.h>#include<gio/gnetworking.h>#include<gio/gunixconnection.h>#endif#include"gnetworkingprivate.h"staticgbooleanipv6_supported;typedefstruct{GSocket*server;GSocket*client;GSocketFamilyfamily;GThread*thread;GMainLoop*loop;GCancellable*cancellable;/* to shut down dgram echo server thread */}IPTestData;staticgpointerecho_server_dgram_thread(gpointeruser_data){IPTestData*data=user_data;GSocketAddress*sa;GCancellable*cancellable=data->cancellable;GSocket*sock;GError*error=NULL;gssizenread,nwrote;gcharbuf[128];sock=data->server;while(TRUE){nread=g_socket_receive_from(sock,&sa,buf,sizeof(buf),cancellable,&error);if(error&&g_error_matches(error,G_IO_ERROR,G_IO_ERROR_CANCELLED))break;g_assert_no_error(error);g_assert_cmpint(nread,>=,0);nwrote=g_socket_send_to(sock,sa,buf,nread,cancellable,&error);if(error&&g_error_matches(error,G_IO_ERROR,G_IO_ERROR_CANCELLED))break;g_assert_no_error(error);g_assert_cmpint(nwrote,==,nread);g_object_unref(sa);}g_clear_error(&error);returnNULL;}staticgpointerecho_server_thread(gpointeruser_data){IPTestData*data=user_data;GSocket*sock;GError*error=NULL;gssizenread,nwrote;gcharbuf[128];sock=g_socket_accept(data->server,NULL,&error);g_assert_no_error(error);while(TRUE){nread=g_socket_receive(sock,buf,sizeof(buf),NULL,&error);g_assert_no_error(error);g_assert_cmpint(nread,>=,0);if(nread==0)break;nwrote=g_socket_send(sock,buf,nread,NULL,&error);g_assert_no_error(error);g_assert_cmpint(nwrote,==,nread);}g_socket_close(sock,&error);g_assert_no_error(error);g_object_unref(sock);returnNULL;}staticIPTestData*create_server_full(GSocketFamilyfamily,GSocketTypesocket_type,GThreadFuncserver_thread,gbooleanv4mapped){IPTestData*data;GSocket*server;GError*error=NULL;GSocketAddress*addr;GInetAddress*iaddr;data=g_slice_new(IPTestData);data->family=family;data->server=server=g_socket_new(family,socket_type,G_SOCKET_PROTOCOL_DEFAULT,&error);g_assert_no_error(error);g_assert_cmpint(g_socket_get_family(server),==,family);g_assert_cmpint(g_socket_get_socket_type(server),==,socket_type);g_assert_cmpint(g_socket_get_protocol(server),==,G_SOCKET_PROTOCOL_DEFAULT);g_socket_set_blocking(server,TRUE);#if defined (IPPROTO_IPV6) && defined (IPV6_V6ONLY)if(v4mapped){g_socket_set_option(data->server,IPPROTO_IPV6,IPV6_V6ONLY,FALSE,NULL);if(!g_socket_speaks_ipv4(data->server)){g_object_unref(data->server);g_slice_free(IPTestData,data);returnNULL;}}#endifif(v4mapped)iaddr=g_inet_address_new_any(family);elseiaddr=g_inet_address_new_loopback(family);addr=g_inet_socket_address_new(iaddr,0);g_object_unref(iaddr);g_assert_cmpint(g_inet_socket_address_get_port(G_INET_SOCKET_ADDRESS(addr)),==,0);g_socket_bind(server,addr,TRUE,&error);g_assert_no_error(error);g_object_unref(addr);addr=g_socket_get_local_address(server,&error);g_assert_no_error(error);g_assert_cmpint(g_inet_socket_address_get_port(G_INET_SOCKET_ADDRESS(addr)),!=,0);g_object_unref(addr);if(socket_type==G_SOCKET_TYPE_STREAM){g_socket_listen(server,&error);g_assert_no_error(error);}else{data->cancellable=g_cancellable_new();}data->thread=g_thread_new("server",server_thread,data);returndata;}staticIPTestData*create_server(GSocketFamilyfamily,GThreadFuncserver_thread,gbooleanv4mapped){returncreate_server_full(family,G_SOCKET_TYPE_STREAM,server_thread,v4mapped);}staticconstgchar*testbuf="0123456789abcdef";staticgbooleantest_ip_async_read_ready(GSocket*client,GIOConditioncond,gpointeruser_data){IPTestData*data=user_data;GError*error=NULL;gssizelen;gcharbuf[128];g_assert_cmpint(cond,==,G_IO_IN);len=g_socket_receive(client,buf,sizeof(buf),NULL,&error);g_assert_no_error(error);g_assert_cmpint(len,==,strlen(testbuf)+1);g_assert_cmpstr(testbuf,==,buf);g_main_loop_quit(data->loop);returnFALSE;}staticgbooleantest_ip_async_write_ready(GSocket*client,GIOConditioncond,gpointeruser_data){IPTestData*data=user_data;GError*error=NULL;GSource*source;gssizelen;g_assert_cmpint(cond,==,G_IO_OUT);len=g_socket_send(client,testbuf,strlen(testbuf)+1,NULL,&error);g_assert_no_error(error);g_assert_cmpint(len,==,strlen(testbuf)+1);source=g_socket_create_source(client,G_IO_IN,NULL);g_source_set_callback(source,(GSourceFunc)test_ip_async_read_ready,data,NULL);g_source_attach(source,NULL);g_source_unref(source);returnFALSE;}staticgbooleantest_ip_async_timed_out(GSocket*client,GIOConditioncond,gpointeruser_data){IPTestData*data=user_data;GError*error=NULL;GSource*source;gssizelen;gcharbuf[128];if(data->family==G_SOCKET_FAMILY_IPV4){g_assert_cmpint(cond,==,G_IO_IN);len=g_socket_receive(client,buf,sizeof(buf),NULL,&error);g_assert_cmpint(len,==,-1);g_assert_error(error,G_IO_ERROR,G_IO_ERROR_TIMED_OUT);g_clear_error(&error);}source=g_socket_create_source(client,G_IO_OUT,NULL);g_source_set_callback(source,(GSourceFunc)test_ip_async_write_ready,data,NULL);g_source_attach(source,NULL);g_source_unref(source);returnFALSE;}staticgbooleantest_ip_async_connected(GSocket*client,GIOConditioncond,gpointeruser_data){IPTestData*data=user_data;GError*error=NULL;GSource*source;gssizelen;gcharbuf[128];g_socket_check_connect_result(client,&error);g_assert_no_error(error);/* We do this after the check_connect_result, since that will give a * more useful assertion in case of error. */g_assert_cmpint(cond,==,G_IO_OUT);g_assert(g_socket_is_connected(client));/* This adds 1 second to "make check", so let's just only do it once. */if(data->family==G_SOCKET_FAMILY_IPV4){len=g_socket_receive(client,buf,sizeof(buf),NULL,&error);g_assert_cmpint(len,==,-1);g_assert_error(error,G_IO_ERROR,G_IO_ERROR_WOULD_BLOCK);g_clear_error(&error);source=g_socket_create_source(client,G_IO_IN,NULL);g_source_set_callback(source,(GSourceFunc)test_ip_async_timed_out,data,NULL);g_source_attach(source,NULL);g_source_unref(source);}elsetest_ip_async_timed_out(client,0,data);returnFALSE;}staticgbooleanidle_test_ip_async_connected(gpointeruser_data){IPTestData*data=user_data;returntest_ip_async_connected(data->client,G_IO_OUT,data);}staticvoidtest_ip_async(GSocketFamilyfamily){IPTestData*data;GError*error=NULL;GSocket*client;GSocketAddress*addr;GSource*source;gssizelen;gcharbuf[128];data=create_server(family,echo_server_thread,FALSE);addr=g_socket_get_local_address(data->server,&error);g_assert_no_error(error);client=g_socket_new(family,G_SOCKET_TYPE_STREAM,G_SOCKET_PROTOCOL_DEFAULT,&error);g_assert_no_error(error);data->client=client;g_assert_cmpint(g_socket_get_family(client),==,family);g_assert_cmpint(g_socket_get_socket_type(client),==,G_SOCKET_TYPE_STREAM);g_assert_cmpint(g_socket_get_protocol(client),==,G_SOCKET_PROTOCOL_DEFAULT);g_socket_set_blocking(client,FALSE);g_socket_set_timeout(client,1);if(g_socket_connect(client,addr,NULL,&error)){g_assert_no_error(error);g_idle_add(idle_test_ip_async_connected,data);}else{g_assert_error(error,G_IO_ERROR,G_IO_ERROR_PENDING);g_clear_error(&error);source=g_socket_create_source(client,G_IO_OUT,NULL);g_source_set_callback(source,(GSourceFunc)test_ip_async_connected,data,NULL);g_source_attach(source,NULL);g_source_unref(source);}g_object_unref(addr);data->loop=g_main_loop_new(NULL,TRUE);g_main_loop_run(data->loop);g_main_loop_unref(data->loop);g_socket_shutdown(client,FALSE,TRUE,&error);g_assert_no_error(error);g_thread_join(data->thread);if(family==G_SOCKET_FAMILY_IPV4){/* Test that reading on a remote-closed socket gets back 0 bytes. */len=g_socket_receive_with_blocking(client,buf,sizeof(buf),TRUE,NULL,&error);g_assert_no_error(error);g_assert_cmpint(len,==,0);}else{/* Test that writing to a remote-closed socket gets back CONNECTION_CLOSED. */len=g_socket_send_with_blocking(client,testbuf,strlen(testbuf)+1,TRUE,NULL,&error);g_assert_error(error,G_IO_ERROR,G_IO_ERROR_CONNECTION_CLOSED);g_assert_cmpint(len,==,-1);g_clear_error(&error);}g_socket_close(client,&error);g_assert_no_error(error);g_socket_close(data->server,&error);g_assert_no_error(error);g_object_unref(data->server);g_object_unref(client);g_slice_free(IPTestData,data);}staticvoidtest_ipv4_async(void){test_ip_async(G_SOCKET_FAMILY_IPV4);}staticvoidtest_ipv6_async(void){if(!ipv6_supported){g_test_skip("No support for IPv6");return;}test_ip_async(G_SOCKET_FAMILY_IPV6);}staticconstgchartestbuf2[]="0123456789abcdefghijklmnopqrstuvwxyz";staticvoidtest_ip_sync(GSocketFamilyfamily){IPTestData*data;GError*error=NULL;GSocket*client;GSocketAddress*addr;gssizelen;gcharbuf[128];data=create_server(family,echo_server_thread,FALSE);addr=g_socket_get_local_address(data->server,&error);g_assert_no_error(error);client=g_socket_new(family,G_SOCKET_TYPE_STREAM,G_SOCKET_PROTOCOL_DEFAULT,&error);g_assert_no_error(error);g_assert_cmpint(g_socket_get_family(client),==,family);g_assert_cmpint(g_socket_get_socket_type(client),==,G_SOCKET_TYPE_STREAM);g_assert_cmpint(g_socket_get_protocol(client),==,G_SOCKET_PROTOCOL_DEFAULT);g_socket_set_blocking(client,TRUE);g_socket_set_timeout(client,1);g_socket_connect(client,addr,NULL,&error);g_assert_no_error(error);g_assert(g_socket_is_connected(client));g_object_unref(addr);/* This adds 1 second to "make check", so let's just only do it once. */if(family==G_SOCKET_FAMILY_IPV4){len=g_socket_receive(client,buf,sizeof(buf),NULL,&error);g_assert_cmpint(len,==,-1);g_assert_error(error,G_IO_ERROR,G_IO_ERROR_TIMED_OUT);g_clear_error(&error);}len=g_socket_send(client,testbuf,strlen(testbuf)+1,NULL,&error);g_assert_no_error(error);g_assert_cmpint(len,==,strlen(testbuf)+1);len=g_socket_receive(client,buf,sizeof(buf),NULL,&error);g_assert_no_error(error);g_assert_cmpint(len,==,strlen(testbuf)+1);g_assert_cmpstr(testbuf,==,buf);{GOutputVectorv[7]={{NULL,},};v[0].buffer=testbuf2+0;v[0].size=3;v[1].buffer=testbuf2+3;v[1].size=5;v[2].buffer=testbuf2+3+5;v[2].size=0;v[3].buffer=testbuf2+3+5;v[3].size=6;v[4].buffer=testbuf2+3+5+6;v[4].size=2;v[5].buffer=testbuf2+3+5+6+2;v[5].size=1;v[6].buffer=testbuf2+3+5+6+2+1;v[6].size=strlen(testbuf2)-(3+5+6+2+1);len=g_socket_send_message(client,NULL,v,G_N_ELEMENTS(v),NULL,0,0,NULL,&error);g_assert_no_error(error);g_assert_cmpint(len,==,strlen(testbuf2));memset(buf,0,sizeof(buf));len=g_socket_receive(client,buf,sizeof(buf),NULL,&error);g_assert_no_error(error);g_assert_cmpint(len,==,strlen(testbuf2));g_assert_cmpstr(testbuf2,==,buf);}g_socket_shutdown(client,FALSE,TRUE,&error);g_assert_no_error(error);g_thread_join(data->thread);if(family==G_SOCKET_FAMILY_IPV4){/* Test that reading on a remote-closed socket gets back 0 bytes. */len=g_socket_receive(client,buf,sizeof(buf),NULL,&error);g_assert_no_error(error);g_assert_cmpint(len,==,0);}else{/* Test that writing to a remote-closed socket gets back CONNECTION_CLOSED. */len=g_socket_send(client,testbuf,strlen(testbuf)+1,NULL,&error);g_assert_error(error,G_IO_ERROR,G_IO_ERROR_CONNECTION_CLOSED);g_assert_cmpint(len,==,-1);g_clear_error(&error);}g_socket_close(client,&error);g_assert_no_error(error);g_socket_close(data->server,&error);g_assert_no_error(error);g_object_unref(data->server);g_object_unref(client);g_slice_free(IPTestData,data);}staticvoidtest_ipv4_sync(void){test_ip_sync(G_SOCKET_FAMILY_IPV4);}staticvoidtest_ipv6_sync(void){if(!ipv6_supported){g_test_skip("No support for IPv6");return;}test_ip_sync(G_SOCKET_FAMILY_IPV6);}staticvoidtest_ip_sync_dgram(GSocketFamilyfamily){IPTestData*data;GError*error=NULL;GSocket*client;GSocketAddress*dest_addr;gssizelen;gcharbuf[128];data=create_server_full(family,G_SOCKET_TYPE_DATAGRAM,echo_server_dgram_thread,FALSE);dest_addr=g_socket_get_local_address(data->server,&error);client=g_socket_new(family,G_SOCKET_TYPE_DATAGRAM,G_SOCKET_PROTOCOL_DEFAULT,&error);g_assert_no_error(error);g_assert_cmpint(g_socket_get_family(client),==,family);g_assert_cmpint(g_socket_get_socket_type(client),==,G_SOCKET_TYPE_DATAGRAM);g_assert_cmpint(g_socket_get_protocol(client),==,G_SOCKET_PROTOCOL_DEFAULT);g_socket_set_blocking(client,TRUE);g_socket_set_timeout(client,1);len=g_socket_send_to(client,dest_addr,testbuf,strlen(testbuf)+1,NULL,&error);g_assert_no_error(error);g_assert_cmpint(len,==,strlen(testbuf)+1);len=g_socket_receive_from(client,NULL,buf,sizeof(buf),NULL,&error);g_assert_no_error(error);g_assert_cmpint(len,==,strlen(testbuf)+1);g_assert_cmpstr(testbuf,==,buf);{GOutputMessagem[3]={{NULL,},};GOutputVectorv[7]={{NULL,},};v[0].buffer=testbuf2+0;v[0].size=3;v[1].buffer=testbuf2+3;v[1].size=5;v[2].buffer=testbuf2+3+5;v[2].size=0;v[3].buffer=testbuf2+3+5;v[3].size=6;v[4].buffer=testbuf2+3+5+6;v[4].size=2;v[5].buffer=testbuf2+3+5+6+2;v[5].size=1;v[6].buffer=testbuf2+3+5+6+2+1;v[6].size=strlen(testbuf2)-(3+5+6+2+1);len=g_socket_send_message(client,dest_addr,v,G_N_ELEMENTS(v),NULL,0,0,NULL,&error);g_assert_no_error(error);g_assert_cmpint(len,==,strlen(testbuf2));memset(buf,0,sizeof(buf));len=g_socket_receive_from(client,NULL,buf,sizeof(buf),NULL,&error);g_assert_no_error(error);g_assert_cmpint(len,==,strlen(testbuf2));g_assert_cmpstr(testbuf2,==,buf);m[0].vectors=&v[0];m[0].num_vectors=1;m[0].address=dest_addr;m[1].vectors=&v[0];m[1].num_vectors=6;m[1].address=dest_addr;m[2].vectors=&v[6];m[2].num_vectors=1;m[2].address=dest_addr;len=g_socket_send_messages(client,m,G_N_ELEMENTS(m),0,NULL,&error);g_assert_no_error(error);g_assert_cmpint(len,==,G_N_ELEMENTS(m));g_assert_cmpint(m[0].bytes_sent,==,3);g_assert_cmpint(m[1].bytes_sent,==,17);g_assert_cmpint(m[2].bytes_sent,==,v[6].size);memset(buf,0,sizeof(buf));len=g_socket_receive_from(client,NULL,buf,sizeof(buf),NULL,&error);g_assert_no_error(error);g_assert_cmpint(len,==,3);memset(buf,0,sizeof(buf));len=g_socket_receive_from(client,NULL,buf,sizeof(buf),NULL,&error);g_assert_no_error(error);/* v[0].size + v[1].size + v[2].size + v[3].size + v[4].size + v[5].size */g_assert_cmpint(len,==,17);g_assert(memcmp(testbuf2,buf,17)==0);memset(buf,0,sizeof(buf));len=g_socket_receive_from(client,NULL,buf,sizeof(buf),NULL,&error);g_assert_no_error(error);g_assert_cmpint(len,==,v[6].size);g_assert_cmpstr(buf,==,v[6].buffer);/* reset since we're re-using the message structs */m[0].bytes_sent=0;m[1].bytes_sent=0;m[2].bytes_sent=0;/* now try to generate an error by omitting the destination address on [1] */m[1].address=NULL;len=g_socket_send_messages(client,m,G_N_ELEMENTS(m),0,NULL,&error);g_assert_error(error,G_IO_ERROR,G_IO_ERROR_FAILED);g_clear_error(&error);g_assert_cmpint(len,==,-1);g_assert_cmpint(m[0].bytes_sent,==,3);g_assert_cmpint(m[1].bytes_sent,==,0);g_assert_cmpint(m[2].bytes_sent,==,0);len=g_socket_receive_from(client,NULL,buf,sizeof(buf),NULL,&error);g_assert_cmpint(len,==,3);}g_cancellable_cancel(data->cancellable);g_thread_join(data->thread);g_socket_close(client,&error);g_assert_no_error(error);g_socket_close(data->server,&error);g_assert_no_error(error);g_object_unref(data->server);g_object_unref(data->cancellable);g_object_unref(client);g_object_unref(dest_addr);g_slice_free(IPTestData,data);}staticvoidtest_ipv4_sync_dgram(void){test_ip_sync_dgram(G_SOCKET_FAMILY_IPV4);}staticvoidtest_ipv6_sync_dgram(void){if(!ipv6_supported){g_test_skip("No support for IPv6");return;}test_ip_sync_dgram(G_SOCKET_FAMILY_IPV6);}staticgpointergraceful_server_thread(gpointeruser_data){IPTestData*data=user_data;GSocket*sock;GError*error=NULL;gssizelen;sock=g_socket_accept(data->server,NULL,&error);g_assert_no_error(error);len=g_socket_send(sock,testbuf,strlen(testbuf)+1,NULL,&error);g_assert_no_error(error);g_assert_cmpint(len,==,strlen(testbuf)+1);returnsock;}staticvoidtest_close_graceful(void){GSocketFamilyfamily=G_SOCKET_FAMILY_IPV4;IPTestData*data;GError*error=NULL;GSocket*client,*server;GSocketAddress*addr;gssizelen;gcharbuf[128];data=create_server(family,graceful_server_thread,FALSE);addr=g_socket_get_local_address(data->server,&error);g_assert_no_error(error);client=g_socket_new(family,G_SOCKET_TYPE_STREAM,G_SOCKET_PROTOCOL_DEFAULT,&error);g_assert_no_error(error);g_assert_cmpint(g_socket_get_family(client),==,family);g_assert_cmpint(g_socket_get_socket_type(client),==,G_SOCKET_TYPE_STREAM);g_assert_cmpint(g_socket_get_protocol(client),==,G_SOCKET_PROTOCOL_DEFAULT);g_socket_set_blocking(client,TRUE);g_socket_set_timeout(client,1);g_socket_connect(client,addr,NULL,&error);g_assert_no_error(error);g_assert(g_socket_is_connected(client));g_object_unref(addr);server=g_thread_join(data->thread);/* similar to g_tcp_connection_set_graceful_disconnect(), but explicit */g_socket_shutdown(server,FALSE,TRUE,&error);g_assert_no_error(error);/* we must timeout */g_socket_condition_wait(client,G_IO_HUP,NULL,&error);g_assert_error(error,G_IO_ERROR,G_IO_ERROR_TIMED_OUT);g_clear_error(&error);/* check that the remaining data is received */len=g_socket_receive(client,buf,strlen(testbuf)+1,NULL,&error);g_assert_no_error(error);g_assert_cmpint(len,==,strlen(testbuf)+1);/* and only then the connection is closed */len=g_socket_receive(client,buf,sizeof(buf),NULL,&error);g_assert_no_error(error);g_assert_cmpint(len,==,0);g_socket_close(server,&error);g_assert_no_error(error);g_socket_close(client,&error);g_assert_no_error(error);g_object_unref(server);g_object_unref(data->server);g_object_unref(client);g_slice_free(IPTestData,data);}#if defined (IPPROTO_IPV6) && defined (IPV6_V6ONLY)staticgpointerv4mapped_server_thread(gpointeruser_data){IPTestData*data=user_data;GSocket*sock;GError*error=NULL;GSocketAddress*addr;sock=g_socket_accept(data->server,NULL,&error);g_assert_no_error(error);g_assert_cmpint(g_socket_get_family(sock),==,G_SOCKET_FAMILY_IPV6);addr=g_socket_get_local_address(sock,&error);g_assert_no_error(error);g_assert_cmpint(g_socket_address_get_family(addr),==,G_SOCKET_FAMILY_IPV4);g_object_unref(addr);addr=g_socket_get_remote_address(sock,&error);g_assert_no_error(error);g_assert_cmpint(g_socket_address_get_family(addr),==,G_SOCKET_FAMILY_IPV4);g_object_unref(addr);g_socket_close(sock,&error);g_assert_no_error(error);g_object_unref(sock);returnNULL;}staticvoidtest_ipv6_v4mapped(void){IPTestData*data;GError*error=NULL;GSocket*client;GSocketAddress*addr,*v4addr;GInetAddress*iaddr;if(!ipv6_supported){g_test_skip("No support for IPv6");return;}data=create_server(G_SOCKET_FAMILY_IPV6,v4mapped_server_thread,TRUE);if(data==NULL){g_test_message("Test not run: not supported by the OS");return;}client=g_socket_new(G_SOCKET_FAMILY_IPV4,G_SOCKET_TYPE_STREAM,G_SOCKET_PROTOCOL_DEFAULT,&error);g_assert_no_error(error);g_socket_set_blocking(client,TRUE);g_socket_set_timeout(client,1);addr=g_socket_get_local_address(data->server,&error);g_assert_no_error(error);iaddr=g_inet_address_new_loopback(G_SOCKET_FAMILY_IPV4);v4addr=g_inet_socket_address_new(iaddr,g_inet_socket_address_get_port(G_INET_SOCKET_ADDRESS(addr)));g_object_unref(iaddr);g_object_unref(addr);g_socket_connect(client,v4addr,NULL,&error);g_assert_no_error(error);g_assert(g_socket_is_connected(client));g_thread_join(data->thread);g_socket_close(client,&error);g_assert_no_error(error);g_socket_close(data->server,&error);g_assert_no_error(error);g_object_unref(data->server);g_object_unref(client);g_object_unref(v4addr);g_slice_free(IPTestData,data);}#endifstaticvoidtest_timed_wait(void){IPTestData*data;GError*error=NULL;GSocket*client;GSocketAddress*addr;gint64start_time;gintpoll_duration;data=create_server(G_SOCKET_FAMILY_IPV4,echo_server_thread,FALSE);addr=g_socket_get_local_address(data->server,&error);g_assert_no_error(error);client=g_socket_new(G_SOCKET_FAMILY_IPV4,G_SOCKET_TYPE_STREAM,G_SOCKET_PROTOCOL_DEFAULT,&error);g_assert_no_error(error);g_socket_set_blocking(client,TRUE);g_socket_set_timeout(client,1);g_socket_connect(client,addr,NULL,&error);g_assert_no_error(error);g_object_unref(addr);start_time=g_get_monotonic_time();g_socket_condition_timed_wait(client,G_IO_IN,100000/* 100 ms */,NULL,&error);g_assert_error(error,G_IO_ERROR,G_IO_ERROR_TIMED_OUT);g_clear_error(&error);poll_duration=g_get_monotonic_time()-start_time;g_assert_cmpint(poll_duration,>=,98000);g_assert_cmpint(poll_duration,<,112000);g_socket_close(client,&error);g_assert_no_error(error);g_thread_join(data->thread);g_socket_close(data->server,&error);g_assert_no_error(error);g_object_unref(data->server);g_object_unref(client);g_slice_free(IPTestData,data);}staticintduplicate_fd(intfd){#ifdef G_OS_WIN32HANDLEnewfd;if(!DuplicateHandle(GetCurrentProcess(),(HANDLE)fd,GetCurrentProcess(),&newfd,0,FALSE,DUPLICATE_SAME_ACCESS)){return-1;}return(int)newfd;#elsereturndup(fd);#endif}staticvoidtest_fd_reuse(void){IPTestData*data;GError*error=NULL;GSocket*client;GSocket*client2;GSocketAddress*addr;intfd;gssizelen;gcharbuf[128];g_test_bug("741707");data=create_server(G_SOCKET_FAMILY_IPV4,echo_server_thread,FALSE);addr=g_socket_get_local_address(data->server,&error);g_assert_no_error(error);client=g_socket_new(G_SOCKET_FAMILY_IPV4,G_SOCKET_TYPE_STREAM,G_SOCKET_PROTOCOL_DEFAULT,&error);g_assert_no_error(error);g_socket_set_blocking(client,TRUE);g_socket_set_timeout(client,1);g_socket_connect(client,addr,NULL,&error);g_assert_no_error(error);g_assert(g_socket_is_connected(client));g_object_unref(addr);/* we have to dup otherwise the fd gets closed twice on unref */fd=duplicate_fd(g_socket_get_fd(client));client2=g_socket_new_from_fd(fd,&error);g_assert_no_error(error);g_assert_cmpint(g_socket_get_family(client2),==,g_socket_get_family(client));g_assert_cmpint(g_socket_get_socket_type(client2),==,g_socket_get_socket_type(client));g_assert_cmpint(g_socket_get_protocol(client2),==,G_SOCKET_PROTOCOL_TCP);len=g_socket_send(client2,testbuf,strlen(testbuf)+1,NULL,&error);g_assert_no_error(error);g_assert_cmpint(len,==,strlen(testbuf)+1);len=g_socket_receive(client2,buf,sizeof(buf),NULL,&error);g_assert_no_error(error);g_assert_cmpint(len,==,strlen(testbuf)+1);g_assert_cmpstr(testbuf,==,buf);g_socket_shutdown(client,FALSE,TRUE,&error);g_assert_no_error(error);/* The semantics of dup()+shutdown() are ambiguous; this call will succeed * on Linux, but return ENOTCONN on OS X. */g_socket_shutdown(client2,FALSE,TRUE,NULL);g_thread_join(data->thread);g_socket_close(client,&error);g_assert_no_error(error);g_socket_close(client2,&error);g_assert_no_error(error);g_socket_close(data->server,&error);g_assert_no_error(error);g_object_unref(data->server);g_object_unref(client);g_object_unref(client2);g_slice_free(IPTestData,data);}staticvoidtest_sockaddr(void){structsockaddr_in6sin6,gsin6;GSocketAddress*saddr;GInetSocketAddress*isaddr;GInetAddress*iaddr;GError*error=NULL;memset(&sin6,0,sizeof(sin6));sin6.sin6_family=AF_INET6;sin6.sin6_addr=in6addr_loopback;sin6.sin6_port=g_htons(42);sin6.sin6_scope_id=17;sin6.sin6_flowinfo=1729;saddr=g_socket_address_new_from_native(&sin6,sizeof(sin6));g_assert(G_IS_INET_SOCKET_ADDRESS(saddr));isaddr=G_INET_SOCKET_ADDRESS(saddr);iaddr=g_inet_socket_address_get_address(isaddr);g_assert_cmpint(g_inet_address_get_family(iaddr),==,G_SOCKET_FAMILY_IPV6);g_assert(g_inet_address_get_is_loopback(iaddr));g_assert_cmpint(g_inet_socket_address_get_port(isaddr),==,42);g_assert_cmpint(g_inet_socket_address_get_scope_id(isaddr),==,17);g_assert_cmpint(g_inet_socket_address_get_flowinfo(isaddr),==,1729);g_socket_address_to_native(saddr,&gsin6,sizeof(gsin6),&error);g_assert_no_error(error);g_assert(memcmp(&sin6.sin6_addr,&gsin6.sin6_addr,sizeof(structin6_addr))==0);g_assert_cmpint(sin6.sin6_port,==,gsin6.sin6_port);g_assert_cmpint(sin6.sin6_scope_id,==,gsin6.sin6_scope_id);g_assert_cmpint(sin6.sin6_flowinfo,==,gsin6.sin6_flowinfo);g_object_unref(saddr);}#ifdef G_OS_UNIXstaticvoidtest_unix_from_fd(void){gintfd;GError*error;GSocket*s;fd=socket(AF_UNIX,SOCK_STREAM,0);g_assert_cmpint(fd,!=,-1);error=NULL;s=g_socket_new_from_fd(fd,&error);g_assert_no_error(error);g_assert_cmpint(g_socket_get_family(s),==,G_SOCKET_FAMILY_UNIX);g_assert_cmpint(g_socket_get_socket_type(s),==,G_SOCKET_TYPE_STREAM);g_assert_cmpint(g_socket_get_protocol(s),==,G_SOCKET_PROTOCOL_DEFAULT);g_object_unref(s);}staticvoidtest_unix_connection(void){gintfd;GError*error;GSocket*s;GSocketConnection*c;fd=socket(AF_UNIX,SOCK_STREAM,0);g_assert_cmpint(fd,!=,-1);error=NULL;s=g_socket_new_from_fd(fd,&error);g_assert_no_error(error);c=g_socket_connection_factory_create_connection(s);g_assert(G_IS_UNIX_CONNECTION(c));g_object_unref(c);g_object_unref(s);}staticGSocketConnection*create_connection_for_fd(intfd){GError*err=NULL;GSocket*socket;GSocketConnection*connection;socket=g_socket_new_from_fd(fd,&err);g_assert_no_error(err);g_assert(G_IS_SOCKET(socket));connection=g_socket_connection_factory_create_connection(socket);g_assert(G_IS_UNIX_CONNECTION(connection));g_object_unref(socket);returnconnection;}#define TEST_DATA "failure to say failure to say 'i love gnome-panel!'."staticvoidtest_unix_connection_ancillary_data(void){GError*err=NULL;gintpv[2],sv[3];gintstatus,fd,len;charbuffer[1024];pid_tpid;status=pipe(pv);g_assert_cmpint(status,==,0);status=socketpair(PF_UNIX,SOCK_STREAM,0,sv);g_assert_cmpint(status,==,0);pid=fork();g_assert_cmpint(pid,>=,0);/* Child: close its copy of the write end of the pipe, receive it * again from the parent over the socket, and write some text to it. * * Parent: send the write end of the pipe (still open for the * parent) over the socket, close it, and read some text from the * read end of the pipe. */if(pid==0){GSocketConnection*connection;close(sv[1]);connection=create_connection_for_fd(sv[0]);status=close(pv[1]);g_assert_cmpint(status,==,0);err=NULL;fd=g_unix_connection_receive_fd(G_UNIX_CONNECTION(connection),NULL,&err);g_assert_no_error(err);g_assert_cmpint(fd,>,-1);g_object_unref(connection);dolen=write(fd,TEST_DATA,sizeof(TEST_DATA));while(len==-1&&errno==EINTR);g_assert_cmpint(len,==,sizeof(TEST_DATA));exit(0);}else{GSocketConnection*connection;close(sv[0]);connection=create_connection_for_fd(sv[1]);err=NULL;g_unix_connection_send_fd(G_UNIX_CONNECTION(connection),pv[1],NULL,&err);g_assert_no_error(err);g_object_unref(connection);status=close(pv[1]);g_assert_cmpint(status,==,0);memset(buffer,0xff,sizeofbuffer);dolen=read(pv[0],buffer,sizeofbuffer);while(len==-1&&errno==EINTR);g_assert_cmpint(len,==,sizeof(TEST_DATA));g_assert_cmpstr(buffer,==,TEST_DATA);waitpid(pid,&status,0);g_assert(WIFEXITED(status));g_assert_cmpint(WEXITSTATUS(status),==,0);}/* TODO: add test for g_unix_connection_send_credentials() and * g_unix_connection_receive_credentials(). */}#endif /* G_OS_UNIX */staticvoidtest_reuse_tcp(void){GSocket*sock1,*sock2;GError*error=NULL;GInetAddress*iaddr;GSocketAddress*addr;sock1=g_socket_new(G_SOCKET_FAMILY_IPV4,G_SOCKET_TYPE_STREAM,G_SOCKET_PROTOCOL_DEFAULT,&error);g_assert_no_error(error);iaddr=g_inet_address_new_loopback(G_SOCKET_FAMILY_IPV4);addr=g_inet_socket_address_new(iaddr,0);g_object_unref(iaddr);g_socket_bind(sock1,addr,TRUE,&error);g_object_unref(addr);g_assert_no_error(error);g_socket_listen(sock1,&error);g_assert_no_error(error);sock2=g_socket_new(G_SOCKET_FAMILY_IPV4,G_SOCKET_TYPE_STREAM,G_SOCKET_PROTOCOL_DEFAULT,&error);g_assert_no_error(error);addr=g_socket_get_local_address(sock1,&error);g_assert_no_error(error);g_socket_bind(sock2,addr,TRUE,&error);g_assert_error(error,G_IO_ERROR,G_IO_ERROR_ADDRESS_IN_USE);g_clear_error(&error);g_object_unref(addr);g_object_unref(sock1);g_object_unref(sock2);}staticvoidtest_reuse_udp(void){GSocket*sock1,*sock2;GError*error=NULL;GInetAddress*iaddr;GSocketAddress*addr;sock1=g_socket_new(G_SOCKET_FAMILY_IPV4,G_SOCKET_TYPE_DATAGRAM,G_SOCKET_PROTOCOL_DEFAULT,&error);g_assert_no_error(error);iaddr=g_inet_address_new_loopback(G_SOCKET_FAMILY_IPV4);addr=g_inet_socket_address_new(iaddr,0);g_object_unref(iaddr);g_socket_bind(sock1,addr,TRUE,&error);g_object_unref(addr);g_assert_no_error(error);sock2=g_socket_new(G_SOCKET_FAMILY_IPV4,G_SOCKET_TYPE_DATAGRAM,G_SOCKET_PROTOCOL_DEFAULT,&error);g_assert_no_error(error);addr=g_socket_get_local_address(sock1,&error);g_assert_no_error(error);g_socket_bind(sock2,addr,TRUE,&error);g_object_unref(addr);g_assert_no_error(error);g_object_unref(sock1);g_object_unref(sock2);}staticvoidtest_get_available(gconstpointeruser_data){GSocketTypesocket_type=GPOINTER_TO_UINT(user_data);GError*err=NULL;GSocket*listener,*server,*client;GInetAddress*addr;GSocketAddress*saddr;gchardata[]="0123456789abcdef";gcharbuf[34];gssizenread;listener=g_socket_new(G_SOCKET_FAMILY_IPV4,socket_type,G_SOCKET_PROTOCOL_DEFAULT,&err);g_assert_no_error(err);g_assert(G_IS_SOCKET(listener));client=g_socket_new(G_SOCKET_FAMILY_IPV4,socket_type,G_SOCKET_PROTOCOL_DEFAULT,&err);g_assert_no_error(err);g_assert(G_IS_SOCKET(client));if(socket_type==G_SOCKET_TYPE_STREAM){g_socket_set_option(client,IPPROTO_TCP,TCP_NODELAY,TRUE,&err);g_assert_no_error(err);}addr=g_inet_address_new_any(G_SOCKET_FAMILY_IPV4);saddr=g_inet_socket_address_new(addr,0);g_socket_bind(listener,saddr,TRUE,&err);g_assert_no_error(err);g_object_unref(saddr);g_object_unref(addr);saddr=g_socket_get_local_address(listener,&err);g_assert_no_error(err);if(socket_type==G_SOCKET_TYPE_STREAM){g_socket_listen(listener,&err);g_assert_no_error(err);g_socket_connect(client,saddr,NULL,&err);g_assert_no_error(err);server=g_socket_accept(listener,NULL,&err);g_assert_no_error(err);g_socket_set_blocking(server,FALSE);g_object_unref(listener);}elseserver=listener;g_socket_send_to(client,saddr,data,sizeof(data),NULL,&err);g_assert_no_error(err);while(!g_socket_condition_wait(server,G_IO_IN,NULL,NULL));g_assert_cmpint(g_socket_get_available_bytes(server),==,sizeof(data));g_socket_send_to(client,saddr,data,sizeof(data),NULL,&err);g_assert_no_error(err);/* We need to wait until the data has actually been copied into the * server socket's buffers, but g_socket_condition_wait() won't help * here since the socket is definitely already readable. So there's * a race condition in checking its available bytes. In the TCP * case, we poll for a bit until the new data shows up. In the UDP * case, there's not much we can do, but at least the failure mode * is passes-when-it-shouldn't, not fails-when-it-shouldn't. */if(socket_type==G_SOCKET_TYPE_STREAM){inttries;for(tries=0;tries<100;tries++){if(g_socket_get_available_bytes(server)>sizeof(data))break;g_usleep(100000);}g_assert_cmpint(g_socket_get_available_bytes(server),==,2*sizeof(data));}else{g_usleep(100000);g_assert_cmpint(g_socket_get_available_bytes(server),==,sizeof(data));}g_assert_cmpint(sizeof(buf),>=,2*sizeof(data));nread=g_socket_receive(server,buf,sizeof(buf),NULL,&err);g_assert_no_error(err);if(socket_type==G_SOCKET_TYPE_STREAM){g_assert_cmpint(nread,==,2*sizeof(data));g_assert_cmpint(g_socket_get_available_bytes(server),==,0);}else{g_assert_cmpint(nread,==,sizeof(data));g_assert_cmpint(g_socket_get_available_bytes(server),==,sizeof(data));}nread=g_socket_receive(server,buf,sizeof(buf),NULL,&err);if(socket_type==G_SOCKET_TYPE_STREAM){g_assert_cmpint(nread,==,-1);g_assert_error(err,G_IO_ERROR,G_IO_ERROR_WOULD_BLOCK);g_clear_error(&err);}else{g_assert_cmpint(nread,==,sizeof(data));g_assert_no_error(err);}g_assert_cmpint(g_socket_get_available_bytes(server),==,0);g_socket_close(server,&err);g_assert_no_error(err);g_object_unref(saddr);g_object_unref(server);g_object_unref(client);}intmain(intargc,char*argv[]){GSocket*sock;GError*error=NULL;g_test_init(&argc,&argv,NULL);g_test_bug_base("https://bugzilla.gnome.org/");sock=g_socket_new(G_SOCKET_FAMILY_IPV6,G_SOCKET_TYPE_STREAM,G_SOCKET_PROTOCOL_DEFAULT,&error);if(sock!=NULL){ipv6_supported=TRUE;g_object_unref(sock);}else{g_assert_error(error,G_IO_ERROR,G_IO_ERROR_NOT_SUPPORTED);g_clear_error(&error);}g_test_add_func("/socket/ipv4_sync",test_ipv4_sync);g_test_add_func("/socket/ipv4_async",test_ipv4_async);g_test_add_func("/socket/ipv6_sync",test_ipv6_sync);g_test_add_func("/socket/ipv6_async",test_ipv6_async);g_test_add_func("/socket/ipv4_sync/datagram",test_ipv4_sync_dgram);g_test_add_func("/socket/ipv6_sync/datagram",test_ipv6_sync_dgram);#if defined (IPPROTO_IPV6) && defined (IPV6_V6ONLY)g_test_add_func("/socket/ipv6_v4mapped",test_ipv6_v4mapped);#endifg_test_add_func("/socket/close_graceful",test_close_graceful);g_test_add_func("/socket/timed_wait",test_timed_wait);g_test_add_func("/socket/fd_reuse",test_fd_reuse);g_test_add_func("/socket/address",test_sockaddr);#ifdef G_OS_UNIXg_test_add_func("/socket/unix-from-fd",test_unix_from_fd);g_test_add_func("/socket/unix-connection",test_unix_connection);g_test_add_func("/socket/unix-connection-ancillary-data",test_unix_connection_ancillary_data);#endifg_test_add_func("/socket/reuse/tcp",test_reuse_tcp);g_test_add_func("/socket/reuse/udp",test_reuse_udp);g_test_add_data_func("/socket/get_available/datagram",GUINT_TO_POINTER(G_SOCKET_TYPE_DATAGRAM),test_get_available);g_test_add_data_func("/socket/get_available/stream",GUINT_TO_POINTER(G_SOCKET_TYPE_STREAM),test_get_available);returng_test_run();}