php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
transports.c
Go to the documentation of this file.
1/*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | https://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Author: Wez Furlong <wez@thebrainroom.com> |
14 +----------------------------------------------------------------------+
15*/
16
17#include "php.h"
18#include "php_streams_int.h"
19#include "ext/standard/file.h"
20
21static HashTable xport_hash;
22
24{
25 return &xport_hash;
26}
27
29{
30 zend_string *str = zend_string_init_interned(protocol, strlen(protocol), 1);
31
32 zend_hash_update_ptr(&xport_hash, str, factory);
34 return SUCCESS;
35}
36
37PHPAPI int php_stream_xport_unregister(const char *protocol)
38{
39 return zend_hash_str_del(&xport_hash, protocol, strlen(protocol));
40}
41
42#define ERR_REPORT(out_err, fmt, arg) \
43 if (out_err) { *out_err = strpprintf(0, fmt, arg); } \
44 else { php_error_docref(NULL, E_WARNING, fmt, arg); }
45
46#define ERR_RETURN(out_err, local_err, fmt) \
47 if (out_err) { *out_err = local_err; } \
48 else { php_error_docref(NULL, E_WARNING, fmt, local_err ? ZSTR_VAL(local_err) : "Unspecified error"); \
49 if (local_err) { zend_string_release_ex(local_err, 0); local_err = NULL; } \
50 }
51
53 int flags, const char *persistent_id,
54 struct timeval *timeout,
56 zend_string **error_string,
57 int *error_code
59{
60 php_stream *stream = NULL;
62 const char *p, *protocol, *orig_path = NULL;
63 size_t n = 0;
64 bool failed = false;
65 bool bailout = false;
66 zend_string *error_text = NULL;
67 struct timeval default_timeout = { 0, 0 };
68
69 default_timeout.tv_sec = FG(default_socket_timeout);
70
71 if (timeout == NULL) {
72 timeout = &default_timeout;
73 }
74
75 /* check for a cached persistent socket */
76 if (persistent_id) {
77 switch(php_stream_from_persistent_id(persistent_id, &stream)) {
79 /* use a 0-second timeout when checking if the socket
80 * has already died */
82 return stream;
83 }
84 /* dead - kill it */
85 php_stream_pclose(stream);
86 stream = NULL;
87
88 /* fall through */
89
91 default:
92 /* failed; get a new one */
93 ;
94 }
95 }
96
97 orig_path = name;
98 for (p = name; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; p++) {
99 n++;
100 }
101
102 if ((*p == ':') && (n > 1) && !strncmp("://", p, 3)) {
103 protocol = name;
104 name = p + 3;
105 namelen -= n + 3;
106 } else {
107 protocol = "tcp";
108 n = 3;
109 }
110
111 if (protocol) {
112 if (NULL == (factory = zend_hash_str_find_ptr(&xport_hash, protocol, n))) {
113 char wrapper_name[32];
114
115 if (n >= sizeof(wrapper_name))
116 n = sizeof(wrapper_name) - 1;
117 PHP_STRLCPY(wrapper_name, protocol, sizeof(wrapper_name), n);
118
119 ERR_REPORT(error_string, "Unable to find the socket transport \"%s\" - did you forget to enable it when you configured PHP?",
120 wrapper_name);
121
122 return NULL;
123 }
124 }
125
126 if (factory == NULL) {
127 /* should never happen */
128 php_error_docref(NULL, E_WARNING, "Could not find a factory !?");
129 return NULL;
130 }
131
132 stream = (factory)(protocol, n,
133 (char*)name, namelen, persistent_id, options, flags, timeout,
135
136 if (stream) {
137 zend_try {
139 stream->orig_path = pestrdup(orig_path, persistent_id ? 1 : 0);
140
141 if ((flags & STREAM_XPORT_SERVER) == 0) {
142 /* client */
143
145 if (-1 == php_stream_xport_connect(stream, name, namelen,
147 timeout, &error_text, error_code)) {
148
149 ERR_RETURN(error_string, error_text, "connect() failed: %s");
150
151 failed = true;
152 }
153 }
154
155 } else {
156 /* server */
157 if (flags & STREAM_XPORT_BIND) {
158 if (0 != php_stream_xport_bind(stream, name, namelen, &error_text)) {
159 ERR_RETURN(error_string, error_text, "bind() failed: %s");
160 failed = true;
161 } else if (flags & STREAM_XPORT_LISTEN) {
162 zval *zbacklog = NULL;
163 int backlog = 32;
164
165 if (PHP_STREAM_CONTEXT(stream) && (zbacklog = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "backlog")) != NULL) {
166 backlog = zval_get_long(zbacklog);
167 }
168
169 if (0 != php_stream_xport_listen(stream, backlog, &error_text)) {
170 ERR_RETURN(error_string, error_text, "listen() failed: %s");
171 failed = true;
172 }
173 }
174 if (!failed) {
175 stream->flags |= PHP_STREAM_FLAG_NO_IO;
176 }
177 }
178 }
179 } zend_catch {
180 bailout = true;
181 } zend_end_try();
182 }
183
184 if (failed || bailout) {
185 /* failure means that they don't get a stream to play with */
186 if (persistent_id) {
187 php_stream_pclose(stream);
188 } else {
189 php_stream_close(stream);
190 }
191 stream = NULL;
192 if (bailout) {
193 zend_bailout();
194 }
195 }
196
197 return stream;
198}
199
200/* Bind the stream to a local address */
202 const char *name, size_t namelen,
203 zend_string **error_text
204 )
205{
207 int ret;
208
209 memset(&param, 0, sizeof(param));
210 param.op = STREAM_XPORT_OP_BIND;
211 param.inputs.name = (char*)name;
212 param.inputs.namelen = namelen;
213 param.want_errortext = error_text ? 1 : 0;
214
216
218 if (error_text) {
219 *error_text = param.outputs.error_text;
220 }
221
222 return param.outputs.returncode;
223 }
224
225 return ret;
226}
227
228/* Connect to a remote address */
230 const char *name, size_t namelen,
231 int asynchronous,
232 struct timeval *timeout,
233 zend_string **error_text,
234 int *error_code
235 )
236{
238 int ret;
239
240 memset(&param, 0, sizeof(param));
241 param.op = asynchronous ? STREAM_XPORT_OP_CONNECT_ASYNC: STREAM_XPORT_OP_CONNECT;
242 param.inputs.name = (char*)name;
243 param.inputs.namelen = namelen;
244 param.inputs.timeout = timeout;
245
246 param.want_errortext = error_text ? 1 : 0;
247
249
251 if (error_text) {
252 *error_text = param.outputs.error_text;
253 }
254 if (error_code) {
256 }
257 return param.outputs.returncode;
258 }
259
260 return ret;
261
262}
263
264/* Prepare to listen */
265PHPAPI int php_stream_xport_listen(php_stream *stream, int backlog, zend_string **error_text)
266{
268 int ret;
269
270 memset(&param, 0, sizeof(param));
271 param.op = STREAM_XPORT_OP_LISTEN;
272 param.inputs.backlog = backlog;
273 param.want_errortext = error_text ? 1 : 0;
274
276
278 if (error_text) {
279 *error_text = param.outputs.error_text;
280 }
281
282 return param.outputs.returncode;
283 }
284
285 return ret;
286}
287
288/* Get the next client and their address (as a string) */
290 zend_string **textaddr,
291 void **addr, socklen_t *addrlen,
292 struct timeval *timeout,
293 zend_string **error_text
294 )
295{
297 int ret;
298
299 memset(&param, 0, sizeof(param));
300
301 param.op = STREAM_XPORT_OP_ACCEPT;
302 param.inputs.timeout = timeout;
303 param.want_addr = addr ? 1 : 0;
304 param.want_textaddr = textaddr ? 1 : 0;
305 param.want_errortext = error_text ? 1 : 0;
306
308
310 *client = param.outputs.client;
311 if (addr) {
312 *addr = param.outputs.addr;
313 *addrlen = param.outputs.addrlen;
314 }
315 if (textaddr) {
316 *textaddr = param.outputs.textaddr;
317 }
318 if (error_text) {
319 *error_text = param.outputs.error_text;
320 }
321
322 return param.outputs.returncode;
323 }
324 return ret;
325}
326
327PHPAPI int php_stream_xport_get_name(php_stream *stream, int want_peer,
328 zend_string **textaddr,
329 void **addr, socklen_t *addrlen
330 )
331{
333 int ret;
334
335 memset(&param, 0, sizeof(param));
336
337 param.op = want_peer ? STREAM_XPORT_OP_GET_PEER_NAME : STREAM_XPORT_OP_GET_NAME;
338 param.want_addr = addr ? 1 : 0;
339 param.want_textaddr = textaddr ? 1 : 0;
340
342
344 if (addr) {
345 *addr = param.outputs.addr;
346 *addrlen = param.outputs.addrlen;
347 }
348 if (textaddr) {
349 *textaddr = param.outputs.textaddr;
350 }
351
352 return param.outputs.returncode;
353 }
354 return ret;
355}
356
358{
360 int ret;
361
362 memset(&param, 0, sizeof(param));
363 param.op = STREAM_XPORT_CRYPTO_OP_SETUP;
364 param.inputs.method = crypto_method;
365 param.inputs.session = session_stream;
366
368
370 return param.outputs.returncode;
371 }
372
373 php_error_docref("streams.crypto", E_WARNING, "This stream does not support SSL/crypto");
374
375 return ret;
376}
377
379{
381 int ret;
382
383 memset(&param, 0, sizeof(param));
384 param.op = STREAM_XPORT_CRYPTO_OP_ENABLE;
385 param.inputs.activate = activate;
386
388
390 return param.outputs.returncode;
391 }
392
393 php_error_docref("streams.crypto", E_WARNING, "This stream does not support SSL/crypto");
394
395 return ret;
396}
397
398/* Similar to recv() system call; read data from the stream, optionally
399 * peeking, optionally retrieving OOB data */
400PHPAPI int php_stream_xport_recvfrom(php_stream *stream, char *buf, size_t buflen,
401 int flags, void **addr, socklen_t *addrlen, zend_string **textaddr
402 )
403{
405 int ret = 0;
406 int recvd_len = 0;
407#if 0
408 int oob;
409
410 if (flags == 0 && addr == NULL) {
411 return php_stream_read(stream, buf, buflen);
412 }
413
414 if (stream->readfilters.head) {
415 php_error_docref(NULL, E_WARNING, "Cannot peek or fetch OOB data from a filtered stream");
416 return -1;
417 }
418
419 oob = (flags & STREAM_OOB) == STREAM_OOB;
420
421 if (!oob && addr == NULL) {
422 /* must be peeking at regular data; copy content from the buffer
423 * first, then adjust the pointer/len before handing off to the
424 * stream */
425 recvd_len = stream->writepos - stream->readpos;
426 if (recvd_len > buflen) {
427 recvd_len = buflen;
428 }
429 if (recvd_len) {
430 memcpy(buf, stream->readbuf, recvd_len);
431 buf += recvd_len;
432 buflen -= recvd_len;
433 }
434 /* if we filled their buffer, return */
435 if (buflen == 0) {
436 return recvd_len;
437 }
438 }
439#endif
440
441 /* otherwise, we are going to bypass the buffer */
442
443 memset(&param, 0, sizeof(param));
444
445 param.op = STREAM_XPORT_OP_RECV;
446 param.want_addr = addr ? 1 : 0;
447 param.want_textaddr = textaddr ? 1 : 0;
448 param.inputs.buf = buf;
449 param.inputs.buflen = buflen;
450 param.inputs.flags = flags;
451
453
455 if (addr) {
456 *addr = param.outputs.addr;
457 *addrlen = param.outputs.addrlen;
458 }
459 if (textaddr) {
460 *textaddr = param.outputs.textaddr;
461 }
462 return recvd_len + param.outputs.returncode;
463 }
464 return recvd_len ? recvd_len : -1;
465}
466
467/* Similar to send() system call; send data to the stream, optionally
468 * sending it as OOB data */
469PHPAPI int php_stream_xport_sendto(php_stream *stream, const char *buf, size_t buflen,
470 int flags, void *addr, socklen_t addrlen)
471{
473 int ret = 0;
474 int oob;
475
476#if 0
477 if (flags == 0 && addr == NULL) {
478 return php_stream_write(stream, buf, buflen);
479 }
480#endif
481
482 oob = (flags & STREAM_OOB) == STREAM_OOB;
483
484 if ((oob || addr) && stream->writefilters.head) {
485 php_error_docref(NULL, E_WARNING, "Cannot write OOB data, or data to a targeted address on a filtered stream");
486 return -1;
487 }
488
489 memset(&param, 0, sizeof(param));
490
491 param.op = STREAM_XPORT_OP_SEND;
492 param.want_addr = addr ? 1 : 0;
493 param.inputs.buf = (char*)buf;
494 param.inputs.buflen = buflen;
495 param.inputs.flags = flags;
496 param.inputs.addr = addr;
497 param.inputs.addrlen = addrlen;
498
500
502 return param.outputs.returncode;
503 }
504 return -1;
505}
506
507/* Similar to shutdown() system call; shut down part of a full-duplex
508 * connection */
510{
512 int ret = 0;
513
514 memset(&param, 0, sizeof(param));
515
516 param.op = STREAM_XPORT_OP_SHUTDOWN;
517 param.how = how;
518
520
522 return param.outputs.returncode;
523 }
524 return -1;
525}
unsigned int socklen_t
Definition fastcgi.c:87
zend_long n
Definition ffi.c:4979
memcpy(ptr1, ptr2, size)
memset(ptr, 0, type->size)
zend_ffi_ctype_name_buf buf
Definition ffi.c:4685
const php_stream_filter_factory * factory
Definition filters.c:1900
#define NULL
Definition gdcache.h:45
#define SUCCESS
Definition hash_sha3.c:261
PHPAPI ZEND_COLD void php_error_docref(const char *docref, int type, const char *format,...)
Definition main.c:1173
#define PHP_STRLCPY(dst, src, size, src_size)
Definition php.h:142
#define PHPAPI
Definition php.h:71
JMP_BUF bailout
Definition php_ffi.h:49
PHP_JSON_API size_t int options
Definition php_json.h:102
php_json_error_code error_code
Definition php_json.h:92
PHPAPI php_stream_context * php_stream_context_set(php_stream *stream, php_stream_context *context)
Definition streams.c:2346
PHPAPI zval * php_stream_context_get_option(php_stream_context *context, const char *wrappername, const char *optionname)
Definition streams.c:2407
struct _php_stream_xport_crypto_param php_stream_xport_crypto_param
#define STREAM_XPORT_SERVER
#define STREAM_XPORT_BIND
#define STREAM_XPORT_CONNECT_ASYNC
php_stream_xport_crypt_method_t
struct _php_stream_xport_param php_stream_xport_param
#define STREAM_XPORT_CONNECT
php_stream_transport_factory_func * php_stream_transport_factory
#define STREAM_XPORT_LISTEN
struct _php_stream php_stream
Definition php_streams.h:96
struct _php_stream_context php_stream_context
Definition php_streams.h:98
#define php_stream_pclose(stream)
#define php_stream_read(stream, buf, count)
PHPAPI int php_stream_from_persistent_id(const char *persistent_id, php_stream **stream)
Definition streams.c:111
#define STREAMS_DC
Definition php_streams.h:53
#define PHP_STREAM_OPTION_XPORT_API
#define PHP_STREAM_OPTION_CRYPTO_API
#define PHP_STREAM_FLAG_NO_IO
#define php_stream_close(stream)
#define PHP_STREAM_CONTEXT(stream)
#define PHP_STREAM_PERSISTENT_FAILURE
#define PHP_STREAM_PERSISTENT_SUCCESS
#define PHP_STREAM_OPTION_CHECK_LIVENESS
#define STREAMS_REL_CC
Definition php_streams.h:55
#define php_stream_set_option(stream, option, value, ptrvalue)
#define PHP_STREAM_OPTION_RETURN_OK
#define php_stream_write(stream, buf, count)
p
Definition session.c:1105
ptrdiff_t namelen
Definition session.c:1097
#define FG(v)
Definition file.h:117
enum _php_stream_xport_crypto_param::@140346054352235315366005246212154160231254101314 op
struct _php_stream_xport_crypto_param::@234115165332033214161101206371265150065200217213 outputs
php_stream_xport_crypt_method_t method
struct _php_stream_xport_crypto_param::@042362176013144336133052271202115307340250073237 inputs
struct _php_stream_xport_param::@015355061030136034370173273234023140274215071026 inputs
struct _php_stream_xport_param::@000113327003134033162122300162113175151127354335 outputs
enum _php_stream_xport_param::@374135164235347147303334377011004260152245232316 op
uint32_t flags
zend_off_t readpos
php_stream_filter_chain writefilters
php_stream_filter_chain readfilters
char * orig_path
zend_off_t writepos
unsigned char * readbuf
Definition dce.c:49
PHPAPI int php_stream_xport_connect(php_stream *stream, const char *name, size_t namelen, int asynchronous, struct timeval *timeout, zend_string **error_text, int *error_code)
Definition transports.c:229
PHPAPI int php_stream_xport_crypto_enable(php_stream *stream, int activate)
Definition transports.c:378
PHPAPI int php_stream_xport_listen(php_stream *stream, int backlog, zend_string **error_text)
Definition transports.c:265
PHPAPI int php_stream_xport_accept(php_stream *stream, php_stream **client, zend_string **textaddr, void **addr, socklen_t *addrlen, struct timeval *timeout, zend_string **error_text)
Definition transports.c:289
PHPAPI HashTable * php_stream_xport_get_hash(void)
Definition transports.c:23
PHPAPI int php_stream_xport_shutdown(php_stream *stream, stream_shutdown_t how)
Definition transports.c:509
#define ERR_RETURN(out_err, local_err, fmt)
Definition transports.c:46
PHPAPI int php_stream_xport_register(const char *protocol, php_stream_transport_factory factory)
Definition transports.c:28
PHPAPI int php_stream_xport_get_name(php_stream *stream, int want_peer, zend_string **textaddr, void **addr, socklen_t *addrlen)
Definition transports.c:327
PHPAPI php_stream * _php_stream_xport_create(const char *name, size_t namelen, int options, int flags, const char *persistent_id, struct timeval *timeout, php_stream_context *context, zend_string **error_string, int *error_code STREAMS_DC)
Definition transports.c:52
PHPAPI int php_stream_xport_unregister(const char *protocol)
Definition transports.c:37
PHPAPI int php_stream_xport_crypto_setup(php_stream *stream, php_stream_xport_crypt_method_t crypto_method, php_stream *session_stream)
Definition transports.c:357
PHPAPI int php_stream_xport_bind(php_stream *stream, const char *name, size_t namelen, zend_string **error_text)
Definition transports.c:201
#define ERR_REPORT(out_err, fmt, arg)
Definition transports.c:42
PHPAPI int php_stream_xport_recvfrom(php_stream *stream, char *buf, size_t buflen, int flags, void **addr, socklen_t *addrlen, zend_string **textaddr)
Definition transports.c:400
PHPAPI int php_stream_xport_sendto(php_stream *stream, const char *buf, size_t buflen, int flags, void *addr, socklen_t addrlen)
Definition transports.c:469
#define zend_catch
Definition zend.h:277
#define zend_try
Definition zend.h:270
#define zend_end_try()
Definition zend.h:280
#define zend_bailout()
Definition zend.h:268
#define pestrdup(s, persistent)
Definition zend_alloc.h:206
struct _zval_struct zval
strlen(string $string)
strncmp(string $string1, string $string2, int $length)
zend_string_release_ex(func->internal_function.function_name, 0)
#define E_WARNING
Definition zend_errors.h:24
ZEND_API zend_result ZEND_FASTCALL zend_hash_str_del(HashTable *ht, const char *str, size_t len)
Definition zend_hash.c:1661
struct _zend_string zend_string
ZEND_API zend_string_init_interned_func_t zend_string_init_interned
Definition zend_string.c:31
struct _zend_array HashTable
Definition zend_types.h:386
zend_string * name
zval * ret