removed some useless spaces; not very important, I know :)
[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     }
163
164     try {
165         alarm(10);
166         start(server_v4);
167         senf::TCPv4ClientSocketHandle sock;
168         BOOST_CHECK_NO_THROW( sock.bind(senf::INet4SocketAddress("127.0.0.1:23456")) );
169         BOOST_CHECK_NO_THROW( sock.connect(senf::INet4SocketAddress("127.0.0.1:12345")) );
170         BOOST_CHECK( sock.peer() == senf::INet4SocketAddress("127.0.0.1:12345") );
171         BOOST_CHECK( sock.local() == senf::INet4SocketAddress("127.0.0.1:23456") );
172         BOOST_CHECK( sock.blocking() );
173         BOOST_CHECK_NO_THROW( sock.protocol().rcvbuf(2048) );
174         BOOST_CHECK_EQUAL( sock.protocol().rcvbuf(), 2048u );
175         BOOST_CHECK_NO_THROW( sock.protocol().sndbuf(2048) );
176         BOOST_CHECK_EQUAL( sock.protocol().sndbuf(), 2048u );
177         BOOST_CHECK_NO_THROW( sock.write("TEST-WRITE") );
178         BOOST_CHECK_EQUAL( sock.read(), "TEST-WRITE" );
179         BOOST_CHECK( !sock.eof() );
180         sock.write("QUIT");
181         sleep(1);
182         stop();
183         sleep(1);
184         BOOST_CHECK_EQUAL( sock.read(), "" );
185         BOOST_CHECK( sock.eof() );
186         BOOST_CHECK( !sock );
187         alarm(0);
188     } catch (...) {
189         alarm(0);
190         sleep(1);
191         stop();
192         sleep(1);
193         throw;
194     }
195
196     {
197         senf::TCPv4ClientSocketHandle sock;
198
199         // Since this is a TCP socket, most of the calls will fail or
200         // are at least not sensible ...
201         // I'll have to move those to a UDPSocket test ... they should
202         // realy only be in the UDP Protocol implementation
203 //        BOOST_CHECK_NO_THROW( sock.protocol().mcTTL() );
204 //        BOOST_CHECK_THROW( sock.protocol().mcTTL(1), senf::SystemException );
205 //        BOOST_CHECK_NO_THROW( sock.protocol().mcLoop() );
206 //        BOOST_CHECK_NO_THROW( sock.protocol().mcLoop(false) );
207 //        BOOST_CHECK_NO_THROW( sock.protocol().mcAddMembership("224.0.0.1:0") );
208 //        BOOST_CHECK_NO_THROW( sock.protocol().mcAddMembership("224.0.0.1:0","127.0.0.1:0") );
209 //        BOOST_CHECK_NO_THROW( sock.protocol().mcDropMembership("224.0.0.1:0","127.0.0.1:0") );
210 //        BOOST_CHECK_NO_THROW( sock.protocol().mcDropMembership("224.0.0.1:0") );
211 //        BOOST_CHECK_THROW( sock.protocol().mcIface("lo"), senf::SystemException );
212
213         // The following setsockopts are hard to REALLY test ...
214         BOOST_CHECK_NO_THROW( sock.protocol().nodelay(true) );
215         BOOST_CHECK( sock.protocol().nodelay() );
216         BOOST_CHECK_EQUAL( sock.protocol().siocinq(), 0u );
217         BOOST_CHECK_EQUAL( sock.protocol().siocoutq(), 0u );
218
219         BOOST_CHECK_NO_THROW( sock.protocol().reuseaddr(true) );
220         BOOST_CHECK( sock.protocol().reuseaddr() );
221         BOOST_CHECK_NO_THROW( sock.protocol().linger(true,0) );
222         BOOST_CHECK( sock.protocol().linger() == std::make_pair(true, 0u) );
223     }
224 }
225
226 BOOST_AUTO_UNIT_TEST(tcpv6ClientSocketHandle)
227 {
228     {
229         senf::TCPv6ClientSocketHandle sock;
230
231         BOOST_CHECK_THROW( sock.connect(senf::INet6SocketAddress("[::1]:12345")), 
232                            senf::SystemException );
233     }
234
235     try {
236         alarm(10);
237         start(server_v6);
238         senf::TCPv6ClientSocketHandle sock;
239         BOOST_CHECK_NO_THROW( sock.bind(senf::INet6SocketAddress("[::1]:23456")) );
240         BOOST_CHECK_NO_THROW( sock.connect(senf::INet6SocketAddress("[::1]:12345")) );
241         BOOST_CHECK( sock.peer() == senf::INet6SocketAddress("[::1]:12345") );
242         BOOST_CHECK( sock.local() == senf::INet6SocketAddress("[::1]:23456") );
243         BOOST_CHECK( sock.blocking() );
244         BOOST_CHECK_NO_THROW( sock.protocol().rcvbuf(2048) );
245         BOOST_CHECK_EQUAL( sock.protocol().rcvbuf(), 2048u );
246         BOOST_CHECK_NO_THROW( sock.protocol().sndbuf(2048) );
247         BOOST_CHECK_EQUAL( sock.protocol().sndbuf(), 2048u );
248         BOOST_CHECK_NO_THROW( sock.write("TEST-WRITE") );
249         BOOST_CHECK_EQUAL( sock.read(), "TEST-WRITE" );
250         // this fails with ENOFILE ... why ????
251         // BOOST_CHECK_NO_THROW( sock.protocol().timestamp() );
252         BOOST_CHECK( !sock.eof() );
253         sock.write("QUIT");
254         sleep(1);
255         stop();
256         sleep(1);
257         BOOST_CHECK_EQUAL( sock.read(), "" );
258         BOOST_CHECK( sock.eof() );
259         BOOST_CHECK( !sock );
260         alarm(0);
261     } catch (...) {
262         alarm(0);
263         sleep(1);
264         stop();
265         sleep(1);
266         throw;
267     }
268
269     {
270         senf::TCPv6ClientSocketHandle sock;
271
272         // The following setsockopts are hard to REALLY test ...
273         BOOST_CHECK_NO_THROW( sock.protocol().nodelay(true) );
274         BOOST_CHECK( sock.protocol().nodelay() );
275         BOOST_CHECK_EQUAL( sock.protocol().siocinq(), 0u );
276         BOOST_CHECK_EQUAL( sock.protocol().siocoutq(), 0u );
277
278         BOOST_CHECK_NO_THROW( sock.protocol().reuseaddr(true) );
279         BOOST_CHECK( sock.protocol().reuseaddr() );
280         BOOST_CHECK_NO_THROW( sock.protocol().linger(true,0) );
281         BOOST_CHECK( sock.protocol().linger() == std::make_pair(true, 0u) );
282     }
283 }
284
285 ///////////////////////////////////////////////////////////////////////////
286
287 namespace {
288
289     void client_v4()
290     {
291         int sock = socket(PF_INET,SOCK_STREAM,0);
292         if (sock<0) fail("client_v4","socket()");
293         struct sockaddr_in sin;
294         ::memset(&sin,0,sizeof(sin));
295         sin.sin_family = AF_INET;
296         sin.sin_port = htons(12346);
297         sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
298         if (connect(sock,(struct sockaddr *)&sin,sizeof(sin)) < 0)
299             fail("client_v4","connect()");
300
301         char buffer[1024];
302         while (1) {
303             int n = read(sock,buffer,1024);
304             if (n == 4 && strncmp(buffer,"QUIT",4) == 0)
305                 break;
306             write(sock,buffer,n);
307         }
308
309         if (shutdown(sock, SHUT_RDWR) < 0) fail("client_v4","shutdown()");
310         if (close(sock) < 0) fail("client_v4","close()");
311     }
312
313     void client_v6()
314     {
315         int sock = socket(PF_INET6,SOCK_STREAM,0);
316         if (sock<0) fail("client_v6","socket()");
317         struct sockaddr_in6 sin;
318         ::memset(&sin,0,sizeof(sin));
319         sin.sin6_family = AF_INET6;
320         sin.sin6_port = htons(12347);
321         sin.sin6_addr = in6addr_loopback;
322         if (connect(sock,(struct sockaddr *)&sin,sizeof(sin)) < 0)
323             fail("client_v6","connect()");
324
325         char buffer[1024];
326         while (1) {
327             int n = read(sock,buffer,1024);
328             if (n == 4 && strncmp(buffer,"QUIT",4) == 0)
329                 break;
330             write(sock,buffer,n);
331         }
332
333         if (shutdown(sock, SHUT_RDWR) < 0) fail("client_v6","shutdown()");
334         if (close(sock) < 0) fail("client_v6","close()");
335     }
336
337 }
338
339 BOOST_AUTO_UNIT_TEST(tcpv4ServerSocketHandle)
340 {
341     try {
342         alarm(10);
343         BOOST_CHECKPOINT("Opening server socket");
344         senf::TCPv4ServerSocketHandle server (senf::INet4SocketAddress("127.0.0.1:12346"));
345         BOOST_CHECKPOINT("Starting client");
346         start(client_v4);
347
348         BOOST_CHECKPOINT("Accepting connection");
349         senf::TCPv4ClientSocketHandle client = server.accept();
350         BOOST_CHECK_NO_THROW(client.write("QUIT"));
351
352         BOOST_CHECKPOINT("Stopping client");
353         sleep(1);
354         stop();
355         alarm(0);
356     } catch (...) {
357         alarm(0);
358         sleep(1);
359         stop();
360         sleep(1);
361         throw;
362     }
363 }
364
365 BOOST_AUTO_UNIT_TEST(tcpv6ServerSocketHandle)
366 {
367     try {
368         alarm(10);
369         BOOST_CHECKPOINT("Opening server socket");
370         senf::TCPv6ServerSocketHandle server (senf::INet6SocketAddress("[::1]:12347"));
371         BOOST_CHECKPOINT("Starting client");
372         start(client_v6);
373
374         BOOST_CHECKPOINT("Accepting connection");
375         senf::TCPv6ClientSocketHandle client = server.accept();
376         BOOST_CHECK_NO_THROW(client.write("QUIT"));
377
378         BOOST_CHECKPOINT("Stopping client");
379         sleep(1);
380         stop();
381         alarm(0);
382     } catch (...) {
383         alarm(0);
384         sleep(1);
385         stop();
386         sleep(1);
387         throw;
388     }
389 }
390
391 ///////////////////////////////cc.e////////////////////////////////////////
392 #undef prefix_
393
394 \f
395 // Local Variables:
396 // mode: c++
397 // fill-column: 100
398 // c-file-style: "senf"
399 // indent-tabs-mode: nil
400 // ispell-local-dictionary: "american"
401 // compile-command: "scons -u test"
402 // comment-column: 40
403 // End: