#ifndef __COMMON2_H__
#define __COMMON2_H__

#pragma warning (disable : 4996)

#include <sys/types.h> // basic type definitions
#include <fcntl.h> // fcntl(), ...
//#include <pthread.h> // pthread_create(), ...
//#include <poll.h> // poll()
//#include <sys/epoll.h> // epoll()
//#include <sys/socket.h> // socket(), AF_INET, ...
//#include <arpa/inet.h> // htons(), htonl(), ...
//#include <netdb.h> // gethostbyname(), ...
//#include <unistd.h> // close(), ...

#include <stdio.h> // printf(), ...
#include <stdlib.h> // exit(), ...
#include <string.h> // strerror(), ...
#include <errno.h> // errno

#include <WinSock2.h> // socket(), SOCKET, INVALID_SOCKET, SOCKET_ERROR, ...
#include <WS2tcpip.h> // inet_pton(), inet_ntop(), socklen_t, ...

// SOCKET_ERROR, INVALID_SOCKET은 WinSock2.h가 이미 정의하므로 다시 정의하지 않는다.
// (SOCKET은 UINT_PTR이고, INVALID_SOCKET은 (SOCKET)(~0)이다.)

// Winsock 오류 코드를 시스템 메시지로 바꿔 출력
// (Winsock은 errno를 설정하지 않으므로 WSAGetLastError()의 값을 사용한다.)
static void print_wsa_error(const char *msg, int errcode)
{
	wchar_t *wbuf = NULL;
	FormatMessageW(
		FORMAT_MESSAGE_ALLOCATE_BUFFER |
		FORMAT_MESSAGE_FROM_SYSTEM |
		FORMAT_MESSAGE_IGNORE_INSERTS,
		NULL, errcode,
		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
		(wchar_t *)&wbuf, 0, NULL);

	// /utf-8로 컴파일하므로 콘솔 출력도 UTF-8로 맞춘다.
	char msgbuf[512] = "알 수 없는 오류";
	if (wbuf != NULL) {
		WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, msgbuf, sizeof(msgbuf), NULL, NULL);
		LocalFree(wbuf);
	}

	// 시스템 메시지 끝의 "\r\n" 제거
	size_t len = strlen(msgbuf);
	while (len > 0 && (msgbuf[len - 1] == '\r' || msgbuf[len - 1] == '\n'))
		msgbuf[--len] = '\0';

	printf("[%s] (%d) %s\n", msg, errcode, msgbuf);
}

// 소켓 함수 오류 출력 후 종료
void err_quit(const char *msg)
{
	print_wsa_error(msg, WSAGetLastError());
	exit(1);
}

// 소켓 함수 오류 출력
void err_display(const char *msg)
{
	print_wsa_error(msg, WSAGetLastError());
}

// 소켓 함수 오류 출력
void err_display(int errcode)
{
	print_wsa_error("오류", errcode);
}

#endif // !__COMMON2_H__
