#ifndef _SSOCKET_H_ #define _SSOCKET_H_ #include #include #define SSOCKET_VERSION_MAJOR 1 #define SSOCKET_VERSION_MINOR 0 #define SSOCKET_VERSION_PATCH 2 #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 #define strcasecmp _stricmp #define strncasecmp _strnicmp #define socklen_t int #elif LINUX_PART #include #include #include #include #define SOCKET long long int //#define INVALID_SOCKET (SOCKET)(~0) #endif #include "tthread.h" #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 #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_sock(SOCKET* sock); static inline int sock_connect(SOCKET sock, const char* connect_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_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 void sock_thread(void(*thread_func)(void*), void* data); #define _SOCKET_TEST_IP "127.0.0.1" #define _SOCKET_TEST_PORT 6789 static inline int _socket(SOCKET* sock, const char* ip, const char* port); static inline int _connect(SOCKET sock, const char* ip, const char* port); static inline int _bind(SOCKET sock, const char* ip, const char* port); static inline int _bindlisten(SOCKET sock, const char* ip, const char* port); static inline int _sock(SOCKET* sock, int af, int type); static inline int make_sock(SOCKET* sock) { return make_sock_tcp4(sock); }; 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 _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; } } static inline int _socket(SOCKET* sock, const char* ip, const char* port) { struct addrinfo inf = { 0 }; struct addrinfo* res_addr = NULL; int res = getaddrinfo(ip, port, &inf, &res_addr); if (res != 0) { return _sock_eai_res_map(res); } for (struct addrinfo* p = res_addr; 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; } freeaddrinfo(res_addr); return ERR_SOCK_SUCCESS; } } freeaddrinfo(res_addr); return ERR_SOCK_CONNECT; } static inline int _connect(SOCKET sock, const char* ip, const char* port) { struct addrinfo inf = { 0 }; struct addrinfo* res_addr = NULL; int res = getaddrinfo(ip, port, &inf, &res_addr); if (res != 0) { return _sock_eai_res_map(res); } for (struct addrinfo* p = res_addr; p != NULL; p = p->ai_next) { if (connect(sock, p->ai_addr, p->ai_addrlen) == 0) { freeaddrinfo(res_addr); return ERR_SOCK_SUCCESS; } } freeaddrinfo(res_addr); return ERR_SOCK_CONNECT; } static inline int _bind(SOCKET sock, const char* ip, const char* port) { struct addrinfo inf = { 0 }; struct addrinfo* res_addr = NULL; int res = getaddrinfo(ip, port, &inf, &res_addr); if (res != 0) { return ERR_SOCK_ADDRINFO; } for (struct addrinfo* p = res_addr; p != NULL; p = p->ai_next) { if (bind(sock, p->ai_addr, p->ai_addrlen) == 0) { freeaddrinfo(res_addr); return ERR_SOCK_SUCCESS; } } freeaddrinfo(res_addr); return ERR_SOCK_CONNECT; } static inline int _bindlisten(SOCKET sock, const char* ip, const char* port) { int res = _bind(sock, ip, port); if(res == ERR_SOCK_SUCCESS){ if (listen(sock, SOMAXCONN) == 0) { return ERR_SOCK_SUCCESS; } return ERR_SOCK_LISTEN; } return res; } static inline int sock_connect(SOCKET sock, const char* connect_ip, unsigned short port) { char buf[8] = { 0 }; sprintf(buf, "%u", port); return _connect(sock, connect_ip, buf); } static inline int sock_bindlisten(SOCKET sock, const char* server_ip, unsigned short port) { char buf[8] = { 0 }; sprintf(buf, "%u", port); return _bindlisten(sock, server_ip, buf); } static inline int sock_accpet(SOCKET sock,SOCKET* client, char** accept_ip, unsigned short* port) { struct sockaddr_in caddr = { 0 }; socklen_t addrLen = sizeof(struct sockaddr_in); if(client == NULL) { return ERR_SOCK_NULLPTR; } *client = accept(sock,(struct sockaddr*) &caddr, &addrLen); if (*client == -1) { return ERR_SOCK_ACCEPT; } char* ip = (char*)malloc(32); if(ip == NULL) { return ERR_SOCK_MALLOC; } int buffLen = strlen( inet_ntoa(caddr.sin_addr) ); if(accept_ip != NULL) { strncpy(ip, inet_ntoa(caddr.sin_addr), buffLen); ip[buffLen] = '\0'; *accept_ip = ip; } if(port != NULL) { *port = ntohs(caddr.sin_port); } return ERR_SOCK_SUCCESS; } static inline int make_server_sock(SOCKET* sock, const char* server_ip, unsigned short port) { int res = make_sock(sock); if(res != ERR_SOCK_SUCCESS) { return res; } res = sock_bindlisten(*sock, server_ip, port); if(res != ERR_SOCK_SUCCESS) { return res; } return ERR_SOCK_SUCCESS; } static inline int make_client_sock(SOCKET* sock, const char* connect_ip, unsigned short port) { int res = make_sock(sock); if(res != ERR_SOCK_SUCCESS) { return res; } if(connect_ip) { res = sock_connect(*sock, connect_ip, port); if(res != ERR_SOCK_SUCCESS) { return res; } } return ERR_SOCK_SUCCESS; } 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, // }; // 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); } static inline void sock_thread(void(*thread_func)(void*), void* data) { #if WIN_PART CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)thread_func, data, 0, NULL); #elif LINUX_PART pthread_t pid; pthread_create(&pid, 0, (void*(*)(void*))thread_func, data); #endif } #ifdef __cplusplus } #endif #endif //_SSOCKET_H_