#ifndef _SSOCKET_H_ #define _SSOCKET_H_ #include #include #include #include "sysenv.h" #if _OS_WIN #define WIN_PART 1 #elif _OS_LINUX #define LINUX_PART 1 #else #error "Not Supported Operator System" #endif #if WIN_PART #include #include #include #ifndef strcasecmp #define strcasecmp _stricmp #endif #ifndef strncasecmp #define strncasecmp _strnicmp #endif //#define socklen_t int #elif LINUX_PART #include #include #include #include #include #define SOCKET long long int #define INVALID_SOCKET (SOCKET)(~0) #endif #ifndef ZZY_SLEEP #define ZZY_SLEEP #if WIN_PART #define sleeps(s) Sleep(s*1000) #define sleepms(ms) Sleep(ms) #elif LINUX_PART #define sleeps(s) sleep(s) #define sleepms(ms) usleep(ms*1000) #endif #endif #define _SOCKET_TEST_IP4 "127.0.0.1" #define _SOCKET_TEST_IP6 "::1" #define _SOCKET_TEST_PORT 26789 #ifdef __cplusplus extern "C" { #endif enum { ERR_SOCK_SUCCESS, ERR_SOCK_MALLOC, ERR_SOCK_NULLPTR, ERR_SOCK_WSAStartup, ERR_SOCK_DETERMINE_AGREEMENT, ERR_SOCK_CREATE_SOCKET, ERR_SOCK_BIND, ERR_SOCK_LISTEN, ERR_SOCK_ACCEPT, ERR_SOCK_CONNECT, ERR_SOCK_ADDRINFO, //getaddrinfo ERR_SOCK_EAI_MAPPING_NOT_EXIST, ERR_SOCK_EAI_AGAIN, ERR_SOCK_EAI_BADFLAGS, ERR_SOCK_EAI_FAIL, ERR_SOCK_EAI_FAMILY, ERR_SOCK_EAI_MEMORY, ERR_SOCK_EAI_NONAME, ERR_SOCK_EAI_SERVICE, ERR_SOCK_EAI_SOCKTYPE, }; static inline int make_server_sock(SOCKET* sock, const char* server_ip, unsigned short port); static inline int make_client_sock(SOCKET* sock, const char* connect_ip, unsigned short port); static inline void close_sock(SOCKET sock); static inline void out_sock_err(FILE* output, int errcode); static inline void get_sock_err(char* buff_128, size_t buff_len, int errcode); static inline int make_server_sock_ex(SOCKET* sock, const char* server_ip, const char* port, struct addrinfo** resaddr); static inline int make_client_sock_ex(SOCKET* sock, const char* connect_ip, const char* port, struct addrinfo** resaddr); static inline int make_sock(SOCKET* sock); static inline int sock_connect(SOCKET sock, const char* connect_ip, unsigned short port); static inline int sock_bind(SOCKET sock, const char* server_ip, unsigned short port); static inline int sock_bindlisten(SOCKET sock, const char* server_ip, unsigned short port); static inline int sock_accpet(SOCKET sock, SOCKET* client, char** accept_ip, unsigned short* port); static inline int make_sock_tcp4(SOCKET* sock) { return _sock(sock, AF_INET, SOCK_STREAM); } static inline int make_sock_tcp6(SOCKET* sock) { return _sock(sock, AF_INET6, SOCK_STREAM); } static inline int make_sock_udp4(SOCKET* sock) { return _sock(sock, AF_INET, SOCK_DGRAM); } static inline int make_sock_udp6(SOCKET* sock) { return _sock(sock, AF_INET6, SOCK_DGRAM); } static inline int _getaddrinfo(struct addrinfo* inf, struct addrinfo** resaddr, const char* ip, const char* port); static inline int _socket(SOCKET* sock, struct addrinfo* resaddr); static inline int _connect(SOCKET sock, struct addrinfo* resaddr); static inline int _bind(SOCKET sock, struct addrinfo* resaddr); static inline int _bindlisten(SOCKET sock, struct addrinfo* resaddr); static inline int _accept(SOCKET sock, SOCKET* client, struct addrinfo* inf); static inline int _sock(SOCKET* sock, int af, int type); //not recommand and it will be remove static inline int make_sock(SOCKET* sock) { return make_sock_tcp4(sock); }; static inline int _sock(SOCKET* sock, int af, int type) { #ifdef WIN_PART WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { return -ERR_SOCK_WSAStartup; } if (HIBYTE(wsaData.wVersion) != 2 || \ LOBYTE(wsaData.wVersion) != 2) { return -ERR_SOCK_DETERMINE_AGREEMENT; } #endif *sock = socket(af, type, 0); if (*sock == INVALID_SOCKET) { return -ERR_SOCK_CREATE_SOCKET; } return ERR_SOCK_SUCCESS; } static inline int _sock_eai_res_map(int res) { switch (res) { case EAI_AGAIN: return ERR_SOCK_EAI_AGAIN; case EAI_BADFLAGS: return ERR_SOCK_EAI_BADFLAGS; case EAI_FAIL: return ERR_SOCK_EAI_FAIL; case EAI_FAMILY: return ERR_SOCK_EAI_FAMILY; case EAI_MEMORY: return ERR_SOCK_EAI_MEMORY; case EAI_NONAME: return ERR_SOCK_EAI_NONAME; case EAI_SERVICE: return ERR_SOCK_EAI_SERVICE; case EAI_SOCKTYPE: return ERR_SOCK_EAI_SOCKTYPE; default: return ERR_SOCK_EAI_MAPPING_NOT_EXIST; } } // need to using freeaddrinfo to free static inline int _getaddrinfo(struct addrinfo* inf, struct addrinfo** resaddr, const char* ip, const char* port) { if (resaddr == NULL) { return ERR_SOCK_NULLPTR; } int res = getaddrinfo(ip, port, inf, resaddr); if (res != 0) { return -(_sock_eai_res_map(res)); } return ERR_SOCK_SUCCESS; } static inline int _socket(SOCKET* sock, struct addrinfo* resaddr) { for (struct addrinfo* p = resaddr; p != NULL; p = p->ai_next) { if (*sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) { if (*sock == INVALID_SOCKET) { return -ERR_SOCK_CREATE_SOCKET; } return ERR_SOCK_SUCCESS; } } return -ERR_SOCK_CONNECT; } static inline int _connect(SOCKET sock, struct addrinfo* resaddr) { for (struct addrinfo* p = resaddr; p != NULL; p = p->ai_next) { if (connect(sock, p->ai_addr, p->ai_addrlen) == 0) { return ERR_SOCK_SUCCESS; } } return -ERR_SOCK_CONNECT; } static inline int _bind(SOCKET sock, struct addrinfo* resaddr) { for (struct addrinfo* p = resaddr; p != NULL; p = p->ai_next) { if (bind(sock, p->ai_addr, p->ai_addrlen) == 0) { return ERR_SOCK_SUCCESS; } } return -ERR_SOCK_CONNECT; } static inline int _bindlisten(SOCKET sock, struct addrinfo* resaddr) { int res = _bind(sock, resaddr); if(res == ERR_SOCK_SUCCESS){ if (listen(sock, SOMAXCONN) == 0) { return ERR_SOCK_SUCCESS; } return -ERR_SOCK_LISTEN; } return res; } static inline int _accept(SOCKET sock, SOCKET* client, struct addrinfo* inf) { int res = ERR_SOCK_SUCCESS; socklen_t addrLen = sizeof(struct addrinfo); if (client == NULL) { return -ERR_SOCK_NULLPTR; } *client = accept(sock, (struct sockaddr*)inf, &addrLen); if (*client == INVALID_SOCKET) { return -ERR_SOCK_ACCEPT; } return ERR_SOCK_SUCCESS; } static inline int sock_connect(SOCKET sock, const char* connect_ip, unsigned short port) { int res = ERR_SOCK_SUCCESS; char buf[8] = { 0 }; sprintf(buf, "%u", port); struct addrinfo inf = { 0 }; struct addrinfo* resaddr = NULL; res = _getaddrinfo(&inf, &resaddr, connect_ip, buf); if (res != ERR_SOCK_SUCCESS) goto RES; res = _connect(sock, resaddr); if (res != ERR_SOCK_SUCCESS) goto RES; RES: if (resaddr) freeaddrinfo(resaddr); return res; } static inline int sock_bind(SOCKET sock, const char* server_ip, unsigned short port) { int res = ERR_SOCK_SUCCESS; char buf[8] = { 0 }; sprintf(buf, "%u", port); struct addrinfo inf = { 0 }; struct addrinfo* resaddr = NULL; res = _getaddrinfo(&inf, &resaddr, server_ip, buf); if (res != ERR_SOCK_SUCCESS) goto RES; res = _bind(sock, resaddr); if (res != ERR_SOCK_SUCCESS) goto RES; RES: if (resaddr) freeaddrinfo(resaddr); return res; } static inline int sock_bindlisten(SOCKET sock, const char* server_ip, unsigned short port) { int res = ERR_SOCK_SUCCESS; char buf[8] = { 0 }; sprintf(buf, "%u", port); struct addrinfo inf = { 0 }; struct addrinfo* resaddr = NULL; res = _getaddrinfo(&inf, &resaddr, server_ip, buf); if (res != ERR_SOCK_SUCCESS) goto RES; res = _bindlisten(sock, resaddr); if (res != ERR_SOCK_SUCCESS) goto RES; RES: if (resaddr) freeaddrinfo(resaddr); return res; } static inline int sock_accpet(SOCKET sock,SOCKET* client, char** accept_ip, unsigned short* port) { int res = 0; struct addrinfo inf; if (client == NULL) { return -ERR_SOCK_NULLPTR; } res = _accept(sock, client, &inf); if (res != ERR_SOCK_SUCCESS) return res; if (accept_ip == NULL) return ERR_SOCK_SUCCESS; char* hostname = (char*)malloc(32); char* servInfo = (char*)malloc(8); if(hostname == NULL) { return -ERR_SOCK_MALLOC; } if (servInfo == NULL) { free(hostname); return -ERR_SOCK_MALLOC; } res = getnameinfo((struct sockaddr*)&inf, sizeof(struct addrinfo), hostname, 32, servInfo, 8, NI_NUMERICHOST);// NI_NUMERICHOST NI_NUMERICSERV if (res != 0) { return -ERR_SOCK_ACCEPT; } *accept_ip = hostname; if (port != NULL) { *port = (unsigned short)atoi(servInfo); } return ERR_SOCK_SUCCESS; } static inline int make_server_sock(SOCKET* sock, const char* server_ip, unsigned short port) { char buf[8] = { 0 }; sprintf(buf, "%u", port); int res = make_server_sock_ex(sock, server_ip, buf, NULL); return res; } static inline int make_client_sock(SOCKET* sock, const char* connect_ip, unsigned short port) { char buf[8] = { 0 }; sprintf(buf, "%u", port); int res = make_client_sock_ex(sock, connect_ip, buf, NULL); return res; } static inline int make_server_sock_ex(SOCKET* sock, const char* server_ip, const char* port, struct addrinfo** resaddr) { #ifdef WIN_PART WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { return -ERR_SOCK_WSAStartup; } if (HIBYTE(wsaData.wVersion) != 2 || \ LOBYTE(wsaData.wVersion) != 2) { return -ERR_SOCK_DETERMINE_AGREEMENT; } #endif int res = ERR_SOCK_SUCCESS; struct addrinfo inf = { 0 }; struct addrinfo* addr = NULL; res = _getaddrinfo(&inf, &addr, server_ip, port); if (res != ERR_SOCK_SUCCESS) goto END; res = _socket(sock, addr); if (res != ERR_SOCK_SUCCESS) goto END; res = _bindlisten(*sock, addr); if (res != ERR_SOCK_SUCCESS) goto END; END: if (resaddr == NULL) { freeaddrinfo(addr); } else { *resaddr = addr; } return res; } static inline int make_client_sock_ex(SOCKET* sock, const char* connect_ip, const char* port, struct addrinfo** resaddr) { #ifdef WIN_PART WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { return -ERR_SOCK_WSAStartup; } if (HIBYTE(wsaData.wVersion) != 2 || \ LOBYTE(wsaData.wVersion) != 2) { return -ERR_SOCK_DETERMINE_AGREEMENT; } #endif int res = ERR_SOCK_SUCCESS; struct addrinfo inf = { 0 }; struct addrinfo* addr = NULL; res = _getaddrinfo(&inf, &addr, connect_ip, port); if (res != ERR_SOCK_SUCCESS) goto END; res = _socket(sock, addr); if (res != ERR_SOCK_SUCCESS) goto END; if (connect_ip) { res = _connect(*sock, addr); if (res != ERR_SOCK_SUCCESS) goto END; } END: if (resaddr == NULL) { freeaddrinfo(addr); } else { *resaddr = addr; } return res; } static inline void close_sock(SOCKET sock) { if(sock == -1) return; #if WIN_PART closesocket(sock); #elif LINUX_PART close(sock); #endif } static inline void out_sock_err(FILE* output, int errcode) { fprintf(output, "%d", errcode); } static inline void get_sock_err(char* buff_128, size_t buff_len, int errcode) { if(buff_len < 128) { return; } // enum { // ERR_SOCK_SUCCESS, // ERR_SOCK_MALLOC, // ERR_SOCK_NULLPTR, // ERR_SOCK_WSAStartup, // ERR_SOCK_DETERMINE_AGREEMENT, // ERR_SOCK_CREATE_SOCKET, // ERR_SOCK_BIND, // ERR_SOCK_LISTEN, // ERR_SOCK_ACCEPT, // ERR_SOCK_CONNECT, // ERR_SOCK_ADDRINFO, // //getaddrinfo // ERR_SOCK_EAI_MAPPING_NOT_EXIST, // ERR_SOCK_EAI_AGAIN, // ERR_SOCK_EAI_BADFLAGS, // ERR_SOCK_EAI_FAIL, // ERR_SOCK_EAI_FAMILY, // ERR_SOCK_EAI_MEMORY, // ERR_SOCK_EAI_NONAME, // ERR_SOCK_EAI_SERVICE, // ERR_SOCK_EAI_SOCKTYPE, // }; // https://learn.microsoft.com/zh-cn/windows/win32/api/ws2tcpip/nf-ws2tcpip-getaddrinfo?redirectedfrom=MSDN // https://learn.microsoft.com/en-gb/windows/win32/api/ws2tcpip/nf-ws2tcpip-getaddrinfo?redirectedfrom=MSDN // Error value WSA equivalent Description // EAI_AGAIN WSATRY_AGAIN A temporary failure in name resolution occurred. // EAI_BADFLAGS WSAEINVAL An invalid value was provided for the ai_flags member of the pHints parameter. // EAI_FAIL WSANO_RECOVERY A nonrecoverable failure in name resolution occurred. // EAI_FAMILY WSAEAFNOSUPPORT The ai_family member of the pHints parameter is not supported. // EAI_MEMORY WSA_NOT_ENOUGH_MEMORY A memory allocation failure occurred. // EAI_NONAME WSAHOST_NOT_FOUND The name does not resolve for the supplied parameters or the pNodeName and pServiceName parameters were not provided. // EAI_SERVICE WSATYPE_NOT_FOUND The pServiceName parameter is not supported for the specified ai_socktype member of the pHints parameter. // EAI_SOCKTYPE WSAESOCKTNOSUPPORT The ai_socktype member of the pHints parameter is not supported. sprintf(buff_128, "%3d", errcode); } #ifdef __cplusplus } #endif #endif //_SSOCKET_H_