blob: ba3a63184dba23ee9b97f75da32e4c36534deff3 [file] [log] [blame]
Gavin McDonald0b75e1a2010-10-28 02:12:01 +00001<?php
2/*
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 * @package thrift.transport
21 */
22
23
24/**
25 * Sockets implementation of the TTransport interface.
26 *
27 * @package thrift.transport
28 */
29class TSocket extends TTransport {
30
31 /**
32 * Handle to PHP socket
33 *
34 * @var resource
35 */
36 private $handle_ = null;
37
38 /**
39 * Remote hostname
40 *
41 * @var string
42 */
43 protected $host_ = 'localhost';
44
45 /**
46 * Remote port
47 *
48 * @var int
49 */
50 protected $port_ = '9090';
51
52 /**
53 * Send timeout in milliseconds
54 *
55 * @var int
56 */
57 private $sendTimeout_ = 100;
58
59 /**
60 * Recv timeout in milliseconds
61 *
62 * @var int
63 */
64 private $recvTimeout_ = 750;
65
66 /**
67 * Is send timeout set?
68 *
69 * @var bool
70 */
71 private $sendTimeoutSet_ = FALSE;
72
73 /**
74 * Persistent socket or plain?
75 *
76 * @var bool
77 */
78 private $persist_ = FALSE;
79
80 /**
81 * Debugging on?
82 *
83 * @var bool
84 */
85 protected $debug_ = FALSE;
86
87 /**
88 * Debug handler
89 *
90 * @var mixed
91 */
92 protected $debugHandler_ = null;
93
94 /**
95 * Socket constructor
96 *
97 * @param string $host Remote hostname
98 * @param int $port Remote port
99 * @param bool $persist Whether to use a persistent socket
100 * @param string $debugHandler Function to call for error logging
101 */
102 public function __construct($host='localhost',
103 $port=9090,
104 $persist=FALSE,
105 $debugHandler=null) {
106 $this->host_ = $host;
107 $this->port_ = $port;
108 $this->persist_ = $persist;
109 $this->debugHandler_ = $debugHandler ? $debugHandler : 'error_log';
110 }
111
112 /**
113 * Sets the send timeout.
114 *
115 * @param int $timeout Timeout in milliseconds.
116 */
117 public function setSendTimeout($timeout) {
118 $this->sendTimeout_ = $timeout;
119 }
120
121 /**
122 * Sets the receive timeout.
123 *
124 * @param int $timeout Timeout in milliseconds.
125 */
126 public function setRecvTimeout($timeout) {
127 $this->recvTimeout_ = $timeout;
128 }
129
130 /**
131 * Sets debugging output on or off
132 *
133 * @param bool $debug
134 */
135 public function setDebug($debug) {
136 $this->debug_ = $debug;
137 }
138
139 /**
140 * Get the host that this socket is connected to
141 *
142 * @return string host
143 */
144 public function getHost() {
145 return $this->host_;
146 }
147
148 /**
149 * Get the remote port that this socket is connected to
150 *
151 * @return int port
152 */
153 public function getPort() {
154 return $this->port_;
155 }
156
157 /**
158 * Tests whether this is open
159 *
160 * @return bool true if the socket is open
161 */
162 public function isOpen() {
163 return is_resource($this->handle_);
164 }
165
166 /**
167 * Connects the socket.
168 */
169 public function open() {
170
171 if ($this->persist_) {
172 $this->handle_ = @pfsockopen($this->host_,
173 $this->port_,
174 $errno,
175 $errstr,
176 $this->sendTimeout_/1000.0);
177 } else {
178 $this->handle_ = @fsockopen($this->host_,
179 $this->port_,
180 $errno,
181 $errstr,
182 $this->sendTimeout_/1000.0);
183 }
184
185 // Connect failed?
186 if ($this->handle_ === FALSE) {
187 $error = 'TSocket: Could not connect to '.$this->host_.':'.$this->port_.' ('.$errstr.' ['.$errno.'])';
188 if ($this->debug_) {
189 call_user_func($this->debugHandler_, $error);
190 }
191 throw new TException($error);
192 }
193
194 stream_set_timeout($this->handle_, 0, $this->sendTimeout_*1000);
195 $this->sendTimeoutSet_ = TRUE;
196 }
197
198 /**
199 * Closes the socket.
200 */
201 public function close() {
202 if (!$this->persist_) {
203 @fclose($this->handle_);
204 $this->handle_ = null;
205 }
206 }
207
208 /**
209 * Uses stream get contents to do the reading
210 *
211 * @param int $len How many bytes
212 * @return string Binary data
213 */
214 public function readAll($len) {
215 if ($this->sendTimeoutSet_) {
216 stream_set_timeout($this->handle_, 0, $this->recvTimeout_*1000);
217 $this->sendTimeoutSet_ = FALSE;
218 }
219 // This call does not obey stream_set_timeout values!
220 // $buf = @stream_get_contents($this->handle_, $len);
221
222 $pre = null;
223 while (TRUE) {
224 $buf = @fread($this->handle_, $len);
225 if ($buf === FALSE || $buf === '') {
226 $md = stream_get_meta_data($this->handle_);
227 if ($md['timed_out']) {
228 throw new TException('TSocket: timed out reading '.$len.' bytes from '.
229 $this->host_.':'.$this->port_);
230 } else {
231 throw new TException('TSocket: Could not read '.$len.' bytes from '.
232 $this->host_.':'.$this->port_);
233 }
234 } else if (($sz = strlen($buf)) < $len) {
235 $md = stream_get_meta_data($this->handle_);
236 if ($md['timed_out']) {
237 throw new TException('TSocket: timed out reading '.$len.' bytes from '.
238 $this->host_.':'.$this->port_);
239 } else {
240 $pre .= $buf;
241 $len -= $sz;
242 }
243 } else {
244 return $pre.$buf;
245 }
246 }
247 }
248
249 /**
250 * Read from the socket
251 *
252 * @param int $len How many bytes
253 * @return string Binary data
254 */
255 public function read($len) {
256 if ($this->sendTimeoutSet_) {
257 stream_set_timeout($this->handle_, 0, $this->recvTimeout_*1000);
258 $this->sendTimeoutSet_ = FALSE;
259 }
260 $data = @fread($this->handle_, $len);
261 if ($data === FALSE || $data === '') {
262 $md = stream_get_meta_data($this->handle_);
263 if ($md['timed_out']) {
264 throw new TException('TSocket: timed out reading '.$len.' bytes from '.
265 $this->host_.':'.$this->port_);
266 } else {
267 throw new TException('TSocket: Could not read '.$len.' bytes from '.
268 $this->host_.':'.$this->port_);
269 }
270 }
271 return $data;
272 }
273
274 /**
275 * Write to the socket.
276 *
277 * @param string $buf The data to write
278 */
279 public function write($buf) {
280 if (!$this->sendTimeoutSet_) {
281 stream_set_timeout($this->handle_, 0, $this->sendTimeout_*1000);
282 $this->sendTimeoutSet_ = TRUE;
283 }
284 while (strlen($buf) > 0) {
285 $got = @fwrite($this->handle_, $buf);
286 if ($got === 0 || $got === FALSE) {
287 $md = stream_get_meta_data($this->handle_);
288 if ($md['timed_out']) {
289 throw new TException('TSocket: timed out writing '.strlen($buf).' bytes from '.
290 $this->host_.':'.$this->port_);
291 } else {
292 throw new TException('TSocket: Could not write '.strlen($buf).' bytes '.
293 $this->host_.':'.$this->port_);
294 }
295 }
296 $buf = substr($buf, $got);
297 }
298 }
299
300 /**
301 * Flush output to the socket.
302 */
303 public function flush() {
304 $ret = fflush($this->handle_);
305 if ($ret === FALSE) {
306 throw new TException('TSocket: Could not flush: '.
307 $this->host_.':'.$this->port_);
308 }
309 }
310}
311
312?>