Skip to content

Commit

Permalink
Added PyCore::fileno()
Browse files Browse the repository at this point in the history
  • Loading branch information
matyhtf committed Feb 18, 2024
1 parent 22a5392 commit 07a3e60
Show file tree
Hide file tree
Showing 8 changed files with 160 additions and 3 deletions.
File renamed without changes.
28 changes: 28 additions & 0 deletions examples/socket/pysock2stream.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php
$socket = PyCore::import('socket');

const HOST = "127.0.0.1";
const PORT = 5432;

$client = $socket->socket($socket->AF_INET, $socket->SOCK_STREAM);
$client->connect(PyCore::tuple([HOST, PORT]));
$fp = fopen('php://fd/' . $client->fileno(), 'rw');

while (1) {
echo "> ";
$msg = trim(fgets(STDIN));
if ($msg == 'quit') {
break;
}
fwrite($fp, $msg);
$data = fread($fp, 1024);
if (empty($data)) {
break;
}
echo $data . PHP_EOL;
}

echo 'Connection closed. Please enter any characters to exit the program. ' . PHP_EOL;
fclose($fp);

fgets(STDIN);
27 changes: 27 additions & 0 deletions examples/socket/stream2pysock.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

$socket = PyCore::import('socket');

$HOST = "127.0.0.1";
$PORT = 5432;

$fp = stream_socket_client("tcp://$HOST:$PORT", $errno, $errstr, 30);
if (!$fp) {
exit("Error: $errstr ($errno)\n");
}
$client = $socket->fromfd(PyCore::fileno($fp), $socket->AF_INET, $socket->SOCK_STREAM);
fclose($fp);

while (1) {
echo "> ";
$msg = trim(fgets(STDIN));
if ($msg == 'quit') {
break;
}
$client->sendall(PyCore::bytes($msg));
$data = $client->recv(1024);
if (empty($data)) {
break;
}
echo strval($data) . PHP_EOL;
}
4 changes: 4 additions & 0 deletions examples/socket/test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?php
$svr = stream_socket_server("tcp://127.0.0.1:0", $errno, $errstr);
$name = stream_socket_get_name($svr, false);
var_dump($name);
56 changes: 56 additions & 0 deletions src/php/core.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
#include <unordered_set>
#include <string>

#include <php_network.h>
#include <php_streams.h>
#include <zend_exceptions.h>

#include "stubs/phpy_core_arginfo.h"

static zend_class_entry *PyCore_ce;
Expand Down Expand Up @@ -312,3 +316,55 @@ ZEND_METHOD(PyCore, bytes) {
phpy::php::new_object(return_value, pv);
Py_DECREF(pv);
}

ZEND_METHOD(PyCore, fileno) {
zval *zfp;

ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_RESOURCE(zfp)
ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);

if (Z_TYPE_P(zfp) != IS_RESOURCE) {
RETURN_FALSE;
}

php_socket_t fd = -1;
php_stream *stream;
FILE *fp = NULL;

php_stream_from_zval_no_verify(stream, zfp);
if (stream == NULL) {
zend_throw_exception(zend_ce_exception, "Only stream type resource is supported", 0);
RETURN_FALSE;
}

if (php_stream_is(stream, PHP_STREAM_IS_MEMORY) || php_stream_is(stream, PHP_STREAM_IS_TEMP)) {
zend_throw_exception(zend_ce_exception, "Memory and temporary file stream is not supported", 0);
RETURN_FALSE;
} else if (php_stream_can_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL) == SUCCESS) {
if (php_stream_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL, (void **) &fd, 1) !=
SUCCESS ||
fd < 0) {
RETURN_FALSE;
}
} else if (php_stream_can_cast(stream, PHP_STREAM_AS_FD | PHP_STREAM_CAST_INTERNAL) == SUCCESS) {
if (php_stream_cast(stream, PHP_STREAM_AS_FD | PHP_STREAM_CAST_INTERNAL, (void **) &fd, 1) != SUCCESS ||
fd < 0) {
RETURN_FALSE;
}
} else if (php_stream_can_cast(stream, PHP_STREAM_AS_STDIO | PHP_STREAM_CAST_INTERNAL) == SUCCESS) {
if (php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void **) &fp, 1) != SUCCESS) {
RETURN_FALSE;
}
fd = fileno(fp);
} else { /* STDIN, STDOUT, STDERR etc. */
fd = Z_LVAL_P(zfp);
}

if (!ZEND_VALID_SOCKET(fd)) {
zend_throw_exception(zend_ce_exception, "Invalid file descriptor", 0);
RETURN_FALSE;
} else {
RETURN_LONG(fd);
}
}
10 changes: 9 additions & 1 deletion stubs/phpy_core.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

/**
* @method static print(PyObject $o)
* @method static exec(string $code, $global=null, $locals=null)
* @method static exec(string $code, $global = null, $locals = null)
*/
class PyCore
{
Expand Down Expand Up @@ -55,6 +55,14 @@ public static function next(PyObject $iter): mixed

}

/**
* @param resource $fp
*/
public static function fileno($fp): int|false
{

}

public static function __callStatic(string $name, array $arguments): mixed
{

Expand Down
8 changes: 7 additions & 1 deletion stubs/phpy_core_arginfo.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: b8e614338d2752e08b50813e91a2e87f8c2381cb */
* Stub hash: 87e81f483f5af1cadd5eed23f061fa9e204ea85a */

ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_PyCore_import, 0, 1, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 0)
Expand Down Expand Up @@ -34,6 +34,10 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_PyCore_next, 0, 1, IS_MIXE
ZEND_ARG_OBJ_INFO(0, iter, PyObject, 0)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_PyCore_fileno, 0, 1, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_INFO(0, fp)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_PyCore___callStatic, 0, 2, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, arguments, IS_ARRAY, 0)
Expand All @@ -49,6 +53,7 @@ ZEND_METHOD(PyCore, object);
ZEND_METHOD(PyCore, fn);
ZEND_METHOD(PyCore, scalar);
ZEND_METHOD(PyCore, next);
ZEND_METHOD(PyCore, fileno);
ZEND_METHOD(PyCore, __callStatic);


Expand All @@ -62,6 +67,7 @@ static const zend_function_entry class_PyCore_methods[] = {
ZEND_ME(PyCore, fn, arginfo_class_PyCore_fn, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
ZEND_ME(PyCore, scalar, arginfo_class_PyCore_scalar, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
ZEND_ME(PyCore, next, arginfo_class_PyCore_next, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
ZEND_ME(PyCore, fileno, arginfo_class_PyCore_fileno, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
ZEND_ME(PyCore, __callStatic, arginfo_class_PyCore___callStatic, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
ZEND_FE_END
};
30 changes: 29 additions & 1 deletion tests/phpunit/CoreTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,40 @@ public function testRange()
$this->assertEquals(PyCore::scalar(PyCore::range(3)), range(0, 2));
}

public function testObject() {
public function testObject()
{
$o = PyCore::object("hello world");
$this->assertTrue($o instanceof PyObject);
$this->assertStringContainsString('zend_string', strval(PyCore::type($o)));

$o = PyCore::object(123456789);
$this->assertStringContainsString('int', strval(PyCore::type($o)));
}

public function testFileno()
{
$this->assertEquals(0, PyCore::fileno(STDIN));
$this->assertEquals(1, PyCore::fileno(STDOUT));
$this->assertEquals(2, PyCore::fileno(STDERR));

$size = 1 * 1024 * 1024;
try {
$fp = fopen("php://temp/maxmemory:$size", 'r+');
$fd = PyCore::fileno($fp);
} catch (\Throwable $e) {
$this->assertStringContainsString('not supported', $e->getMessage());
}

$fp = fopen(__FILE__, 'r');
$this->assertGreaterThan(0, PyCore::fileno($fp));

$svr = stream_socket_server("tcp://127.0.0.1:0", $errno, $errstr);
$this->assertNotEmpty($svr);

$name = stream_socket_get_name($svr, false);
[$host, $port] = explode(':', $name);
$this->assertEquals('127.0.0.1', $host);
$this->assertGreaterThan(0, PyCore::fileno($svr));
$this->assertGreaterThan(1024, $port);
}
}

0 comments on commit 07a3e60

Please sign in to comment.