44
55use Bolt \Bolt ;
66use Bolt \error \ConnectException ;
7+ use Bolt \error \ConnectionTimeoutException ;
78
89/**
910 * Socket class
@@ -20,6 +21,10 @@ class Socket extends AConnection
2021 */
2122 private $ socket = false ;
2223
24+ private const POSSIBLE_TIMEOUTS_CODES = [11 , 10060 ];
25+ /** @var float|null */
26+ private $ timetAtTimeoutConfiguration ;
27+
2328 /**
2429 * Create socket connection
2530 * @return bool
@@ -42,11 +47,7 @@ public function connect(): bool
4247
4348 socket_set_option ($ this ->socket , SOL_TCP , TCP_NODELAY , 1 );
4449 socket_set_option ($ this ->socket , SOL_SOCKET , SO_KEEPALIVE , 1 );
45- $ timeoutSeconds = floor ($ this ->timeout );
46- $ microSeconds = floor (($ this ->timeout - $ timeoutSeconds ) * 1000000 );
47- $ timeoutOption = ['sec ' => $ timeoutSeconds , 'usec ' => $ microSeconds ];
48- socket_set_option ($ this ->socket , SOL_SOCKET , SO_RCVTIMEO , $ timeoutOption );
49- socket_set_option ($ this ->socket , SOL_SOCKET , SO_SNDTIMEO , $ timeoutOption );
50+ $ this ->configureTimeout ();
5051
5152 $ conn = @socket_connect ($ this ->socket , $ this ->ip , $ this ->port );
5253 if (!$ conn ) {
@@ -75,10 +76,9 @@ public function write(string $buffer)
7576 $ this ->printHex ($ buffer );
7677
7778 while (0 < $ size ) {
78- $ sent = socket_write ($ this ->socket , $ buffer , $ size );
79+ $ sent = @ socket_write ($ this ->socket , $ buffer , $ size );
7980 if ($ sent === false ) {
80- $ code = socket_last_error ($ this ->socket );
81- throw new ConnectException (socket_strerror ($ code ), $ code );
81+ $ this ->throwConnectException ();
8282 }
8383
8484 $ buffer = mb_strcut ($ buffer , $ sent , null , '8bit ' );
@@ -101,10 +101,9 @@ public function read(int $length = 2048): string
101101 }
102102
103103 do {
104- $ readed = socket_read ($ this ->socket , $ length - mb_strlen ($ output , '8bit ' ), PHP_BINARY_READ );
104+ $ readed = @ socket_read ($ this ->socket , $ length - mb_strlen ($ output , '8bit ' ), PHP_BINARY_READ );
105105 if ($ readed === false ) {
106- $ code = socket_last_error ($ this ->socket );
107- throw new ConnectException (socket_strerror ($ code ), $ code );
106+ $ this ->throwConnectException ();
108107 }
109108 $ output .= $ readed ;
110109 } while (mb_strlen ($ output , '8bit ' ) < $ length );
@@ -125,4 +124,36 @@ public function disconnect()
125124 @socket_close ($ this ->socket );
126125 }
127126 }
127+
128+ public function setTimeout (float $ timeout ): void
129+ {
130+ parent ::setTimeout ($ timeout );
131+ $ this ->configureTimeout ();
132+ }
133+
134+ private function configureTimeout (): void
135+ {
136+ $ timeoutSeconds = floor ($ this ->timeout );
137+ $ microSeconds = floor (($ this ->timeout - $ timeoutSeconds ) * 1000000 );
138+ $ timeoutOption = ['sec ' => $ timeoutSeconds , 'usec ' => $ microSeconds ];
139+ socket_set_option ($ this ->socket , SOL_SOCKET , SO_RCVTIMEO , $ timeoutOption );
140+ socket_set_option ($ this ->socket , SOL_SOCKET , SO_SNDTIMEO , $ timeoutOption );
141+ $ this ->timetAtTimeoutConfiguration = microtime (true );
142+ }
143+
144+ /**
145+ * @throws ConnectException
146+ * @throws ConnectionTimeoutException
147+ */
148+ private function throwConnectException (): void
149+ {
150+ $ code = socket_last_error ($ this ->socket );
151+ if (in_array ($ code , self ::POSSIBLE_TIMEOUTS_CODES )) {
152+ $ timediff = microtime (true ) - $ this ->timetAtTimeoutConfiguration ;
153+ if ($ timediff >= $ this ->timeout ) {
154+ throw ConnectionTimeoutException::createFromTimeout ($ this ->timeout );
155+ }
156+ }
157+ throw new ConnectException (socket_strerror ($ code ), $ code );
158+ }
128159}
0 commit comments