Skip to content

Commit 8796014

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 8796014

File tree

7 files changed

+113
-26
lines changed

7 files changed

+113
-26
lines changed

README.md

+41-6
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,21 @@ 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,
5557
callable $callback,
5658
): void
57-
public tcpServer(int $port, callable $callback): void
59+
public tcpServer(
60+
int $port,
61+
?int $connections,
62+
?int $nbytes,
63+
callable $callback,
64+
): void
5865
public writev(int|resource $fd, string $message): void
5966
public static parseHttpRequest(string $request, int $headerlimit = 100): iterable
6067
public static parseHttpResponse(string $response, int $headerlimit = 100): iterable
@@ -133,6 +140,8 @@ Hello, user
133140
public Mrloop::addReadStream(
134141
resource $stream,
135142
?int $nbytes,
143+
?int $vcount,
144+
?int $offset,
136145
callable $callback,
137146
): void
138147
```
@@ -144,7 +153,12 @@ Funnels file descriptor in readable stream into event loop and thence executes a
144153
- **stream** (resource) - A userspace-defined readable stream.
145154
> The file descriptor in the stream is internally given a non-blocking disposition.
146155
- **nbytes** (int|null) - The number of bytes to read.
147-
> Specifying `null` will condition the use of an 8KB buffer.
156+
> Specifying `null` will condition the use of a 1KB buffer.
157+
- **vcount** (int|null) - The number of read vectors to use.
158+
> Specifying `null` will condition the use of 2 vectors.
159+
> Any value north of `8` will likely result in an inefficient read.
160+
- **offset** (int|null) - The point at which to start the read operation.
161+
> Specifying `null` will condition the use of an offset of `0`.
148162
- **callback** (callable) - The binary function through which the file's contents and read result code are propagated.
149163

150164
**Return value(s)**
@@ -158,13 +172,15 @@ $loop = Mrloop::init();
158172

159173
$loop->addReadStream(
160174
$fd = \fopen('/path/to/file', 'r'),
161-
null,
175+
null, // 1024
176+
null, // 2
177+
null, // 0
162178
function (string $contents, int $res) use ($fd) {
163179
if ($res === 0) {
164180
echo \sprintf("%s\n", $contents);
165-
166-
\fclose($fd);
167181
}
182+
183+
\fclose($fd);
168184
},
169185
);
170186

@@ -184,6 +200,7 @@ File contents...
184200
public Mrloop::addWriteStream(
185201
resource $stream,
186202
string $contents,
203+
?int $vcount,
187204
callable $callback,
188205
): void
189206
```
@@ -195,6 +212,9 @@ Funnels file descriptor in writable stream into event loop and thence executes a
195212
- **stream** (resource) - A userspace-defined writable stream.
196213
> The file descriptor in the stream is internally given a non-blocking disposition.
197214
- **contents** (string) - The contents to write to the file descriptor.
215+
- **vcount** (int|null) - The number of write vectors to use.
216+
> Specifying `null` will condition the use of 2 vectors.
217+
> Any value north of `8` will likely result in an inefficient write.
198218
- **callback** (callable) - The unary function through which the number of written bytes is propagated.
199219

200220
**Return value(s)**
@@ -211,6 +231,7 @@ $file = '/path/to/file';
211231
$loop->addWriteStream(
212232
$fd = \fopen($file, 'w'),
213233
"file contents...\n",
234+
null,
214235
function (int $nbytes) use ($fd, $file) {
215236
echo \sprintf("Wrote %d bytes to %s\n", $nbytes, $file);
216237

@@ -231,14 +252,25 @@ Wrote 18 bytes to /path/to/file
231252
### `Mrloop::tcpServer`
232253

233254
```php
234-
public Mrloop::tcpServer(int $port, callable $callback): void
255+
public Mrloop::tcpServer(
256+
int $port,
257+
?int $connections,
258+
?int $nbytes,
259+
callable $callback,
260+
): void
235261
```
236262

237263
Instantiates a simple TCP server.
238264

239265
**Parameter(s)**
240266

241267
- **port** (int) - The port on which to listen for incoming connections.
268+
- **connections** (int|null) - The maximum number of connections to accept.
269+
> 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.
270+
> Specifying `null` will condition the use of a `1024` connection threshold.
271+
- **nbytes** (int|null) - The maximum number of readable bytes for each connection.
272+
> This setting is akin to the `client_max_body_size` option in NGINX.
273+
> Specifying null will condition the use of an `8192` byte threshold.
242274
- **callback** (callable) - The binary function with which to define a response to a client.
243275
> Refer to the segment to follow for more information on the callback.
244276
- **Callback parameters**
@@ -259,6 +291,8 @@ $loop = Mrloop::init();
259291

260292
$loop->tcpServer(
261293
8080,
294+
null,
295+
null,
262296
function (string $message, iterable $client) {
263297
// print access log
264298
echo \sprintf(
@@ -311,6 +345,7 @@ $loop = Mrloop::init();
311345

312346
$loop->tcpServer(
313347
8080,
348+
null,
314349
function (string $message, iterable $client) use ($loop) {
315350
[
316351
'client_addr' => $addr,

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;

src/loop.h

+8-3
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,15 @@
2323
ZEND_PARSE_PARAMETERS_END()
2424
#endif
2525

26-
#define DEFAULT_STREAM_BUFF_LEN 8192
27-
#define DEFAULT_CONN_BUFF_LEN 65536
26+
#define DEFAULT_STREAM_BUFF_LEN 1024
27+
#define DEFAULT_CONN_BUFF_LEN 8132
2828
#define DEFAULT_HTTP_HEADER_LIMIT 100
29+
#define DEFAULT_VECTOR_COUNT 2
30+
#define DEFAULT_READV_OFFSET 0
2931
#define PHP_MRLOOP_TIMER 1
3032
#define PHP_MRLOOP_PERIODIC_TIMER 2
3133
#define PHP_MRLOOP_FUTURE_TICK 3
34+
#define PHP_MRLOOP_MAX_TCP_CONNECTIONS 1024
3235

3336
struct php_mrloop_t;
3437
struct php_mrloop_cb_t;
@@ -60,7 +63,7 @@ struct php_mrloop_conn_t
6063
/* client socket address */
6164
char *addr;
6265
/* data sent over client socket */
63-
char buffer[DEFAULT_CONN_BUFF_LEN];
66+
char *buffer;
6467
/* client socket port */
6568
size_t port;
6669
/* scatter-gather I/O primitives */
@@ -97,6 +100,8 @@ php_mrloop_cb_t *tcp_cb;
97100
php_mrloop_cb_t *sig_cb[3];
98101
/* signal callback count */
99102
size_t sigc;
103+
/* TCP buffer size */
104+
size_t tcp_buff_size;
100105
ZEND_END_MODULE_GLOBALS(mrloop)
101106
/* }}} */
102107

tests/002.phpt

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ $loop = Mrloop::init();
1010
$loop->addReadStream(
1111
$fd = \popen('pwd', 'r'),
1212
null,
13+
null,
14+
null,
1315
function (...$args) use ($fd, $loop) {
1416
[$message] = $args;
1517

0 commit comments

Comments
 (0)