udp/tcp 비동기 통신은 현재 가능

This commit is contained in:
2025-06-08 01:11:23 +09:00
parent 5fdae769e2
commit 5ba62b5312
7 changed files with 251 additions and 89 deletions

View File

@@ -40,7 +40,7 @@ void IOCP::destruct() {
#endif
}
void IOCP::registerSocket(IOCPPASSINDATA* data) {
void IOCP::registerTCPSocket(IOCPPASSINDATA* data) {
#ifdef _WIN32
HANDLE returnData = ::CreateIoCompletionPort(
(HANDLE)data->socket->sock, completionPort_, data->socket->sock, 0);
@@ -50,20 +50,51 @@ void IOCP::registerSocket(IOCPPASSINDATA* data) {
recv_data->event = IOCPEVENT::READ;
recv_data->socket = data->socket;
DWORD recvbytes = 0, flags = 0;
int result = ::WSARecv(recv_data->socket->sock, &recv_data->wsabuf, 1,
&recvbytes, &flags, &recv_data->overlapped, NULL);
int result = SOCKET_ERROR;
::WSARecv(recv_data->socket->sock, &recv_data->wsabuf, 1, &recvbytes, &flags,
&recv_data->overlapped, NULL);
if (result == SOCKET_ERROR) {
int err = ::WSAGetLastError();
if (err != WSA_IO_PENDING) {
spdlog::error("WSARecv failed: {}", err);
// 반드시 여기서 리턴하거나 처리해야 합니다.
auto err_msg = std::format("WSARecv failed: {}", err);
throw std::runtime_error(err_msg);
}
}
#endif
}
int IOCP::recv(IOCPPASSINDATA* data) { //읽은 바이트수가 무조건 100임? 왜..?
void IOCP::registerUDPSocket(IOCPPASSINDATA* data, Address recv_addr) {
#ifdef _WIN32
HANDLE returnData = ::CreateIoCompletionPort(
(HANDLE)data->socket->sock, completionPort_, data->socket->sock, 0);
if (returnData == 0) completionPort_ = returnData;
IOCPPASSINDATA* recv_data = new IOCPPASSINDATA(data->bufsize);
recv_data->event = IOCPEVENT::READ;
recv_data->socket = data->socket;
DWORD recvbytes = 0, flags = 0;
int result = SOCKET_ERROR;
::WSARecvFrom(recv_data->socket->sock, &recv_data->wsabuf, 1, &recvbytes,
&flags, &recv_addr.addr, &recv_addr.length,
&recv_data->overlapped, NULL);
if (result == SOCKET_ERROR) {
int err = ::WSAGetLastError();
if (err != WSA_IO_PENDING) {
auto err_msg = std::format("WSARecv failed: {}", err);
throw std::runtime_error(err_msg);
}
}
#endif
}
int IOCP::recv(IOCPPASSINDATA* data) { // 읽은 바이트수가 무조건 100임? 왜..?
SOCKET sock = data->socket->sock;
std::lock_guard lock(*GetRecvQueueMutex_(sock));
auto queue = GetRecvQueue_(sock);
@@ -148,14 +179,49 @@ void IOCP::iocpWatcher_(utils::ThreadPool* IOCPThread) {
auto queue_list = GetRecvQueue_(data->socket->sock);
if (data->event == IOCPEVENT::READ) {
if (proto_ == SessionProtocol::TLS || proto_ == SessionProtocol::QUIC) {
// DEBUG: BIO_write 전 OpenSSL 에러 스택 확인 (혹시 모를 이전 에러)
ERR_print_errors_fp(stderr); // 이미 오류 스택에 뭔가 있는지 확인용
fprintf(stderr, "--- Before BIO_write ---\n");
::BIO_write(::SSL_get_rbio(data->ssl.get()), data->wsabuf.buf,
cbTransfrred);
// DEBUG: BIO_write 후 OpenSSL 에러 스택 확인 (BIO_write에서 에러 발생 시)
ERR_print_errors_fp(stderr); // BIO_write에서도 에러가 발생할 수 있음
fprintf(stderr, "--- After BIO_write, cbTransfrred: %lu ---\n",
cbTransfrred);
while ((red_data = ::SSL_read(data->ssl.get(), buf.data(), buf.size())) >
0) {
queue_list->emplace_back(std::make_pair(
std::vector<char>(buf.begin(), buf.begin() + red_data), 0));
}
if (red_data == -1) {
auto ssl_error_code = SSL_get_error(
data->ssl.get(), red_data); // 여기서 SSL_get_error 결과 저장
auto err_msg = std::format("SSL_read failed with SSL_get_error: {}",
ssl_error_code);
fprintf(stderr, "%s\n", err_msg.c_str());
// *** 가장 중요한 부분: SSL_ERROR_SSL일 때 상세 에러를 강제로 출력 시도
// ***
if (ssl_error_code == SSL_ERROR_SSL) {
fprintf(stderr, "Detailed SSL_ERROR_SSL trace:\n");
unsigned long err_peek;
// ERR_get_error()를 사용하여 스택의 모든 오류를 팝하고 출력
while ((err_peek = ERR_get_error()) != 0) {
char err_str[256];
ERR_error_string_n(err_peek, err_str, sizeof(err_str));
fprintf(stderr, "OpenSSL stack error: %s\n", err_str);
}
} else {
// SSL_ERROR_SSL이 아닌 다른 오류 (SYSCALL, WANT_READ 등)일 경우
// ERR_print_errors_fp는 여전히 유용할 수 있음
ERR_print_errors_fp(stderr);
}
throw std::runtime_error(err_msg); // 예외 발생
}
} else {
::memcpy(buf.data(), data->wsabuf.buf, data->transferredbytes);
queue_list->emplace_back(std::make_pair(
@@ -230,7 +296,8 @@ void IOCP::packet_sender_(SOCKET sock) {
int data_len = 0;
if (proto_ == SessionProtocol::TLS || proto_ == SessionProtocol::QUIC) {
int ret = ::SSL_write(front->ssl.get(), front->wsabuf.buf, front->wsabuf.len);
int ret =
::SSL_write(front->ssl.get(), front->wsabuf.buf, front->wsabuf.len);
if (ret <= 0) {
int err = ::SSL_get_error(front->ssl.get(), ret);
if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
@@ -242,7 +309,8 @@ void IOCP::packet_sender_(SOCKET sock) {
break;
}
while ((data_len = ::BIO_read(::SSL_get_wbio(front->ssl.get()), buf.data(), buf.size())) > 0) {
while ((data_len = ::BIO_read(::SSL_get_wbio(front->ssl.get()),
buf.data(), buf.size())) > 0) {
wsabuf.buf = buf.data();
wsabuf.len = data_len;

View File

@@ -12,6 +12,7 @@ int Socket::init(int domain, int type, int protocol) {
this->domain = domain;
sock = ::socket(domain, type, protocol);
// sock = ::WSASocket(domain, type, protocol, NULL, 0, WSA_FLAG_OVERLAPPED);
if (sock == INVALID_SOCKET) spdlog::critical("socket()");
valid_ = true;
@@ -65,6 +66,26 @@ int Socket::bind(Address __addr) {
return retVal;
}
int Socket::connect(Address& serveraddr) {
std::string addr_string = serveraddr;
int retVal = -1;
if (serveraddr.family == AF_INET)
retVal = ::connect(sock, (const sockaddr*)&serveraddr.addr_in,
serveraddr.length);
else
retVal = ::connect(sock, (const sockaddr*)&serveraddr.addr_in6,
serveraddr.length);
memcpy(&remoteAddr, &serveraddr, sizeof(Address));
if (retVal == INVALID_SOCKET) {
#ifdef _WIN32
int err = WSAGetLastError();
spdlog::error("connect() failed: WSA error {} (0x{:X})", err, err);
#endif
spdlog::error("connect()");
}
return retVal;
}
int Socket::recvfrom(void* __restrict __buf, size_t __n, int __flags,
struct Address& __addr) {
std::lock_guard<std::mutex> lock(readMutex);

View File

@@ -4,4 +4,24 @@ namespace Network {
int UDPSocket::init(int domain) { return init(domain, SOCK_DGRAM, 0); }
int UDPSocket::connect(Address &serveraddr) {
std::string addr_string = serveraddr;
int retVal = -1;
if (serveraddr.family == AF_INET)
retVal = ::connect(sock, (const sockaddr *)&serveraddr.addr_in,
serveraddr.length);
else
retVal = ::connect(sock, (const sockaddr *)&serveraddr.addr_in6,
serveraddr.length);
memcpy(&remoteAddr, &serveraddr, sizeof(Address));
if (retVal == INVALID_SOCKET) {
#ifdef _WIN32
int err = WSAGetLastError();
spdlog::error("connect() failed: WSA error {} (0x{:X})", err, err);
#endif
spdlog::error("connect()");
}
return retVal;
}
} // namespace Network