blob: f7ecce0691fd1fe1ec575c3abd0e6b123cb19888 [file] [log] [blame]
Mark Slee6e536442006-06-30 18:28:50 +00001<?php
2
3/**
4 * Sockets implementation of the TTransport interface.
5 *
6 * @package thrift.transport
7 * @author Mark Slee <mcslee@facebook.com>
8 */
9class TSocket extends TTransport {
10
11 /**
12 * Handle to PHP socket
13 *
14 * @var resource
15 */
16 private $handle_ = null;
17
18 /**
19 * Remote hostname
20 *
21 * @var string
22 */
Mark Sleeade2c832006-09-08 03:41:50 +000023 protected $host_ = 'localhost';
Mark Slee6e536442006-06-30 18:28:50 +000024
25 /**
26 * Remote port
27 *
28 * @var int
29 */
Mark Sleeade2c832006-09-08 03:41:50 +000030 protected $port_ = '9090';
31
32 /**
33 * Send timeout in milliseconds
34 *
35 * @var int
36 */
37 private $sendTimeout_ = 100;
38
39 /**
40 * Recv timeout in milliseconds
41 *
42 * @var int
43 */
44 private $recvTimeout_ = 750;
45
46 /**
47 * Is send timeout set?
48 *
49 * @var bool
50 */
51 private $sendTimeoutSet_ = FALSE;
Mark Slee6e536442006-06-30 18:28:50 +000052
53 /**
54 * Persistent socket or plain?
55 *
56 * @var bool
57 */
Mark Sleeade2c832006-09-08 03:41:50 +000058 private $persist_ = FALSE;
59
60 /**
61 * Debugging on?
62 *
63 * @var bool
64 */
robertb0fac3e2007-01-15 23:53:25 +000065 protected $debug_ = FALSE;
Mark Slee6e536442006-06-30 18:28:50 +000066
67 /**
Mark Sleead58f952007-01-03 19:23:50 +000068 * Debug handler
69 *
70 * @var mixed
71 */
robertb0fac3e2007-01-15 23:53:25 +000072 protected $debugHandler_ = null;
Mark Sleead58f952007-01-03 19:23:50 +000073
74 /**
Mark Slee6e536442006-06-30 18:28:50 +000075 * Socket constructor
76 *
Mark Sleead58f952007-01-03 19:23:50 +000077 * @param string $host Remote hostname
78 * @param int $port Remote port
79 * @param bool $persist Whether to use a persistent socket
80 * @param string $debugHandler Function to call for error logging
Mark Slee6e536442006-06-30 18:28:50 +000081 */
Mark Sleead58f952007-01-03 19:23:50 +000082 public function __construct($host='localhost',
83 $port=9090,
84 $persist=FALSE,
85 $debugHandler=null) {
Mark Slee6e536442006-06-30 18:28:50 +000086 $this->host_ = $host;
87 $this->port_ = $port;
88 $this->persist_ = $persist;
Mark Sleead58f952007-01-03 19:23:50 +000089 $this->debugHandler_ = $debugHandler ? $debugHandler : 'error_log';
Mark Slee6e536442006-06-30 18:28:50 +000090 }
91
92 /**
Mark Sleeade2c832006-09-08 03:41:50 +000093 * Sets the send timeout.
94 *
95 * @param int $timeout
96 */
97 public function setSendTimeout($timeout) {
98 $this->sendTimeout_ = $timeout;
99 }
100
101 /**
102 * Sets the receive timeout.
103 *
104 * @param int $timeout
105 */
106 public function setRecvTimeout($timeout) {
107 $this->recvTimeout_ = $timeout;
108 }
109
110 /**
111 * Sets debugging output on or off
112 *
113 * @param bool $debug
114 */
115 public function setDebug($debug) {
116 $this->debug_ = $debug;
117 }
118
119 /**
Mark Slee6e536442006-06-30 18:28:50 +0000120 * Tests whether this is open
121 *
122 * @return bool true if the socket is open
123 */
124 public function isOpen() {
125 return is_resource($this->handle_);
126 }
127
128 /**
129 * Connects the socket.
130 */
131 public function open() {
132 if ($this->persist_) {
Mark Sleed7cc1c42006-10-04 16:49:07 +0000133 $this->handle_ = @pfsockopen($this->host_,
134 $this->port_,
135 $errno,
136 $errstr,
137 $this->sendTimeout_/1000.0);
138 } else {
139 $this->handle_ = @fsockopen($this->host_,
Mark Sleeade2c832006-09-08 03:41:50 +0000140 $this->port_,
141 $errno,
142 $errstr,
143 $this->sendTimeout_/1000.0);
Mark Slee6e536442006-06-30 18:28:50 +0000144 }
Mark Sleeade2c832006-09-08 03:41:50 +0000145
146 // Connect failed?
147 if ($this->handle_ === FALSE) {
Martin Kraemer0b64e772007-02-07 22:39:58 +0000148 $error = 'TSocket: Could not connect to '.$this->host_.':'.$this->port_.' ('.$errstr.' ['.$errno.'])';
Mark Sleeade2c832006-09-08 03:41:50 +0000149 if ($this->debug_) {
Mark Sleee7714a62007-01-11 01:26:00 +0000150 call_user_func($this->debugHandler_, $error);
Mark Sleeade2c832006-09-08 03:41:50 +0000151 }
152 throw new Exception($error);
Mark Slee6e536442006-06-30 18:28:50 +0000153 }
Mark Sleeade2c832006-09-08 03:41:50 +0000154
155 stream_set_timeout($this->handle_, 0, $this->sendTimeout_*1000);
156 $this->sendTimeoutSet_ = TRUE;
Mark Slee6e536442006-06-30 18:28:50 +0000157 }
158
159 /**
Mark Sleeade2c832006-09-08 03:41:50 +0000160 * Closes the socket.
Mark Slee6e536442006-06-30 18:28:50 +0000161 */
162 public function close() {
163 if (!$this->persist_) {
Mark Sleeade2c832006-09-08 03:41:50 +0000164 @fclose($this->handle_);
165 $this->handle_ = null;
Mark Slee6e536442006-06-30 18:28:50 +0000166 }
167 }
168
169 /**
170 * Uses stream get contents to do the reading
Mark Sleeade2c832006-09-08 03:41:50 +0000171 *
172 * @param int $len How many bytes
173 * @return string Binary data
Mark Slee6e536442006-06-30 18:28:50 +0000174 */
175 public function readAll($len) {
Mark Sleeade2c832006-09-08 03:41:50 +0000176 if ($this->sendTimeoutSet_) {
177 stream_set_timeout($this->handle_, 0, $this->recvTimeout_*1000);
178 $this->sendTimeoutSet_ = FALSE;
179 }
Mark Slee794993d2006-09-20 01:56:10 +0000180 // This call does not obey stream_set_timeout values!
181 // $buf = @stream_get_contents($this->handle_, $len);
182
183 $pre = null;
Mark Slee29f5f672006-09-28 03:19:03 +0000184 while (TRUE) {
Mark Slee794993d2006-09-20 01:56:10 +0000185 $buf = @fread($this->handle_, $len);
Mark Sleee598d072006-11-21 02:01:22 +0000186 if ($buf === FALSE || $buf === '') {
Martin Kraemer0b64e772007-02-07 22:39:58 +0000187 $md = stream_get_meta_data($this->handle_);
188 if ($md['timed_out']) {
189 throw new Exception('TSocket: timed out reading '.$len.' bytes from '.
190 $this->host_.':'.$this->port_);
191 } else {
192 throw new Exception('TSocket: Could not read '.$len.' bytes from '.
193 $this->host_.':'.$this->port_);
194 }
Mark Slee794993d2006-09-20 01:56:10 +0000195 } else if (($sz = strlen($buf)) < $len) {
196 $md = stream_get_meta_data($this->handle_);
197 if ($md['timed_out']) {
198 throw new Exception('TSocket: timed out reading '.$len.' bytes from '.
199 $this->host_.':'.$this->port_);
200 } else {
201 $pre .= $buf;
202 $len -= $sz;
203 }
204 } else {
205 return $pre.$buf;
206 }
Mark Sleeade2c832006-09-08 03:41:50 +0000207 }
Mark Slee6e536442006-06-30 18:28:50 +0000208 }
209
210 /**
211 * Read from the socket
Mark Sleeade2c832006-09-08 03:41:50 +0000212 *
213 * @param int $len How many bytes
214 * @return string Binary data
Mark Slee6e536442006-06-30 18:28:50 +0000215 */
216 public function read($len) {
Mark Sleeade2c832006-09-08 03:41:50 +0000217 if ($this->sendTimeoutSet_) {
218 stream_set_timeout($this->handle_, 0, $this->recvTimeout_*1000);
219 $this->sendTimeoutSet_ = FALSE;
220 }
Mark Slee794993d2006-09-20 01:56:10 +0000221 $data = @fread($this->handle_, $len);
Mark Sleee598d072006-11-21 02:01:22 +0000222 if ($data === FALSE || $data === '') {
Martin Kraemer0b64e772007-02-07 22:39:58 +0000223 $md = stream_get_meta_data($this->handle_);
224 if ($md['timed_out']) {
225 throw new Exception('TSocket: timed out reading '.$len.' bytes from '.
226 $this->host_.':'.$this->port_);
227 } else {
228 throw new Exception('TSocket: Could not read '.$len.' bytes from '.
229 $this->host_.':'.$this->port_);
230 }
Mark Slee6e536442006-06-30 18:28:50 +0000231 }
232 return $data;
233 }
234
235 /**
236 * Write to the socket.
Mark Sleeade2c832006-09-08 03:41:50 +0000237 *
238 * @param string $buf The data to write
Mark Slee6e536442006-06-30 18:28:50 +0000239 */
240 public function write($buf) {
Mark Sleeade2c832006-09-08 03:41:50 +0000241 if (!$this->sendTimeoutSet_) {
242 stream_set_timeout($this->handle_, 0, $this->sendTimeout_*1000);
243 $this->sendTimeoutSet_ = TRUE;
244 }
Mark Sleed395d572007-02-27 01:16:55 +0000245 while (strlen($buf) > 0) {
Mark Sleeade2c832006-09-08 03:41:50 +0000246 $got = @fwrite($this->handle_, $buf);
247 if ($got === 0 || $got === FALSE) {
Martin Kraemer0b64e772007-02-07 22:39:58 +0000248 $md = stream_get_meta_data($this->handle_);
249 if ($md['timed_out']) {
250 throw new Exception('TSocket: timed out writing '.$len.' bytes from '.
251 $this->host_.':'.$this->port_);
252 } else {
253 throw new Exception('TSocket: Could not write '.strlen($buf).' bytes '.
254 $this->host_.':'.$this->port_);
255 }
Mark Slee6e536442006-06-30 18:28:50 +0000256 }
257 $buf = substr($buf, $got);
258 }
259 }
260
261 /**
262 * Flush output to the socket.
263 */
264 public function flush() {
Mark Sleeade2c832006-09-08 03:41:50 +0000265 $ret = fflush($this->handle_);
266 if ($ret === FALSE) {
267 throw new Exception('TSocket: Could not flush: '.
268 $this->host_.':'.$this->port_);
269 }
Mark Slee6e536442006-06-30 18:28:50 +0000270 }
271}
272
273?>