Skip to content

Commit 3960570

Browse files
author
ace411
committed
feat: modify extension internals
- instate operation error checks in php_mrloop_writev_cb and php_mrloop_readv_cb callbacks - register global TCP connection data buffer size - add connection data size and connection count parameters to tcpServer() function - duplicate client connection file descriptor in php_mrloop_tcp_server_recv callback - add vector count and offset parameters to addReadStream() function - add vector count parameter to addWriteStream() function - change DEFAULT_STREAM_BUFF_LEN and DEFAULT_CONN_BUFF_LEN values - define DEFAULT_VECTOR_COUNT, DEFAULT_READV_OFFSET and PHP_MRLOOP_MAX_TCP_CONNECTIONS
1 parent 12ed780 commit 3960570

File tree

7 files changed

+148
-47
lines changed

7 files changed

+148
-47
lines changed

README.md

+52-6
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,22 @@ class Mrloop
4747
public addReadStream(
4848
resource $stream,
4949
?int $nbytes,
50+
?int $vcount,
51+
?int $offset,
5052
callable $callback,
5153
): void
5254
public addWriteStream(
5355
resource $stream,
5456
string $contents,
57+
?int $vcount,
58+
callable $callback,
59+
): void
60+
public tcpServer(
61+
int $port,
62+
?int $connections,
63+
?int $nbytes,
5564
callable $callback,
5665
): void
57-
public tcpServer(int $port, callable $callback): void
5866
public writev(int|resource $fd, string $message): void
5967
public static parseHttpRequest(string $request, int $headerlimit = 100): iterable
6068
public static parseHttpResponse(string $response, int $headerlimit = 100): iterable
@@ -133,6 +141,8 @@ Hello, user
133141
public Mrloop::addReadStream(
134142
resource $stream,
135143
?int $nbytes,
144+
?int $vcount,
145+
?int $offset,
136146
callable $callback,
137147
): void
138148
```
@@ -144,7 +154,12 @@ Funnels file descriptor in readable stream into event loop and thence executes a
144154
- **stream** (resource) - A userspace-defined readable stream.
145155
> The file descriptor in the stream is internally given a non-blocking disposition.
146156
- **nbytes** (int|null) - The number of bytes to read.
147-
> Specifying `null` will condition the use of an 8KB buffer.
157+
> Specifying `null` will condition the use of a 1KB buffer.
158+
- **vcount** (int|null) - The number of read vectors to use.
159+
> Specifying `null` will condition the use of 2 vectors.
160+
> Any value north of `8` will likely result in an inefficient read.
161+
- **offset** (int|null) - The point at which to start the read operation.
162+
> Specifying `null` will condition the use of an offset of `0`.
148163
- **callback** (callable) - The binary function through which the file's contents and read result code are propagated.
149164

150165
**Return value(s)**
@@ -159,12 +174,14 @@ $loop = Mrloop::init();
159174
$loop->addReadStream(
160175
$fd = \fopen('/path/to/file', 'r'),
161176
null,
177+
null,
178+
null,
162179
function (string $contents, int $res) use ($fd) {
163180
if ($res === 0) {
164181
echo \sprintf("%s\n", $contents);
165-
166-
\fclose($fd);
167182
}
183+
184+
\fclose($fd);
168185
},
169186
);
170187

@@ -184,6 +201,7 @@ File contents...
184201
public Mrloop::addWriteStream(
185202
resource $stream,
186203
string $contents,
204+
?int $vcount,
187205
callable $callback,
188206
): void
189207
```
@@ -195,6 +213,9 @@ Funnels file descriptor in writable stream into event loop and thence executes a
195213
- **stream** (resource) - A userspace-defined writable stream.
196214
> The file descriptor in the stream is internally given a non-blocking disposition.
197215
- **contents** (string) - The contents to write to the file descriptor.
216+
- **vcount** (int|null) - The number of write vectors to use.
217+
> Specifying `null` will condition the use of 2 vectors.
218+
> Any value north of `8` will likely result in an inefficient write.
198219
- **callback** (callable) - The unary function through which the number of written bytes is propagated.
199220

200221
**Return value(s)**
@@ -211,6 +232,7 @@ $file = '/path/to/file';
211232
$loop->addWriteStream(
212233
$fd = \fopen($file, 'w'),
213234
"file contents...\n",
235+
null,
214236
function (int $nbytes) use ($fd, $file) {
215237
echo \sprintf("Wrote %d bytes to %s\n", $nbytes, $file);
216238

@@ -231,14 +253,25 @@ Wrote 18 bytes to /path/to/file
231253
### `Mrloop::tcpServer`
232254

233255
```php
234-
public Mrloop::tcpServer(int $port, callable $callback): void
256+
public Mrloop::tcpServer(
257+
int $port,
258+
?int $connections,
259+
?int $nbytes,
260+
callable $callback,
261+
): void
235262
```
236263

237264
Instantiates a simple TCP server.
238265

239266
**Parameter(s)**
240267

241268
- **port** (int) - The port on which to listen for incoming connections.
269+
- **connections** (int|null) - The maximum number of connections to accept.
270+
> This parameter does not have any effect when a version of mrloop in which the `mr_tcp_server` function lacks the `max_conn` parameter is included in the compilation process.
271+
> Specifying `null` will condition the use of a `1024` connection threshold.
272+
- **nbytes** (int|null) - The maximum number of readable bytes for each connection.
273+
> This setting is akin to the `client_max_body_size` option in NGINX.
274+
> Specifying null will condition the use of an `8192` byte threshold.
242275
- **callback** (callable) - The binary function with which to define a response to a client.
243276
> Refer to the segment to follow for more information on the callback.
244277
- **Callback parameters**
@@ -259,6 +292,8 @@ $loop = Mrloop::init();
259292

260293
$loop->tcpServer(
261294
8080,
295+
null,
296+
null,
262297
function (string $message, iterable $client) {
263298
// print access log
264299
echo \sprintf(
@@ -311,6 +346,8 @@ $loop = Mrloop::init();
311346

312347
$loop->tcpServer(
313348
8080,
349+
null,
350+
null,
314351
function (string $message, iterable $client) use ($loop) {
315352
[
316353
'client_addr' => $addr,
@@ -376,6 +413,8 @@ $loop = Mrloop::init();
376413

377414
$loop->tcpServer(
378415
8080,
416+
null,
417+
null,
379418
function (mixed ...$args) {
380419
[$message,] = $args;
381420
$response = static fn (
@@ -451,10 +490,13 @@ $loop = Mrloop::init();
451490
$loop->addWriteStream(
452491
$sock = \stream_socket_client('tcp://www.example.com:80'),
453492
"GET / HTTP/1.0\r\nHost: www.example.com\r\nAccept: */*\r\n\r\n",
493+
null,
454494
function ($nbytes) use ($loop, $sock) {
455495
$loop->addReadStream(
456496
$sock,
457497
null,
498+
null,
499+
null,
458500
function ($data, $res) use ($sock, $loop) {
459501
var_dump(Mrloop::parseHttpResponse($data));
460502

@@ -713,6 +755,8 @@ $loop = Mrloop::init();
713755
$loop->addReadStream(
714756
$fd = \fopen('/path/to/file', 'r'),
715757
null,
758+
null,
759+
null,
716760
function (...$args) use ($fd) {
717761
[$contents] = $args;
718762

@@ -784,7 +828,9 @@ $loop = Mrloop::init();
784828

785829
$loop->addReadStream(
786830
$fd = \fopen('/path/to/file', 'r'),
787-
'File contents...',
831+
null,
832+
null,
833+
null,
788834
function ($contents, $res) use ($fd, $loop) {
789835
echo \sprintf("%s\n", $contents);
790836

mrloop_arginfo.h

+8-3
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@ ZEND_ARG_TYPE_INFO(0, interval, IS_DOUBLE, 0)
1818
ZEND_ARG_TYPE_INFO(0, callback, IS_CALLABLE, 0)
1919
ZEND_END_ARG_INFO()
2020

21-
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Mrloop_tcpServer, 0, 0, 2)
21+
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Mrloop_tcpServer, 0, 0, 4)
2222
ZEND_ARG_TYPE_INFO(0, port, IS_LONG, 0)
23+
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, connections, IS_LONG, 0, "null")
24+
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, nbytes, IS_LONG, 0, "null")
2325
ZEND_ARG_TYPE_INFO(0, callback, IS_CALLABLE, 0)
2426
ZEND_END_ARG_INFO()
2527

@@ -38,15 +40,18 @@ ZEND_ARG_TYPE_INFO(0, signal, IS_LONG, 0)
3840
ZEND_ARG_TYPE_INFO(0, callback, IS_CALLABLE, 0)
3941
ZEND_END_ARG_INFO()
4042

41-
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Mrloop_addReadStream, 0, 0, 3)
43+
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Mrloop_addReadStream, 0, 0, 5)
4244
ZEND_ARG_TYPE_INFO(0, stream, IS_RESOURCE, 0)
4345
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, nbytes, IS_LONG, 0, "null")
46+
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, vcount, IS_LONG, 0, "null")
47+
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, offset, IS_LONG, 0, "null")
4448
ZEND_ARG_TYPE_INFO(0, callback, IS_CALLABLE, 0)
4549
ZEND_END_ARG_INFO()
4650

47-
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Mrloop_addWriteStream, 0, 0, 3)
51+
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Mrloop_addWriteStream, 0, 0, 4)
4852
ZEND_ARG_TYPE_INFO(0, stream, IS_RESOURCE, 0)
4953
ZEND_ARG_TYPE_INFO(0, contents, IS_STRING, 0)
54+
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, vcount, IS_LONG, 0, "null")
5055
ZEND_ARG_TYPE_INFO(0, callback, IS_CALLABLE, 0)
5156
ZEND_END_ARG_INFO()
5257

src/loop.c

+52-13
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,11 @@ static void php_mrloop_add_future_tick(INTERNAL_FUNCTION_PARAMETERS)
192192

193193
static void php_mrloop_readv_cb(void *data, int res)
194194
{
195+
if (res < 0)
196+
{
197+
PHP_MRLOOP_THROW(strerror(-res));
198+
}
199+
195200
php_mrloop_cb_t *cb;
196201
php_iovec_t *iov;
197202
zval args[2], result;
@@ -222,6 +227,11 @@ static void php_mrloop_readv_cb(void *data, int res)
222227
}
223228
static void php_mrloop_writev_cb(void *data, int res)
224229
{
230+
if (res < 0)
231+
{
232+
PHP_MRLOOP_THROW(strerror(-res));
233+
}
234+
225235
php_mrloop_cb_t *cb = (php_mrloop_cb_t *)data;
226236
zval args[1], result;
227237
ZVAL_LONG(&args[0], res);
@@ -251,8 +261,9 @@ static void *php_mrloop_tcp_client_setup(int fd, char **buffer, int *bsize)
251261

252262
conn = emalloc(sizeof(php_mrloop_conn_t));
253263
conn->fd = fd;
264+
conn->buffer = emalloc(MRLOOP_G(tcp_buff_size));
254265
*buffer = conn->buffer;
255-
*bsize = DEFAULT_CONN_BUFF_LEN;
266+
*bsize = MRLOOP_G(tcp_buff_size);
256267

257268
socklen = sizeof(php_sockaddr_t);
258269

@@ -277,6 +288,7 @@ static int php_mrloop_tcp_server_recv(void *conn, int fd, ssize_t nbytes, char *
277288
{
278289
mr_close(loop, client->fd);
279290
efree(client->addr);
291+
efree(client->buffer);
280292
efree(client);
281293

282294
return 1;
@@ -288,7 +300,7 @@ static int php_mrloop_tcp_server_recv(void *conn, int fd, ssize_t nbytes, char *
288300
array_init(&args[1]);
289301
add_assoc_string(&args[1], "client_addr", (char *)client->addr);
290302
add_assoc_long(&args[1], "client_port", client->port);
291-
add_assoc_long(&args[1], "client_fd", client->fd);
303+
add_assoc_long(&args[1], "client_fd", dup(client->fd));
292304

293305
MRLOOP_G(tcp_cb)->fci.retval = &result;
294306
MRLOOP_G(tcp_cb)->fci.param_count = 2;
@@ -321,24 +333,39 @@ static void php_mrloop_tcp_server_listen(INTERNAL_FUNCTION_PARAMETERS)
321333
php_mrloop_t *this;
322334
zend_fcall_info fci;
323335
zend_fcall_info_cache fci_cache;
324-
zend_long port;
336+
zend_long port, max_conn, nbytes;
337+
bool max_conn_null, nbytes_null;
338+
size_t nconn, fnbytes;
325339

326340
obj = getThis();
327341
fci = empty_fcall_info;
328342
fci_cache = empty_fcall_info_cache;
343+
max_conn_null = true;
344+
nbytes_null = true;
329345

330-
ZEND_PARSE_PARAMETERS_START(2, 2)
346+
ZEND_PARSE_PARAMETERS_START(4, 4)
331347
Z_PARAM_LONG(port)
348+
Z_PARAM_LONG_OR_NULL(max_conn, max_conn_null)
349+
Z_PARAM_LONG_OR_NULL(nbytes, nbytes_null)
332350
Z_PARAM_FUNC(fci, fci_cache)
333351
ZEND_PARSE_PARAMETERS_END();
334352

335353
this = PHP_MRLOOP_OBJ(obj);
336354

355+
fnbytes = (size_t)(nbytes_null == true ? DEFAULT_CONN_BUFF_LEN : nbytes);
356+
MRLOOP_G(tcp_buff_size) = fnbytes;
357+
337358
MRLOOP_G(tcp_cb) = emalloc(sizeof(php_mrloop_cb_t));
338359
PHP_CB_TO_MRLOOP_CB(MRLOOP_G(tcp_cb), fci, fci_cache);
339360
MRLOOP_G(tcp_cb)->data = this->loop;
340361

362+
nconn = (size_t)(max_conn_null == true ? PHP_MRLOOP_MAX_TCP_CONNECTIONS : (max_conn == 0 ? PHP_MRLOOP_MAX_TCP_CONNECTIONS : max_conn));
363+
364+
#ifdef MRLOOP_H
365+
mr_tcp_server(this->loop, (int)port, nconn, php_mrloop_tcp_client_setup, php_mrloop_tcp_server_recv);
366+
#else
341367
mr_tcp_server(this->loop, (int)port, php_mrloop_tcp_client_setup, php_mrloop_tcp_server_recv);
368+
#endif
342369

343370
return;
344371
}
@@ -528,21 +555,25 @@ static void php_mrloop_add_read_stream(INTERNAL_FUNCTION_PARAMETERS)
528555
php_iovec_t *iov;
529556
zend_fcall_info fci;
530557
zend_fcall_info_cache fci_cache;
531-
zend_long nbytes;
532-
bool nbytes_null;
558+
zend_long nbytes, vcount, offset;
559+
bool nbytes_null, vcount_null, offset_null;
533560
int fd; // php_socket_t fd;
534561
php_stream *stream;
535-
size_t fnbytes;
562+
size_t fnbytes, fvcount, foffset;
536563

537564
obj = getThis();
538565
nbytes_null = true;
566+
vcount_null = true;
567+
offset_null = true;
539568
fci = empty_fcall_info;
540569
fci_cache = empty_fcall_info_cache;
541570
fd = -1;
542571

543-
ZEND_PARSE_PARAMETERS_START(3, 3)
572+
ZEND_PARSE_PARAMETERS_START(5, 5)
544573
Z_PARAM_RESOURCE(res)
545574
Z_PARAM_LONG_OR_NULL(nbytes, nbytes_null)
575+
Z_PARAM_LONG_OR_NULL(vcount, vcount_null)
576+
Z_PARAM_LONG_OR_NULL(offset, offset_null)
546577
Z_PARAM_FUNC(fci, fci_cache)
547578
ZEND_PARSE_PARAMETERS_END();
548579

@@ -552,6 +583,8 @@ static void php_mrloop_add_read_stream(INTERNAL_FUNCTION_PARAMETERS)
552583
PHP_STREAM_TO_FD(stream, res, fd);
553584

554585
fnbytes = (size_t)(nbytes_null == true ? DEFAULT_STREAM_BUFF_LEN : nbytes);
586+
fvcount = (size_t)(vcount_null == true ? DEFAULT_VECTOR_COUNT : vcount);
587+
foffset = (size_t)(offset_null == true ? DEFAULT_READV_OFFSET : offset);
555588

556589
iov = emalloc(sizeof(php_iovec_t));
557590
iov->iov_base = emalloc(fnbytes);
@@ -562,7 +595,7 @@ static void php_mrloop_add_read_stream(INTERNAL_FUNCTION_PARAMETERS)
562595

563596
cb->data = iov;
564597

565-
mr_readvcb(this->loop, fd, iov, 1, 0, cb, php_mrloop_readv_cb);
598+
mr_readvcb(this->loop, fd, iov, fvcount, foffset, cb, php_mrloop_readv_cb);
566599
mr_flush(this->loop);
567600

568601
return;
@@ -576,18 +609,22 @@ static void php_mrloop_add_write_stream(INTERNAL_FUNCTION_PARAMETERS)
576609
php_iovec_t *iov;
577610
zend_fcall_info fci;
578611
zend_fcall_info_cache fci_cache;
612+
zend_long vcount;
613+
bool vcount_null;
579614
int fd;
580615
php_stream *stream;
581-
size_t nbytes;
616+
size_t nbytes, fvcount;
582617

583618
obj = getThis();
584619
fci = empty_fcall_info;
585620
fci_cache = empty_fcall_info_cache;
586621
fd = -1;
622+
vcount_null = true;
587623

588-
ZEND_PARSE_PARAMETERS_START(3, 3)
624+
ZEND_PARSE_PARAMETERS_START(4, 4)
589625
Z_PARAM_RESOURCE(res)
590626
Z_PARAM_STR(contents)
627+
Z_PARAM_LONG_OR_NULL(vcount, vcount_null)
591628
Z_PARAM_FUNC(fci, fci_cache)
592629
ZEND_PARSE_PARAMETERS_END();
593630

@@ -607,7 +644,9 @@ static void php_mrloop_add_write_stream(INTERNAL_FUNCTION_PARAMETERS)
607644

608645
cb->data = iov;
609646

610-
mr_writevcb(this->loop, fd, iov, 1, cb, php_mrloop_writev_cb);
647+
fvcount = (size_t)(vcount_null == true ? DEFAULT_VECTOR_COUNT : vcount);
648+
649+
mr_writevcb(this->loop, fd, iov, fvcount, cb, php_mrloop_writev_cb);
611650
mr_flush(this->loop);
612651

613652
return;
@@ -642,7 +681,7 @@ static void php_mrloop_writev(INTERNAL_FUNCTION_PARAMETERS)
642681

643682
if (fcntl(fd, F_GETFD) < 0)
644683
{
645-
PHP_MRLOOP_THROW("Detected invalid file descriptor");
684+
PHP_MRLOOP_THROW(strerror(errno));
646685
mr_stop(this->loop);
647686

648687
return;

0 commit comments

Comments
 (0)