blob: 7c4795834a88b7005f3c12960724ead217e425c8 [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
Mark Slee4902c052007-03-01 00:31:30 +000011 */
12
13/**
Mark Slee6e536442006-06-30 18:28:50 +000014 * Sockets implementation of the TTransport interface.
15 *
16 * @package thrift.transport
Mark Slee6e536442006-06-30 18:28:50 +000017 */
18class TSocket extends TTransport {
19
20 /**
21 * Handle to PHP socket
22 *
23 * @var resource
24 */
25 private $handle_ = null;
26
27 /**
28 * Remote hostname
Mark Slee0cdc6c82007-11-13 10:19:08 +000029 *
Mark Slee6e536442006-06-30 18:28:50 +000030 * @var string
31 */
Mark Sleeade2c832006-09-08 03:41:50 +000032 protected $host_ = 'localhost';
Mark Slee6e536442006-06-30 18:28:50 +000033
34 /**
35 * Remote port
36 *
37 * @var int
38 */
Mark Sleeade2c832006-09-08 03:41:50 +000039 protected $port_ = '9090';
40
41 /**
42 * Send timeout in milliseconds
43 *
44 * @var int
45 */
46 private $sendTimeout_ = 100;
47
48 /**
49 * Recv timeout in milliseconds
50 *
51 * @var int
52 */
53 private $recvTimeout_ = 750;
54
55 /**
56 * Is send timeout set?
57 *
58 * @var bool
59 */
60 private $sendTimeoutSet_ = FALSE;
Mark Slee6e536442006-06-30 18:28:50 +000061
62 /**
63 * Persistent socket or plain?
64 *
65 * @var bool
66 */
Mark Sleeade2c832006-09-08 03:41:50 +000067 private $persist_ = FALSE;
68
69 /**
70 * Debugging on?
71 *
72 * @var bool
73 */
robertb0fac3e2007-01-15 23:53:25 +000074 protected $debug_ = FALSE;
Mark Slee6e536442006-06-30 18:28:50 +000075
76 /**
Mark Sleead58f952007-01-03 19:23:50 +000077 * Debug handler
78 *
79 * @var mixed
80 */
robertb0fac3e2007-01-15 23:53:25 +000081 protected $debugHandler_ = null;
Mark Sleead58f952007-01-03 19:23:50 +000082
83 /**
Mark Slee6e536442006-06-30 18:28:50 +000084 * Socket constructor
85 *
Mark Sleead58f952007-01-03 19:23:50 +000086 * @param string $host Remote hostname
87 * @param int $port Remote port
88 * @param bool $persist Whether to use a persistent socket
89 * @param string $debugHandler Function to call for error logging
Mark Slee6e536442006-06-30 18:28:50 +000090 */
Mark Sleead58f952007-01-03 19:23:50 +000091 public function __construct($host='localhost',
92 $port=9090,
93 $persist=FALSE,
94 $debugHandler=null) {
Mark Slee6e536442006-06-30 18:28:50 +000095 $this->host_ = $host;
96 $this->port_ = $port;
97 $this->persist_ = $persist;
Mark Sleead58f952007-01-03 19:23:50 +000098 $this->debugHandler_ = $debugHandler ? $debugHandler : 'error_log';
Mark Slee6e536442006-06-30 18:28:50 +000099 }
100
101 /**
Mark Sleeade2c832006-09-08 03:41:50 +0000102 * Sets the send timeout.
103 *
104 * @param int $timeout
105 */
106 public function setSendTimeout($timeout) {
107 $this->sendTimeout_ = $timeout;
108 }
109
110 /**
111 * Sets the receive timeout.
112 *
113 * @param int $timeout
114 */
115 public function setRecvTimeout($timeout) {
116 $this->recvTimeout_ = $timeout;
117 }
118
119 /**
120 * Sets debugging output on or off
121 *
122 * @param bool $debug
123 */
124 public function setDebug($debug) {
125 $this->debug_ = $debug;
126 }
127
128 /**
Mark Slee0cdc6c82007-11-13 10:19:08 +0000129 * Get the host that this socket is connected to
130 *
131 * @return string host
132 */
133 public function getHost() {
134 return $this->host_;
135 }
136
137 /**
138 * Get the remote port that this socket is connected to
139 *
140 * @return int port
141 */
142 public function getPort() {
143 return $this->port_;
144 }
145
146 /**
Mark Slee6e536442006-06-30 18:28:50 +0000147 * Tests whether this is open
148 *
149 * @return bool true if the socket is open
150 */
151 public function isOpen() {
152 return is_resource($this->handle_);
153 }
154
155 /**
156 * Connects the socket.
157 */
158 public function open() {
Mark Slee0cdc6c82007-11-13 10:19:08 +0000159
Mark Slee6e536442006-06-30 18:28:50 +0000160 if ($this->persist_) {
Mark Sleed7cc1c42006-10-04 16:49:07 +0000161 $this->handle_ = @pfsockopen($this->host_,
162 $this->port_,
163 $errno,
164 $errstr,
165 $this->sendTimeout_/1000.0);
166 } else {
167 $this->handle_ = @fsockopen($this->host_,
Mark Sleeade2c832006-09-08 03:41:50 +0000168 $this->port_,
169 $errno,
170 $errstr,
171 $this->sendTimeout_/1000.0);
Mark Slee6e536442006-06-30 18:28:50 +0000172 }
Mark Sleeade2c832006-09-08 03:41:50 +0000173
174 // Connect failed?
175 if ($this->handle_ === FALSE) {
Martin Kraemer0b64e772007-02-07 22:39:58 +0000176 $error = 'TSocket: Could not connect to '.$this->host_.':'.$this->port_.' ('.$errstr.' ['.$errno.'])';
Mark Sleeade2c832006-09-08 03:41:50 +0000177 if ($this->debug_) {
Mark Sleee7714a62007-01-11 01:26:00 +0000178 call_user_func($this->debugHandler_, $error);
Mark Sleeade2c832006-09-08 03:41:50 +0000179 }
Mark Slee76791962007-03-14 02:47:35 +0000180 throw new TException($error);
Mark Slee6e536442006-06-30 18:28:50 +0000181 }
Mark Slee0cdc6c82007-11-13 10:19:08 +0000182
Mark Sleeade2c832006-09-08 03:41:50 +0000183 stream_set_timeout($this->handle_, 0, $this->sendTimeout_*1000);
184 $this->sendTimeoutSet_ = TRUE;
Mark Slee6e536442006-06-30 18:28:50 +0000185 }
186
187 /**
Mark Sleeade2c832006-09-08 03:41:50 +0000188 * Closes the socket.
Mark Slee6e536442006-06-30 18:28:50 +0000189 */
190 public function close() {
191 if (!$this->persist_) {
Mark Sleeade2c832006-09-08 03:41:50 +0000192 @fclose($this->handle_);
193 $this->handle_ = null;
Mark Slee6e536442006-06-30 18:28:50 +0000194 }
195 }
Mark Slee0cdc6c82007-11-13 10:19:08 +0000196
Mark Slee6e536442006-06-30 18:28:50 +0000197 /**
198 * Uses stream get contents to do the reading
Mark Sleeade2c832006-09-08 03:41:50 +0000199 *
200 * @param int $len How many bytes
201 * @return string Binary data
Mark Slee6e536442006-06-30 18:28:50 +0000202 */
203 public function readAll($len) {
Mark Sleeade2c832006-09-08 03:41:50 +0000204 if ($this->sendTimeoutSet_) {
205 stream_set_timeout($this->handle_, 0, $this->recvTimeout_*1000);
206 $this->sendTimeoutSet_ = FALSE;
207 }
Mark Slee794993d2006-09-20 01:56:10 +0000208 // This call does not obey stream_set_timeout values!
209 // $buf = @stream_get_contents($this->handle_, $len);
210
211 $pre = null;
Mark Slee29f5f672006-09-28 03:19:03 +0000212 while (TRUE) {
Mark Slee794993d2006-09-20 01:56:10 +0000213 $buf = @fread($this->handle_, $len);
Mark Sleee598d072006-11-21 02:01:22 +0000214 if ($buf === FALSE || $buf === '') {
Martin Kraemer0b64e772007-02-07 22:39:58 +0000215 $md = stream_get_meta_data($this->handle_);
216 if ($md['timed_out']) {
Mark Slee76791962007-03-14 02:47:35 +0000217 throw new TException('TSocket: timed out reading '.$len.' bytes from '.
218 $this->host_.':'.$this->port_);
Martin Kraemer0b64e772007-02-07 22:39:58 +0000219 } else {
Mark Slee76791962007-03-14 02:47:35 +0000220 throw new TException('TSocket: Could not read '.$len.' bytes from '.
221 $this->host_.':'.$this->port_);
Martin Kraemer0b64e772007-02-07 22:39:58 +0000222 }
Mark Slee794993d2006-09-20 01:56:10 +0000223 } else if (($sz = strlen($buf)) < $len) {
224 $md = stream_get_meta_data($this->handle_);
225 if ($md['timed_out']) {
Mark Slee76791962007-03-14 02:47:35 +0000226 throw new TException('TSocket: timed out reading '.$len.' bytes from '.
227 $this->host_.':'.$this->port_);
Mark Slee794993d2006-09-20 01:56:10 +0000228 } else {
229 $pre .= $buf;
230 $len -= $sz;
231 }
232 } else {
233 return $pre.$buf;
234 }
Mark Sleeade2c832006-09-08 03:41:50 +0000235 }
Mark Slee6e536442006-06-30 18:28:50 +0000236 }
237
238 /**
239 * Read from the socket
Mark Sleeade2c832006-09-08 03:41:50 +0000240 *
241 * @param int $len How many bytes
242 * @return string Binary data
Mark Slee6e536442006-06-30 18:28:50 +0000243 */
244 public function read($len) {
Mark Sleeade2c832006-09-08 03:41:50 +0000245 if ($this->sendTimeoutSet_) {
246 stream_set_timeout($this->handle_, 0, $this->recvTimeout_*1000);
247 $this->sendTimeoutSet_ = FALSE;
248 }
Mark Slee794993d2006-09-20 01:56:10 +0000249 $data = @fread($this->handle_, $len);
Mark Sleee598d072006-11-21 02:01:22 +0000250 if ($data === FALSE || $data === '') {
Martin Kraemer0b64e772007-02-07 22:39:58 +0000251 $md = stream_get_meta_data($this->handle_);
252 if ($md['timed_out']) {
Mark Slee76791962007-03-14 02:47:35 +0000253 throw new TException('TSocket: timed out reading '.$len.' bytes from '.
254 $this->host_.':'.$this->port_);
Martin Kraemer0b64e772007-02-07 22:39:58 +0000255 } else {
Mark Slee76791962007-03-14 02:47:35 +0000256 throw new TException('TSocket: Could not read '.$len.' bytes from '.
257 $this->host_.':'.$this->port_);
Martin Kraemer0b64e772007-02-07 22:39:58 +0000258 }
Mark Slee6e536442006-06-30 18:28:50 +0000259 }
260 return $data;
261 }
262
263 /**
264 * Write to the socket.
Mark Sleeade2c832006-09-08 03:41:50 +0000265 *
266 * @param string $buf The data to write
Mark Slee6e536442006-06-30 18:28:50 +0000267 */
268 public function write($buf) {
Mark Sleeade2c832006-09-08 03:41:50 +0000269 if (!$this->sendTimeoutSet_) {
270 stream_set_timeout($this->handle_, 0, $this->sendTimeout_*1000);
271 $this->sendTimeoutSet_ = TRUE;
272 }
Mark Sleed395d572007-02-27 01:16:55 +0000273 while (strlen($buf) > 0) {
Mark Sleeade2c832006-09-08 03:41:50 +0000274 $got = @fwrite($this->handle_, $buf);
275 if ($got === 0 || $got === FALSE) {
Martin Kraemer0b64e772007-02-07 22:39:58 +0000276 $md = stream_get_meta_data($this->handle_);
277 if ($md['timed_out']) {
David Reiss1931b122008-07-17 19:36:34 +0000278 throw new TException('TSocket: timed out writing '.strlen($buf).' bytes from '.
Mark Slee76791962007-03-14 02:47:35 +0000279 $this->host_.':'.$this->port_);
Martin Kraemer0b64e772007-02-07 22:39:58 +0000280 } else {
Mark Slee76791962007-03-14 02:47:35 +0000281 throw new TException('TSocket: Could not write '.strlen($buf).' bytes '.
282 $this->host_.':'.$this->port_);
Martin Kraemer0b64e772007-02-07 22:39:58 +0000283 }
Mark Slee6e536442006-06-30 18:28:50 +0000284 }
285 $buf = substr($buf, $got);
286 }
287 }
288
289 /**
290 * Flush output to the socket.
291 */
292 public function flush() {
Mark Sleeade2c832006-09-08 03:41:50 +0000293 $ret = fflush($this->handle_);
294 if ($ret === FALSE) {
Mark Slee76791962007-03-14 02:47:35 +0000295 throw new TException('TSocket: Could not flush: '.
296 $this->host_.':'.$this->port_);
Mark Sleeade2c832006-09-08 03:41:50 +0000297 }
Mark Slee6e536442006-06-30 18:28:50 +0000298 }
299}
300
301?>