📄 sockets.c
字号:
/* +----------------------------------------------------------------------+ | PHP Version 4 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2007 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.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> | | Sterling Hughes <sterling@php.net> | | Jason Greene <jason@php.net> | | WinSock: Daniel Beulshausen <daniel@php4win.de> | +----------------------------------------------------------------------+ *//* $Id: sockets.c,v 1.125.2.29.2.7 2007/01/01 09:46:47 sebastian Exp $ */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include "php.h"#if HAVE_SOCKETS#ifndef _XOPEN_SOURCE_EXTENDED#define _XOPEN_SOURCE_EXTENDED#endif#define _XPG4_2#define __EXTENSIONS__#include "php_network.h"#include "ext/standard/info.h"#include "php_ini.h"#ifndef PHP_WIN32# 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># include <sys/uio.h># define IS_INVALID_SOCKET(a) (a->bsd_socket < 0)# define set_errno(a) (errno = a)# ifdef HAVE_SET_H_ERRNO# define SET_H_ERRNO(newval) set_h_errno(newval)# else# define SET_H_ERRNO(newval) h_errno = (newval)# endif#else /* windows */# include "php_sockets.h"# include "php_sockets_win.h"# define IS_INVALID_SOCKET(a) (a->bsd_socket == INVALID_SOCKET)#endifZEND_DECLARE_MODULE_GLOBALS(sockets)#ifndef MSG_WAITALL#ifdef LINUX#define MSG_WAITALL 0x00000100#else#define MSG_WAITALL 0x00000000#endif#endif#ifndef SUN_LEN#define SUN_LEN(su) (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))#endif#ifndef PF_INET#define PF_INET AF_INET#endifstatic char *php_strerror(int error TSRMLS_DC);#define PHP_NORMAL_READ 0x0001#define PHP_BINARY_READ 0x0002#define PHP_SOCKET_ERROR(socket,msg,errn) socket->error = errn; \ SOCKETS_G(last_error) = errn; \ php_error(E_WARNING, "%s() %s [%d]: %s", \ get_active_function_name(TSRMLS_C), msg, errn, php_strerror(errn TSRMLS_CC))static int le_iov;#define le_iov_name "Socket I/O vector"static int le_socket;#define le_socket_name "Socket"static unsigned char first_through_third_args_force_ref[] ={3, BYREF_FORCE, BYREF_FORCE, BYREF_FORCE};static unsigned char second_and_third_args_force_ref[] ={3, BYREF_NONE, BYREF_FORCE, BYREF_FORCE};static unsigned char second_arg_of_four_force_ref[] ={4, BYREF_NONE, BYREF_FORCE, BYREF_NONE, BYREF_NONE};static unsigned char fourth_arg_force_ref[] ={4, BYREF_NONE, BYREF_NONE, BYREF_NONE, BYREF_FORCE};static unsigned char second_fifth_and_sixth_args_force_ref[] ={6, BYREF_NONE, BYREF_FORCE, BYREF_NONE, BYREF_NONE, BYREF_FORCE, BYREF_FORCE};static unsigned char third_through_seventh_args_force_ref[] ={7, BYREF_NONE, BYREF_NONE, BYREF_FORCE, BYREF_FORCE, BYREF_FORCE, BYREF_FORCE, BYREF_FORCE};/* {{{ sockets_functions[] */function_entry sockets_functions[] = { PHP_FE(socket_iovec_alloc, NULL) PHP_FE(socket_iovec_free, NULL) PHP_FE(socket_iovec_set, NULL) PHP_FE(socket_iovec_fetch, NULL) PHP_FE(socket_iovec_add, NULL) PHP_FE(socket_iovec_delete, NULL) PHP_FE(socket_select, first_through_third_args_force_ref) PHP_FE(socket_create, NULL) PHP_FE(socket_create_listen, NULL) PHP_FE(socket_create_pair, fourth_arg_force_ref) PHP_FE(socket_accept, NULL) PHP_FE(socket_set_nonblock, NULL) PHP_FE(socket_set_block, NULL) PHP_FE(socket_listen, NULL) PHP_FE(socket_close, NULL) PHP_FE(socket_write, NULL) PHP_FE(socket_read, NULL) PHP_FE(socket_getsockname, second_and_third_args_force_ref) PHP_FE(socket_getpeername, second_and_third_args_force_ref) PHP_FE(socket_connect, NULL) PHP_FE(socket_strerror, NULL) PHP_FE(socket_bind, NULL) PHP_FE(socket_recv, second_arg_of_four_force_ref) PHP_FE(socket_send, NULL) PHP_FE(socket_recvfrom, second_fifth_and_sixth_args_force_ref) PHP_FE(socket_sendto, NULL)#ifdef HAVE_CMSGHDR PHP_FE(socket_recvmsg, third_through_seventh_args_force_ref)#endif PHP_FE(socket_sendmsg, NULL) PHP_FE(socket_readv, NULL) PHP_FE(socket_writev, NULL) PHP_FE(socket_get_option, NULL) PHP_FE(socket_set_option, NULL) PHP_FE(socket_shutdown, NULL) PHP_FE(socket_last_error, NULL) PHP_FE(socket_clear_error, NULL) /* for downwards compatability */ PHP_FALIAS(socket_getopt, socket_get_option, NULL) PHP_FALIAS(socket_setopt, socket_set_option, NULL) {NULL, NULL, NULL}};/* }}} */zend_module_entry sockets_module_entry = { STANDARD_MODULE_HEADER, "sockets", sockets_functions, PHP_MINIT(sockets), NULL, PHP_RINIT(sockets), PHP_RSHUTDOWN(sockets), PHP_MINFO(sockets), NO_VERSION_YET, STANDARD_MODULE_PROPERTIES};#ifdef COMPILE_DL_SOCKETSZEND_GET_MODULE(sockets)#endif/* inet_ntop should be used instead of inet_ntoa */int inet_ntoa_lock = 0;static void php_destroy_iovec(zend_rsrc_list_entry *rsrc TSRMLS_DC){ unsigned int i; php_iovec_t *iov = (php_iovec_t *) rsrc->ptr; if (iov->count && iov->iov_array) { for (i = 0; i < iov->count; i++) { efree(iov->iov_array[i].iov_base); } efree(iov->iov_array); efree(iov); }}static void php_destroy_socket(zend_rsrc_list_entry *rsrc TSRMLS_DC){ php_socket *php_sock = (php_socket *) rsrc->ptr; close(php_sock->bsd_socket); efree(php_sock);}static int php_open_listen_sock(php_socket **php_sock, int port, int backlog TSRMLS_DC){ struct sockaddr_in la; struct hostent *hp; php_socket *sock = (php_socket*)emalloc(sizeof(php_socket)); *php_sock = sock;#ifndef PHP_WIN32 if ((hp = gethostbyname("0.0.0.0")) == NULL) {#else if ((hp = gethostbyname("localhost")) == NULL) {#endif efree(sock); return 0; } memcpy((char *) &la.sin_addr, hp->h_addr, hp->h_length); la.sin_family = hp->h_addrtype; la.sin_port = htons((unsigned short) port); sock->bsd_socket = socket(PF_INET, SOCK_STREAM, 0); if (IS_INVALID_SOCKET(sock)) { PHP_SOCKET_ERROR(sock, "unable to create listening socket", errno); efree(sock); return 0; } sock->type = PF_INET; if (bind(sock->bsd_socket, (struct sockaddr *)&la, sizeof(la)) < 0) { PHP_SOCKET_ERROR(sock, "unable to bind to given adress", errno); close(sock->bsd_socket); efree(sock); return 0; } if (listen(sock->bsd_socket, backlog) < 0) { PHP_SOCKET_ERROR(sock, "unable to listen on socket", errno); close(sock->bsd_socket); efree(sock); return 0; } return 1;}static int php_accept_connect(php_socket *in_sock, php_socket **new_sock, struct sockaddr *la TSRMLS_DC){ socklen_t salen; php_socket *out_sock = (php_socket*)emalloc(sizeof(php_socket)); *new_sock = out_sock; salen = sizeof(*la); out_sock->bsd_socket = accept(in_sock->bsd_socket, la, &salen); if (IS_INVALID_SOCKET(out_sock)) { PHP_SOCKET_ERROR(out_sock, "unable to accept incoming connection", errno); efree(out_sock); return 0; } return 1;}/* {{{ php_read -- wrapper around read() so that it only reads to a \r or \n. */static int php_read(int bsd_socket, void *buf, size_t maxlen, int flags){ int m = 0; size_t n = 0; int no_read = 0; int nonblock = 0; char *t = (char *) buf; m = fcntl(bsd_socket, F_GETFL); if (m < 0) { return m; } nonblock = (m & O_NONBLOCK); m = 0; set_errno(0); *t = '\0'; while (*t != '\n' && *t != '\r' && n < maxlen) { if (m > 0) { t++; n++; } else if (m == 0) { no_read++; if (nonblock && no_read >= 2) { return n; /* The first pass, m always is 0, so no_read becomes 1 * in the first pass. no_read becomes 2 in the second pass, * and if this is nonblocking, we should return.. */ } if (no_read > 200) { set_errno(ECONNRESET); return -1; } } if (n < maxlen) { m = recv(bsd_socket, (void *) t, 1, flags); } if (errno != 0 && errno != ESPIPE && errno != EAGAIN) { return -1; } set_errno(0); } if (n < maxlen) { n++; /* The only reasons it makes it to here is * if '\n' or '\r' are encountered. So, increase * the return by 1 to make up for the lack of the * '\n' or '\r' in the count (since read() takes * place at the end of the loop..) */ } return n;}/* }}} */static char *php_strerror(int error TSRMLS_DC){ const char *buf;#ifndef PHP_WIN32 if (error < -10000) { error = -error - 10000;#ifdef HAVE_HSTRERROR buf = hstrerror(error);#else { if (SOCKETS_G(strerror_buf)) { efree(SOCKETS_G(strerror_buf)); } spprintf(&(SOCKETS_G(strerror_buf)), 0, "Host lookup error %d", error); buf = SOCKETS_G(strerror_buf); }#endif } else { buf = strerror(error); }#else { LPTSTR tmp = NULL; buf = NULL; if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &tmp, 0, NULL)) { if (SOCKETS_G(strerror_buf)) { efree(SOCKETS_G(strerror_buf)); } SOCKETS_G(strerror_buf) = estrdup(tmp); LocalFree(tmp); buf = SOCKETS_G(strerror_buf); } }#endif return (buf ? (char *) buf : "");}/* Sets addr by hostname, or by ip in string form (AF_INET) */static int php_set_inet_addr(struct sockaddr_in *sin, char *string, php_socket *php_sock TSRMLS_DC){ struct in_addr tmp; struct hostent *host_entry; if (inet_aton(string, &tmp)) { sin->sin_addr.s_addr = tmp.s_addr; } else { if (! (host_entry = gethostbyname(string))) { /* Note: < -10000 indicates a host lookup error */#ifdef PHP_WIN32 PHP_SOCKET_ERROR(php_sock, "Host lookup failed", WSAGetLastError());#else PHP_SOCKET_ERROR(php_sock, "Host lookup failed", (-10000 - h_errno));#endif return 0; } if (host_entry->h_addrtype != AF_INET) { php_error(E_WARNING, "%s() Host lookup failed: Non AF_INET domain returned on AF_INET socket", get_active_function_name(TSRMLS_C)); return 0; } memcpy(&(sin->sin_addr.s_addr), host_entry->h_addr_list[0], host_entry->h_length); } return 1;}static void php_sockets_init_globals(zend_sockets_globals *sockets_globals TSRMLS_DC){ sockets_globals->last_error = 0; sockets_globals->strerror_buf = NULL;}/* {{{ PHP_MINIT_FUNCTION */PHP_MINIT_FUNCTION(sockets){ struct protoent *pe; ZEND_INIT_MODULE_GLOBALS(sockets, php_sockets_init_globals, NULL); le_socket = zend_register_list_destructors_ex(php_destroy_socket, NULL, le_socket_name, module_number); le_iov = zend_register_list_destructors_ex(php_destroy_iovec, NULL, le_iov_name, module_number); REGISTER_LONG_CONSTANT("AF_UNIX", AF_UNIX, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("AF_INET", AF_INET, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SOCK_STREAM", SOCK_STREAM, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SOCK_DGRAM", SOCK_DGRAM, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SOCK_RAW", SOCK_RAW, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SOCK_SEQPACKET",SOCK_SEQPACKET, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SOCK_RDM", SOCK_RDM, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("MSG_OOB", MSG_OOB, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("MSG_WAITALL", MSG_WAITALL, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("MSG_PEEK", MSG_PEEK, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("MSG_DONTROUTE", MSG_DONTROUTE, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SO_DEBUG", SO_DEBUG, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SO_REUSEADDR", SO_REUSEADDR, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SO_KEEPALIVE", SO_KEEPALIVE, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SO_DONTROUTE", SO_DONTROUTE, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SO_LINGER", SO_LINGER, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SO_BROADCAST", SO_BROADCAST, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SO_OOBINLINE", SO_OOBINLINE, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SO_SNDBUF", SO_SNDBUF, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SO_RCVBUF", SO_RCVBUF, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SO_SNDLOWAT", SO_SNDLOWAT, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SO_RCVLOWAT", SO_RCVLOWAT, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SO_SNDTIMEO", SO_SNDTIMEO, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SO_RCVTIMEO", SO_RCVTIMEO, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SO_TYPE", SO_TYPE, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SO_ERROR", SO_ERROR, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SOL_SOCKET", SOL_SOCKET, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SOMAXCONN", SOMAXCONN, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PHP_NORMAL_READ", PHP_NORMAL_READ, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PHP_BINARY_READ", PHP_BINARY_READ, CONST_CS | CONST_PERSISTENT);#ifndef WIN32# include "unix_socket_constants.h"#else# include "win32_socket_constants.h"#endif if ((pe = getprotobyname("tcp"))) { REGISTER_LONG_CONSTANT("SOL_TCP", pe->p_proto, CONST_CS | CONST_PERSISTENT); } if ((pe = getprotobyname("udp"))) { REGISTER_LONG_CONSTANT("SOL_UDP", pe->p_proto, CONST_CS | CONST_PERSISTENT); } return SUCCESS;}/* }}} *//* {{{ PHP_MINFO_FUNCTION */PHP_MINFO_FUNCTION(sockets){ php_info_print_table_start(); php_info_print_table_row(2, "Sockets Support", "enabled"); php_info_print_table_end();}/* }}} *//* {{{ PHP_RINIT_FUNCTION */PHP_RINIT_FUNCTION(sockets){ return SUCCESS;}/* }}} *//* {{{ PHP_RSHUTDOWN_FUNCTION */PHP_RSHUTDOWN_FUNCTION(sockets){ if (SOCKETS_G(strerror_buf)) { efree(SOCKETS_G(strerror_buf)); SOCKETS_G(strerror_buf) = NULL; } return SUCCESS;}/* }}} */ int php_sock_array_to_fd_set(zval *sock_array, fd_set *fds, SOCKET *max_fd TSRMLS_DC) { zval **element; php_socket *php_sock; int num = 0; if (Z_TYPE_P(sock_array) != IS_ARRAY) return 0; for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(sock_array)); zend_hash_get_current_data(Z_ARRVAL_P(sock_array), (void **) &element) == SUCCESS; zend_hash_move_forward(Z_ARRVAL_P(sock_array))) { php_sock = (php_socket*) zend_fetch_resource(element TSRMLS_CC, -1, le_socket_name, NULL, 1, le_socket); if (!php_sock) continue; /* If element is not a resource, skip it */ FD_SET(php_sock->bsd_socket, fds); if (php_sock->bsd_socket > *max_fd) { *max_fd = php_sock->bsd_socket; } num++; } return num ? 1 : 0;}int php_sock_array_from_fd_set(zval *sock_array, fd_set *fds TSRMLS_DC) { zval **element; zval **dest_element; php_socket *php_sock;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -