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