blob: 5ca23e725c0c9027ea7ac5b2b669f375348e442b [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 */
65 private $debug_ = FALSE;
Mark Slee6e536442006-06-30 18:28:50 +000066
67 /**
68 * Socket constructor
69 *
70 * @param string $host Remote hostname
71 * @param int $port Remote port
72 * @param bool $persist Whether to use a persistent socket
73 */
Mark Sleeade2c832006-09-08 03:41:50 +000074 public function __construct($host='localhost', $port=9090, $persist=FALSE) {
Mark Slee6e536442006-06-30 18:28:50 +000075 $this->host_ = $host;
76 $this->port_ = $port;
77 $this->persist_ = $persist;
78 }
79
80 /**
Mark Sleeade2c832006-09-08 03:41:50 +000081 * Sets the send timeout.
82 *
83 * @param int $timeout
84 */
85 public function setSendTimeout($timeout) {
86 $this->sendTimeout_ = $timeout;
87 }
88
89 /**
90 * Sets the receive timeout.
91 *
92 * @param int $timeout
93 */
94 public function setRecvTimeout($timeout) {
95 $this->recvTimeout_ = $timeout;
96 }
97
98 /**
99 * Sets debugging output on or off
100 *
101 * @param bool $debug
102 */
103 public function setDebug($debug) {
104 $this->debug_ = $debug;
105 }
106
107 /**
Mark Slee6e536442006-06-30 18:28:50 +0000108 * Tests whether this is open
109 *
110 * @return bool true if the socket is open
111 */
112 public function isOpen() {
113 return is_resource($this->handle_);
114 }
115
116 /**
117 * Connects the socket.
118 */
119 public function open() {
120 if ($this->persist_) {
Mark Sleeade2c832006-09-08 03:41:50 +0000121 $this->handle_ = pfsockopen($this->host_,
122 $this->port_,
123 $errno,
124 $errstr,
125 $this->sendTimeout_/1000.0);
Mark Slee6e536442006-06-30 18:28:50 +0000126 } else {
Mark Sleeade2c832006-09-08 03:41:50 +0000127 $this->handle_ = fsockopen($this->host_,
128 $this->port_,
129 $errno,
130 $errstr,
131 $this->sendTimeout_/1000.0);
Mark Slee6e536442006-06-30 18:28:50 +0000132 }
Mark Sleeade2c832006-09-08 03:41:50 +0000133
134 // Connect failed?
135 if ($this->handle_ === FALSE) {
136 $error = 'TSocket: Could not connect to '.$this->host_.':'.$this->port_;
137 if ($this->debug_) {
138 error_log($error);
139 }
140 throw new Exception($error);
Mark Slee6e536442006-06-30 18:28:50 +0000141 }
Mark Sleeade2c832006-09-08 03:41:50 +0000142
143 stream_set_timeout($this->handle_, 0, $this->sendTimeout_*1000);
144 $this->sendTimeoutSet_ = TRUE;
Mark Slee6e536442006-06-30 18:28:50 +0000145 }
146
147 /**
Mark Sleeade2c832006-09-08 03:41:50 +0000148 * Closes the socket.
Mark Slee6e536442006-06-30 18:28:50 +0000149 */
150 public function close() {
151 if (!$this->persist_) {
Mark Sleeade2c832006-09-08 03:41:50 +0000152 @fclose($this->handle_);
153 $this->handle_ = null;
Mark Slee6e536442006-06-30 18:28:50 +0000154 }
155 }
156
157 /**
158 * Uses stream get contents to do the reading
Mark Sleeade2c832006-09-08 03:41:50 +0000159 *
160 * @param int $len How many bytes
161 * @return string Binary data
Mark Slee6e536442006-06-30 18:28:50 +0000162 */
163 public function readAll($len) {
Mark Sleeade2c832006-09-08 03:41:50 +0000164 if ($this->sendTimeoutSet_) {
165 stream_set_timeout($this->handle_, 0, $this->recvTimeout_*1000);
166 $this->sendTimeoutSet_ = FALSE;
167 }
Mark Slee794993d2006-09-20 01:56:10 +0000168 // This call does not obey stream_set_timeout values!
169 // $buf = @stream_get_contents($this->handle_, $len);
170
171 $pre = null;
Mark Slee29f5f672006-09-28 03:19:03 +0000172 while (TRUE) {
Mark Slee794993d2006-09-20 01:56:10 +0000173 $buf = @fread($this->handle_, $len);
Mark Slee29f5f672006-09-28 03:19:03 +0000174 if (!$buf) {
Mark Slee794993d2006-09-20 01:56:10 +0000175 throw new Exception('TSocket: Could not read '.$len.' bytes from '.
176 $this->host_.':'.$this->port_);
177 } else if (($sz = strlen($buf)) < $len) {
178 $md = stream_get_meta_data($this->handle_);
179 if ($md['timed_out']) {
180 throw new Exception('TSocket: timed out reading '.$len.' bytes from '.
181 $this->host_.':'.$this->port_);
182 } else {
183 $pre .= $buf;
184 $len -= $sz;
185 }
186 } else {
187 return $pre.$buf;
188 }
Mark Sleeade2c832006-09-08 03:41:50 +0000189 }
Mark Slee6e536442006-06-30 18:28:50 +0000190 }
191
192 /**
193 * Read from the socket
Mark Sleeade2c832006-09-08 03:41:50 +0000194 *
195 * @param int $len How many bytes
196 * @return string Binary data
Mark Slee6e536442006-06-30 18:28:50 +0000197 */
198 public function read($len) {
Mark Sleeade2c832006-09-08 03:41:50 +0000199 if ($this->sendTimeoutSet_) {
200 stream_set_timeout($this->handle_, 0, $this->recvTimeout_*1000);
201 $this->sendTimeoutSet_ = FALSE;
202 }
Mark Slee794993d2006-09-20 01:56:10 +0000203 $data = @fread($this->handle_, $len);
Mark Slee6e536442006-06-30 18:28:50 +0000204 if ($data === FALSE) {
205 throw new Exception('TSocket: Could not read '.$len.' bytes from '.
206 $this->host_.':'.$this->port_);
207 }
208 return $data;
209 }
210
211 /**
212 * Write to the socket.
Mark Sleeade2c832006-09-08 03:41:50 +0000213 *
214 * @param string $buf The data to write
Mark Slee6e536442006-06-30 18:28:50 +0000215 */
216 public function write($buf) {
Mark Sleeade2c832006-09-08 03:41:50 +0000217 if (!$this->sendTimeoutSet_) {
218 stream_set_timeout($this->handle_, 0, $this->sendTimeout_*1000);
219 $this->sendTimeoutSet_ = TRUE;
220 }
Mark Slee6e536442006-06-30 18:28:50 +0000221 while (!empty($buf)) {
Mark Sleeade2c832006-09-08 03:41:50 +0000222 $got = @fwrite($this->handle_, $buf);
223 if ($got === 0 || $got === FALSE) {
Mark Slee6e536442006-06-30 18:28:50 +0000224 throw new Exception('TSocket: Could not write '.strlen($buf).' bytes '.
225 $this->host_.':'.$this->port_);
226 }
227 $buf = substr($buf, $got);
228 }
229 }
230
231 /**
232 * Flush output to the socket.
233 */
234 public function flush() {
Mark Sleeade2c832006-09-08 03:41:50 +0000235 $ret = fflush($this->handle_);
236 if ($ret === FALSE) {
237 throw new Exception('TSocket: Could not flush: '.
238 $this->host_.':'.$this->port_);
239 }
Mark Slee6e536442006-06-30 18:28:50 +0000240 }
241}
242
243?>