Skip to content

Commit 51ead69

Browse files
committed
Added Socket::write_sync()
1 parent 3cc412d commit 51ead69

File tree

5 files changed

+101
-0
lines changed

5 files changed

+101
-0
lines changed

core-tests/src/network/socket.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,3 +333,46 @@ TEST(socket, check_liveness) {
333333
t1.join();
334334
t2.join();
335335
}
336+
337+
#define CRLF "\r\n"
338+
339+
TEST(socket, sync) {
340+
auto sock = make_socket(SW_SOCK_TCP, SW_FD_STREAM, 0);
341+
342+
swoole::network::Address addr;
343+
ASSERT_TRUE(addr.assign("tcp://httpbin.org:80"));
344+
345+
ASSERT_EQ(sock->connect(addr), 0);
346+
347+
const char *req = "GET / HTTP/1.1" CRLF \
348+
"Host: httpbin.org" CRLF \
349+
"User-Agent: curl/7.81.0" CRLF \
350+
"Accept: */*" CRLF \
351+
"Connection: close" CRLF \
352+
CRLF CRLF;
353+
ssize_t n = strlen(req);
354+
ASSERT_EQ(sock->write_sync(req, n), n);
355+
356+
string resp;
357+
SW_LOOP {
358+
char buf[1024];
359+
n = sock->read_sync(buf, sizeof(buf));
360+
if (n == 0) {
361+
break;
362+
}
363+
ASSERT_GT(n, 0);
364+
resp.append(buf, n);
365+
}
366+
367+
ASSERT_GT(resp.length(), 4096);
368+
sock->free();
369+
}
370+
371+
TEST(socket, ipv6_addr) {
372+
auto sock = make_socket(SW_SOCK_TCP6, SW_FD_STREAM, 0);
373+
swoole::network::Address addr;
374+
ASSERT_TRUE(addr.assign("tcp://[::1]:12345"));
375+
ASSERT_EQ(sock->connect(addr), SW_ERR);
376+
ASSERT_EQ(errno, ECONNREFUSED);
377+
sock->free();
378+
}

include/swoole_error.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ enum swErrorCode {
5454

5555
SW_ERROR_BAD_IPV6_ADDRESS = 720,
5656
SW_ERROR_UNREGISTERED_SIGNAL,
57+
SW_ERROR_BAD_HOST_ADDR,
5758

5859
// EventLoop
5960
SW_ERROR_EVENT_SOCKET_REMOVED = 800,

include/swoole_socket.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,12 @@ struct Address {
108108
SocketType type;
109109

110110
bool assign(SocketType _type, const std::string &_host, int _port);
111+
bool assign(const std::string &url);
112+
111113
const char *get_ip() {
112114
return get_addr();
113115
}
116+
114117
int get_port();
115118
const char *get_addr();
116119

@@ -498,6 +501,12 @@ struct Socket {
498501
*/
499502
ssize_t read_sync(void *__buf, size_t __len, int timeout_ms = -1);
500503

504+
/**
505+
* Write data to the socket synchronously without setting non-blocking or blocking IO,
506+
* and allow interruptions by signals.
507+
*/
508+
ssize_t write_sync(const void *__buf, size_t __len, int timeout_ms = -1);
509+
501510
int shutdown(int __how) {
502511
return ::shutdown(fd, __how);
503512
}

src/network/address.cc

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
#include "swoole_socket.h"
1818

19+
#include <regex>
20+
1921
namespace swoole {
2022
namespace network {
2123

@@ -74,5 +76,40 @@ bool Address::assign(SocketType _type, const std::string &_host, int _port) {
7476
return false;
7577
}
7678

79+
bool Address::assign(const std::string &url) {
80+
std::regex pattern(R"((tcp|udp)://([\[\]a-zA-Z0-9.-:]+):(\d+))");
81+
std::smatch match;
82+
83+
if (std::regex_match(url, match, pattern)) {
84+
std::string host = match[2];
85+
auto port = std::stoi(match[3]);
86+
87+
if (host[0] == '[') {
88+
type = SW_SOCK_TCP6;
89+
addr.inet_v6.sin6_family = AF_INET6;
90+
addr.inet_v6.sin6_port = htons(port);
91+
len = sizeof(addr.inet_v6);
92+
if (inet_pton(AF_INET6, host.substr(1, host.size() - 2).c_str(), addr.inet_v6.sin6_addr.s6_addr)) {
93+
return true;
94+
}
95+
} else {
96+
type = SW_SOCK_TCP;
97+
addr.inet_v4.sin_family = AF_INET;
98+
addr.inet_v4.sin_port = htons(port);
99+
len = sizeof(addr.inet_v4);
100+
if (!inet_pton(AF_INET, host.c_str(), &addr.inet_v4.sin_addr.s_addr)) {
101+
if (gethostbyname(AF_INET, host.c_str(), (char *) &addr.inet_v4.sin_addr.s_addr) < 0) {
102+
swoole_set_last_error(SW_ERROR_DNSLOOKUP_RESOLVE_FAILED);
103+
return false;
104+
}
105+
}
106+
return true;
107+
}
108+
}
109+
110+
swoole_error_log(SW_LOG_NOTICE, SW_ERROR_BAD_HOST_ADDR, "Invalid address['%s']", url.c_str());
111+
return false;
112+
}
113+
77114
} // namespace network
78115
} // namespace swoole

src/network/socket.cc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -781,6 +781,17 @@ ssize_t Socket::read_sync(void *__buf, size_t __len, int timeout_ms) {
781781
}
782782
}
783783

784+
ssize_t Socket::write_sync(const void *__buf, size_t __len, int timeout_ms) {
785+
struct pollfd event;
786+
event.fd = fd;
787+
event.events = POLLOUT;
788+
if (poll(&event, 1, timeout_ms) == 1) {
789+
return write(__buf, __len);
790+
} else {
791+
return -1;
792+
}
793+
}
794+
784795
ssize_t Socket::readv(IOVector *io_vector) {
785796
ssize_t retval;
786797

0 commit comments

Comments
 (0)