Skip to content

Commit

Permalink
Enhanced support raw socket (#5079)
Browse files Browse the repository at this point in the history
* Enhanced support for raw socket

* optimize code

* fix

* fix 2
  • Loading branch information
matyhtf committed Jun 26, 2023
1 parent a3fc526 commit a2c46af
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 29 deletions.
4 changes: 2 additions & 2 deletions ext-src/swoole_socket_coro.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1231,7 +1231,7 @@ PHP_FUNCTION(swoole_coroutine_socketpair) {

php_swoole_check_reactor();

auto sock_type = swoole::network::Socket::convert_to_type(domain, type, protocol);
auto sock_type = swoole::network::Socket::convert_to_type(domain, type);

zend_object *s1 = php_swoole_create_socket_from_fd(pair[0], sock_type);
if (s1 == nullptr) {
Expand Down Expand Up @@ -1362,7 +1362,7 @@ static PHP_METHOD(swoole_socket_coro, connect) {

swoole_get_socket_coro(sock, ZEND_THIS);

if (sock->socket->get_sock_domain() == AF_INET6 || sock->socket->get_sock_domain() == AF_INET) {
if (sock->socket->is_port_required()) {
if (ZEND_NUM_ARGS() == 1) {
php_swoole_error(E_WARNING, "Socket of type AF_INET/AF_INET6 requires port argument");
RETURN_FALSE;
Expand Down
4 changes: 4 additions & 0 deletions include/swoole_coroutine_socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ class Socket {
return sock_fd == SW_BAD_SOCKET;
}

bool is_port_required() {
return type <= SW_SOCK_UDP6;
}

bool check_liveness();
ssize_t peek(void *__buf, size_t __n);
ssize_t recv(void *__buf, size_t __n);
Expand Down
26 changes: 17 additions & 9 deletions include/swoole_socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -568,16 +568,21 @@ struct Socket {
return catch_error(err);
}

static inline SocketType convert_to_type(int domain, int type, int protocol = 0) {
switch (domain) {
case AF_INET:
return type == SOCK_STREAM ? SW_SOCK_TCP : SW_SOCK_UDP;
case AF_INET6:
return type == SOCK_STREAM ? SW_SOCK_TCP6 : SW_SOCK_UDP6;
case AF_UNIX:
return type == SOCK_STREAM ? SW_SOCK_UNIX_STREAM : SW_SOCK_UNIX_DGRAM;
default:
static inline SocketType convert_to_type(int domain, int type) {
if (domain == AF_INET && type == SOCK_STREAM) {
return SW_SOCK_TCP;
} else if (domain == AF_INET6 && type == SOCK_STREAM) {
return SW_SOCK_TCP6;
} else if (domain == AF_UNIX && type == SOCK_STREAM) {
return SW_SOCK_UNIX_STREAM;
} else if (domain == AF_INET && type == SOCK_DGRAM) {
return SW_SOCK_UDP;
} else if (domain == AF_INET6 && type == SOCK_DGRAM) {
return SW_SOCK_UDP6;
} else if (domain == AF_UNIX && type == SOCK_DGRAM) {
return SW_SOCK_UNIX_DGRAM;
} else {
return SW_SOCK_RAW;
}
}

Expand Down Expand Up @@ -633,6 +638,9 @@ int getaddrinfo(GetaddrinfoRequest *req);
} // namespace network
network::Socket *make_socket(int fd, FdType fd_type);
network::Socket *make_socket(SocketType socket_type, FdType fd_type, int flags);
network::Socket *make_socket(
SocketType type, FdType fd_type, int sock_domain, int sock_type, int socket_protocol, int flags);
int socket(int sock_domain, int sock_type, int socket_protocol, int flags);
network::Socket *make_server_socket(SocketType socket_type,
const char *address,
int port = 0,
Expand Down
17 changes: 9 additions & 8 deletions src/coroutine/socket.cc
Original file line number Diff line number Diff line change
Expand Up @@ -472,13 +472,14 @@ bool Socket::http_proxy_handshake() {
return ret;
}

void Socket::init_sock_type(SocketType _sw_type) {
type = _sw_type;
network::Socket::get_domain_and_type(_sw_type, &sock_domain, &sock_type);
void Socket::init_sock_type(SocketType _type) {
type = _type;
network::Socket::get_domain_and_type(_type, &sock_domain, &sock_type);
}

bool Socket::init_sock() {
socket = make_socket(type, SW_FD_CO_SOCKET, SW_SOCK_CLOEXEC | SW_SOCK_NONBLOCK);
socket =
make_socket(type, SW_FD_CO_SOCKET, sock_domain, sock_type, sock_protocol, SW_SOCK_NONBLOCK | SW_SOCK_CLOEXEC);
if (socket == nullptr) {
return false;
}
Expand All @@ -501,7 +502,7 @@ bool Socket::init_reactor_socket(int _fd) {

Socket::Socket(int _domain, int _type, int _protocol)
: sock_domain(_domain), sock_type(_type), sock_protocol(_protocol) {
type = network::Socket::convert_to_type(_domain, _type, _protocol);
type = network::Socket::convert_to_type(_domain, _type);
if (sw_unlikely(!init_sock())) {
return;
}
Expand All @@ -517,20 +518,20 @@ Socket::Socket(SocketType _type) {
}

Socket::Socket(int _fd, SocketType _type) {
init_sock_type(_type);
if (sw_unlikely(!init_reactor_socket(_fd))) {
return;
}
if (_type == SW_SOCK_RAW) {
return;
}
init_sock_type(_type);
socket->set_nonblock();
init_options();
}

Socket::Socket(int _fd, int _domain, int _type, int _protocol)
: sock_domain(_domain), sock_type(_type), sock_protocol(_protocol) {
type = network::Socket::convert_to_type(_domain, _type, _protocol);
type = network::Socket::convert_to_type(_domain, _type);
if (sw_unlikely(!init_reactor_socket(_fd))) {
return;
}
Expand Down Expand Up @@ -658,7 +659,7 @@ bool Socket::connect(std::string _host, int _port, int flags) {
_port = http_proxy->proxy_port;
}

if (sock_domain == AF_INET6 || sock_domain == AF_INET) {
if (is_port_required()) {
if (_port == -1) {
set_err(EINVAL, "Socket of type AF_INET/AF_INET6 requires port argument");
return false;
Expand Down
35 changes: 25 additions & 10 deletions src/network/socket.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1468,9 +1468,28 @@ Socket *make_socket(SocketType type, FdType fd_type, int flags) {
if (Socket::get_domain_and_type(type, &sock_domain, &sock_type) < 0) {
swoole_warning("unknown socket type [%d]", type);
errno = ESOCKTNOSUPPORT;
swoole_set_last_error(errno);
return nullptr;
}

return make_socket(type, fd_type, sock_domain, sock_type, 0, flags);
}

Socket *make_socket(SocketType type, FdType fd_type, int sock_domain, int sock_type, int socket_protocol, int flags) {
int sockfd = swoole::socket(sock_domain, sock_type, socket_protocol, flags);
if (sockfd < 0) {
swoole_set_last_error(errno);
return nullptr;
}

auto _socket = swoole::make_socket(sockfd, fd_type);
_socket->nonblock = !!(flags & SW_SOCK_NONBLOCK);
_socket->cloexec = !!(flags & SW_SOCK_CLOEXEC);
_socket->socket_type = type;
return _socket;
}

int socket(int sock_domain, int sock_type, int socket_protocol, int flags) {
bool nonblock = flags & SW_SOCK_NONBLOCK;
bool cloexec = flags & SW_SOCK_CLOEXEC;

Expand All @@ -1482,27 +1501,23 @@ Socket *make_socket(SocketType type, FdType fd_type, int flags) {
if (cloexec) {
sock_flags |= SOCK_CLOEXEC;
}
int sockfd = socket(sock_domain, sock_type | sock_flags, 0);
int sockfd = ::socket(sock_domain, sock_type | sock_flags, socket_protocol);
if (sockfd < 0) {
return nullptr;
return sockfd;
}
#else
int sockfd = socket(sock_domain, sock_type, 0);
int sockfd = ::socket(sock_domain, sock_type, socket_protocol);
if (sockfd < 0) {
return nullptr;
return sockfd;
}
if (nonblock || cloexec) {
if (!network::_fcntl_set_option(sockfd, nonblock ? 1 : -1, cloexec ? 1 : -1)) {
close(sockfd);
return nullptr;
return sockfd;
}
}
#endif
auto _socket = swoole::make_socket(sockfd, fd_type);
_socket->nonblock = nonblock;
_socket->cloexec = cloexec;
_socket->socket_type = type;
return _socket;
return sockfd;
}

Socket *make_server_socket(SocketType type, const char *address, int port, int backlog) {
Expand Down
19 changes: 19 additions & 0 deletions tests/swoole_socket_coro/icmp.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
--TEST--
swoole_socket_coro: icmp
--SKIPIF--
<?php require __DIR__ . '/../include/skipif.inc'; ?>
--FILE--
<?php
require __DIR__ . '/../include/bootstrap.php';
Co\run(function () {
/* ICMP ping packet with a pre-calculated checksum */
$host = '127.0.0.1';
$package = "\x08\x00\x7d\x4b\x00\x00\x00\x00PingHost";
$socket = new Swoole\Coroutine\Socket(AF_INET, SOCK_RAW, 1);
$socket->connect($host);
$socket->send($package, strlen($package));
$pkt = $socket->recv(256);
Assert::notEmpty($pkt);
});
?>
--EXPECT--

0 comments on commit a2c46af

Please sign in to comment.