4bb827b02cf5f94e9bfd5357d0f39a44ff78deee
[senf.git] / senf / Socket / Protocols / INet / TCPSocketHandle.test.cc
1 // $Id$
2 //
3 // Copyright (C) 2006
4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 //
6 // The contents of this file are subject to the Fraunhofer FOKUS Public License
7 // Version 1.0 (the "License"); you may not use this file except in compliance
8 // with the License. You may obtain a copy of the License at 
9 // http://senf.berlios.de/license.html
10 //
11 // The Fraunhofer FOKUS Public License Version 1.0 is based on, 
12 // but modifies the Mozilla Public License Version 1.1.
13 // See the full license text for the amendments.
14 //
15 // Software distributed under the License is distributed on an "AS IS" basis, 
16 // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 
17 // for the specific language governing rights and limitations under the License.
18 //
19 // The Original Code is Fraunhofer FOKUS code.
20 //
21 // The Initial Developer of the Original Code is Fraunhofer-Gesellschaft e.V. 
22 // (registered association), Hansastraße 27 c, 80686 Munich, Germany.
23 // All Rights Reserved.
24 //
25 // Contributor(s):
26 //   Stefan Bund <g0dil@berlios.de>
27
28 /** \file
29     \brief TCPSocketHandle unit tests */
30
31 //#include "TCPSocketHandle.test.hh"
32 //#include "TCPSocketHandle.test.ih"
33
34 // Custom includes
35 #include <sys/types.h>
36 #include <sys/ioctl.h>
37 #include <sys/wait.h>
38 #include <unistd.h>
39 #include <sys/socket.h>
40 #include <netinet/in.h>
41 #include <iostream>
42 #include "TCPSocketHandle.hh"
43 #include "net.test.hh"
44
45 #include <senf/Utils/auto_unit_test.hh>
46 #include <boost/test/test_tools.hpp>
47
48 #define prefix_
49 //-/////////////////////////////////////////////////////////////////////////////////////////////////
50
51 //-/////////////////////////////////////////////////////////////////////////////////////////////////
52
53 namespace {
54
55     void server_v4()
56     {
57         int serv = socket(PF_INET,SOCK_STREAM,0);
58         if (serv<0) fail("server_v4","socket()");
59         int v = 1;
60         if (setsockopt(serv,SOL_SOCKET,SO_REUSEADDR,&v,sizeof(v))<0)
61             fail("server_v4","setsockopt()");
62         struct sockaddr_in sin;
63         ::memset(&sin,0,sizeof(sin));
64         sin.sin_family = AF_INET;
65         sin.sin_port = htons(port(0));
66         sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
67         if (bind(serv,(struct sockaddr *)&sin,sizeof(sin))<0) fail("server_v4","bind()");
68         if (listen(serv,1)<0) fail("server_v4","listen()");
69         int sock = accept(serv,0,0);
70         if (sock < 0) fail("server_v4","accept()");
71
72         char buffer[1024];
73         while (1) {
74             int n = read(sock,buffer,1024);
75             if (n == 4 && strncmp(buffer,"QUIT",4) == 0)
76                 break;
77             senf::IGNORE( write(sock,buffer,n) );
78         }
79
80         if (shutdown(sock, SHUT_RDWR) < 0) fail("server_v4","shutdown()");
81         if (close(sock) < 0) fail("server_v4","close()");
82         if (close(serv) < 0) fail("server_v4","close()");
83     }
84
85     void server_v6()
86     {
87         int serv = socket(PF_INET6,SOCK_STREAM,0);
88         if (serv<0) fail("server_v6","socket()");
89         int v = 1;
90         if (setsockopt(serv,SOL_SOCKET,SO_REUSEADDR,&v,sizeof(v))<0)
91             fail("server_v6","setsockopt()");
92         struct sockaddr_in6 sin;
93         ::memset(&sin,0,sizeof(sin));
94         sin.sin6_family = AF_INET6;
95         sin.sin6_port = htons(port(0));
96         sin.sin6_addr = in6addr_loopback;
97         if (bind(serv,(struct sockaddr *)&sin,sizeof(sin))<0) fail("server_v6","bind()");
98         if (listen(serv,1)<0) fail("server_v6","listen()");
99         int sock = accept(serv,0,0);
100         if (sock < 0) fail("server_v6","accept()");
101
102         char buffer[1024];
103         while (1) {
104             int n = read(sock,buffer,1024);
105             if (n == 4 && strncmp(buffer,"QUIT",4) == 0)
106                 break;
107             senf::IGNORE( write(sock,buffer,n) );
108         }
109
110         if (shutdown(sock, SHUT_RDWR) < 0) fail("server_v6","shutdown()");
111         if (close(sock) < 0) fail("server_v6","close()");
112         if (close(serv) < 0) fail("server_v6","close()");
113     }
114
115 }
116
117 SENF_AUTO_UNIT_TEST(tcpv4ClientSocketHandle)
118 {
119     {
120         senf::TCPv4ClientSocketHandle sock;
121
122         BOOST_CHECK_THROW( sock.connect(senf::INet4SocketAddress(localhost4str(0))),
123                            senf::SystemException );
124     }
125
126     try {
127         alarm(10);
128         start(server_v4);
129         senf::TCPv4ClientSocketHandle sock;
130         SENF_CHECK_NO_THROW( sock.bind(senf::INet4SocketAddress(localhost4str(1))) );
131         SENF_CHECK_NO_THROW( sock.connect(senf::INet4SocketAddress(localhost4str(0))) );
132         BOOST_CHECK( sock.peer() == senf::INet4SocketAddress(localhost4str(0)) );
133         BOOST_CHECK( sock.local() == senf::INet4SocketAddress(localhost4str(1)) );
134         BOOST_CHECK( sock.blocking() );
135         SENF_CHECK_NO_THROW( sock.protocol().rcvbuf(2048) );
136         BOOST_CHECK_EQUAL( sock.protocol().rcvbuf(), 2048u );
137         SENF_CHECK_NO_THROW( sock.protocol().sndbuf(2048) );
138         BOOST_CHECK_EQUAL( sock.protocol().sndbuf(), 2048u );
139         SENF_CHECK_NO_THROW( sock.write(std::string("TEST-WRITE")) );
140         BOOST_CHECK_EQUAL( sock.read(), std::string("TEST-WRITE") );
141         BOOST_CHECK( !sock.eof() );
142         sock.write(std::string("QUIT"));
143         sleep(1);
144         stop();
145         sleep(1);
146         BOOST_CHECK_EQUAL( sock.read(), "" );
147         BOOST_CHECK( sock.eof() );
148         BOOST_CHECK( !sock );
149         alarm(0);
150     } catch (...) {
151         alarm(0);
152         sleep(1);
153         stop();
154         sleep(1);
155         throw;
156     }
157
158     {
159         senf::TCPv4ClientSocketHandle sock;
160
161         // Since this is a TCP socket, most of the calls will fail or
162         // are at least not sensible ...
163         // I'll have to move those to a UDPSocket test ... they should
164         // realy only be in the UDP Protocol implementation
165 //        SENF_CHECK_NO_THROW( sock.protocol().mcTTL() );
166 //        BOOST_CHECK_THROW( sock.protocol().mcTTL(1), senf::SystemException );
167 //        SENF_CHECK_NO_THROW( sock.protocol().mcLoop() );
168 //        SENF_CHECK_NO_THROW( sock.protocol().mcLoop(false) );
169 //        SENF_CHECK_NO_THROW( sock.protocol().mcAddMembership("224.0.0.1:0") );
170 //        SENF_CHECK_NO_THROW( sock.protocol().mcAddMembership("224.0.0.1:0","127.0.0.1:0") );
171 //        SENF_CHECK_NO_THROW( sock.protocol().mcDropMembership("224.0.0.1:0","127.0.0.1:0") );
172 //        SENF_CHECK_NO_THROW( sock.protocol().mcDropMembership("224.0.0.1:0") );
173 //        BOOST_CHECK_THROW( sock.protocol().mcIface("lo"), senf::SystemException );
174
175         // The following setsockopts are hard to REALLY test ...
176         SENF_CHECK_NO_THROW( sock.protocol().nodelay(true) );
177         BOOST_CHECK( sock.protocol().nodelay() );
178         BOOST_CHECK_EQUAL( sock.protocol().siocinq(), 0u );
179         BOOST_CHECK_EQUAL( sock.protocol().siocoutq(), 0u );
180
181         SENF_CHECK_NO_THROW( sock.protocol().reuseaddr(true) );
182         BOOST_CHECK( sock.protocol().reuseaddr() );
183         SENF_CHECK_NO_THROW( sock.protocol().linger(true,0) );
184         BOOST_CHECK( sock.protocol().linger() == std::make_pair(true, 0u) );
185     }
186 }
187
188 SENF_AUTO_UNIT_TEST(tcpv6ClientSocketHandle)
189 {
190     {
191         senf::TCPv6ClientSocketHandle sock;
192
193         BOOST_CHECK_THROW( sock.connect(senf::INet6SocketAddress(localhost6str(0))),
194                            senf::SystemException );
195     }
196
197     try {
198         alarm(10);
199         start(server_v6);
200         senf::TCPv6ClientSocketHandle sock;
201         SENF_CHECK_NO_THROW( sock.bind(senf::INet6SocketAddress(localhost6str(1))) );
202         SENF_CHECK_NO_THROW( sock.connect(senf::INet6SocketAddress(localhost6str(0))) );
203         BOOST_CHECK( sock.peer() == senf::INet6SocketAddress(localhost6str(0)) );
204         BOOST_CHECK( sock.local() == senf::INet6SocketAddress(localhost6str(1)) );
205         BOOST_CHECK( sock.blocking() );
206         SENF_CHECK_NO_THROW( sock.protocol().rcvbuf(2048) );
207         BOOST_CHECK_EQUAL( sock.protocol().rcvbuf(), 2048u );
208         SENF_CHECK_NO_THROW( sock.protocol().sndbuf(2048) );
209         BOOST_CHECK_EQUAL( sock.protocol().sndbuf(), 2048u );
210         SENF_CHECK_NO_THROW( sock.write(std::string("TEST-WRITE")) );
211         BOOST_CHECK_EQUAL( sock.read(), std::string("TEST-WRITE") );
212         // this fails with ENOFILE ... why ????
213         // SENF_CHECK_NO_THROW( sock.protocol().timestamp() );
214         BOOST_CHECK( !sock.eof() );
215         sock.write(std::string("QUIT"));
216         sleep(1);
217         stop();
218         sleep(1);
219         BOOST_CHECK_EQUAL( sock.read(), "" );
220         BOOST_CHECK( sock.eof() );
221         BOOST_CHECK( !sock );
222         alarm(0);
223     } catch (...) {
224         alarm(0);
225         sleep(1);
226         stop();
227         sleep(1);
228         throw;
229     }
230
231     {
232         senf::TCPv6ClientSocketHandle sock;
233
234         // The following setsockopts are hard to REALLY test ...
235         SENF_CHECK_NO_THROW( sock.protocol().nodelay(true) );
236         BOOST_CHECK( sock.protocol().nodelay() );
237         BOOST_CHECK_EQUAL( sock.protocol().siocinq(), 0u );
238         BOOST_CHECK_EQUAL( sock.protocol().siocoutq(), 0u );
239
240         SENF_CHECK_NO_THROW( sock.protocol().reuseaddr(true) );
241         BOOST_CHECK( sock.protocol().reuseaddr() );
242         SENF_CHECK_NO_THROW( sock.protocol().linger(true,0) );
243         BOOST_CHECK( sock.protocol().linger() == std::make_pair(true, 0u) );
244     }
245 }
246
247 //-/////////////////////////////////////////////////////////////////////////////////////////////////
248
249 namespace {
250
251     void client_v4()
252     {
253         int sock = socket(PF_INET,SOCK_STREAM,0);
254         if (sock<0) fail("client_v4","socket()");
255         struct sockaddr_in sin;
256         ::memset(&sin,0,sizeof(sin));
257         sin.sin_family = AF_INET;
258         sin.sin_port = htons(port(2));
259         sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
260         if (connect(sock,(struct sockaddr *)&sin,sizeof(sin)) < 0)
261             fail("client_v4","connect()");
262
263         char buffer[1024];
264         while (1) {
265             int n = read(sock,buffer,1024);
266             if (n == 4 && strncmp(buffer,"QUIT",4) == 0)
267                 break;
268             senf::IGNORE( write(sock,buffer,n) );
269         }
270
271         if (shutdown(sock, SHUT_RDWR) < 0) fail("client_v4","shutdown()");
272         if (close(sock) < 0) fail("client_v4","close()");
273     }
274
275     void client_v6()
276     {
277         int sock = socket(PF_INET6,SOCK_STREAM,0);
278         if (sock<0) fail("client_v6","socket()");
279         struct sockaddr_in6 sin;
280         ::memset(&sin,0,sizeof(sin));
281         sin.sin6_family = AF_INET6;
282         sin.sin6_port = htons(port(3));
283         sin.sin6_addr = in6addr_loopback;
284         if (connect(sock,(struct sockaddr *)&sin,sizeof(sin)) < 0)
285             fail("client_v6","connect()");
286
287         char buffer[1024];
288         while (1) {
289             int n = read(sock,buffer,1024);
290             if (n == 4 && strncmp(buffer,"QUIT",4) == 0)
291                 break;
292             senf::IGNORE( write(sock,buffer,n) );
293         }
294
295         if (shutdown(sock, SHUT_RDWR) < 0) fail("client_v6","shutdown()");
296         if (close(sock) < 0) fail("client_v6","close()");
297     }
298
299 }
300
301 SENF_AUTO_UNIT_TEST(tcpv4ServerSocketHandle)
302 {
303     try {
304         alarm(10);
305         BOOST_CHECKPOINT("Opening server socket");
306         senf::TCPv4ServerSocketHandle server (senf::INet4SocketAddress(localhost4str(2)));
307         BOOST_CHECKPOINT("Starting client");
308         start(client_v4);
309
310         BOOST_CHECKPOINT("Accepting connection");
311         senf::TCPv4ClientSocketHandle client = server.accept();
312         SENF_CHECK_NO_THROW(client.write(std::string("QUIT")));
313
314         BOOST_CHECKPOINT("Stopping client");
315         sleep(1);
316         stop();
317         alarm(0);
318     } catch (...) {
319         alarm(0);
320         sleep(1);
321         stop();
322         sleep(1);
323         throw;
324     }
325 }
326
327 SENF_AUTO_UNIT_TEST(tcpv6ServerSocketHandle)
328 {
329     try {
330         alarm(10);
331         BOOST_CHECKPOINT("Opening server socket");
332         senf::TCPv6ServerSocketHandle server (senf::INet6SocketAddress(localhost6str(3)));
333         BOOST_CHECKPOINT("Starting client");
334         start(client_v6);
335
336         BOOST_CHECKPOINT("Accepting connection");
337         senf::TCPv6ClientSocketHandle client = server.accept();
338         SENF_CHECK_NO_THROW(client.write(std::string("QUIT")));
339
340         BOOST_CHECKPOINT("Stopping client");
341         sleep(1);
342         stop();
343         alarm(0);
344     } catch (...) {
345         alarm(0);
346         sleep(1);
347         stop();
348         sleep(1);
349         throw;
350     }
351 }
352
353 //-/////////////////////////////////////////////////////////////////////////////////////////////////
354 #undef prefix_
355
356 \f
357 // Local Variables:
358 // mode: c++
359 // fill-column: 100
360 // c-file-style: "senf"
361 // indent-tabs-mode: nil
362 // ispell-local-dictionary: "american"
363 // compile-command: "scons -u test"
364 // comment-column: 40
365 // End: