]> granicus.if.org Git - php/commitdiff
* Makefile.in
authorChris Vandomelen <chrisv@php.net>
Mon, 3 Jul 2000 04:35:57 +0000 (04:35 +0000)
committerChris Vandomelen <chrisv@php.net>
Mon, 3 Jul 2000 04:35:57 +0000 (04:35 +0000)
  config.m4
  php_sockets.h
  sockets.c
  sockets.php:
  - Added files needed for Unix-style sockets support in PHP.

ext/sockets/Makefile.in [new file with mode: 0644]
ext/sockets/config.m4 [new file with mode: 0644]
ext/sockets/php_sockets.h [new file with mode: 0644]
ext/sockets/sockets.c [new file with mode: 0644]
ext/sockets/sockets.php [new file with mode: 0644]

diff --git a/ext/sockets/Makefile.in b/ext/sockets/Makefile.in
new file mode 100644 (file)
index 0000000..acfca2c
--- /dev/null
@@ -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 (file)
index 0000000..8fcb0d6
--- /dev/null
@@ -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 (file)
index 0000000..adea0f7
--- /dev/null
@@ -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 (file)
index 0000000..2796634
--- /dev/null
@@ -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 (file)
index 0000000..3bb624c
--- /dev/null
@@ -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";
+?>