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