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