Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v0.1.0 changes #5

Merged
merged 1 commit into from
Nov 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 52 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,22 @@ class Mrloop
public addReadStream(
resource $stream,
?int $nbytes,
?int $vcount,
?int $offset,
callable $callback,
): void
public addWriteStream(
resource $stream,
string $contents,
?int $vcount,
callable $callback,
): void
public tcpServer(
int $port,
?int $connections,
?int $nbytes,
callable $callback,
): void
public tcpServer(int $port, callable $callback): void
public writev(int|resource $fd, string $message): void
public static parseHttpRequest(string $request, int $headerlimit = 100): iterable
public static parseHttpResponse(string $response, int $headerlimit = 100): iterable
Expand Down Expand Up @@ -133,6 +141,8 @@ Hello, user
public Mrloop::addReadStream(
resource $stream,
?int $nbytes,
?int $vcount,
?int $offset,
callable $callback,
): void
```
Expand All @@ -144,7 +154,12 @@ Funnels file descriptor in readable stream into event loop and thence executes a
- **stream** (resource) - A userspace-defined readable stream.
> The file descriptor in the stream is internally given a non-blocking disposition.
- **nbytes** (int|null) - The number of bytes to read.
> Specifying `null` will condition the use of an 8KB buffer.
> Specifying `null` will condition the use of a 1KB buffer.
- **vcount** (int|null) - The number of read vectors to use.
> Specifying `null` will condition the use of 2 vectors.
> Any value north of `8` will likely result in an inefficient read.
- **offset** (int|null) - The point at which to start the read operation.
> Specifying `null` will condition the use of an offset of `0`.
- **callback** (callable) - The binary function through which the file's contents and read result code are propagated.

**Return value(s)**
Expand All @@ -159,12 +174,14 @@ $loop = Mrloop::init();
$loop->addReadStream(
$fd = \fopen('/path/to/file', 'r'),
null,
null,
null,
function (string $contents, int $res) use ($fd) {
if ($res === 0) {
echo \sprintf("%s\n", $contents);

\fclose($fd);
}

\fclose($fd);
},
);

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

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

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

```php
public Mrloop::tcpServer(int $port, callable $callback): void
public Mrloop::tcpServer(
int $port,
?int $connections,
?int $nbytes,
callable $callback,
): void
```

Instantiates a simple TCP server.

**Parameter(s)**

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

$loop->tcpServer(
8080,
null,
null,
function (string $message, iterable $client) {
// print access log
echo \sprintf(
Expand Down Expand Up @@ -311,6 +346,8 @@ $loop = Mrloop::init();

$loop->tcpServer(
8080,
null,
null,
function (string $message, iterable $client) use ($loop) {
[
'client_addr' => $addr,
Expand Down Expand Up @@ -376,6 +413,8 @@ $loop = Mrloop::init();

$loop->tcpServer(
8080,
null,
null,
function (mixed ...$args) {
[$message,] = $args;
$response = static fn (
Expand Down Expand Up @@ -451,10 +490,13 @@ $loop = Mrloop::init();
$loop->addWriteStream(
$sock = \stream_socket_client('tcp://www.example.com:80'),
"GET / HTTP/1.0\r\nHost: www.example.com\r\nAccept: */*\r\n\r\n",
null,
function ($nbytes) use ($loop, $sock) {
$loop->addReadStream(
$sock,
null,
null,
null,
function ($data, $res) use ($sock, $loop) {
var_dump(Mrloop::parseHttpResponse($data));

Expand Down Expand Up @@ -713,6 +755,8 @@ $loop = Mrloop::init();
$loop->addReadStream(
$fd = \fopen('/path/to/file', 'r'),
null,
null,
null,
function (...$args) use ($fd) {
[$contents] = $args;

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

$loop->addReadStream(
$fd = \fopen('/path/to/file', 'r'),
'File contents...',
null,
null,
null,
function ($contents, $res) use ($fd, $loop) {
echo \sprintf("%s\n", $contents);

Expand Down
11 changes: 8 additions & 3 deletions mrloop_arginfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ ZEND_ARG_TYPE_INFO(0, interval, IS_DOUBLE, 0)
ZEND_ARG_TYPE_INFO(0, callback, IS_CALLABLE, 0)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Mrloop_tcpServer, 0, 0, 2)
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Mrloop_tcpServer, 0, 0, 4)
ZEND_ARG_TYPE_INFO(0, port, IS_LONG, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, connections, IS_LONG, 0, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, nbytes, IS_LONG, 0, "null")
ZEND_ARG_TYPE_INFO(0, callback, IS_CALLABLE, 0)
ZEND_END_ARG_INFO()

Expand All @@ -38,15 +40,18 @@ ZEND_ARG_TYPE_INFO(0, signal, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, callback, IS_CALLABLE, 0)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Mrloop_addReadStream, 0, 0, 3)
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Mrloop_addReadStream, 0, 0, 5)
ZEND_ARG_TYPE_INFO(0, stream, IS_RESOURCE, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, nbytes, IS_LONG, 0, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, vcount, IS_LONG, 0, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, offset, IS_LONG, 0, "null")
ZEND_ARG_TYPE_INFO(0, callback, IS_CALLABLE, 0)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Mrloop_addWriteStream, 0, 0, 3)
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Mrloop_addWriteStream, 0, 0, 4)
ZEND_ARG_TYPE_INFO(0, stream, IS_RESOURCE, 0)
ZEND_ARG_TYPE_INFO(0, contents, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, vcount, IS_LONG, 0, "null")
ZEND_ARG_TYPE_INFO(0, callback, IS_CALLABLE, 0)
ZEND_END_ARG_INFO()

Expand Down
65 changes: 52 additions & 13 deletions src/loop.c
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,11 @@ static void php_mrloop_add_future_tick(INTERNAL_FUNCTION_PARAMETERS)

static void php_mrloop_readv_cb(void *data, int res)
{
if (res < 0)
{
PHP_MRLOOP_THROW(strerror(-res));
}

php_mrloop_cb_t *cb;
php_iovec_t *iov;
zval args[2], result;
Expand Down Expand Up @@ -222,6 +227,11 @@ static void php_mrloop_readv_cb(void *data, int res)
}
static void php_mrloop_writev_cb(void *data, int res)
{
if (res < 0)
{
PHP_MRLOOP_THROW(strerror(-res));
}

php_mrloop_cb_t *cb = (php_mrloop_cb_t *)data;
zval args[1], result;
ZVAL_LONG(&args[0], res);
Expand Down Expand Up @@ -251,8 +261,9 @@ static void *php_mrloop_tcp_client_setup(int fd, char **buffer, int *bsize)

conn = emalloc(sizeof(php_mrloop_conn_t));
conn->fd = fd;
conn->buffer = emalloc(MRLOOP_G(tcp_buff_size));
*buffer = conn->buffer;
*bsize = DEFAULT_CONN_BUFF_LEN;
*bsize = MRLOOP_G(tcp_buff_size);

socklen = sizeof(php_sockaddr_t);

Expand All @@ -277,6 +288,7 @@ static int php_mrloop_tcp_server_recv(void *conn, int fd, ssize_t nbytes, char *
{
mr_close(loop, client->fd);
efree(client->addr);
efree(client->buffer);
efree(client);

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

MRLOOP_G(tcp_cb)->fci.retval = &result;
MRLOOP_G(tcp_cb)->fci.param_count = 2;
Expand Down Expand Up @@ -321,24 +333,39 @@ static void php_mrloop_tcp_server_listen(INTERNAL_FUNCTION_PARAMETERS)
php_mrloop_t *this;
zend_fcall_info fci;
zend_fcall_info_cache fci_cache;
zend_long port;
zend_long port, max_conn, nbytes;
bool max_conn_null, nbytes_null;
size_t nconn, fnbytes;

obj = getThis();
fci = empty_fcall_info;
fci_cache = empty_fcall_info_cache;
max_conn_null = true;
nbytes_null = true;

ZEND_PARSE_PARAMETERS_START(2, 2)
ZEND_PARSE_PARAMETERS_START(4, 4)
Z_PARAM_LONG(port)
Z_PARAM_LONG_OR_NULL(max_conn, max_conn_null)
Z_PARAM_LONG_OR_NULL(nbytes, nbytes_null)
Z_PARAM_FUNC(fci, fci_cache)
ZEND_PARSE_PARAMETERS_END();

this = PHP_MRLOOP_OBJ(obj);

fnbytes = (size_t)(nbytes_null == true ? DEFAULT_CONN_BUFF_LEN : nbytes);
MRLOOP_G(tcp_buff_size) = fnbytes;

MRLOOP_G(tcp_cb) = emalloc(sizeof(php_mrloop_cb_t));
PHP_CB_TO_MRLOOP_CB(MRLOOP_G(tcp_cb), fci, fci_cache);
MRLOOP_G(tcp_cb)->data = this->loop;

nconn = (size_t)(max_conn_null == true ? PHP_MRLOOP_MAX_TCP_CONNECTIONS : (max_conn == 0 ? PHP_MRLOOP_MAX_TCP_CONNECTIONS : max_conn));

#ifdef MRLOOP_H
mr_tcp_server(this->loop, (int)port, nconn, php_mrloop_tcp_client_setup, php_mrloop_tcp_server_recv);
#else
mr_tcp_server(this->loop, (int)port, php_mrloop_tcp_client_setup, php_mrloop_tcp_server_recv);
#endif

return;
}
Expand Down Expand Up @@ -528,21 +555,25 @@ static void php_mrloop_add_read_stream(INTERNAL_FUNCTION_PARAMETERS)
php_iovec_t *iov;
zend_fcall_info fci;
zend_fcall_info_cache fci_cache;
zend_long nbytes;
bool nbytes_null;
zend_long nbytes, vcount, offset;
bool nbytes_null, vcount_null, offset_null;
int fd; // php_socket_t fd;
php_stream *stream;
size_t fnbytes;
size_t fnbytes, fvcount, foffset;

obj = getThis();
nbytes_null = true;
vcount_null = true;
offset_null = true;
fci = empty_fcall_info;
fci_cache = empty_fcall_info_cache;
fd = -1;

ZEND_PARSE_PARAMETERS_START(3, 3)
ZEND_PARSE_PARAMETERS_START(5, 5)
Z_PARAM_RESOURCE(res)
Z_PARAM_LONG_OR_NULL(nbytes, nbytes_null)
Z_PARAM_LONG_OR_NULL(vcount, vcount_null)
Z_PARAM_LONG_OR_NULL(offset, offset_null)
Z_PARAM_FUNC(fci, fci_cache)
ZEND_PARSE_PARAMETERS_END();

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

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

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

cb->data = iov;

mr_readvcb(this->loop, fd, iov, 1, 0, cb, php_mrloop_readv_cb);
mr_readvcb(this->loop, fd, iov, fvcount, foffset, cb, php_mrloop_readv_cb);
mr_flush(this->loop);

return;
Expand All @@ -576,18 +609,22 @@ static void php_mrloop_add_write_stream(INTERNAL_FUNCTION_PARAMETERS)
php_iovec_t *iov;
zend_fcall_info fci;
zend_fcall_info_cache fci_cache;
zend_long vcount;
bool vcount_null;
int fd;
php_stream *stream;
size_t nbytes;
size_t nbytes, fvcount;

obj = getThis();
fci = empty_fcall_info;
fci_cache = empty_fcall_info_cache;
fd = -1;
vcount_null = true;

ZEND_PARSE_PARAMETERS_START(3, 3)
ZEND_PARSE_PARAMETERS_START(4, 4)
Z_PARAM_RESOURCE(res)
Z_PARAM_STR(contents)
Z_PARAM_LONG_OR_NULL(vcount, vcount_null)
Z_PARAM_FUNC(fci, fci_cache)
ZEND_PARSE_PARAMETERS_END();

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

cb->data = iov;

mr_writevcb(this->loop, fd, iov, 1, cb, php_mrloop_writev_cb);
fvcount = (size_t)(vcount_null == true ? DEFAULT_VECTOR_COUNT : vcount);

mr_writevcb(this->loop, fd, iov, fvcount, cb, php_mrloop_writev_cb);
mr_flush(this->loop);

return;
Expand Down Expand Up @@ -642,7 +681,7 @@ static void php_mrloop_writev(INTERNAL_FUNCTION_PARAMETERS)

if (fcntl(fd, F_GETFD) < 0)
{
PHP_MRLOOP_THROW("Detected invalid file descriptor");
PHP_MRLOOP_THROW(strerror(errno));
mr_stop(this->loop);

return;
Expand Down
Loading