blob: b2bea9147e35b475bc91c08474f73d16222e1265 [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) {
148 $error = 'TSocket: Could not connect to '.$this->host_.':'.$this->port_;
149 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 === '') {
Mark Slee794993d2006-09-20 01:56:10 +0000187 throw new Exception('TSocket: Could not read '.$len.' bytes from '.
188 $this->host_.':'.$this->port_);
189 } else if (($sz = strlen($buf)) < $len) {
190 $md = stream_get_meta_data($this->handle_);
191 if ($md['timed_out']) {
192 throw new Exception('TSocket: timed out reading '.$len.' bytes from '.
193 $this->host_.':'.$this->port_);
194 } else {
195 $pre .= $buf;
196 $len -= $sz;
197 }
198 } else {
199 return $pre.$buf;
200 }
Mark Sleeade2c832006-09-08 03:41:50 +0000201 }
Mark Slee6e536442006-06-30 18:28:50 +0000202 }
203
204 /**
205 * Read from the socket
Mark Sleeade2c832006-09-08 03:41:50 +0000206 *
207 * @param int $len How many bytes
208 * @return string Binary data
Mark Slee6e536442006-06-30 18:28:50 +0000209 */
210 public function read($len) {
Mark Sleeade2c832006-09-08 03:41:50 +0000211 if ($this->sendTimeoutSet_) {
212 stream_set_timeout($this->handle_, 0, $this->recvTimeout_*1000);
213 $this->sendTimeoutSet_ = FALSE;
214 }
Mark Slee794993d2006-09-20 01:56:10 +0000215 $data = @fread($this->handle_, $len);
Mark Sleee598d072006-11-21 02:01:22 +0000216 if ($data === FALSE || $data === '') {
Mark Slee6e536442006-06-30 18:28:50 +0000217 throw new Exception('TSocket: Could not read '.$len.' bytes from '.
218 $this->host_.':'.$this->port_);
219 }
220 return $data;
221 }
222
223 /**
224 * Write to the socket.
Mark Sleeade2c832006-09-08 03:41:50 +0000225 *
226 * @param string $buf The data to write
Mark Slee6e536442006-06-30 18:28:50 +0000227 */
228 public function write($buf) {
Mark Sleeade2c832006-09-08 03:41:50 +0000229 if (!$this->sendTimeoutSet_) {
230 stream_set_timeout($this->handle_, 0, $this->sendTimeout_*1000);
231 $this->sendTimeoutSet_ = TRUE;
232 }
Mark Slee6e536442006-06-30 18:28:50 +0000233 while (!empty($buf)) {
Mark Sleeade2c832006-09-08 03:41:50 +0000234 $got = @fwrite($this->handle_, $buf);
235 if ($got === 0 || $got === FALSE) {
Mark Slee6e536442006-06-30 18:28:50 +0000236 throw new Exception('TSocket: Could not write '.strlen($buf).' bytes '.
237 $this->host_.':'.$this->port_);
238 }
239 $buf = substr($buf, $got);
240 }
241 }
242
243 /**
244 * Flush output to the socket.
245 */
246 public function flush() {
Mark Sleeade2c832006-09-08 03:41:50 +0000247 $ret = fflush($this->handle_);
248 if ($ret === FALSE) {
249 throw new Exception('TSocket: Could not flush: '.
250 $this->host_.':'.$this->port_);
251 }
Mark Slee6e536442006-06-30 18:28:50 +0000252 }
253}
254
255?>