📄 sockets.c
字号:
HashTable *new_hash; int num = 0; if (Z_TYPE_P(sock_array) != IS_ARRAY) return 0; ALLOC_HASHTABLE(new_hash); zend_hash_init(new_hash, 0, NULL, ZVAL_PTR_DTOR, 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 */ if (FD_ISSET(php_sock->bsd_socket, fds)) { /* Add fd to new array */ zend_hash_next_index_insert(new_hash, (void *)element, sizeof(zval *), (void **)&dest_element); if (dest_element) zval_add_ref(dest_element); } num++; } /* Destroy old array, add new one */ zend_hash_destroy(Z_ARRVAL_P(sock_array)); efree(Z_ARRVAL_P(sock_array)); zend_hash_internal_pointer_reset(new_hash); Z_ARRVAL_P(sock_array) = new_hash; return num ? 1 : 0;}/* {{{ proto int socket_select(array &read_fds, array &write_fds, &array except_fds, int tv_sec[, int tv_usec]) Runs the select() system call on the sets mentioned with a timeout specified by tv_sec and tv_usec */PHP_FUNCTION(socket_select){ zval *r_array, *w_array, *e_array, *sec; struct timeval tv; struct timeval *tv_p = NULL; fd_set rfds, wfds, efds; SOCKET max_fd = 0; int retval, sets = 0; long usec = 0; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a!a!a!z!|l", &r_array, &w_array, &e_array, &sec, &usec) == FAILURE) return; FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); if (r_array != NULL) sets += php_sock_array_to_fd_set(r_array, &rfds, &max_fd TSRMLS_CC); if (w_array != NULL) sets += php_sock_array_to_fd_set(w_array, &wfds, &max_fd TSRMLS_CC); if (e_array != NULL) sets += php_sock_array_to_fd_set(e_array, &efds, &max_fd TSRMLS_CC); if (!sets) { php_error(E_WARNING, "%s() no resource arrays were passed to select", get_active_function_name(TSRMLS_C)); RETURN_FALSE; } /* If seconds is not set to null, build the timeval, else we wait indefinitely */ if (sec != NULL) { zval tmp; if (Z_TYPE_P(sec) != IS_LONG) { tmp = *sec; zval_copy_ctor(&tmp); convert_to_long(&tmp); sec = &tmp; } /* Solaris + BSD do not like microsecond values which are >= 1 sec */ if (usec > 999999) { tv.tv_sec = Z_LVAL_P(sec) + (usec / 1000000); tv.tv_usec = usec % 1000000; } else { tv.tv_sec = Z_LVAL_P(sec); tv.tv_usec = usec; } tv_p = &tv; if (sec == &tmp) { zval_dtor(&tmp); } } retval = select(max_fd+1, &rfds, &wfds, &efds, tv_p); if (retval == -1) { SOCKETS_G(last_error) = errno; php_error(E_WARNING, "%s() %s [%d]: %s", get_active_function_name(TSRMLS_C), "unable to select", errno, php_strerror(errno TSRMLS_CC)); RETURN_FALSE; } if (r_array != NULL) php_sock_array_from_fd_set(r_array, &rfds TSRMLS_CC); if (w_array != NULL) php_sock_array_from_fd_set(w_array, &wfds TSRMLS_CC); if (e_array != NULL) php_sock_array_from_fd_set(e_array, &efds TSRMLS_CC); RETURN_LONG(retval);}/* }}} *//* {{{ proto resource socket_create_listen(int port[, int backlog]) Opens a socket on port to accept connections */PHP_FUNCTION(socket_create_listen){ php_socket *php_sock; long port, backlog = 128; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|l", &port, &backlog) == FAILURE) return; if (!php_open_listen_sock(&php_sock, port, backlog TSRMLS_CC)) { RETURN_FALSE; } php_sock->error = 0; ZEND_REGISTER_RESOURCE(return_value, php_sock, le_socket);}/* }}} *//* {{{ proto resource socket_accept(resource socket) Accepts a connection on the listening socket fd */PHP_FUNCTION(socket_accept){ zval *arg1; php_socket *php_sock, *new_sock; struct sockaddr_in sa; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &arg1) == FAILURE) return; ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket); if (!php_accept_connect(php_sock, &new_sock, (struct sockaddr *) &sa TSRMLS_CC)) { RETURN_FALSE; } new_sock->error = 0; ZEND_REGISTER_RESOURCE(return_value, new_sock, le_socket);}/* }}} *//* {{{ proto bool socket_set_nonblock(resource socket) Sets nonblocking mode on a socket resource */PHP_FUNCTION(socket_set_nonblock){ zval *arg1; php_socket *php_sock; int flags; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &arg1) == FAILURE) return; ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket); flags = fcntl(php_sock->bsd_socket, F_GETFL); /* Safely append non blocking to other flags unless the get fails. * Note: This does not abort on failure becuse getfl will always fail * under the current win32 code. */ if (flags > -1) flags |= O_NONBLOCK; else flags = O_NONBLOCK; if (fcntl(php_sock->bsd_socket, F_SETFL, flags) > -1) { RETURN_TRUE; } RETURN_FALSE;}/* }}} *//* {{{ proto bool socket_set_block(resource socket) Sets blocking mode on a socket resource */PHP_FUNCTION(socket_set_block){ zval *arg1; php_socket *php_sock; int flags; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &arg1) == FAILURE) return; ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket); flags = fcntl(php_sock->bsd_socket, F_GETFL); /* Safely remove blocking from flags unless the get fails. * Note: This does not abort on failure becuse getfl will always fail * under the current win32 code. */ if (flags > -1) flags &= ~O_NONBLOCK; else flags = 0; if (fcntl(php_sock->bsd_socket, F_SETFL, flags) > -1) { RETURN_TRUE; } RETURN_FALSE;}/* }}} *//* {{{ proto bool socket_listen(resource socket[, int backlog]) Sets the maximum number of connections allowed to be waited for on the socket specified by fd */PHP_FUNCTION(socket_listen){ zval *arg1; php_socket *php_sock; long backlog = 0; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &arg1, &backlog) == FAILURE) return; ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket); if (listen(php_sock->bsd_socket, backlog) != 0) { PHP_SOCKET_ERROR(php_sock, "unable to listen on socket", errno); RETURN_FALSE; } RETURN_TRUE;}/* }}} *//* {{{ proto void socket_close(resource socket) Closes a file descriptor */PHP_FUNCTION(socket_close){ zval *arg1; php_socket *php_sock; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &arg1) == FAILURE) return; ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket); zend_list_delete(Z_RESVAL_P(arg1));}/* }}} *//* {{{ proto int socket_write(resource socket, string buf[, int length]) Writes the buffer to the socket resource, length is optional */PHP_FUNCTION(socket_write){ zval *arg1; php_socket *php_sock; int retval, str_len; long length; char *str; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|l", &arg1, &str, &str_len, &length) == FAILURE) return; ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket); if (ZEND_NUM_ARGS() < 3) { length = str_len; }#ifndef PHP_WIN32 retval = write(php_sock->bsd_socket, str, MIN(length, str_len));#else retval = send(php_sock->bsd_socket, str, min(length, str_len), 0);#endif if (retval < 0) { PHP_SOCKET_ERROR(php_sock, "unable to write to socket", errno); RETURN_FALSE; } RETURN_LONG(retval);}/* }}} *//* {{{ proto string socket_read(resource socket, int length [, int type]) Reads a maximum of length bytes from socket */PHP_FUNCTION(socket_read){ zval *arg1; php_socket *php_sock; char *tmpbuf; int retval; long length, type = PHP_BINARY_READ; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl|l", &arg1, &length, &type) == FAILURE) return; /* overflow check */ if((length + 1) < 2) { RETURN_FALSE; } tmpbuf = emalloc(length + 1); ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket); if (type == PHP_NORMAL_READ) { retval = php_read(php_sock->bsd_socket, tmpbuf, length, 0); } else { retval = recv(php_sock->bsd_socket, tmpbuf, length, 0); } if (retval == -1) { /* if the socket is in non-blocking mode and there's no data to read, don't output any error, as this is a normal situation, and not an error */ if (errno == EAGAIN#ifdef EWOULDBLOCK || errno == EWOULDBLOCK#endif ) { php_sock->error = errno; SOCKETS_G(last_error) = errno; } else { PHP_SOCKET_ERROR(php_sock, "unable to read from socket", errno); } efree(tmpbuf); RETURN_FALSE; } tmpbuf = erealloc(tmpbuf, retval + 1); tmpbuf[ retval ] = '\0' ; RETURN_STRINGL(tmpbuf, retval, 0);}/* }}} *//* {{{ proto bool socket_getsockname(resource socket, string &addr[, int &port]) Queries the remote side of the given socket which may either result in host/port or in a UNIX filesystem path, dependent on its type. */PHP_FUNCTION(socket_getsockname){ zval *arg1, *addr, *port = NULL; php_sockaddr_storage sa_storage; php_socket *php_sock; struct sockaddr *sa; struct sockaddr_in *sin; struct sockaddr_un *s_un; char *addr_string; socklen_t salen = sizeof(php_sockaddr_storage); if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz|z", &arg1, &addr, &port) == FAILURE) return; ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket); sa = (struct sockaddr *) &sa_storage; if (getsockname(php_sock->bsd_socket, sa, &salen) != 0) { PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket name", errno); RETURN_FALSE; } switch (sa->sa_family) { case AF_INET: sin = (struct sockaddr_in *) sa; while (inet_ntoa_lock == 1); inet_ntoa_lock = 1; addr_string = inet_ntoa(sin->sin_addr); inet_ntoa_lock = 0; zval_dtor(addr); ZVAL_STRING(addr, addr_string, 1); if (port != NULL) { zval_dtor(port); ZVAL_LONG(port, htons(sin->sin_port)); } RETURN_TRUE; case AF_UNIX: s_un = (struct sockaddr_un *) sa; zval_dtor(addr); ZVAL_STRING(addr, s_un->sun_path, 1); RETURN_TRUE; default: php_error(E_WARNING, "%s() Unsupported address family %d", get_active_function_name(TSRMLS_C), sa->sa_family); RETURN_FALSE; }}/* }}} *//* {{{ proto bool socket_getpeername(resource socket, string &addr[, int &port]) Queries the remote side of the given socket which may either result in host/port or in a UNIX filesystem path, dependent on its type. */PHP_FUNCTION(socket_getpeername){ zval *arg1, *arg2, *arg3 = NULL; php_sockaddr_storage sa_storage; php_socket *php_sock; struct sockaddr *sa; struct sockaddr_in *sin; struct sockaddr_un *s_un; char *addr_string; socklen_t salen = sizeof(php_sockaddr_storage); if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz|z", &arg1, &arg2, &arg3) == FAILURE) return; ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket); sa = (struct sockaddr *) &sa_storage; if (getpeername(php_sock->bsd_socket, sa, &salen) < 0) { PHP_SOCKET_ERROR(php_sock, "unable to retrieve peer name", errno); RETURN_FALSE; } switch (sa->sa_family) { case AF_INET: sin = (struct sockaddr_in *) sa; while (inet_ntoa_lock == 1); inet_ntoa_lock = 1; addr_string = inet_ntoa(sin->sin_addr); inet_ntoa_lock = 0; zval_dtor(arg2); ZVAL_STRING(arg2, addr_string, 1); if (arg3 != NULL) { zval_dtor(arg3); ZVAL_LONG(arg3, htons(sin->sin_port)); } RETURN_TRUE; case AF_UNIX: s_un = (struct sockaddr_un *) sa; zval_dtor(arg2); ZVAL_STRING(arg2, s_un->sun_path, 1); RETURN_TRUE; default: php_error(E_WARNING, "%s() Unsupported address family %d", get_active_function_name(TSRMLS_C), sa->sa_family); RETURN_FALSE; }}/* }}} *//* {{{ proto resource socket_create(int domain, int type, int protocol) Creates an endpoint for communication in the domain specified by domain, of type specified by type */PHP_FUNCTION(socket_create){ long arg1, arg2, arg3; php_socket *php_sock = (php_socket*)emalloc(sizeof(php_socket)); if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lll", &arg1, &arg2, &arg3) == FAILURE) { efree(php_sock); return; } if (arg1 != AF_UNIX && arg1 != AF_INET) { php_error(E_WARNING, "%s() invalid socket domain [%ld] specified for argument 1, assuming AF_INET", get_active_function_name(TSRMLS_C), arg1); arg1 = AF_INET; } if (arg2 > 10) { php_error(E_WARNING, "%s() invalid socket type [%ld] specified for argument 2, assuming SOCK_STREAM", get_active_function_name(TSRMLS_C), arg2); arg2 = SOCK_STREAM; } php_sock->bsd_socket = socket(arg1, arg2, arg3); php_sock->type = arg1; if (IS_INVALID_SOCKET(php_sock)) { SOCKETS_G(last_error) = errno; php_error(E_WARNING, "%s() Unable to create socket [%d]: %s", get_active_function_name(TSRMLS_C), errno, php_strerror(errno TSRMLS_CC)); efree(php_sock); RETURN_FALSE; } php_sock->error = 0; ZEND_REGISTER_RESOURCE(return_value, php_sock, le_socket);}/* }}} *//* {{{ proto bool socket_connect(resource socket, string addr [, int port]) Opens a connection to addr:port on the socket specified by socket */PHP_FUNCTION(socket_connect){ zval *arg1; php_socket *php_sock; struct sockaddr_in sin; struct sockaddr_un s_un; char *addr; int retval, addr_len; long port; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|l", &arg1, &addr, &addr_len, &port) == FAILURE) return; ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket); switch(php_sock->type) { case AF_INET: if (ZEND_NUM_ARGS() != 3) { php_error(E_WARNING, "%s() Socket of type AF_INET requires 3 arguments", get_active_function_name(TSRMLS_C)); RETURN_FALSE; } sin.sin_family = AF_INET; sin.sin_port = htons((unsigned short int)port); if (! php_set_inet_addr(&sin, addr, php_sock TSRMLS_CC)) { RETURN_FALSE; } retval = connect(php_sock->bsd_socket, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)); break; case AF_UNIX: s_un.sun_family = AF_UNIX; snprintf(s_un.sun_path, 108, "%s", addr); retval = connect(php_sock->bsd_socket, (struct sockaddr *) &s_un, SUN_LEN(&s_un)); break; default: php_error(E_WARNING, "%s() Unsupported socket type %d", get_active_function_name(TSRMLS_C), php_sock->type); RETURN_FALSE; } if (retval != 0) { PHP_SOCKET_ERROR(php_sock, "unable to connect", errno); RETURN_FALSE; } RETURN_TRUE;}/* }}} *//* {{{ proto string socket_strerror(int errno) Returns a string describing an error */PHP_FUNCTION(socket_strerror){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -