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