blob: 1600b6f7732c71816f24aec8cdd87f031769a146 [file] [log] [blame]
Mark Slee6e536442006-06-30 18:28:50 +00001<?php
2
3/**
Mark Slee4902c052007-03-01 00:31:30 +00004 * Copyright (c) 2006- Facebook
5 * Distributed under the Thrift Software License
6 *
7 * See accompanying file LICENSE or visit the Thrift site at:
8 * http://developers.facebook.com/thrift/
9 *
10 * @package thrift.transport
11 * @author Mark Slee <mcslee@facebook.com>
12 */
13
14/**
Mark Slee6e536442006-06-30 18:28:50 +000015 * Sockets implementation of the TTransport interface.
16 *
17 * @package thrift.transport
18 * @author Mark Slee <mcslee@facebook.com>
19 */
20class TSocket extends TTransport {
21
22 /**
23 * Handle to PHP socket
24 *
25 * @var resource
26 */
27 private $handle_ = null;
28
29 /**
30 * Remote hostname
31 *
32 * @var string
33 */
Mark Sleeade2c832006-09-08 03:41:50 +000034 protected $host_ = 'localhost';
Mark Slee6e536442006-06-30 18:28:50 +000035
36 /**
37 * Remote port
38 *
39 * @var int
40 */
Mark Sleeade2c832006-09-08 03:41:50 +000041 protected $port_ = '9090';
42
43 /**
44 * Send timeout in milliseconds
45 *
46 * @var int
47 */
48 private $sendTimeout_ = 100;
49
50 /**
51 * Recv timeout in milliseconds
52 *
53 * @var int
54 */
55 private $recvTimeout_ = 750;
56
57 /**
58 * Is send timeout set?
59 *
60 * @var bool
61 */
62 private $sendTimeoutSet_ = FALSE;
Mark Slee6e536442006-06-30 18:28:50 +000063
64 /**
65 * Persistent socket or plain?
66 *
67 * @var bool
68 */
Mark Sleeade2c832006-09-08 03:41:50 +000069 private $persist_ = FALSE;
70
71 /**
72 * Debugging on?
73 *
74 * @var bool
75 */
robertb0fac3e2007-01-15 23:53:25 +000076 protected $debug_ = FALSE;
Mark Slee6e536442006-06-30 18:28:50 +000077
78 /**
Mark Sleead58f952007-01-03 19:23:50 +000079 * Debug handler
80 *
81 * @var mixed
82 */
robertb0fac3e2007-01-15 23:53:25 +000083 protected $debugHandler_ = null;
Mark Sleead58f952007-01-03 19:23:50 +000084
85 /**
Mark Slee6e536442006-06-30 18:28:50 +000086 * Socket constructor
87 *
Mark Sleead58f952007-01-03 19:23:50 +000088 * @param string $host Remote hostname
89 * @param int $port Remote port
90 * @param bool $persist Whether to use a persistent socket
91 * @param string $debugHandler Function to call for error logging
Mark Slee6e536442006-06-30 18:28:50 +000092 */
Mark Sleead58f952007-01-03 19:23:50 +000093 public function __construct($host='localhost',
94 $port=9090,
95 $persist=FALSE,
96 $debugHandler=null) {
Mark Slee6e536442006-06-30 18:28:50 +000097 $this->host_ = $host;
98 $this->port_ = $port;
99 $this->persist_ = $persist;
Mark Sleead58f952007-01-03 19:23:50 +0000100 $this->debugHandler_ = $debugHandler ? $debugHandler : 'error_log';
Mark Slee6e536442006-06-30 18:28:50 +0000101 }
102
103 /**
Mark Sleeade2c832006-09-08 03:41:50 +0000104 * Sets the send timeout.
105 *
106 * @param int $timeout
107 */
108 public function setSendTimeout($timeout) {
109 $this->sendTimeout_ = $timeout;
110 }
111
112 /**
113 * Sets the receive timeout.
114 *
115 * @param int $timeout
116 */
117 public function setRecvTimeout($timeout) {
118 $this->recvTimeout_ = $timeout;
119 }
120
121 /**
122 * Sets debugging output on or off
123 *
124 * @param bool $debug
125 */
126 public function setDebug($debug) {
127 $this->debug_ = $debug;
128 }
129
130 /**
Mark Slee6e536442006-06-30 18:28:50 +0000131 * Tests whether this is open
132 *
133 * @return bool true if the socket is open
134 */
135 public function isOpen() {
136 return is_resource($this->handle_);
137 }
138
139 /**
140 * Connects the socket.
141 */
142 public function open() {
143 if ($this->persist_) {
Mark Sleed7cc1c42006-10-04 16:49:07 +0000144 $this->handle_ = @pfsockopen($this->host_,
145 $this->port_,
146 $errno,
147 $errstr,
148 $this->sendTimeout_/1000.0);
149 } else {
150 $this->handle_ = @fsockopen($this->host_,
Mark Sleeade2c832006-09-08 03:41:50 +0000151 $this->port_,
152 $errno,
153 $errstr,
154 $this->sendTimeout_/1000.0);
Mark Slee6e536442006-06-30 18:28:50 +0000155 }
Mark Sleeade2c832006-09-08 03:41:50 +0000156
157 // Connect failed?
158 if ($this->handle_ === FALSE) {
Martin Kraemer0b64e772007-02-07 22:39:58 +0000159 $error = 'TSocket: Could not connect to '.$this->host_.':'.$this->port_.' ('.$errstr.' ['.$errno.'])';
Mark Sleeade2c832006-09-08 03:41:50 +0000160 if ($this->debug_) {
Mark Sleee7714a62007-01-11 01:26:00 +0000161 call_user_func($this->debugHandler_, $error);
Mark Sleeade2c832006-09-08 03:41:50 +0000162 }
163 throw new Exception($error);
Mark Slee6e536442006-06-30 18:28:50 +0000164 }
Mark Sleeade2c832006-09-08 03:41:50 +0000165
166 stream_set_timeout($this->handle_, 0, $this->sendTimeout_*1000);
167 $this->sendTimeoutSet_ = TRUE;
Mark Slee6e536442006-06-30 18:28:50 +0000168 }
169
170 /**
Mark Sleeade2c832006-09-08 03:41:50 +0000171 * Closes the socket.
Mark Slee6e536442006-06-30 18:28:50 +0000172 */
173 public function close() {
174 if (!$this->persist_) {
Mark Sleeade2c832006-09-08 03:41:50 +0000175 @fclose($this->handle_);
176 $this->handle_ = null;
Mark Slee6e536442006-06-30 18:28:50 +0000177 }
178 }
179
180 /**
181 * Uses stream get contents to do the reading
Mark Sleeade2c832006-09-08 03:41:50 +0000182 *
183 * @param int $len How many bytes
184 * @return string Binary data
Mark Slee6e536442006-06-30 18:28:50 +0000185 */
186 public function readAll($len) {
Mark Sleeade2c832006-09-08 03:41:50 +0000187 if ($this->sendTimeoutSet_) {
188 stream_set_timeout($this->handle_, 0, $this->recvTimeout_*1000);
189 $this->sendTimeoutSet_ = FALSE;
190 }
Mark Slee794993d2006-09-20 01:56:10 +0000191 // This call does not obey stream_set_timeout values!
192 // $buf = @stream_get_contents($this->handle_, $len);
193
194 $pre = null;
Mark Slee29f5f672006-09-28 03:19:03 +0000195 while (TRUE) {
Mark Slee794993d2006-09-20 01:56:10 +0000196 $buf = @fread($this->handle_, $len);
Mark Sleee598d072006-11-21 02:01:22 +0000197 if ($buf === FALSE || $buf === '') {
Martin Kraemer0b64e772007-02-07 22:39:58 +0000198 $md = stream_get_meta_data($this->handle_);
199 if ($md['timed_out']) {
200 throw new Exception('TSocket: timed out reading '.$len.' bytes from '.
201 $this->host_.':'.$this->port_);
202 } else {
203 throw new Exception('TSocket: Could not read '.$len.' bytes from '.
204 $this->host_.':'.$this->port_);
205 }
Mark Slee794993d2006-09-20 01:56:10 +0000206 } else if (($sz = strlen($buf)) < $len) {
207 $md = stream_get_meta_data($this->handle_);
208 if ($md['timed_out']) {
209 throw new Exception('TSocket: timed out reading '.$len.' bytes from '.
210 $this->host_.':'.$this->port_);
211 } else {
212 $pre .= $buf;
213 $len -= $sz;
214 }
215 } else {
216 return $pre.$buf;
217 }
Mark Sleeade2c832006-09-08 03:41:50 +0000218 }
Mark Slee6e536442006-06-30 18:28:50 +0000219 }
220
221 /**
222 * Read from the socket
Mark Sleeade2c832006-09-08 03:41:50 +0000223 *
224 * @param int $len How many bytes
225 * @return string Binary data
Mark Slee6e536442006-06-30 18:28:50 +0000226 */
227 public function read($len) {
Mark Sleeade2c832006-09-08 03:41:50 +0000228 if ($this->sendTimeoutSet_) {
229 stream_set_timeout($this->handle_, 0, $this->recvTimeout_*1000);
230 $this->sendTimeoutSet_ = FALSE;
231 }
Mark Slee794993d2006-09-20 01:56:10 +0000232 $data = @fread($this->handle_, $len);
Mark Sleee598d072006-11-21 02:01:22 +0000233 if ($data === FALSE || $data === '') {
Martin Kraemer0b64e772007-02-07 22:39:58 +0000234 $md = stream_get_meta_data($this->handle_);
235 if ($md['timed_out']) {
236 throw new Exception('TSocket: timed out reading '.$len.' bytes from '.
237 $this->host_.':'.$this->port_);
238 } else {
239 throw new Exception('TSocket: Could not read '.$len.' bytes from '.
240 $this->host_.':'.$this->port_);
241 }
Mark Slee6e536442006-06-30 18:28:50 +0000242 }
243 return $data;
244 }
245
246 /**
247 * Write to the socket.
Mark Sleeade2c832006-09-08 03:41:50 +0000248 *
249 * @param string $buf The data to write
Mark Slee6e536442006-06-30 18:28:50 +0000250 */
251 public function write($buf) {
Mark Sleeade2c832006-09-08 03:41:50 +0000252 if (!$this->sendTimeoutSet_) {
253 stream_set_timeout($this->handle_, 0, $this->sendTimeout_*1000);
254 $this->sendTimeoutSet_ = TRUE;
255 }
Mark Sleed395d572007-02-27 01:16:55 +0000256 while (strlen($buf) > 0) {
Mark Sleeade2c832006-09-08 03:41:50 +0000257 $got = @fwrite($this->handle_, $buf);
258 if ($got === 0 || $got === FALSE) {
Martin Kraemer0b64e772007-02-07 22:39:58 +0000259 $md = stream_get_meta_data($this->handle_);
260 if ($md['timed_out']) {
261 throw new Exception('TSocket: timed out writing '.$len.' bytes from '.
262 $this->host_.':'.$this->port_);
263 } else {
264 throw new Exception('TSocket: Could not write '.strlen($buf).' bytes '.
265 $this->host_.':'.$this->port_);
266 }
Mark Slee6e536442006-06-30 18:28:50 +0000267 }
268 $buf = substr($buf, $got);
269 }
270 }
271
272 /**
273 * Flush output to the socket.
274 */
275 public function flush() {
Mark Sleeade2c832006-09-08 03:41:50 +0000276 $ret = fflush($this->handle_);
277 if ($ret === FALSE) {
278 throw new Exception('TSocket: Could not flush: '.
279 $this->host_.':'.$this->port_);
280 }
Mark Slee6e536442006-06-30 18:28:50 +0000281 }
282}
283
284?>