add connfail test
Apocalypse
13 years ago
2 | 2 | # ABSTRACT: Server-side handle for SSLify |
3 | 3 | |
4 | 4 | # Import the SSL death routines |
5 | use Net::SSLeay 1.36 qw( die_now die_if_ssl_error ); | |
5 | use Net::SSLeay 1.36 qw( die_now die_if_ssl_error ERROR_WANT_READ ERROR_WANT_WRITE ); | |
6 | 6 | |
7 | 7 | # Ties the socket |
8 | 8 | sub TIEHANDLE { |
43 | 43 | $self->{'status'} = Net::SSLeay::accept( $self->{'ssl'} ); |
44 | 44 | } |
45 | 45 | |
46 | if ( $self->{'status'} == 0 ) { | |
47 | # TODO error? | |
46 | # Only process the stuff if we actually have a callback! | |
47 | return unless defined $self->{'on_connect'}; | |
48 | ||
49 | if ( $self->{'status'} <= 0 ) { | |
50 | # http://www.openssl.org/docs/ssl/SSL_get_error.html | |
51 | my $errval = Net::SSLeay::get_error( $self->{'ssl'}, $self->{'status'} ); | |
52 | ||
53 | # TODO should we skip ERROR_WANT_ACCEPT and ERROR_WANT_CONNECT ? | |
54 | # also, ERROR_WANT_ACCEPT isn't exported by Net::SSLeay, huh? | |
55 | if ( $errval != ERROR_WANT_READ and $errval != ERROR_WANT_WRITE ) { | |
56 | # call the hook function for error connect | |
57 | $self->{'on_connect'}->( $self->{'orig_socket'}, 'ERR', $errval ); | |
58 | } | |
48 | 59 | } elsif ( $self->{'status'} == 1 ) { |
49 | 60 | # call the hook function for successful connect |
50 | $self->{'on_connect'}->( $self->{'orig_socket'} ) if defined $self->{'on_connect'}; | |
61 | $self->{'on_connect'}->( $self->{'orig_socket'}, 'OK' ); | |
51 | 62 | } |
52 | 63 | } |
53 | 64 | |
60 | 71 | my( $buf, $len, $offset ) = \( @_ ); |
61 | 72 | |
62 | 73 | # Check connection status |
63 | $self->_check_status if $self->{'status'} == -1; | |
74 | $self->_check_status if $self->{'status'} <= 0; | |
64 | 75 | |
65 | 76 | # If we have no offset, replace the buffer with some input |
66 | 77 | if ( ! defined $$offset ) { |
100 | 111 | my( $self, $buf, $len, $offset ) = @_; |
101 | 112 | |
102 | 113 | # Check connection status |
103 | $self->_check_status if $self->{'status'} == -1; | |
114 | $self->_check_status if $self->{'status'} <= 0; | |
104 | 115 | |
105 | 116 | # If we have nothing to offset, then start from the beginning |
106 | 117 | if ( ! defined $offset ) { |
5 | 5 | |
6 | 6 | my $numtests; |
7 | 7 | BEGIN { |
8 | $numtests = 20; | |
8 | $numtests = 17; | |
9 | 9 | |
10 | 10 | eval "use Test::NoWarnings"; |
11 | 11 | if ( ! $@ ) { |
12 | 12 | # increment by one |
13 | 13 | $numtests++; |
14 | ||
15 | 14 | } |
16 | 15 | } |
17 | 16 | |
20 | 19 | use POE 1.267; |
21 | 20 | use POE::Component::Client::TCP; |
22 | 21 | use POE::Component::Server::TCP; |
23 | use POE::Component::SSLify qw/Client_SSLify Server_SSLify SSLify_Options SSLify_GetCipher SSLify_ContextCreate SSLify_GetSocket SSLify_GetStatus/; | |
22 | use POE::Component::SSLify qw/Client_SSLify Server_SSLify SSLify_Options SSLify_GetCipher SSLify_GetSocket SSLify_GetStatus/; | |
24 | 23 | |
25 | 24 | # TODO rewrite this to use Test::POE::Server::TCP and stuff :) |
26 | 25 | |
48 | 47 | }, |
49 | 48 | ClientPreConnect => sub |
50 | 49 | { |
51 | eval { SSLify_Options('mylib/example.key', 'mylib/example.crt', 'sslv3') }; | |
52 | eval { SSLify_Options('../mylib/example.key', '../mylib/example.crt', 'sslv3') } if ($@); | |
50 | eval { SSLify_Options('mylib/example.key', 'mylib/example.crt') }; | |
51 | eval { SSLify_Options('../mylib/example.key', '../mylib/example.crt') } if ($@); | |
53 | 52 | ok(!$@, "SERVER: SSLify_Options $@"); |
54 | 53 | |
55 | 54 | my $socket = eval { Server_SSLify( $_[ARG0], sub { |
56 | my $socket = shift; | |
57 | pass( "Got connect hook for server" ); | |
55 | my( $socket, $status, $errval ) = @_; | |
56 | ||
57 | pass( "SERVER: Got connect hook" ); | |
58 | is( $status, 'OK', "SERVER: Status received from callback is OK" ); | |
58 | 59 | |
59 | 60 | ## At this point, connection MUST be encrypted. |
60 | 61 | my $cipher = SSLify_GetCipher($socket); |
62 | 63 | ok( SSLify_GetStatus($socket) == 1, "SERVER: SSLify_GetStatus is done" ); |
63 | 64 | } ) }; |
64 | 65 | ok(!$@, "SERVER: Server_SSLify $@"); |
65 | ok(1, 'SERVER: SSLify_GetCipher: '. SSLify_GetCipher($socket)); | |
66 | 66 | ok( SSLify_GetStatus($socket) == -1, "SERVER: SSLify_GetStatus is pending" ); |
67 | ||
68 | # We pray that IO::Handle is sane... | |
69 | ok( SSLify_GetSocket( $socket )->blocking == 0, 'SERVER: SSLified socket is non-blocking?'); | |
70 | 67 | |
71 | 68 | return ($socket); |
72 | 69 | }, |
104 | 101 | }, |
105 | 102 | PreConnect => sub |
106 | 103 | { |
107 | my $ctx = eval { SSLify_ContextCreate(undef, undef, 'sslv3') }; | |
108 | ok(!$@, "CLIENT: SSLify_ContextCreate $@"); | |
109 | my $socket = eval { Client_SSLify($_[ARG0], undef, undef, $ctx, sub { | |
110 | my $socket = shift; | |
104 | my $socket = eval { Client_SSLify($_[ARG0], sub { | |
105 | my( $socket, $status, $errval ) = @_; | |
111 | 106 | |
112 | pass( "Got connect hook for client" ); | |
107 | pass( "CLIENT: Got connect hook" ); | |
108 | is( $status, 'OK', "CLIENT: Status received from callback is OK" ); | |
113 | 109 | |
114 | 110 | ## At this point, connection MUST be encrypted. |
115 | 111 | my $cipher = SSLify_GetCipher($socket); |
119 | 115 | $poe_kernel->post( 'myclient' => 'shutdown' ); |
120 | 116 | }) }; |
121 | 117 | ok(!$@, "CLIENT: Client_SSLify $@"); |
122 | ok(1, 'CLIENT: SSLify_GetCipher: '. SSLify_GetCipher($socket)); | |
123 | 118 | ok( SSLify_GetStatus($socket) == -1, "CLIENT: SSLify_GetStatus is pending" ); |
124 | ||
125 | # We pray that IO::Handle is sane... | |
126 | ok( SSLify_GetSocket( $socket )->blocking == 0, 'CLIENT: SSLified socket is non-blocking?'); | |
127 | 119 | |
128 | 120 | return ($socket); |
129 | 121 | }, |
131 | 123 | { |
132 | 124 | my ($kernel, $heap, $line) = @_[KERNEL, HEAP, ARG0]; |
133 | 125 | |
134 | $kernel->yield('shutdown'); | |
126 | die "Should have never got any input from the server!"; | |
135 | 127 | }, |
136 | 128 | ServerError => sub |
137 | 129 | { |
0 | #!/usr/bin/perl | |
1 | ||
2 | # Thanks to ASCENT for this test! | |
3 | ||
4 | use strict; use warnings; | |
5 | ||
6 | my $numtests; | |
7 | BEGIN { | |
8 | $numtests = 8; | |
9 | ||
10 | eval "use Test::NoWarnings"; | |
11 | if ( ! $@ ) { | |
12 | # increment by one | |
13 | $numtests++; | |
14 | } | |
15 | } | |
16 | ||
17 | use Test::More tests => $numtests; | |
18 | ||
19 | use POE 1.267; | |
20 | use POE::Component::Client::TCP; | |
21 | use POE::Component::Server::TCP; | |
22 | use POE::Component::SSLify qw/Client_SSLify SSLify_GetSocket SSLify_GetStatus/; | |
23 | ||
24 | # TODO rewrite this to use Test::POE::Server::TCP and stuff :) | |
25 | ||
26 | my $port; | |
27 | ||
28 | POE::Component::Server::TCP->new | |
29 | ( | |
30 | Alias => 'myserver', | |
31 | Address => '127.0.0.1', | |
32 | Port => 0, | |
33 | ||
34 | Started => sub | |
35 | { | |
36 | use Socket qw/sockaddr_in/; | |
37 | $port = (sockaddr_in($_[HEAP]->{listener}->getsockname))[0]; | |
38 | }, | |
39 | ClientConnected => sub | |
40 | { | |
41 | ok(1, 'SERVER: accepted'); | |
42 | }, | |
43 | ClientDisconnected => sub | |
44 | { | |
45 | ok(1, 'SERVER: client disconnected'); | |
46 | $_[KERNEL]->post( 'myserver' => 'shutdown'); | |
47 | }, | |
48 | ClientInput => sub | |
49 | { | |
50 | my ($kernel, $heap, $line) = @_[KERNEL, HEAP, ARG0]; | |
51 | ||
52 | # purposefully send garbage so we screw up the ssl connect on the client-side | |
53 | $heap->{client}->put( 'garbage in, garbage out' ); | |
54 | }, | |
55 | ClientError => sub | |
56 | { | |
57 | # Thanks to H. Merijn Brand for spotting this FAIL in 5.12.0! | |
58 | # The default PoCo::Server::TCP handler will throw a warning, which causes Test::NoWarnings to FAIL :( | |
59 | my ($syscall, $errno, $error) = @_[ ARG0..ARG2 ]; | |
60 | ||
61 | # Since this test purposefully sends garbage, we expect a connection reset by peer | |
62 | # not ok 7 - Got SERVER read error 104: Connection reset by peer | |
63 | ||
64 | # TODO are there other "errors" that is harmless? | |
65 | $error = "Normal disconnection" unless $error; | |
66 | my $msg = "Got SERVER $syscall error $errno: $error"; | |
67 | unless ( $syscall eq 'read' and $errno == 104 ) { | |
68 | fail( $msg ); | |
69 | } else { | |
70 | diag( $msg ) if $ENV{TEST_VERBOSE}; | |
71 | } | |
72 | }, | |
73 | ); | |
74 | ||
75 | POE::Component::Client::TCP->new | |
76 | ( | |
77 | Alias => 'myclient', | |
78 | RemoteAddress => '127.0.0.1', | |
79 | RemotePort => $port, | |
80 | Connected => sub | |
81 | { | |
82 | ok(1, 'CLIENT: connected'); | |
83 | }, | |
84 | PreConnect => sub | |
85 | { | |
86 | my $socket = eval { Client_SSLify($_[ARG0], sub { | |
87 | my( $socket, $status, $errval ) = @_; | |
88 | ||
89 | pass( "CLIENT: Got connect hook" ); | |
90 | is( $status, 'ERR', "CLIENT: Status received from callback is ERR - $errval" ); | |
91 | ||
92 | $poe_kernel->post( 'myclient' => 'shutdown' ); | |
93 | }) }; | |
94 | ok(!$@, "CLIENT: Client_SSLify $@"); | |
95 | ok( SSLify_GetStatus($socket) == -1, "CLIENT: SSLify_GetStatus is pending" ); | |
96 | ||
97 | return ($socket); | |
98 | }, | |
99 | ServerInput => sub | |
100 | { | |
101 | my ($kernel, $heap, $line) = @_[KERNEL, HEAP, ARG0]; | |
102 | ||
103 | die "Should have never got any input from the server!"; | |
104 | }, | |
105 | ServerError => sub | |
106 | { | |
107 | # Thanks to H. Merijn Brand for spotting this FAIL in 5.12.0! | |
108 | # The default PoCo::Client::TCP handler will throw a warning, which causes Test::NoWarnings to FAIL :( | |
109 | my ($syscall, $errno, $error) = @_[ ARG0..ARG2 ]; | |
110 | ||
111 | # TODO are there other "errors" that is harmless? | |
112 | $error = "Normal disconnection" unless $error; | |
113 | my $msg = "Got CLIENT $syscall error $errno: $error"; | |
114 | unless ( $syscall eq 'read' and $errno == 0 ) { | |
115 | fail( $msg ); | |
116 | } else { | |
117 | diag( $msg ) if $ENV{TEST_VERBOSE}; | |
118 | } | |
119 | }, | |
120 | ); | |
121 | ||
122 | $poe_kernel->run(); | |
123 | ||
124 | pass( 'shut down sanely' ); | |
125 | ||
126 | exit 0; |