initial import
[Business-OnlinePayment-PPIPayMover.git] / lib / Business / OnlinePayment / PPIPayMover / SecureHttp.pm
1 use strict;\r
2 package Business::OnlinePayment::PPIPayMover::SecureHttp;\r
3 use Socket;\r
4 use Net::SSLeay qw(die_now die_if_ssl_error) ;\r
5 1;\r
6 \r
7 # constuctor\r
8 sub new\r
9 {\r
10   my $class = shift;\r
11   my $self = {};\r
12   bless $self, $class;\r
13   $self->{ctx} = undef;\r
14   $self->{ssl} = undef;\r
15   $self->{strError} = ""; \r
16   return $self;\r
17 }\r
18 \r
19 sub Init\r
20 {\r
21   my $self = shift;  \r
22   \r
23   Net::SSLeay::load_error_strings();\r
24   Net::SSLeay::ERR_load_crypto_strings();\r
25   Net::SSLeay::SSLeay_add_ssl_algorithms();\r
26   Net::SSLeay::randomize();\r
27   \r
28   $self->{ctx} = Net::SSLeay::CTX_new();\r
29   if(!$self->{ctx}) {\r
30       $self->{strError} .= "Failed to create SSL_CTX. \n" .\r
31          "SSLeay error: " . Net::SSLeay::ERR_error_string(Net::SSLeay::ERR_get_error);\r
32       return 0;\r
33   }\r
34   \r
35   if(!Net::SSLeay::CTX_set_options($self->{ctx}, &Net::SSLeay::OP_ALL)) {\r
36       # For some reason the if statement above always returns false,\r
37       # but SSLeay reports no error.  Ignore this error, since\r
38       # everything still works fine.\r
39       #\r
40       #$self->{strError} .= "Failed to set SSL_CTX options. \n" .\r
41       #   "SSLeay error: " . Net::SSLeay::ERR_error_string(Net::SSLeay::ERR_get_error) . "\n";\r
42   }\r
43   \r
44   $self->{ssl} = Net::SSLeay::new($self->{ctx});\r
45   if(!$self->{ssl}) {\r
46       $self->{strError} .= "Failed to create an SSL. \n" .\r
47          "SSLeay error: " . Net::SSLeay::ERR_error_string(Net::SSLeay::ERR_get_error);\r
48       return 0;\r
49   }\r
50   \r
51   return 1;\r
52 }\r
53 \r
54 sub Connect\r
55 {\r
56   my $self = shift;\r
57   my ($destServer, $port) = @_;\r
58   $port = getservbyname($port, 'tcp') unless $port =~ /^\d+$/;\r
59   \r
60   my $destIp = gethostbyname ($destServer);\r
61   if(!defined($destIp)) { \r
62       $self->{strError} .= "Couldn't resolve host name (gethostbyname) using host: $destServer\n";\r
63       return 0;\r
64   } \r
65   \r
66   my $destServerSockAddr = sockaddr_in($port, $destIp);\r
67   \r
68   if(!socket (S, AF_INET, SOCK_STREAM, 0)) {\r
69       $self->{strError} .= "Failed to create a socket. $!";\r
70       return 0;\r
71   }\r
72   \r
73   if(!connect (S, $destServerSockAddr)) {\r
74       $self->{strError} .= "Failed to connect. $!";\r
75       return 0;\r
76   }\r
77   \r
78   select (S); $| = 1; select (STDOUT);   # Eliminate STDIO buffering\r
79   Net::SSLeay::set_fd($self->{ssl}, fileno(S));   # Must use fileno\r
80   if (! Net::SSLeay::connect($self->{ssl})) {\r
81     $self->{strError} .= "Failed to make an ssl connect. \n" .\r
82       "SSLeay error: " . Net::SSLeay::ERR_error_string(Net::SSLeay::ERR_get_error);\r
83      return 0;\r
84   }\r
85   \r
86   return 1;\r
87 }\r
88 \r
89 sub DoSecurePost\r
90 {\r
91   my $self = shift;\r
92   my ($strPath, $strContent, $Response) = @_;\r
93   my $PostString = "POST ";\r
94   $PostString .= $strPath;\r
95   $PostString .= " HTTP/1.0\r\nContent-Type: application/x-www-form-urlencoded\r\n";\r
96   $PostString .= "Content-Length: ";\r
97   $PostString .= length($strContent);\r
98   $PostString .= "  \r\n\r\n";\r
99   $PostString .= $strContent;\r
100   \r
101   if(!Net::SSLeay::ssl_write_all($self->{ssl}, $PostString)) {\r
102       $self->{strError} .= "Failed to write. " .\r
103          "SSLeay error: " . Net::SSLeay::ERR_error_string(Net::SSLeay::ERR_get_error);\r
104     return 0;\r
105   }\r
106   \r
107   shutdown S, 1;  # Half close --> No more output, sends EOF to server\r
108 \r
109   if( $^O eq "MSWin32" ) {\r
110     # Windows doesn't implement ALRM signal, \r
111     # so don't use a timeout.  \r
112     # May hang client system.\r
113     $$Response = Net::SSLeay::ssl_read_all($self->{ssl});\r
114   } else {\r
115     # This block uses the alarm signal\r
116     # to see if the server times out responding.\r
117     eval {\r
118       local $SIG{ ALRM } = sub {\r
119         $self->{strError} .= "Server timed out.";\r
120         close S;\r
121       };\r
122       alarm 270;    # Alarm on 4.5 min timeout\r
123       # Read in response from server\r
124       $$Response = Net::SSLeay::ssl_read_all($self->{ssl});\r
125     };\r
126     alarm 0;    # Alarm off\r
127     \r
128   }\r
129 \r
130   if ( !defined( $$Response ) ) {\r
131     $self->{strError} .= "Failed to read from socket. " .\r
132          "SSLeay error: " . Net::SSLeay::ERR_error_string(Net::SSLeay::ERR_get_error);\r
133     return 0;\r
134   }\r
135   return 1;\r
136 }\r
137 \r
138 sub DisconnectFromServer\r
139 {\r
140   my $self = shift;\r
141   Net::SSLeay::free ($self->{ssl});               # Tear down connection\r
142   Net::SSLeay::CTX_free ($self->{ctx});\r
143   close S;\r
144 }\r
145 \r
146 sub CleanUp\r
147 {\r
148   return 1;\r
149 }\r
150 \r
151 sub GetErrorString\r
152 {\r
153   my $self = shift;\r
154   return $self->{strError};\r
155 }\r