2000-07-03 04:35:57 +00:00
|
|
|
/*
|
|
|
|
+----------------------------------------------------------------------+
|
|
|
|
| PHP version 4.0 |
|
|
|
|
+----------------------------------------------------------------------+
|
|
|
|
| Copyright (c) 1997, 1998, 1999, 2000 The PHP Group |
|
|
|
|
+----------------------------------------------------------------------+
|
|
|
|
| This source file is subject to version 2.02 of the PHP license, |
|
|
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
|
|
| available at through the world-wide-web at |
|
|
|
|
| http://www.php.net/license/2_02.txt. |
|
|
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
|
|
| license@php.net so we can mail you a copy immediately. |
|
|
|
|
+----------------------------------------------------------------------+
|
|
|
|
| Authors: |
|
|
|
|
| Chris Vandomelen <chrisv@b0rked.dhs.org> |
|
|
|
|
+----------------------------------------------------------------------+
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* $Id$ */
|
|
|
|
|
|
|
|
#include "php.h"
|
|
|
|
#include "php_ini.h"
|
|
|
|
#include "php_sockets.h"
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <netdb.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <netinet/tcp.h>
|
|
|
|
#include <sys/un.h>
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <signal.h>
|
|
|
|
|
|
|
|
/* You should tweak config.m4 so this symbol (or some else suitable)
|
|
|
|
gets defined.
|
|
|
|
*/
|
|
|
|
#if HAVE_SOCKETS
|
|
|
|
|
|
|
|
#ifdef ZTS
|
|
|
|
int sockets_globals_id;
|
|
|
|
#else
|
|
|
|
php_sockets_globals sockets_globals;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define ZVAL(arg, type) ((*(arg))->value.type)
|
|
|
|
|
|
|
|
/* Perform convert_to_long_ex on a list of items */
|
|
|
|
|
|
|
|
void v_convert_to_long_ex(int items,...)
|
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
zval **arg;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
va_start(ap, items);
|
|
|
|
|
|
|
|
for (i = 0; i < items; i++) {
|
|
|
|
arg = va_arg(ap, zval **);
|
|
|
|
convert_to_long_ex(arg);
|
|
|
|
}
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* *INDENT-OFF* */
|
|
|
|
static unsigned char second_and_third_args_force_ref[] =
|
|
|
|
{3, BYREF_NONE, BYREF_FORCE, BYREF_FORCE};
|
|
|
|
|
|
|
|
/* Every user visible function must have an entry in sockets_functions[].
|
|
|
|
*/
|
|
|
|
function_entry sockets_functions[] =
|
|
|
|
{
|
|
|
|
PHP_FE(confirm_sockets_compiled, NULL) /* For testing, remove later. */
|
|
|
|
PHP_FE(fd_alloc, NULL) /* OK */
|
|
|
|
PHP_FE(fd_dealloc, NULL) /* OK */
|
|
|
|
PHP_FE(fd_set, NULL) /* OK */
|
|
|
|
PHP_FE(fd_isset, NULL) /* OK */
|
|
|
|
PHP_FE(fd_clear, NULL) /* OK */
|
|
|
|
PHP_FE(fd_zero, NULL) /* OK */
|
|
|
|
PHP_FE(select, NULL) /* OK */
|
|
|
|
PHP_FE(open_listen_sok, NULL) /* OK */
|
|
|
|
PHP_FE(accept_connect, NULL) /* OK */
|
|
|
|
PHP_FE(set_nonblock, NULL) /* OK */
|
|
|
|
PHP_FE(listen, NULL) /* OK */
|
|
|
|
PHP_FE(close, NULL) /* OK */
|
|
|
|
PHP_FE(write, NULL) /* OK */
|
|
|
|
PHP_FE(read, second_arg_force_ref) /* OK */
|
|
|
|
#if 0
|
|
|
|
/* If and when asynchronous context switching is avaliable, this will work. Otherwise, forget it. */
|
|
|
|
PHP_FE(signal, NULL)
|
|
|
|
#endif
|
|
|
|
#if 0
|
|
|
|
/* These are defined elsewhere.. would these be more appropriate? */
|
|
|
|
PHP_FE(gethostbyname, second_arg_force_ref) /* OK */
|
|
|
|
PHP_FE(gethostbyaddr, second_arg_force_ref) /* OK */
|
|
|
|
#endif
|
|
|
|
PHP_FE(getsockname, second_and_third_args_force_ref) /* OK */
|
|
|
|
PHP_FE(getpeername, second_and_third_args_force_ref) /* OK */
|
|
|
|
PHP_FE(socket, NULL) /* OK */
|
|
|
|
PHP_FE(connect, NULL) /* OK */
|
|
|
|
PHP_FE(strerror, NULL) /* OK */
|
|
|
|
PHP_FE(bind, NULL)
|
|
|
|
{NULL, NULL, NULL} /* Must be the last line in sockets_functions[] */
|
|
|
|
};
|
|
|
|
|
|
|
|
/* *INDENT-ON* */
|
|
|
|
|
|
|
|
zend_module_entry sockets_module_entry =
|
|
|
|
{
|
|
|
|
"sockets",
|
|
|
|
sockets_functions,
|
|
|
|
PHP_MINIT(sockets),
|
|
|
|
PHP_MSHUTDOWN(sockets),
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
PHP_MINFO(sockets),
|
|
|
|
STANDARD_MODULE_PROPERTIES
|
|
|
|
};
|
|
|
|
|
|
|
|
int le_destroy;
|
|
|
|
|
|
|
|
#ifdef COMPILE_DL_SOCKETS
|
|
|
|
ZEND_GET_MODULE(sockets)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Remove comments and fill if you need to have entries in php.ini
|
|
|
|
PHP_INI_BEGIN()
|
|
|
|
PHP_INI_END()
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void destroy_fd_sets(fd_set * set)
|
|
|
|
{
|
|
|
|
efree(set);
|
|
|
|
}
|
|
|
|
|
|
|
|
PHP_MINIT_FUNCTION(sockets)
|
|
|
|
{
|
|
|
|
/* Remove comments if you have entries in php.ini
|
|
|
|
REGISTER_INI_ENTRIES();
|
|
|
|
*/
|
|
|
|
le_destroy = register_list_destructors(destroy_fd_sets, NULL);
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
PHP_MSHUTDOWN_FUNCTION(sockets)
|
|
|
|
{
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
PHP_MINFO_FUNCTION(sockets)
|
|
|
|
{
|
|
|
|
php_info_print_table_start();
|
|
|
|
php_info_print_table_header(2, "sockets support", "enabled");
|
|
|
|
php_info_print_table_end();
|
|
|
|
|
|
|
|
/* Remove comments if you have entries in php.ini
|
|
|
|
DISPLAY_INI_ENTRIES();
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Remove the following function when you have succesfully modified config.m4
|
|
|
|
so that your module can be compiled into PHP, it exists only for testing
|
|
|
|
purposes. */
|
|
|
|
|
|
|
|
/* Every user-visible function in PHP should document itself in the source */
|
|
|
|
/* {{{ proto string confirm_sockets_compiled(string arg)
|
|
|
|
Return a string to confirm that the module is compiled in */
|
|
|
|
PHP_FUNCTION(confirm_sockets_compiled)
|
|
|
|
{
|
|
|
|
zval **arg;
|
|
|
|
int len;
|
|
|
|
char string[256];
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg) == FAILURE) {
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
convert_to_string_ex(arg);
|
|
|
|
|
|
|
|
len = sprintf(string, "Congratulations, you have successfully modified ext/sockets/config.m4, module %s is compiled in PHP", Z_STRVAL_PP(arg));
|
|
|
|
RETVAL_STRINGL(string, len, 1);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
/* The previous line is meant for emacs, so it can correctly fold and unfold
|
|
|
|
functions in source code. See the corresponding marks just before function
|
|
|
|
definition, where the functions purpose is also documented. Please follow
|
|
|
|
this convention for the convenience of others editing your code.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* {{{ proto resource fd_alloc(void)
|
2000-07-05 18:33:32 +00:00
|
|
|
Allocate a file descriptor set */
|
2000-07-03 04:35:57 +00:00
|
|
|
PHP_FUNCTION(fd_alloc)
|
|
|
|
{
|
|
|
|
fd_set *set;
|
|
|
|
zval *new_resource;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
set = emalloc(sizeof(fd_set));
|
|
|
|
if (!set) {
|
|
|
|
zend_error(E_ERROR, "Can't allocate memory for fd_set");
|
|
|
|
RETVAL_FALSE;
|
|
|
|
}
|
|
|
|
ret = ZEND_REGISTER_RESOURCE(new_resource, set, le_destroy);
|
|
|
|
RETURN_RESOURCE(ret);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto void fd_dealloc(void)
|
2000-07-05 18:33:32 +00:00
|
|
|
De-allocate a file descriptor set */
|
|
|
|
/* ** BUG: This is currently a no-op! */
|
2000-07-03 04:35:57 +00:00
|
|
|
PHP_FUNCTION(fd_dealloc)
|
|
|
|
{
|
|
|
|
RETVAL_TRUE;
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto bool fd_set(long fd, resource set)
|
|
|
|
Add a file descriptor to a set */
|
|
|
|
PHP_FUNCTION(fd_set)
|
|
|
|
{
|
|
|
|
zval **set, **fd;
|
|
|
|
fd_set *the_set;
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &fd, &set) == FAILURE) {
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
v_convert_to_long_ex(2, set, fd);
|
|
|
|
|
|
|
|
if ((*set)->type != IS_RESOURCE) {
|
|
|
|
(*set)->type = IS_RESOURCE;
|
|
|
|
}
|
|
|
|
ZEND_FETCH_RESOURCE(the_set, fd_set *, set, -1, "File descriptor set", le_destroy);
|
|
|
|
|
|
|
|
FD_SET((*fd)->value.lval, the_set);
|
|
|
|
|
|
|
|
RETVAL_TRUE;
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto bool fd_clear(long fd, resource set)
|
2000-07-05 18:33:32 +00:00
|
|
|
Clear a file descriptor from a set */
|
2000-07-03 04:35:57 +00:00
|
|
|
PHP_FUNCTION(fd_clear)
|
|
|
|
{
|
|
|
|
zval **set, **fd;
|
|
|
|
fd_set *the_set;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &fd, &set) == FAILURE) {
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
v_convert_to_long_ex(2, set, fd);
|
|
|
|
|
|
|
|
(*set)->type = IS_RESOURCE;
|
|
|
|
|
|
|
|
ZEND_FETCH_RESOURCE(the_set, fd_set *, set, -1, "File descriptor set", le_destroy);
|
|
|
|
|
|
|
|
FD_CLR((*fd)->value.lval, the_set);
|
|
|
|
|
|
|
|
RETVAL_TRUE;
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto bool fd_isset(long fd, resource set)
|
2000-07-05 18:33:32 +00:00
|
|
|
Check to see if a file descriptor is set within the file descriptor set */
|
2000-07-03 04:35:57 +00:00
|
|
|
PHP_FUNCTION(fd_isset)
|
|
|
|
{
|
|
|
|
zval **set, **fd;
|
|
|
|
fd_set *the_set;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &fd, &set) == FAILURE) {
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
v_convert_to_long_ex(2, set, fd);
|
|
|
|
|
|
|
|
(*set)->type = IS_RESOURCE;
|
|
|
|
|
|
|
|
ZEND_FETCH_RESOURCE(the_set, fd_set *, set, -1, "File descriptor set", le_destroy);
|
|
|
|
|
|
|
|
if (FD_ISSET((*fd)->value.lval, the_set)) {
|
|
|
|
RETVAL_TRUE;
|
|
|
|
}
|
|
|
|
RETVAL_FALSE;
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto void fd_zero(resource set)
|
|
|
|
Clear a file descriptor set */
|
|
|
|
PHP_FUNCTION(fd_zero)
|
|
|
|
{
|
|
|
|
zval **set;
|
|
|
|
fd_set *the_set;
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(2, &set) == FAILURE) {
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
convert_to_long_ex(set);
|
|
|
|
|
|
|
|
(*set)->type = IS_RESOURCE;
|
|
|
|
|
|
|
|
ZEND_FETCH_RESOURCE(the_set, fd_set *, set, -1, "File descriptor set", le_destroy);
|
|
|
|
|
|
|
|
FD_ZERO(the_set);
|
|
|
|
|
|
|
|
RETVAL_TRUE;
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto void select(long max_fd, resource readfds, resource writefds, resource exceptfds, long tv_sec, long tv_usec)
|
2000-07-05 18:33:32 +00:00
|
|
|
Runs the select() system call on the sets mentioned with a timeout specified by tv_sec and tv_usec */
|
|
|
|
/*
|
|
|
|
See select(2) man page for details.
|
2000-07-03 04:35:57 +00:00
|
|
|
|
|
|
|
From man page:
|
|
|
|
select waits for a number of file descriptors to change status.
|
|
|
|
|
2000-07-05 18:33:32 +00:00
|
|
|
Three independent sets of descriptors are watched. Those in
|
|
|
|
readfds will be watched to see if characters become avaliable for
|
|
|
|
reading, those in writefds will be watched to see if it is ok to
|
|
|
|
immediately write on them, and those in exceptfds will be watched
|
|
|
|
for exceptions. On exit, the sets are modified in place to
|
|
|
|
indicate which descriptors actually changed status.
|
2000-07-03 04:35:57 +00:00
|
|
|
|
2000-07-05 18:33:32 +00:00
|
|
|
-1 is passed for any sets for which NULL would be passed to the
|
|
|
|
system call.
|
2000-07-03 04:35:57 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
PHP_FUNCTION(select)
|
|
|
|
{
|
|
|
|
zval **max_fd, **readfds, **writefds, **exceptfds, **tv_sec,
|
|
|
|
**tv_usec;
|
|
|
|
struct timeval tv;
|
|
|
|
fd_set *rfds, *wfds, *xfds;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() != 6 || zend_get_parameters_ex(6, &max_fd, &readfds, &writefds, &exceptfds,
|
|
|
|
&tv_sec, &tv_usec) == FAILURE) {
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
v_convert_to_long_ex(6, max_fd, readfds, writefds, exceptfds, tv_sec, tv_usec);
|
|
|
|
|
|
|
|
tv.tv_sec = ZVAL(tv_sec, lval);
|
|
|
|
tv.tv_usec = ZVAL(tv_usec, lval);
|
|
|
|
|
|
|
|
(*readfds)->type = IS_RESOURCE;
|
|
|
|
(*writefds)->type = IS_RESOURCE;
|
|
|
|
(*exceptfds)->type = IS_RESOURCE;
|
|
|
|
|
|
|
|
if (ZVAL(readfds, lval) == 0) {
|
|
|
|
rfds = NULL;
|
|
|
|
} else {
|
|
|
|
ZEND_FETCH_RESOURCE(rfds, fd_set *, readfds, -1, "File descriptor set", le_destroy);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ZVAL(writefds, lval) == 0) {
|
|
|
|
wfds = NULL;
|
|
|
|
} else {
|
|
|
|
ZEND_FETCH_RESOURCE(wfds, fd_set *, writefds, -1, "File descriptor set", le_destroy);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ZVAL(exceptfds, lval) == 0) {
|
|
|
|
xfds = NULL;
|
|
|
|
} else {
|
|
|
|
ZEND_FETCH_RESOURCE(xfds, fd_set *, exceptfds, -1, "File descriptor set", le_destroy);
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = select(ZVAL(max_fd, lval), rfds, wfds, xfds, &tv);
|
|
|
|
|
|
|
|
if (ret < 0) {
|
|
|
|
RETVAL_LONG(-errno);
|
|
|
|
} else {
|
|
|
|
RETVAL_LONG(ret);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto long open_listen_sok(long port)
|
|
|
|
Opens a socket on port to accept connections */
|
|
|
|
|
|
|
|
int open_listen_sok(int port)
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
struct sockaddr_in la;
|
|
|
|
struct hostent *hp;
|
|
|
|
|
|
|
|
if ((hp = gethostbyname("0.0.0.0")) == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
bcopy(hp->h_addr, (char *) &la.sin_addr, hp->h_length);
|
|
|
|
la.sin_family = hp->h_addrtype;
|
|
|
|
la.sin_port = htons(port);
|
|
|
|
|
|
|
|
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if ((bind(fd, (struct sockaddr *) &la, sizeof(la)) < 0)) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
listen(fd, 128);
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
PHP_FUNCTION(open_listen_sok)
|
|
|
|
{
|
|
|
|
zval **port;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &port) == FAILURE) {
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
convert_to_long_ex(port);
|
|
|
|
|
|
|
|
ret = open_listen_sok(ZVAL(port, lval));
|
|
|
|
|
|
|
|
if (ret < 0) {
|
|
|
|
RETURN_LONG(-errno);
|
|
|
|
} else {
|
|
|
|
RETURN_LONG(ret);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto int accept_connect(long fd)
|
2000-07-05 18:33:32 +00:00
|
|
|
Accepts a connection on the listening socket fd */
|
2000-07-03 04:35:57 +00:00
|
|
|
int accept_connect(int fd, struct sockaddr *la)
|
|
|
|
{
|
|
|
|
int foo, m;
|
|
|
|
m = sizeof(*la);
|
|
|
|
if ((foo = accept(fd, la, &m)) < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return foo;
|
|
|
|
}
|
|
|
|
|
|
|
|
PHP_FUNCTION(accept_connect)
|
|
|
|
{
|
|
|
|
zval **fd;
|
|
|
|
int ret;
|
|
|
|
struct sockaddr_in sa;
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &fd) == FAILURE) {
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
convert_to_long_ex(fd);
|
|
|
|
|
|
|
|
ret = accept_connect(ZVAL(fd, lval), (struct sockaddr *) &sa);
|
|
|
|
|
|
|
|
if (ret < 0) {
|
|
|
|
RETURN_LONG(-errno);
|
|
|
|
} else {
|
|
|
|
RETURN_LONG(ret);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto bool set_nonblock(long fd)
|
2000-07-05 18:33:32 +00:00
|
|
|
Sets nonblocking mode for file descriptor fd */
|
2000-07-03 04:35:57 +00:00
|
|
|
PHP_FUNCTION(set_nonblock)
|
|
|
|
{
|
|
|
|
zval **fd;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &fd) == FAILURE) {
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
convert_to_long_ex(fd);
|
|
|
|
|
|
|
|
ret = fcntl(ZVAL(fd, lval), F_SETFL, O_NONBLOCK);
|
|
|
|
if (ret < 0) {
|
|
|
|
RETURN_LONG(-errno);
|
|
|
|
} else {
|
|
|
|
RETURN_LONG(ret);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto bool listen(long fd, long backlog)
|
2000-07-05 18:33:32 +00:00
|
|
|
Sets the maximum number of connections allowed to be waited for on the socket specified by fd */
|
2000-07-03 04:35:57 +00:00
|
|
|
PHP_FUNCTION(listen)
|
|
|
|
{
|
|
|
|
zval **fd, **backlog;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &fd, &backlog) == FAILURE) {
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
v_convert_to_long_ex(2, fd, backlog);
|
|
|
|
|
|
|
|
ret = listen(ZVAL(fd, lval), ZVAL(backlog, lval));
|
|
|
|
|
|
|
|
if (ret < 0) {
|
|
|
|
RETURN_LONG(-errno);
|
|
|
|
} else {
|
|
|
|
RETURN_LONG(ret);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto bool close(long fd)
|
|
|
|
Close a file descriptor */
|
|
|
|
PHP_FUNCTION(close)
|
|
|
|
{
|
|
|
|
zval **arg;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg) == FAILURE) {
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
convert_to_long_ex(arg);
|
|
|
|
ret = close(ZVAL(arg, lval));
|
|
|
|
|
|
|
|
if (ret == -1) {
|
|
|
|
zend_error(E_WARNING, "Invalid file descriptor");
|
|
|
|
RETVAL_FALSE;
|
|
|
|
}
|
|
|
|
RETVAL_TRUE;
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto long write(long fd, string buf, long length)
|
|
|
|
Writes length bytes of buf to the file descriptor fd */
|
|
|
|
PHP_FUNCTION(write)
|
|
|
|
{
|
|
|
|
zval **fd, **buf, **length;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &fd, &buf, &length) == FAILURE) {
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
v_convert_to_long_ex(2, fd, length);
|
|
|
|
convert_to_string_ex(buf);
|
|
|
|
|
|
|
|
if (ZVAL(buf, str.len) < ZVAL(length, lval)) {
|
|
|
|
ret = write(ZVAL(fd, lval), (void *) ZVAL(buf, str.val), ZVAL(buf, str.len));
|
|
|
|
} else {
|
|
|
|
ret = write(ZVAL(fd, lval), (void *) ZVAL(buf, str.val), ZVAL(length, lval));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret < 0) {
|
|
|
|
RETURN_LONG(-errno);
|
|
|
|
} else {
|
|
|
|
RETURN_LONG(ret);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto long read(long fd, string &buf, long length)
|
|
|
|
Reads length bytes from fd into buf */
|
|
|
|
PHP_FUNCTION(read)
|
|
|
|
{
|
|
|
|
zval **fd, **buf, **length;
|
|
|
|
char *tmp;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &fd, &buf, &length) == FAILURE) {
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
v_convert_to_long_ex(2, fd, length);
|
|
|
|
convert_to_string_ex(buf);
|
|
|
|
|
|
|
|
tmp = emalloc(ZVAL(length, lval));
|
|
|
|
ret = read(ZVAL(fd, lval), tmp, ZVAL(length, lval));
|
|
|
|
|
|
|
|
if (ret < 0) {
|
|
|
|
RETURN_LONG(-errno);
|
|
|
|
} else {
|
|
|
|
ZVAL(buf, str.val) = tmp;
|
|
|
|
ZVAL(buf, str.len) = ret;
|
|
|
|
|
|
|
|
RETURN_LONG(ret);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto long getsockname(long fd, string &addr, long &port)
|
2000-07-05 18:33:32 +00:00
|
|
|
Given an fd, stores a string representing sa.sin_addr and the value of sa.sin_port int addr and port describing the local side of a socket */
|
2000-07-03 04:35:57 +00:00
|
|
|
|
|
|
|
/* A lock to prevent inet_ntoa() from causing problems in threading */
|
|
|
|
volatile int inet_ntoa_lock = 0;
|
|
|
|
|
|
|
|
PHP_FUNCTION(getsockname)
|
|
|
|
{
|
|
|
|
zval **fd, **addr, **port;
|
|
|
|
char *tmp;
|
|
|
|
struct sockaddr_in sa;
|
|
|
|
int salen = sizeof(struct sockaddr_in);
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &fd, &addr, &port) == FAILURE) {
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
v_convert_to_long_ex(2, fd, port);
|
|
|
|
convert_to_string_ex(addr);
|
|
|
|
|
|
|
|
ret = getsockname(ZVAL(fd, lval), &sa, &salen);
|
|
|
|
if (ret < 0) {
|
|
|
|
RETURN_LONG(-errno);
|
|
|
|
} else {
|
|
|
|
char *addr_string;
|
|
|
|
while (inet_ntoa_lock == 1);
|
|
|
|
inet_ntoa_lock = 1;
|
|
|
|
addr_string = inet_ntoa(sa.sin_addr);
|
|
|
|
tmp = emalloc(strlen(addr_string) + 1);
|
|
|
|
strncpy(tmp, addr_string, strlen(addr_string));
|
|
|
|
inet_ntoa_lock = 0;
|
|
|
|
|
|
|
|
ZVAL(addr, str.val) = tmp;
|
|
|
|
ZVAL(addr, str.len) = strlen(tmp);
|
|
|
|
ZVAL(port, lval) = htons(sa.sin_port);
|
|
|
|
|
|
|
|
RETURN_LONG(ret);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
/* {{{ proto long gethostbyname(string name, string &addr)
|
|
|
|
Given a hostname, sets addr to be a human-readable version of the host's address */
|
|
|
|
|
|
|
|
/* Another lock to prevent multiple threads from grabbing gethostbyname() */
|
|
|
|
volatile int gethostbyname_lock = 0;
|
|
|
|
|
|
|
|
PHP_FUNCTION(gethostbyname)
|
|
|
|
{
|
|
|
|
zval **name, **addr;
|
|
|
|
int ret;
|
|
|
|
char *tmp, *addr_string;
|
|
|
|
struct hostent *host_struct;
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &name, &addr) == FAILURE) {
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
convert_to_string_ex(name);
|
|
|
|
convert_to_string_ex(addr);
|
|
|
|
|
|
|
|
while (gethostbyname_lock == 1);
|
|
|
|
gethostbyname_lock = 1;
|
|
|
|
|
|
|
|
host_struct = gethostbyname(ZVAL(name, str.val));
|
|
|
|
if (!host_struct) {
|
|
|
|
gethostbyname_lock = 0;
|
|
|
|
RETURN_LONG(-(h_errno) - 10000); /* return a value that is out of range for errno */
|
|
|
|
}
|
|
|
|
if (host_struct->h_addrtype != AF_INET) {
|
|
|
|
gethostbyname_lock = 0;
|
|
|
|
RETURN_LONG(-EINVAL);
|
|
|
|
}
|
|
|
|
while (inet_ntoa_lock == 1);
|
|
|
|
inet_ntoa_lock = 1;
|
|
|
|
|
|
|
|
addr_string = inet_ntoa((struct in_addr) host_struct->h_addr);
|
|
|
|
tmp = emalloc(strlen(addr_string) + 1);
|
|
|
|
strncpy(tmp, addr_string, strlen(addr_string));
|
|
|
|
|
|
|
|
inet_ntoa_lock = 0;
|
|
|
|
gethostbyname_lock = 0;
|
|
|
|
|
|
|
|
ZVAL(addr, str.val) = tmp;
|
|
|
|
ZVAL(addr, str.len) = strlen(tmp);
|
|
|
|
|
|
|
|
RETURN_LONG(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* {{{ proto long getpeername(long fd, string &addr, long &port)
|
2000-07-05 18:33:32 +00:00
|
|
|
Given an fd, stores a string representing sa.sin_addr and the value of sa.sin_port int addr and port describing the remote side of a socket */
|
2000-07-03 04:35:57 +00:00
|
|
|
|
|
|
|
PHP_FUNCTION(getpeername)
|
|
|
|
{
|
|
|
|
zval **fd, **addr, **port;
|
|
|
|
char *tmp;
|
|
|
|
struct sockaddr_in sa;
|
|
|
|
int salen = sizeof(struct sockaddr_in);
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &fd, &addr, &port) == FAILURE) {
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
v_convert_to_long_ex(2, fd, port);
|
|
|
|
convert_to_string_ex(addr);
|
|
|
|
|
|
|
|
ret = getpeername(ZVAL(fd, lval), &sa, &salen);
|
|
|
|
if (ret < 0) {
|
|
|
|
RETURN_LONG(-errno);
|
|
|
|
} else {
|
|
|
|
char *addr_string;
|
|
|
|
while (inet_ntoa_lock == 1);
|
|
|
|
inet_ntoa_lock = 1;
|
|
|
|
addr_string = inet_ntoa(sa.sin_addr);
|
|
|
|
tmp = emalloc(strlen(addr_string) + 1);
|
|
|
|
bzero(tmp, strlen(addr_string) + 1);
|
|
|
|
strncpy(tmp, addr_string, strlen(addr_string));
|
|
|
|
inet_ntoa_lock = 0;
|
|
|
|
|
|
|
|
ZVAL(addr, str.val) = tmp;
|
|
|
|
ZVAL(addr, str.len) = strlen(tmp);
|
|
|
|
ZVAL(port, lval) = htons(sa.sin_port);
|
|
|
|
|
|
|
|
RETURN_LONG(ret);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
/* {{{ proto long gethostbyaddr(string addr, string &name)
|
|
|
|
Given a human-readable address, sets name to be the host's name */
|
|
|
|
|
|
|
|
/* Another lock to prevent multiple threads from grabbing gethostbyname() */
|
|
|
|
volatile int gethostbyaddr_lock = 0;
|
|
|
|
|
|
|
|
PHP_FUNCTION(gethostbyaddr)
|
|
|
|
{
|
|
|
|
zval **name, **addr;
|
|
|
|
int ret;
|
|
|
|
char *tmp, *addr_string;
|
|
|
|
struct hostent *host_struct;
|
|
|
|
struct in_addr addr_buf;
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &addr, &name) == FAILURE) {
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
convert_to_string_ex(name);
|
|
|
|
convert_to_string_ex(addr);
|
|
|
|
|
|
|
|
ret = inet_aton(ZVAL(addr, str.val), &addr_buf);
|
|
|
|
if (ret < 0) {
|
|
|
|
RETURN_LONG(-EINVAL);
|
|
|
|
}
|
|
|
|
while (gethostbyaddr_lock == 1);
|
|
|
|
gethostbyaddr_lock = 1;
|
|
|
|
|
|
|
|
host_struct = gethostbyname((char *) &addr_buf, sizeof(addr_buf), AF_INET);
|
|
|
|
if (!host_struct) {
|
|
|
|
gethostbyaddr_lock = 0;
|
|
|
|
RETURN_LONG(-(h_errno) - 10000);
|
|
|
|
}
|
|
|
|
if (host_struct->h_addrtype != AF_INET) {
|
|
|
|
gethostbyaddr_lock = 0;
|
|
|
|
RETURN_LONG(-EINVAL);
|
|
|
|
}
|
|
|
|
addr_string = host_struct->h_name;
|
|
|
|
tmp = emalloc(strlen(addr_string) + 1);
|
|
|
|
strncpy(tmp, addr_string, strlen(addr_string));
|
|
|
|
|
|
|
|
gethostbyaddr_lock = 0;
|
|
|
|
|
|
|
|
ZVAL(addr, str.val) = tmp;
|
|
|
|
ZVAL(addr, str.len) = strlen(tmp);
|
|
|
|
|
|
|
|
RETURN_LONG(0);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* {{{ proto long socket(string domain, string type, long protocol)
|
2000-07-05 18:33:32 +00:00
|
|
|
Creates an endpoint for communication in the domain specified by domain, of type specified by type */
|
2000-07-03 04:35:57 +00:00
|
|
|
PHP_FUNCTION(socket)
|
|
|
|
{
|
|
|
|
zval **domain, **type, **protocol;
|
|
|
|
int ret;
|
|
|
|
int my_type, my_domain;
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &domain, &type, &protocol) == FAILURE) {
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
convert_to_string_ex(domain);
|
|
|
|
convert_to_string_ex(type);
|
|
|
|
convert_to_long_ex(protocol);
|
|
|
|
|
|
|
|
if (!strcasecmp(ZVAL(domain, str.val), "af_inet")) {
|
|
|
|
my_domain = AF_INET;
|
|
|
|
} else if (!strcasecmp(ZVAL(domain, str.val), "af_unix")) {
|
|
|
|
my_domain = AF_UNIX;
|
|
|
|
} else {
|
|
|
|
zend_error(E_WARNING, "invalid communications domain specified - assuming AF_INET");
|
|
|
|
my_domain = AF_INET;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcasecmp(ZVAL(type, str.val), "sock_stream")) {
|
|
|
|
my_type = SOCK_STREAM;
|
|
|
|
} else if (!strcasecmp(ZVAL(type, str.val), "sock_dgram")) {
|
|
|
|
my_type = SOCK_DGRAM;
|
|
|
|
} else if (!strcasecmp(ZVAL(type, str.val), "sock_raw")) {
|
|
|
|
my_type = SOCK_RAW;
|
|
|
|
} else if (!strcasecmp(ZVAL(type, str.val), "sock_seqpacket")) {
|
|
|
|
my_type = SOCK_SEQPACKET;
|
|
|
|
} else if (!strcasecmp(ZVAL(type, str.val), "sock_rdm")) {
|
|
|
|
my_type = SOCK_RDM;
|
|
|
|
} else {
|
|
|
|
zend_error(E_WARNING, "invalid socket type specified - assuming SOCK_STREAM");
|
|
|
|
my_type = SOCK_STREAM;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = socket(my_domain, my_type, ZVAL(protocol, lval));
|
|
|
|
if (ret < 0) {
|
|
|
|
RETURN_LONG(-errno);
|
|
|
|
} else {
|
|
|
|
RETURN_LONG(ret);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto long connect(long sockfd, string addr, long port)
|
|
|
|
Opens a connection to addr:port on the socket specified by sockfd */
|
|
|
|
PHP_FUNCTION(connect)
|
|
|
|
{
|
|
|
|
zval **sockfd, **addr, **port;
|
|
|
|
struct sockaddr_in sa;
|
|
|
|
int salen = sizeof(sa);
|
|
|
|
int ret;
|
|
|
|
struct in_addr addr_buf;
|
|
|
|
struct hostent *host_struct;
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &sockfd, &addr, &port) == FAILURE) {
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
v_convert_to_long_ex(2, sockfd, port);
|
|
|
|
convert_to_string_ex(addr);
|
|
|
|
|
|
|
|
bzero(&sa, sizeof(sa));
|
|
|
|
sa.sin_port = ZVAL(port, lval);
|
|
|
|
|
|
|
|
if (inet_aton(ZVAL(addr, str.val), &addr_buf) == 0) {
|
|
|
|
sa.sin_addr.s_addr = addr_buf.s_addr;
|
|
|
|
} else {
|
|
|
|
host_struct = gethostbyname(ZVAL(addr, str.val));
|
|
|
|
if (host_struct->h_addrtype != AF_INET) {
|
|
|
|
RETURN_LONG(-EINVAL);
|
|
|
|
}
|
|
|
|
sa.sin_addr.s_addr = (int) *(host_struct->h_addr_list[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = connect(ZVAL(sockfd, lval), (struct sockaddr *) &sa, salen);
|
|
|
|
if (ret < 0) {
|
|
|
|
RETURN_LONG(-errno);
|
|
|
|
} else {
|
|
|
|
RETURN_LONG(ret);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto string strerror(long errno)
|
|
|
|
Returns a string describing an error */
|
|
|
|
PHP_FUNCTION(strerror)
|
|
|
|
{
|
|
|
|
zval **error;
|
|
|
|
const char *buf;
|
|
|
|
char *obuf;
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &error) == FAILURE) {
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
if (ZVAL(error, lval) < -10000) {
|
|
|
|
ZVAL(error, lval) += 10000;
|
|
|
|
buf = hstrerror(-(ZVAL(error, lval)));
|
|
|
|
} else {
|
|
|
|
buf = strerror(-(ZVAL(error, lval)));
|
|
|
|
}
|
|
|
|
|
|
|
|
obuf = estrndup(buf, strlen(buf));
|
|
|
|
ZVAL(&return_value, str.val) = obuf;
|
|
|
|
ZVAL(&return_value, str.len) = strlen(buf);
|
|
|
|
return_value->type = IS_STRING;
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2000-07-05 18:33:32 +00:00
|
|
|
/* {{{ proto long bind(long sockfd, string domain [, string ...])
|
|
|
|
Binds an open socket to a listening port */
|
|
|
|
/* -- domain = "af_unix", 3rd arg is path to socket
|
2000-07-03 04:35:57 +00:00
|
|
|
-- domain = "af_inet", 3rd arg is address to bind to, 4th arg is port */
|
|
|
|
PHP_FUNCTION(bind)
|
|
|
|
{
|
|
|
|
zval **arg0, **arg1, **arg2, **arg3;
|
|
|
|
long ret;
|
|
|
|
void **p;
|
|
|
|
int arg_count;
|
|
|
|
va_list ptr;
|
|
|
|
ELS_FETCH();
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() < 2) {
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
|
|
|
|
p = EG(argument_stack).top_element-2;
|
|
|
|
arg_count = (ulong) *p;
|
|
|
|
|
|
|
|
arg0 = (zval **) p-(arg_count --);
|
|
|
|
arg1 = (zval **) p-(arg_count--);
|
|
|
|
|
|
|
|
convert_to_long_ex(arg0);
|
|
|
|
convert_to_string_ex(arg1);
|
|
|
|
|
|
|
|
if (!strcasecmp(ZVAL(arg1, str.val), "af_unix")) {
|
|
|
|
struct sockaddr_un sa;
|
|
|
|
if (ZEND_NUM_ARGS() != 3) {
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
arg2 = (zval **) p-(arg_count--);
|
|
|
|
snprintf(sa.sun_path, 108, "%s", ZVAL(arg2, str.val));
|
|
|
|
ret = bind(ZVAL(arg0, lval), &sa, sizeof(sa));
|
|
|
|
} else if (!strcasecmp(ZVAL(arg1, str.val), "af_inet")) {
|
|
|
|
struct sockaddr_in sa;
|
|
|
|
struct in_addr addr_buf;
|
|
|
|
if (ZEND_NUM_ARGS() != 4) {
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
arg2 = (zval **) p-(arg_count--);
|
|
|
|
arg3 = (zval **) p-(arg_count--);
|
|
|
|
sa.sin_port = htons(ZVAL(arg3, lval));
|
|
|
|
if (inet_aton(ZVAL(arg2, str.val), &addr_buf) < 0) {
|
|
|
|
struct hostent *host_struct = gethostbyname(ZVAL(arg2, str.val));
|
|
|
|
if (host_struct == NULL) {
|
|
|
|
RETURN_LONG(-(h_errno) - 10000);
|
|
|
|
}
|
|
|
|
sa.sin_addr.s_addr = (int) *(host_struct->h_addr_list[0]);
|
|
|
|
} else {
|
|
|
|
sa.sin_addr.s_addr = addr_buf.s_addr;
|
|
|
|
}
|
|
|
|
ret = bind(ZVAL(arg0, lval), &sa, sizeof(sa));
|
|
|
|
} else {
|
|
|
|
RETURN_LONG(-EPROTONOSUPPORT);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret < 0) {
|
|
|
|
RETURN_LONG(-errno);
|
|
|
|
} else {
|
|
|
|
RETURN_LONG(ret);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
#endif /* HAVE_SOCKETS */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Local variables:
|
|
|
|
* tab-width: 4
|
|
|
|
* c-basic-offset: 4
|
|
|
|
* End:
|
|
|
|
*/
|