2a8659b56652b5f6173eb976b912d5fadf29b343
[senf.git] / Socket / TCPSocketHandle.test.cc
1 // $Id$
2 //
3 // Copyright (C) 2006 
4 // Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
5 // Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
6 //     Stefan Bund <stefan.bund@fokus.fraunhofer.de>
7 //
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 // GNU General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the
20 // Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22
23 // Unit tests
24
25 //#include "TCPSocketHandle.test.hh"
26 //#include "TCPSocketHandle.test.ih"
27
28 // Custom includes
29 #include <sys/types.h>
30 #include <sys/ioctl.h>
31 #include <sys/wait.h>
32 #include <unistd.h>
33 #include <sys/socket.h>
34 #include <netinet/in.h>
35 #include "TCPSocketHandle.hh"
36 #include <iostream>
37
38 #include <boost/test/auto_unit_test.hpp>
39 #include <boost/test/test_tools.hpp>
40
41 #define prefix_
42 ///////////////////////////////cc.p////////////////////////////////////////
43
44 namespace {
45
46     void error(char const * fn, char const * proc="")
47     {
48         std::cerr << "\n" << proc << fn << ": " << strerror(errno) << std::endl;
49     }
50
51     void fail(char const * fn)
52     {
53         error(fn,"server: ");
54         _exit(1);
55     }
56
57     int server_pid = 0;
58
59     void start(void (*fn)())
60     {
61         server_pid = ::fork();
62         if (server_pid < 0) BOOST_FAIL("fork()");
63         if (server_pid == 0) {
64             (*fn)();
65             _exit(0);
66         }
67     }
68
69     void wait()
70     {
71         int status;
72         if (waitpid(server_pid,&status,0)<0)
73             BOOST_FAIL("waitpid()");
74         BOOST_CHECK_EQUAL( status , 0 );
75     }
76
77     void stop()
78     {
79         kill(server_pid,9);
80         wait();
81     }
82
83 }
84
85 ///////////////////////////////////////////////////////////////////////////
86
87 namespace {
88
89     void server()
90     {
91         int serv = socket(PF_INET,SOCK_STREAM,0);
92         if (serv<0) fail("socket()");
93         int v = 1;
94         if (setsockopt(serv,SOL_SOCKET,SO_REUSEADDR,&v,sizeof(v))<0)
95             fail("setsockopt()");
96         struct sockaddr_in sin;
97         sin.sin_family = AF_INET;
98         sin.sin_port = htons(12345);
99         sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
100         if (bind(serv,(struct sockaddr *)&sin,sizeof(sin))<0) fail("bind()");
101         if (listen(serv,1)<0) fail("listen()");
102         int sock = accept(serv,0,0);
103         if (sock < 0) fail("accept()");
104
105         char buffer[1024];
106         while (1) {
107             int n = read(sock,buffer,1024);
108             if (n == 4 && strncmp(buffer,"QUIT",4) == 0)
109                 break;
110             write(sock,buffer,n);
111         }
112
113         if (shutdown(sock, SHUT_RDWR) < 0) fail("shutdown()");
114         if (close(sock) < 0) fail("close()");
115         if (close(serv) < 0) fail("close()");
116     }
117
118 }
119
120 BOOST_AUTO_UNIT_TEST(tcpv4ClientSocketHandle)
121 {
122     {
123         satcom::lib::TCPv4ClientSocketHandle sock;
124
125         BOOST_CHECK_THROW( sock.connect(satcom::lib::INet4Address("127.0.0.1:12345")), satcom::lib::SystemException );
126         BOOST_CHECK_THROW( sock.protocol().connect("127.0.0.1:12345"), satcom::lib::SystemException );
127     }
128
129     {
130         start(server);
131         satcom::lib::TCPv4ClientSocketHandle sock;
132         BOOST_CHECK_NO_THROW( sock.bind("127.0.0.1:23456") );
133         BOOST_CHECK_NO_THROW( sock.connect("127.0.0.1:12345") );
134         BOOST_CHECK( sock.peer() == "127.0.0.1:12345" );
135         BOOST_CHECK( sock.local() == "127.0.0.1:23456" );
136         BOOST_CHECK( sock.blocking() );
137         BOOST_CHECK_NO_THROW( sock.rcvbuf(2048) );
138         BOOST_CHECK_EQUAL( sock.rcvbuf(), 2048u );
139         BOOST_CHECK_NO_THROW( sock.sndbuf(2048) );
140         BOOST_CHECK_EQUAL( sock.sndbuf(), 2048u );
141         BOOST_CHECK_NO_THROW( sock.write("TEST-WRITE") );
142         BOOST_CHECK_EQUAL( sock.read(), "TEST-WRITE" );
143         // this fails with ENOFILE ... why ????
144         // BOOST_CHECK_NO_THROW( sock.protocol().timestamp() );
145         BOOST_CHECK( !sock.eof() );
146         sock.write("QUIT");
147         sleep(1);
148         stop();
149         sleep(1);
150         BOOST_CHECK_EQUAL( sock.read(), "" );
151         BOOST_CHECK( sock.eof() );
152         BOOST_CHECK( !sock );
153     }
154     
155     {
156         satcom::lib::TCPv4ClientSocketHandle sock;
157
158         // Since this is a TCP socket, most of the calls will fail or
159         // are at least not sensible ...
160         // I'll have to move those to a UDPSocket test ... they should
161         // realy only be in the UDP Protocol implementation
162         BOOST_CHECK_NO_THROW( sock.protocol().mcTTL() );
163         BOOST_CHECK_THROW( sock.protocol().mcTTL(1), satcom::lib::SystemException );
164         BOOST_CHECK_NO_THROW( sock.protocol().mcLoop() );
165         BOOST_CHECK_NO_THROW( sock.protocol().mcLoop(false) );
166         BOOST_CHECK_NO_THROW( sock.protocol().mcAddMembership("224.0.0.1:0") );
167         BOOST_CHECK_NO_THROW( sock.protocol().mcAddMembership("224.0.0.1:0","127.0.0.1:0") );
168         BOOST_CHECK_NO_THROW( sock.protocol().mcDropMembership("224.0.0.1:0","127.0.0.1:0") );
169         BOOST_CHECK_NO_THROW( sock.protocol().mcDropMembership("224.0.0.1:0") );
170         BOOST_CHECK_THROW( sock.protocol().mcIface("lo"), satcom::lib::SystemException );
171         
172         // The following setsockopts are hard to REALLY test ...
173         BOOST_CHECK_NO_THROW( sock.protocol().nodelay(true) );
174         BOOST_CHECK( sock.protocol().nodelay() );
175         BOOST_CHECK_EQUAL( sock.protocol().siocinq(), 0u );
176         BOOST_CHECK_EQUAL( sock.protocol().siocoutq(), 0u );
177
178         BOOST_CHECK_NO_THROW( sock.protocol().reuseaddr(true) );
179         BOOST_CHECK( sock.protocol().reuseaddr() );
180         BOOST_CHECK_NO_THROW( sock.protocol().linger(true,0) );
181         BOOST_CHECK( sock.protocol().linger() == std::make_pair(true, 0u) );
182     }
183 }
184
185 ///////////////////////////////////////////////////////////////////////////
186
187 namespace {
188
189     void client()
190     {
191         int sock = socket(PF_INET,SOCK_STREAM,0);
192         if (sock<0) fail("socket()");
193         struct sockaddr_in sin;
194         sin.sin_family = AF_INET;
195         sin.sin_port = htons(12346);
196         sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
197         if (connect(sock,(struct sockaddr *)&sin,sizeof(sin)) < 0)
198             fail("connect()");
199         
200         char buffer[1024];
201         while (1) {
202             int n = read(sock,buffer,1024);
203             if (n == 4 && strncmp(buffer,"QUIT",4) == 0)
204                 break;
205             write(sock,buffer,n);
206         }
207
208         if (shutdown(sock, SHUT_RDWR) < 0) fail("shutdown()");
209         if (close(sock) < 0) fail("close()");
210     }
211
212 }
213
214 BOOST_AUTO_UNIT_TEST(tcpv4ServerSocketHandle)
215 {
216     {
217         BOOST_CHECKPOINT("Opening server socket");
218         satcom::lib::TCPv4ServerSocketHandle server ("127.0.0.1:12346");
219         BOOST_CHECKPOINT("Starting client");
220         start(client);
221
222         BOOST_CHECKPOINT("Accepting connection");
223         satcom::lib::TCPv4ClientSocketHandle client = server.accept();
224         BOOST_CHECK_NO_THROW(client.write("QUIT"));
225
226         BOOST_CHECKPOINT("Stopping client");
227         sleep(1);
228         stop();
229     }
230 }
231
232 ///////////////////////////////cc.e////////////////////////////////////////
233 #undef prefix_
234
235 \f
236 // Local Variables:
237 // mode: c++
238 // c-file-style: "satcom"
239 // End: