Skip to content

Commit 83a80bc

Browse files
committed
[Net] Fix TCP listen/accept by using acceptor from socket creation
1 parent ba9526a commit 83a80bc

File tree

1 file changed

+38
-26
lines changed

1 file changed

+38
-26
lines changed

src/xenia/kernel/xsocket.cc

Lines changed: 38 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,11 @@ X_STATUS XSocket::Initialize(AddressFamily af, Type type, Protocol proto) {
9494
asio::error_code ec;
9595

9696
if (type == Type::X_SOCK_STREAM) {
97-
tcp_socket_.emplace(GetIoContext());
98-
tcp_socket_->open(asio::ip::tcp::v4(), ec);
97+
// Use an acceptor for TCP — it supports bind, listen, and accept natively.
98+
// If Connect() is called later, we transition to a tcp_socket at that
99+
// point.
100+
acceptor_.emplace(GetIoContext());
101+
acceptor_->open(asio::ip::tcp::v4(), ec);
99102
} else if (type == Type::X_SOCK_DGRAM) {
100103
udp_socket_.emplace(GetIoContext());
101104
udp_socket_->open(asio::ip::udp::v4(), ec);
@@ -147,7 +150,7 @@ X_STATUS XSocket::Close() {
147150

148151
X_STATUS XSocket::GetOption(uint32_t level, uint32_t optname, void* optval_ptr,
149152
uint32_t* optlen) {
150-
if (!tcp_socket_ && !udp_socket_) {
153+
if (!tcp_socket_ && !udp_socket_ && !acceptor_) {
151154
return X_STATUS_INVALID_HANDLE;
152155
}
153156

@@ -193,7 +196,7 @@ X_STATUS XSocket::SetOption(uint32_t level, uint32_t optname, void* optval_ptr,
193196
return X_STATUS_SUCCESS;
194197
}
195198

196-
if (!tcp_socket_ && !udp_socket_) {
199+
if (!tcp_socket_ && !udp_socket_ && !acceptor_) {
197200
return X_STATUS_INVALID_HANDLE;
198201
}
199202

@@ -234,7 +237,7 @@ X_STATUS XSocket::SetOption(uint32_t level, uint32_t optname, void* optval_ptr,
234237
}
235238

236239
X_STATUS XSocket::IOControl(uint32_t cmd, uint8_t* arg_ptr) {
237-
if (!tcp_socket_ && !udp_socket_) {
240+
if (!tcp_socket_ && !udp_socket_ && !acceptor_) {
238241
return X_STATUS_INVALID_HANDLE;
239242
}
240243

@@ -245,7 +248,9 @@ X_STATUS XSocket::IOControl(uint32_t cmd, uint8_t* arg_ptr) {
245248
uint32_t value = *reinterpret_cast<uint32_t*>(arg_ptr);
246249
bool non_blocking = (value != 0);
247250

248-
if (tcp_socket_) {
251+
if (acceptor_) {
252+
acceptor_->non_blocking(non_blocking, ec);
253+
} else if (tcp_socket_) {
249254
tcp_socket_->non_blocking(non_blocking, ec);
250255
} else if (udp_socket_) {
251256
udp_socket_->non_blocking(non_blocking, ec);
@@ -281,7 +286,7 @@ X_STATUS XSocket::IOControl(uint32_t cmd, uint8_t* arg_ptr) {
281286
}
282287

283288
X_STATUS XSocket::Connect(N_XSOCKADDR* name, int name_len) {
284-
if (!tcp_socket_ && !udp_socket_) {
289+
if (!tcp_socket_ && !udp_socket_ && !acceptor_) {
285290
return X_STATUS_INVALID_HANDLE;
286291
}
287292

@@ -291,7 +296,23 @@ X_STATUS XSocket::Connect(N_XSOCKADDR* name, int name_len) {
291296

292297
asio::error_code ec;
293298

294-
if (tcp_socket_) {
299+
if (acceptor_) {
300+
// Transition from acceptor to tcp_socket for client connection.
301+
// The acceptor was created in Initialize() before we knew whether this
302+
// socket would listen or connect.
303+
acceptor_->close(ec);
304+
acceptor_.reset();
305+
306+
tcp_socket_.emplace(GetIoContext());
307+
tcp_socket_->open(asio::ip::tcp::v4(), ec);
308+
if (ec) {
309+
last_error_ = AsioErrorToWSAError(ec);
310+
return X_STATUS_UNSUCCESSFUL;
311+
}
312+
313+
asio::ip::tcp::endpoint endpoint(addr, port);
314+
tcp_socket_->connect(endpoint, ec);
315+
} else if (tcp_socket_) {
295316
asio::ip::tcp::endpoint endpoint(addr, port);
296317
tcp_socket_->connect(endpoint, ec);
297318
} else if (udp_socket_) {
@@ -308,7 +329,7 @@ X_STATUS XSocket::Connect(N_XSOCKADDR* name, int name_len) {
308329
}
309330

310331
X_STATUS XSocket::Bind(N_XSOCKADDR_IN* name, int name_len) {
311-
if (!tcp_socket_ && !udp_socket_) {
332+
if (!tcp_socket_ && !udp_socket_ && !acceptor_) {
312333
return X_STATUS_INVALID_HANDLE;
313334
}
314335

@@ -328,7 +349,10 @@ X_STATUS XSocket::Bind(N_XSOCKADDR_IN* name, int name_len) {
328349

329350
asio::error_code ec;
330351

331-
if (tcp_socket_) {
352+
if (acceptor_) {
353+
asio::ip::tcp::endpoint endpoint(addr, port);
354+
acceptor_->bind(endpoint, ec);
355+
} else if (tcp_socket_) {
332356
asio::ip::tcp::endpoint endpoint(addr, port);
333357
tcp_socket_->bind(endpoint, ec);
334358
} else if (udp_socket_) {
@@ -344,7 +368,9 @@ X_STATUS XSocket::Bind(N_XSOCKADDR_IN* name, int name_len) {
344368
bound_ = true;
345369

346370
// Get the actual bound port (important when binding to port 0)
347-
if (tcp_socket_) {
371+
if (acceptor_) {
372+
bound_port_ = acceptor_->local_endpoint(ec).port();
373+
} else if (tcp_socket_) {
348374
bound_port_ = tcp_socket_->local_endpoint(ec).port();
349375
} else if (udp_socket_) {
350376
bound_port_ = udp_socket_->local_endpoint(ec).port();
@@ -358,26 +384,12 @@ X_STATUS XSocket::Bind(N_XSOCKADDR_IN* name, int name_len) {
358384
}
359385

360386
X_STATUS XSocket::Listen(int backlog) {
361-
if (!tcp_socket_) {
387+
if (!acceptor_) {
362388
return X_STATUS_INVALID_HANDLE;
363389
}
364390

365391
asio::error_code ec;
366392

367-
// Create an acceptor and transfer the bound socket's native handle to it
368-
acceptor_.emplace(GetIoContext());
369-
acceptor_->assign(asio::ip::tcp::v4(), tcp_socket_->native_handle(), ec);
370-
if (ec) {
371-
last_error_ = AsioErrorToWSAError(ec);
372-
acceptor_.reset();
373-
return X_STATUS_UNSUCCESSFUL;
374-
}
375-
376-
// Release the socket's handle since the acceptor now owns it
377-
tcp_socket_->release();
378-
tcp_socket_.reset();
379-
380-
// Start listening
381393
acceptor_->listen(backlog, ec);
382394
if (ec) {
383395
last_error_ = AsioErrorToWSAError(ec);

0 commit comments

Comments
 (0)