📄 sockets.c
字号:
struct sockaddr_in *sin = (struct sockaddr_in *) sa; struct sockaddr_un *s_un = (struct sockaddr_un *) sa; socklen_t salen = sizeof(sa_storage); if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rrzzzz|z", &arg1, &arg2, &arg3, &arg4, &arg5, &arg6, &arg7) == FAILURE) return; if(Z_LVAL_P(arg4)<0) RETURN_FALSE; ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket); ZEND_FETCH_RESOURCE(iov, php_iovec_t *, &arg2, -1, le_iov_name, le_iov); if (getsockname(php_sock->bsd_socket, sa, &salen) != 0) { PHP_SOCKET_ERROR(php_sock, "unable to receive message", errno); RETURN_FALSE; } ctl_buf = (Z_LVAL_P(arg4) > sizeof(struct cmsghdr)) ? (struct cmsghdr*)emalloc(Z_LVAL_P(arg4)) : NULL; switch (sa->sa_family) { case AF_INET: if (arg7 == NULL) { efree(ctl_buf); WRONG_PARAM_COUNT; } memset(sa, 0, sizeof(sa_storage)); hdr.msg_name = (void *) sin; hdr.msg_namelen = sizeof(sa_storage); hdr.msg_iov = iov->iov_array; hdr.msg_iovlen = iov->count; hdr.msg_control = ctl_buf ? (void *) ctl_buf : NULL; hdr.msg_controllen = ctl_buf ? Z_LVAL_P(arg4) : 0;#ifndef MISSING_MSGHDR_MSGFLAGS hdr.msg_flags = 0;#endif if (recvmsg(php_sock->bsd_socket, &hdr, Z_LVAL_P(arg5)) < 0) { PHP_SOCKET_ERROR(php_sock, "unable to receive message", errno); RETURN_FALSE; } else { struct cmsghdr *mhdr = (struct cmsghdr *) hdr.msg_control; zval_dtor(arg3); zval_dtor(arg4); zval_dtor(arg5); zval_dtor(arg6); zval_dtor(arg7); ZVAL_LONG(arg4, hdr.msg_controllen);#ifndef MISSING_MSGHDR_MSGFLAGS ZVAL_LONG(arg5, hdr.msg_flags);#endif ZVAL_LONG(arg7, ntohs(sin->sin_port)); if (array_init(arg3) == FAILURE) { php_error(E_WARNING, "%s() cannot intialize array", get_active_function_name(TSRMLS_C)); RETURN_FALSE; } if (mhdr != NULL) { add_assoc_long(arg3, "cmsg_level", mhdr->cmsg_level); add_assoc_long(arg3, "cmsg_type", mhdr->cmsg_type); add_assoc_string(arg3, "cmsg_data", CMSG_DATA(mhdr), 1); } { char *tmp = inet_ntoa(sin->sin_addr); if (tmp == NULL) { ZVAL_STRING(arg6, "0.0.0.0", 1); } else { ZVAL_STRING(arg6, tmp, 1); } } RETURN_TRUE; } case AF_UNIX: memset(sa, 0, sizeof(sa_storage)); hdr.msg_name = (void *) s_un; hdr.msg_namelen = sizeof(struct sockaddr_un); hdr.msg_iov = iov->iov_array; hdr.msg_iovlen = iov->count; if (ctl_buf) { hdr.msg_control = (void *) ctl_buf; hdr.msg_controllen = Z_LVAL_P(arg4); } else { hdr.msg_control = NULL; hdr.msg_controllen = 0; }#ifndef MISSING_MSGHDR_MSGFLAGS hdr.msg_flags = 0;#endif if (recvmsg(php_sock->bsd_socket, &hdr, Z_LVAL_P(arg5)) != 0) { PHP_SOCKET_ERROR(php_sock, "unable to receive message", errno); RETURN_FALSE; } else { struct cmsghdr *mhdr = (struct cmsghdr *) hdr.msg_control; if (mhdr != NULL) { zval_dtor(arg3); zval_dtor(arg4); zval_dtor(arg5); zval_dtor(arg6); ZVAL_LONG(arg4, hdr.msg_controllen);#ifndef MISSING_MSGHDR_MSGFLAGS ZVAL_LONG(arg5, hdr.msg_flags);#endif if (array_init(arg3) == FAILURE) { php_error(E_WARNING, "%s() cannot initialize return value", get_active_function_name(TSRMLS_C)); RETURN_FALSE; } add_assoc_long(arg3, "cmsg_level", mhdr->cmsg_level); add_assoc_long(arg3, "cmsg_type", mhdr->cmsg_type); add_assoc_string(arg3, "cmsg_data", CMSG_DATA(mhdr), 1); } ZVAL_STRING(arg6, 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; }}#endif/* }}} *//* {{{ proto bool socket_sendmsg(resource socket, resource iovec, int flags, string addr [, int port]) Sends a message to a socket, regardless of whether it is connection-oriented or not */PHP_FUNCTION(socket_sendmsg){ zval *arg1, *arg2; php_iovec_t *iov; php_socket *php_sock; struct sockaddr sa; char *addr; socklen_t salen; int addr_len; long flags, port; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rrls|l", &arg1, &arg2, &flags, &addr, &addr_len, &port) == FAILURE) return; ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket); ZEND_FETCH_RESOURCE(iov, php_iovec_t *, &arg2, -1, le_iov_name, le_iov); salen = sizeof(sa); if (getsockname(php_sock->bsd_socket, &sa, &salen) != 0) { PHP_SOCKET_ERROR(php_sock, "unable to send messge", errno); RETURN_FALSE; } switch(sa.sa_family) { case AF_INET: { struct msghdr hdr; struct sockaddr_in *sin = (struct sockaddr_in *) &sa; SET_H_ERRNO(0); set_errno(0); memset(&hdr, 0, sizeof(hdr)); hdr.msg_name = (void *) &sa; hdr.msg_namelen = sizeof(sa); hdr.msg_iov = iov->iov_array; hdr.msg_iovlen = iov->count; memset(sin, 0, sizeof(sa)); sin->sin_family = AF_INET; sin->sin_port = htons((unsigned short)port); if (! php_set_inet_addr(sin, addr, php_sock TSRMLS_CC)) { RETURN_FALSE; } if (sendmsg(php_sock->bsd_socket, &hdr, flags) == -1) { PHP_SOCKET_ERROR(php_sock, "unable to send message", errno); } RETURN_TRUE; } case AF_UNIX: { struct msghdr hdr; struct sockaddr_un *s_un = (struct sockaddr_un *) &sa; set_errno(0); hdr.msg_name = (void *) s_un; hdr.msg_iov = iov->iov_array; hdr.msg_iovlen = iov->count; snprintf(s_un->sun_path, 108, "%s", addr); hdr.msg_namelen = SUN_LEN(s_un); if (sendmsg(php_sock->bsd_socket, &hdr, flags) == -1) { PHP_SOCKET_ERROR(php_sock, "unable to send message", errno); RETURN_FALSE; } RETURN_TRUE; } default: php_error(E_WARNING, "%s() Unsupported address family %d", get_active_function_name(TSRMLS_C), sa.sa_family); RETURN_FALSE; }}/* }}} *//* {{{ proto mixed socket_get_option(resource socket, int level, int optname) Gets socket options for the socket */PHP_FUNCTION(socket_get_option){ zval *arg1; struct linger linger_val; struct timeval tv; int timeout = 0; socklen_t optlen; php_socket *php_sock; int other_val; long level, optname; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rll", &arg1, &level, &optname) == FAILURE) return; ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket); switch(optname) { case SO_LINGER: optlen = sizeof(linger_val); if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&linger_val, &optlen) != 0) { PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno); RETURN_FALSE; } if (array_init(return_value) == FAILURE) { RETURN_FALSE; } add_assoc_long(return_value, "l_onoff", linger_val.l_onoff); add_assoc_long(return_value, "l_linger", linger_val.l_linger); break; case SO_RCVTIMEO: case SO_SNDTIMEO:#ifndef PHP_WIN32 optlen = sizeof(tv); if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&tv, &optlen) != 0) { PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno); RETURN_FALSE; }#else optlen = sizeof(int); if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&timeout, &optlen) != 0) { PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno); RETURN_FALSE; } tv.tv_sec = timeout ? timeout / 1000 : 0; tv.tv_usec = timeout ? (timeout * 1000) % 1000000 : 0;#endif if (array_init(return_value) == FAILURE) { RETURN_FALSE; } add_assoc_long(return_value, "sec", tv.tv_sec); add_assoc_long(return_value, "usec", tv.tv_usec); break; default: optlen = sizeof(other_val); if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&other_val, &optlen) != 0) { PHP_SOCKET_ERROR(php_sock, "unable to retrieve socket option", errno); RETURN_FALSE; } RETURN_LONG(other_val); break; }}/* }}} *//* {{{ proto bool socket_set_option(resource socket, int level, int optname, int|array optval) Sets socket options for the socket */PHP_FUNCTION(socket_set_option){ zval *arg1, *arg4; struct linger lv; struct timeval tv; php_socket *php_sock; int ov, optlen, retval, timeout; long level, optname; void *opt_ptr; HashTable *opt_ht; zval **l_onoff, **l_linger; zval **sec, **usec; /* key name constants */ char *l_onoff_key = "l_onoff"; char *l_linger_key = "l_linger"; char *sec_key = "sec"; char *usec_key = "usec"; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rllz", &arg1, &level, &optname, &arg4) == FAILURE) return; ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket); set_errno(0); switch (optname) { case SO_LINGER: convert_to_array_ex(&arg4); opt_ht = HASH_OF(arg4); if (zend_hash_find(opt_ht, l_onoff_key, strlen(l_onoff_key) + 1, (void **)&l_onoff) == FAILURE) { php_error(E_WARNING, "%s() no key \"%s\" passed in optval", get_active_function_name(TSRMLS_C), l_onoff_key); RETURN_FALSE; } if (zend_hash_find(opt_ht, l_linger_key, strlen(l_linger_key) + 1, (void **)&l_linger) == FAILURE) { php_error(E_WARNING, "%s() no key \"%s\" passed in optval", get_active_function_name(TSRMLS_C), l_linger_key); RETURN_FALSE; } convert_to_long_ex(l_onoff); convert_to_long_ex(l_linger); lv.l_onoff = (unsigned short)Z_LVAL_PP(l_onoff); lv.l_linger = (unsigned short)Z_LVAL_PP(l_linger); optlen = sizeof(lv); opt_ptr = &lv; break; case SO_RCVTIMEO: case SO_SNDTIMEO: convert_to_array_ex(&arg4); opt_ht = HASH_OF(arg4); if (zend_hash_find(opt_ht, sec_key, strlen(sec_key) + 1, (void **)&sec) == FAILURE) { php_error(E_WARNING, "%s() no key \"%s\" passed in optval", get_active_function_name(TSRMLS_C), sec_key); RETURN_FALSE; } if (zend_hash_find(opt_ht, usec_key, strlen(usec_key) + 1, (void **)&usec) == FAILURE) { php_error(E_WARNING, "%s() no key \"%s\" passed in optval", get_active_function_name(TSRMLS_C), usec_key); RETURN_FALSE; } convert_to_long_ex(sec); convert_to_long_ex(usec);#ifndef PHP_WIN32 tv.tv_sec = Z_LVAL_PP(sec); tv.tv_usec = Z_LVAL_PP(usec); optlen = sizeof(tv); opt_ptr = &tv;#else timeout = Z_LVAL_PP(sec) * 1000 + Z_LVAL_PP(usec) / 1000; optlen = sizeof(int); opt_ptr = &timeout;#endif break; default: convert_to_long_ex(&arg4); ov = Z_LVAL_P(arg4); optlen = sizeof(ov); opt_ptr = &ov; break; } retval = setsockopt(php_sock->bsd_socket, level, optname, opt_ptr, optlen); if (retval != 0) { PHP_SOCKET_ERROR(php_sock, "unable to set socket option", errno); RETURN_FALSE; } RETURN_TRUE;}/* }}} *//* {{{ proto bool socket_create_pair(int domain, int type, int protocol, array &fd) Creates a pair of indistinguishable sockets and stores them in fds. */PHP_FUNCTION(socket_create_pair){ zval *retval[2], *fds_array_zval; php_socket *php_sock[2]; SOCKET fds_array[2]; long domain, type, protocol; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lllz", &domain, &type, &protocol, &fds_array_zval) == FAILURE) return; php_sock[0] = (php_socket*)emalloc(sizeof(php_socket)); php_sock[1] = (php_socket*)emalloc(sizeof(php_socket)); if (domain != AF_INET && domain != AF_UNIX) { php_error(E_WARNING, "%s() invalid socket domain [%ld] specified for argument 1, assuming AF_INET", get_active_function_name(TSRMLS_C), domain); domain = AF_INET; } if (type > 10) { php_error(E_WARNING, "%s() invalid socket type [%ld] specified for argument 2, assuming SOCK_STREAM", get_active_function_name(TSRMLS_C), type); type = SOCK_STREAM; } if (socketpair(domain, type, protocol, fds_array) != 0) { SOCKETS_G(last_error) = errno; php_error(E_WARNING, "%s() unable to create socket pair [%d]: %s", get_active_function_name(TSRMLS_C), errno, php_strerror(errno TSRMLS_CC)); efree(php_sock[0]); efree(php_sock[1]); RETURN_FALSE; } zval_dtor(fds_array_zval); if (array_init(fds_array_zval) == FAILURE) { php_error(E_WARNING, "%s() can't initialize array for 4th argument", get_active_function_name(TSRMLS_C)); efree(php_sock[0]); efree(php_sock[1]); RETURN_FALSE; } MAKE_STD_ZVAL(retval[0]); MAKE_STD_ZVAL(retval[1]); php_sock[0]->bsd_socket = fds_array[0]; php_sock[1]->bsd_socket = fds_array[1]; php_sock[0]->type = domain; php_sock[1]->type = domain; php_sock[0]->error = 0; php_sock[1]->error = 0; ZEND_REGISTER_RESOURCE(retval[0], php_sock[0], le_socket); ZEND_REGISTER_RESOURCE(retval[1], php_sock[1], le_socket); add_index_zval(fds_array_zval, 0, retval[0]); add_index_zval(fds_array_zval, 1, retval[1]); RETURN_TRUE;}/* }}} *//* {{{ proto bool socket_shutdown(resource socket[, int how]) Shuts down a socket for receiving, sending, or both. */PHP_FUNCTION(socket_shutdown){ zval *arg1; long how_shutdown = 2; php_socket *php_sock; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &arg1, &how_shutdown) == FAILURE) return; ZEND_FETCH_RESOURCE(php_sock, php_socket*, &arg1, -1, le_socket_name, le_socket); if (shutdown(php_sock->bsd_socket, how_shutdown) != 0) { PHP_SOCKET_ERROR(php_sock, "unable to shutdown socket", errno); RETURN_FALSE; } RETURN_TRUE;}/* }}} *//* {{{ proto int socket_last_error([resource socket]) Returns the last socket error (either the last used or the provided socket resource) */PHP_FUNCTION(socket_last_error){ zval *arg1 = NULL; php_socket *php_sock; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r", &arg1) == FAILURE) return; if (arg1) { ZEND_FETCH_RESOURCE(php_sock, php_socket*, &arg1, -1, le_socket_name, le_socket); RETVAL_LONG(php_sock->error); } else { RETVAL_LONG(SOCKETS_G(last_error)); }}/* }}} *//* {{{ proto void socket_clear_error([resource socket]) Clears the error on the socket or the last error code. */PHP_FUNCTION(socket_clear_error){ zval *arg1 = NULL; php_socket *php_sock; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r", &arg1) == FAILURE) return; if (arg1) { ZEND_FETCH_RESOURCE(php_sock, php_socket*, &arg1, -1, le_socket_name, le_socket); php_sock->error = 0; } else { SOCKETS_G(last_error) = 0; } return;} /* }}} */ #endif/* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -