mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +02:00
* Makefile.in
config.m4 php_sockets.h sockets.c sockets.php: - Added files needed for Unix-style sockets support in PHP.
This commit is contained in:
parent
7a4d4bcd6b
commit
21abde5ca1
5 changed files with 1120 additions and 0 deletions
7
ext/sockets/Makefile.in
Normal file
7
ext/sockets/Makefile.in
Normal file
|
@ -0,0 +1,7 @@
|
|||
# $Id$
|
||||
|
||||
LTLIBRARY_NAME = libsockets.la
|
||||
LTLIBRARY_SOURCES = sockets.c
|
||||
LTLIBRARY_SHARED_NAME = sockets.la
|
||||
|
||||
include $(top_srcdir)/build/dynlib.mk
|
38
ext/sockets/config.m4
Normal file
38
ext/sockets/config.m4
Normal file
|
@ -0,0 +1,38 @@
|
|||
dnl $Id$
|
||||
dnl config.m4 for extension sockets
|
||||
dnl don't forget to call PHP_EXTENSION(sockets)
|
||||
|
||||
dnl Comments in this file start with the string 'dnl'.
|
||||
dnl Remove where necessary. This file will not work
|
||||
dnl without editing.
|
||||
|
||||
dnl If your extension references something external, use with:
|
||||
|
||||
dnl PHP_ARG_WITH(sockets, for sockets support,
|
||||
dnl Make sure that the comment is aligned:
|
||||
dnl [ --with-sockets Include sockets support])
|
||||
|
||||
dnl Otherwise use enable:
|
||||
|
||||
PHP_ARG_ENABLE(sockets, whether to enable sockets support,
|
||||
dnl Make sure that the comment is aligned:
|
||||
[ --enable-sockets Enable sockets support])
|
||||
|
||||
if test "$PHP_SOCKETS" != "no"; then
|
||||
dnl If you will not be testing anything external, like existence of
|
||||
dnl headers, libraries or functions in them, just uncomment the
|
||||
dnl following line and you are ready to go.
|
||||
|
||||
dnl ---------------------------------
|
||||
dnl Headers
|
||||
dnl ---------------------------------
|
||||
|
||||
AC_HEADER_STDC
|
||||
AC_UNISTD_H
|
||||
AC_CHECK_HEADERS(sys/types.h sys/socket.h netdb.h netinet/in.h netinet/tcp.h sys/un.h arpa/inet.h)
|
||||
AC_CHECK_HEADERS(sys/time.h errno.h fcntl.h)
|
||||
|
||||
AC_DEFINE(HAVE_SOCKETS, 1, [ ])
|
||||
dnl Write more examples of tests here...
|
||||
PHP_EXTENSION(sockets, $ext_shared)
|
||||
fi
|
110
ext/sockets/php_sockets.h
Normal file
110
ext/sockets/php_sockets.h
Normal file
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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: |
|
||||
| |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef _PHP_SOCKETS_H
|
||||
#define _PHP_SOCKETS_H
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
/* You should tweak config.m4 so this symbol (or some else suitable)
|
||||
gets defined.
|
||||
*/
|
||||
#if HAVE_SOCKETS
|
||||
|
||||
extern zend_module_entry sockets_module_entry;
|
||||
#define phpext_sockets_ptr &sockets_module_entry
|
||||
|
||||
#ifdef PHP_WIN32
|
||||
#define PHP_SOCKETS_API __declspec(dllexport)
|
||||
#else
|
||||
#define PHP_SOCKETS_API
|
||||
#endif
|
||||
|
||||
PHP_MINIT_FUNCTION(sockets);
|
||||
PHP_MSHUTDOWN_FUNCTION(sockets);
|
||||
PHP_RINIT_FUNCTION(sockets);
|
||||
PHP_RSHUTDOWN_FUNCTION(sockets);
|
||||
PHP_MINFO_FUNCTION(sockets);
|
||||
|
||||
PHP_FUNCTION(confirm_sockets_compiled); /* For testing, remove later. */
|
||||
PHP_FUNCTION(confirm_sockets_compiled);
|
||||
PHP_FUNCTION(fd_alloc);
|
||||
PHP_FUNCTION(fd_dealloc);
|
||||
PHP_FUNCTION(fd_set);
|
||||
PHP_FUNCTION(fd_isset);
|
||||
PHP_FUNCTION(fd_clear);
|
||||
PHP_FUNCTION(fd_zero);
|
||||
PHP_FUNCTION(select);
|
||||
PHP_FUNCTION(open_listen_sok);
|
||||
PHP_FUNCTION(accept_connect);
|
||||
PHP_FUNCTION(set_nonblock);
|
||||
PHP_FUNCTION(listen);
|
||||
PHP_FUNCTION(close);
|
||||
PHP_FUNCTION(write);
|
||||
PHP_FUNCTION(read);
|
||||
PHP_FUNCTION(signal);
|
||||
PHP_FUNCTION(getsockname);
|
||||
PHP_FUNCTION(getpeername);
|
||||
PHP_FUNCTION(socket);
|
||||
PHP_FUNCTION(connect);
|
||||
PHP_FUNCTION(strerror);
|
||||
PHP_FUNCTION(bind);
|
||||
|
||||
/* Fill in this structure and use entries in it
|
||||
for thread safety instead of using true globals.
|
||||
*/
|
||||
typedef struct {
|
||||
/* You can use the next one as type if your module registers any
|
||||
resources. Oh, you can of course rename it to something more
|
||||
suitable, add list entry types or remove it if it not needed.
|
||||
It's just an example.
|
||||
*/
|
||||
int le_sockets;
|
||||
} php_sockets_globals;
|
||||
|
||||
/* In every function that needs to use variables in php_sockets_globals,
|
||||
do call SOCKETSLS_FETCH(); after declaring other variables used by
|
||||
that function, and always refer to them as SOCKETSG(variable).
|
||||
You are encouraged to rename these macros something shorter, see
|
||||
examples in any other php module directory.
|
||||
*/
|
||||
|
||||
#ifdef ZTS
|
||||
#define SOCKETSG(v) (sockets_globals->v)
|
||||
#define SOCKETSLS_FETCH() php_sockets_globals *sockets_globals = ts_resource(gd_sockets_id)
|
||||
#else
|
||||
#define SOCKETSG(v) (sockets_globals.v)
|
||||
#define SOCKETSLS_FETCH()
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#define phpext_sockets_ptr NULL
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _PHP_SOCKETS_H */
|
||||
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* tab-width: 4
|
||||
* c-basic-offset: 4
|
||||
* End:
|
||||
*/
|
955
ext/sockets/sockets.c
Normal file
955
ext/sockets/sockets.c
Normal file
|
@ -0,0 +1,955 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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)
|
||||
Allocate a file descriptor set
|
||||
*/
|
||||
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)
|
||||
De-allocate a file descriptor set
|
||||
** BUG: This is currently a no-op!
|
||||
*/
|
||||
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)
|
||||
Clear a file descriptor from a set
|
||||
*/
|
||||
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)
|
||||
Check to see if a file descriptor is set within the file descrirptor set */
|
||||
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)
|
||||
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.
|
||||
|
||||
From man page:
|
||||
select waits for a number of file descriptors to change status.
|
||||
|
||||
Three independent sets of descriptors are watched. Those in readfds will be watched to see if charac-
|
||||
ters 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.
|
||||
|
||||
-1 is passed for any sets for which NULL would be passed to the system call.
|
||||
*/
|
||||
|
||||
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)
|
||||
accepts a connection on the listening socket fd
|
||||
*/
|
||||
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)
|
||||
sets nonblocking mode for file descriptor fd
|
||||
*/
|
||||
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)
|
||||
sets the maximum number of connections allowed to be waited for on
|
||||
the socket specified by fd */
|
||||
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)
|
||||
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. */
|
||||
|
||||
/* 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)
|
||||
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. */
|
||||
|
||||
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)
|
||||
Creates an endpoint for communication in the domain specified by domain, of type specified by type
|
||||
*/
|
||||
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;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto long bind(long sockfd, string domain, ...)
|
||||
Binds an open socket to a listening port
|
||||
-- domain = "af_unix", 3rd arg is path to socket
|
||||
-- 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:
|
||||
*/
|
10
ext/sockets/sockets.php
Normal file
10
ext/sockets/sockets.php
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?
|
||||
$module = 'sockets';
|
||||
$function = 'confirm_' . $module . '_compiled';
|
||||
if (extension_loaded($module)) {
|
||||
$str = $function($module);
|
||||
} else {
|
||||
$str = "Module $module is not compiled in PHP";
|
||||
}
|
||||
echo "$str\n";
|
||||
?>
|
Loading…
Add table
Add a link
Reference in a new issue