blob: 96f544efca541279a759bc0c12baafefd897ae93 [file] [log] [blame]
Mark Slee254ce202007-05-16 02:21:06 +00001#
2# Copyright (c) 2006- Facebook
3# Distributed under the Thrift Software License
4#
5# See accompanying file LICENSE or visit the Thrift site at:
6# http://developers.facebook.com/thrift/
7#
8# package - thrift.socket
9# author - T Jake Luciani <jakers@gmail.com>
10# author - Mark Slee <mcslee@facebook.com>
11#
12
13require 5.6.0;
14use strict;
15use warnings;
16
17use Thrift;
18use Thrift::Transport;
19
20use IO::Socket::INET;
21use IO::Select;
22
23package Thrift::Socket;
24
25use base('Thrift::Transport');
26
27sub new
28{
29 my $classname = shift;
30 my $host = shift || "localhost";
31 my $port = shift || 9090;
32 my $debugHandler = shift;
33
34 my $self = {
35 host => $host,
36 port => $port,
37 debugHandler => $debugHandler,
38 debug => 0,
39 sendTimeout => 100,
40 recvTimeout => 750,
41 handle => undef,
42 };
43
44 return bless($self,$classname);
45}
46
47
48sub setSendTimeout
49{
50 my $self = shift;
51 my $timeout = shift;
52
53 $self->{sendTimeout} = $timeout;
54}
55
56sub setRecvTimeout
57{
58 my $self = shift;
59 my $timeout = shift;
60
61 $self->{recvTimeout} = $timeout;
62}
63
64
65#
66#Sets debugging output on or off
67#
68# @param bool $debug
69#
70sub setDebug
71{
72 my $self = shift;
73 my $debug = shift;
74
75 $self->{debug} = $debug;
76}
77
78#
79# Tests whether this is open
80#
81# @return bool true if the socket is open
82#
83sub isOpen
84{
85 my $self = shift;
86
T Jake Luciani0d738892008-12-23 03:12:50 +000087 if( defined $self->{handle} ){
88 return ($self->{handle}->handles())[0]->connected;
89 }
90
91 return 0;
Mark Slee254ce202007-05-16 02:21:06 +000092}
93
94#
95# Connects the socket.
96#
97sub open
98{
99 my $self = shift;
100
101 my $sock = IO::Socket::INET->new(PeerAddr => $self->{host},
102 PeerPort => $self->{port},
103 Proto => 'tcp',
104 Timeout => $self->{sendTimeout}/1000)
105 || do {
106 my $error = 'TSocket: Could not connect to '.$self->{host}.':'.$self->{port}.' ('.$!.')';
107
108 if ($self->{debug}) {
109 $self->{debugHandler}->($error);
110 }
111
112 die new Thrift::TException($error);
113
114 };
115
116
117 $self->{handle} = new IO::Select( $sock );
118}
119
120#
121# Closes the socket.
122#
123sub close
124{
125 my $self = shift;
126
T Jake Luciani0d738892008-12-23 03:12:50 +0000127 if( defined $self->{handle} ){
128 close( ($self->{handle}->handles())[0] );
129 }
Mark Slee254ce202007-05-16 02:21:06 +0000130}
131
132#
133# Uses stream get contents to do the reading
134#
135# @param int $len How many bytes
136# @return string Binary data
137#
138sub readAll
139{
140 my $self = shift;
141 my $len = shift;
142
143
T Jake Luciani0d738892008-12-23 03:12:50 +0000144 return unless defined $self->{handle};
145
Mark Slee254ce202007-05-16 02:21:06 +0000146 my $pre = "";
147 while (1) {
148
149 #check for timeout
David Reiss7502e0b2008-03-27 19:45:24 +0000150 my @sockets = $self->{handle}->can_read( $self->{recvTimeout} / 1000 );
Mark Slee254ce202007-05-16 02:21:06 +0000151
152 if(@sockets == 0){
153 die new Thrift::TException('TSocket: timed out reading '.$len.' bytes from '.
154 $self->{host}.':'.$self->{port});
155 }
156
157 my $sock = $sockets[0];
158
159 my ($buf,$sz);
160 $sock->recv($buf, $len);
161
162 if (!defined $buf || $buf eq '') {
163
164 die new Thrift::TException('TSocket: Could not read '.$len.' bytes from '.
165 $self->{host}.':'.$self->{port});
166
167 } elsif (($sz = length($buf)) < $len) {
168
169 $pre .= $buf;
170 $len -= $sz;
171
172 } else {
173 return $pre.$buf;
174 }
175 }
176}
177
178#
179# Read from the socket
180#
181# @param int $len How many bytes
182# @return string Binary data
183#
184sub read
185{
186 my $self = shift;
187 my $len = shift;
188
T Jake Luciani0d738892008-12-23 03:12:50 +0000189 return unless defined $self->{handle};
190
Mark Slee254ce202007-05-16 02:21:06 +0000191 #check for timeout
David Reiss7502e0b2008-03-27 19:45:24 +0000192 my @sockets = $self->{handle}->can_read( $self->{sendTimeout} / 1000 );
Mark Slee254ce202007-05-16 02:21:06 +0000193
194 if(@sockets == 0){
195 die new Thrift::TException('TSocket: timed out reading '.$len.' bytes from '.
196 $self->{host}.':'.$self->{port});
197 }
198
199 my $sock = $sockets[0];
200
201 my ($buf,$sz);
202 $sock->recv($buf, $len);
203
204 if (!defined $buf || $buf eq '') {
205
206 die new TException('TSocket: Could not read '.$len.' bytes from '.
207 $self->{host}.':'.$self->{port});
208
209 }
210
211 return $buf;
212}
213
214
215#
216# Write to the socket.
217#
218# @param string $buf The data to write
219#
220sub write
221{
222 my $self = shift;
223 my $buf = shift;
224
225
T Jake Luciani0d738892008-12-23 03:12:50 +0000226 return unless defined $self->{handle};
227
Mark Slee254ce202007-05-16 02:21:06 +0000228 while (length($buf) > 0) {
229
230
231 #check for timeout
David Reiss7502e0b2008-03-27 19:45:24 +0000232 my @sockets = $self->{handle}->can_write( $self->{recvTimeout} / 1000 );
Mark Slee254ce202007-05-16 02:21:06 +0000233
234 if(@sockets == 0){
235 die new Thrift::TException('TSocket: timed out writing to bytes from '.
236 $self->{host}.':'.$self->{port});
237 }
238
239 my $sock = $sockets[0];
240
241 my $got = $sock->send($buf);
242
243 if (!defined $got || $got == 0 ) {
T Jake Luciani6b407112009-03-02 23:47:20 +0000244 die new Thrift::TException('TSocket: Could not write '.length($buf).' bytes '.
Mark Slee254ce202007-05-16 02:21:06 +0000245 $self->{host}.':'.$self->{host});
246 }
247
248 $buf = substr($buf, $got);
249 }
250}
251
252#
253# Flush output to the socket.
254#
255sub flush
256{
257 my $self = shift;
T Jake Luciani0d738892008-12-23 03:12:50 +0000258
259 return unless defined $self->{handle};
260
Mark Slee254ce202007-05-16 02:21:06 +0000261 my $ret = ($self->{handle}->handles())[0]->flush;
262}
263
2641;