summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
authorChris Vandomelen <chrisv@php.net>2000-07-03 04:35:57 +0000
committerChris Vandomelen <chrisv@php.net>2000-07-03 04:35:57 +0000
commit21abde5ca18f087173f986c6b5c2647e90962648 (patch)
tree627f942064bc1fcf95428c9743deca3e33804b8b /ext
parent7a4d4bcd6ba6da60252f77ab01588e5ec5c54a09 (diff)
downloadphp-git-21abde5ca18f087173f986c6b5c2647e90962648.tar.gz
* Makefile.in
config.m4 php_sockets.h sockets.c sockets.php: - Added files needed for Unix-style sockets support in PHP.
Diffstat (limited to 'ext')
-rw-r--r--ext/sockets/Makefile.in7
-rw-r--r--ext/sockets/config.m438
-rw-r--r--ext/sockets/php_sockets.h110
-rw-r--r--ext/sockets/sockets.c955
-rw-r--r--ext/sockets/sockets.php10
5 files changed, 1120 insertions, 0 deletions
diff --git a/ext/sockets/Makefile.in b/ext/sockets/Makefile.in
new file mode 100644
index 0000000000..acfca2cd39
--- /dev/null
+++ b/ext/sockets/Makefile.in
@@ -0,0 +1,7 @@
+# $Id$
+
+LTLIBRARY_NAME = libsockets.la
+LTLIBRARY_SOURCES = sockets.c
+LTLIBRARY_SHARED_NAME = sockets.la
+
+include $(top_srcdir)/build/dynlib.mk
diff --git a/ext/sockets/config.m4 b/ext/sockets/config.m4
new file mode 100644
index 0000000000..8fcb0d610c
--- /dev/null
+++ b/ext/sockets/config.m4
@@ -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
diff --git a/ext/sockets/php_sockets.h b/ext/sockets/php_sockets.h
new file mode 100644
index 0000000000..adea0f7498
--- /dev/null
+++ b/ext/sockets/php_sockets.h
@@ -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:
+ */
diff --git a/ext/sockets/sockets.c b/ext/sockets/sockets.c
new file mode 100644
index 0000000000..27966340e2
--- /dev/null
+++ b/ext/sockets/sockets.c
@@ -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:
+ */
diff --git a/ext/sockets/sockets.php b/ext/sockets/sockets.php
new file mode 100644
index 0000000000..3bb624cd57
--- /dev/null
+++ b/ext/sockets/sockets.php
@@ -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";
+?>