File Coverage

blib/lib/IO/Stream/MatrixSSL.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             ## no critic (Capitalization)
2             package IO::Stream::MatrixSSL;
3              
4 1     1   29812 use warnings;
  1         3  
  1         40  
5 1     1   7 use strict;
  1         2  
  1         36  
6 1     1   6 use Carp;
  1         7  
  1         98  
7              
8 1     1   945 use version; our $VERSION = qv('1.1.2'); # update POD & Changes & README
  1         2138  
  1         5  
9              
10             # update DEPENDENCIES in POD & Makefile.PL & README
11 1     1   480 use IO::Stream::const;
  0            
  0            
12             use IO::Stream::MatrixSSL::const;
13             use Crypt::MatrixSSL 1.83;
14              
15             use IO::Stream::MatrixSSL::Client;
16             use IO::Stream::MatrixSSL::Server;
17              
18              
19             sub DESTROY {
20             my ($self) = @_;
21             # Free memory in MatrixSSL.
22             matrixSslDeleteSession($self->{_ssl});
23             matrixSslFreeKeys($self->{_ssl_keys});
24             return;
25             }
26              
27             sub T {
28             my ($self) = @_;
29             my $m = $self->{_master};
30             $m->EVENT(0, ETOHANDSHAKE);
31             return;
32             }
33              
34             sub WRITE {
35             my ($self) = @_;
36             if (!$self->{_handshaked}) {
37             $self->{_want_write} = 1;
38             }
39             else {
40             my $m = $self->{_master};
41             my $s = substr $m->{out_buf}, $m->{out_pos}||0;
42             my $n = length $s;
43             while (length $s) {
44             my $s2 = substr $s, 0, $SSL_MAX_PLAINTEXT_LEN, q{};
45             if (matrixSslEncode($self->{_ssl}, $s2, $self->{out_buf}) < 0) {
46             $m->EVENT(0, 'matrixSslEncode');
47             return;
48             }
49             }
50             if (defined $m->{out_pos}) {
51             $m->{out_pos} += $n;
52             } else {
53             $m->{out_buf} = q{};
54             }
55             $m->{out_bytes} += $n;
56             $m->EVENT(OUT);
57             $self->{_slave}->WRITE();
58             }
59             return;
60             }
61              
62             sub EVENT { ## no critic (ProhibitExcessComplexity)
63             my ($self, $e, $err) = @_;
64             my $m = $self->{_master};
65             $e &= ~OUT;
66             if (!$self->{_handshaked}) {
67             $e &= ~SENT;
68             }
69             return if !$e && !$err;
70             if ($e & IN) {
71             $e &= ~IN;
72             while (length $self->{in_buf}) {
73             my ($error, $alertLevel, $alertDescription);
74             my $rc = matrixSslDecode($self->{_ssl}, $self->{in_buf},
75             my $buf=q{}, $error, $alertLevel, $alertDescription);
76             if ($rc == $SSL_PROCESS_DATA) {
77             $e |= IN;
78             $m->{in_buf} .= $buf;
79             $m->{in_bytes} += length $buf;
80             }
81             else {
82             $self->{out_buf} .= $buf;
83             $self->{_slave}->WRITE();
84             ## no critic (ProhibitCascadingIfElse ProhibitDeepNests)
85             if ($rc == $SSL_SUCCESS || $rc == $SSL_SEND_RESPONSE) {
86             if (!$self->{_handshaked}) {
87             if (matrixSslHandshakeIsComplete($self->{_ssl})) {
88             $self->{_handshaked} = 1;
89             undef $self->{_t};
90             if ($self->{_want_write}) {
91             $self->WRITE();
92             }
93             }
94             }
95             }
96             # WARNING After $SSL_ERROR or $SSL_ALERT {in_buf} may
97             # contain non-decoded packets. These packets will be lost,
98             # except in case user will not $stream->close() on this
99             # error AND there will be more data later (got EPOLLIN).
100             # This behaviour is ok because all ERROR/ALERT are fatal
101             # anyway (except NO_CERTIFICATE).
102             # TODO FIXME If we'll support commercial MatrixSSL we
103             # should add handling for NO_CERTIFICATE case.
104             elsif ($rc == $SSL_ERROR) {
105             $err ||= "ssl error: $SSL_alertDescription{$error}";
106             last;
107             }
108             elsif ($rc == $SSL_ALERT) {
109             if ($alertLevel == $SSL_ALERT_LEVEL_WARNING
110             && $alertDescription == $SSL_ALERT_CLOSE_NOTIFY) {
111             # Workaround MatrixSSL bug: ALERT packet doesn't removed
112             # from {in_buf}, and next matrixSslDecode() on this {in_buf}
113             # return SSL_ERROR while CLOSE_NOTIFY alert shouldn't be
114             # error at all. :(
115             # TODO Is it still needed in Crypt::MatrixSSL 1.83?
116             $self->{in_buf} = q{};
117             }
118             else {
119             $err ||= "ssl alert: $SSL_alertLevel{$alertLevel}: $SSL_alertDescription{$alertDescription}";
120             last;
121             }
122             }
123             elsif ($rc == $SSL_PARTIAL) {
124             last;
125             }
126             else {
127             $err ||= "matrixSslDecode: unexpected return code ($rc)";
128             last;
129             }
130             ## use critic
131             }
132             }
133             }
134             if ($e & RESOLVED) {
135             $m->{ip} = $self->{ip};
136             }
137             if ($e & EOF) {
138             $m->{is_eof} = $self->{is_eof};
139             if (!$self->{_handshaked}) {
140             $err ||= 'ssl handshake error: unexpected EOF';
141             }
142             }
143             if ($e & CONNECTED) {
144             $self->{_t} = EV::timer(TOHANDSHAKE, 0, $self->{_cb_t});
145             }
146             $m->EVENT($e, $err);
147             return;
148             }
149              
150              
151             1; # Magic true value required at end of module
152             __END__