Files

1688 lines
32 KiB
C++
Raw Permalink Normal View History

2026-03-28 16:54:11 +11:00
/***************************************************************************************
*
* IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
*
* By downloading, copying, installing or using the software you agree to this license.
* If you do not agree to this license, do not download, install,
* copy or use the software.
*
* Copyright (C) 2014-2024, Happytimesoft Corporation, all rights reserved.
*
* Redistribution and use in binary forms, with or without modification, are permitted.
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*
****************************************************************************************/
#include "sys_inc.h"
#include "util.h"
/***************************************************************************************/
HT_API int get_if_nums()
{
#if __WINDOWS_OS__
char ipt_buf[512];
MIB_IPADDRTABLE * ipt = (MIB_IPADDRTABLE *)ipt_buf;
ULONG ipt_len = sizeof(ipt_buf);
DWORD fr = GetIpAddrTable(ipt, &ipt_len, FALSE);
if (fr != NO_ERROR)
{
return 0;
}
return ipt->dwNumEntries;
#elif defined(IOS)
int count = 0;
struct ifaddrs *if_addrs = NULL;
struct ifaddrs *if_addr = NULL;
if (0 == getifaddrs(&if_addrs))
{
for (if_addr = if_addrs; if_addr != NULL; if_addr = if_addr->ifa_next)
{
if (NULL == if_addr->ifa_addr || if_addr->ifa_addr->sa_family != AF_INET)
{
continue;
}
count++;
}
freeifaddrs(if_addrs);
if_addrs = NULL;
}
return count;
#elif __LINUX_OS__
SOCKET socket_fd;
struct ifreq *ifr;
struct ifconf conf;
char buff[BUFSIZ];
int i, num, count = 0;
socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (socket_fd <= 0)
{
return 0;
}
conf.ifc_len = BUFSIZ;
conf.ifc_buf = buff;
ioctl(socket_fd, SIOCGIFCONF, &conf);
num = conf.ifc_len / sizeof(struct ifreq);
ifr = conf.ifc_req;
for (i=0; i<num; i++)
{
if (ifr->ifr_addr.sa_family == AF_INET)
{
count++;
}
ifr++;
}
closesocket(socket_fd);
return count;
#endif
return 0;
}
HT_API uint32 get_if_ip(int index)
{
#if __WINDOWS_OS__
char ipt_buf[1024];
DWORD i;
MIB_IPADDRTABLE * ipt = (MIB_IPADDRTABLE *)ipt_buf;
ULONG ipt_len = sizeof(ipt_buf);
DWORD fr = GetIpAddrTable(ipt, &ipt_len, FALSE);
if (fr != NO_ERROR)
{
return 0;
}
for (i=0; i<ipt->dwNumEntries; i++)
{
if (i == index)
{
return ipt->table[i].dwAddr;
}
}
#elif defined(IOS)
int count = 0;
struct ifaddrs *if_addrs = NULL;
struct ifaddrs *if_addr = NULL;
struct sockaddr_in * sin;
uint32 ip_addr = 0;
if (0 == getifaddrs(&if_addrs))
{
for (if_addr = if_addrs; if_addr != NULL; if_addr = if_addr->ifa_next)
{
if (NULL == if_addr->ifa_addr || if_addr->ifa_addr->sa_family != AF_INET)
{
continue;
}
if (count++ == index)
{
sin = (struct sockaddr_in *)if_addr->ifa_addr;
ip_addr = sin->sin_addr.s_addr;
break;
}
}
freeifaddrs(if_addrs);
if_addrs = NULL;
}
return ip_addr;
#elif __LINUX_OS__
int i;
SOCKET socket_fd;
struct ifreq *ifr;
struct ifconf conf;
char buff[BUFSIZ];
int num, count = 0;
uint32 ip_addr = 0;
socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
conf.ifc_len = BUFSIZ;
conf.ifc_buf = buff;
ioctl(socket_fd, SIOCGIFCONF, &conf);
num = conf.ifc_len / sizeof(struct ifreq);
ifr = conf.ifc_req;
for (i=0; i<num; i++)
{
if (ifr->ifr_addr.sa_family != AF_INET)
{
ifr++;
continue;
}
if (count++ == index)
{
struct sockaddr_in *sin = (struct sockaddr_in *)(&ifr->ifr_addr);
ip_addr = sin->sin_addr.s_addr;
break;
}
ifr++;
}
closesocket(socket_fd);
return ip_addr;
#endif
return 0;
}
HT_API uint32 get_route_if_ip(uint32 dst_ip)
{
#if __WINDOWS_OS__
DWORD i;
DWORD dwIfIndex,fr;
char ipt_buf[1024];
MIB_IPADDRTABLE *ipt;
ULONG ipt_len;
fr = GetBestInterface(dst_ip, &dwIfIndex);
if (fr != NO_ERROR)
{
return 0;
}
ipt = (MIB_IPADDRTABLE *)ipt_buf;
ipt_len = sizeof(ipt_buf);
fr = GetIpAddrTable(ipt, &ipt_len, FALSE);
if (fr != NO_ERROR)
{
return 0;
}
for (i=0; i<ipt->dwNumEntries; i++)
{
if (ipt->table[i].dwIndex == dwIfIndex)
{
return ipt->table[i].dwAddr;
}
}
#elif defined(IOS)
struct ifaddrs *if_addrs = NULL;
struct ifaddrs *if_addr = NULL;
struct sockaddr_in * sin;
uint32 ip_addr = 0;
if (0 == getifaddrs(&if_addrs))
{
for (if_addr = if_addrs; if_addr != NULL; if_addr = if_addr->ifa_next)
{
if (NULL == if_addr->ifa_addr || if_addr->ifa_addr->sa_family != AF_INET)
{
continue;
}
sin = (struct sockaddr_in *)if_addr->ifa_addr;
if (((if_addr->ifa_flags & IFF_LOOPBACK) == 0) && (if_addr->ifa_flags & IFF_UP))
{
ip_addr = sin->sin_addr.s_addr;
break;
}
}
freeifaddrs(if_addrs);
if_addrs = NULL;
}
return ip_addr;
#elif __LINUX_OS__
int i;
SOCKET socket_fd;
struct ifreq *ifr;
struct ifconf conf;
char buff[BUFSIZ];
int num;
uint32 ip_addr = 0;
socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
conf.ifc_len = BUFSIZ;
conf.ifc_buf = buff;
ioctl(socket_fd, SIOCGIFCONF, &conf);
num = conf.ifc_len / sizeof(struct ifreq);
ifr = conf.ifc_req;
for (i=0; i<num; i++)
{
if (ifr->ifr_addr.sa_family != AF_INET)
{
ifr++;
continue;
}
ioctl(socket_fd, SIOCGIFFLAGS, ifr);
if (((ifr->ifr_flags & IFF_LOOPBACK) == 0) && (ifr->ifr_flags & IFF_UP))
{
struct sockaddr_in *sin = (struct sockaddr_in *)(&ifr->ifr_addr);
ip_addr = sin->sin_addr.s_addr;
break;
}
ifr++;
}
closesocket(socket_fd);
return ip_addr;
#endif
return 0;
}
HT_API uint32 get_default_if_ip()
{
uint32 ip = get_route_if_ip(0);
if (ip != 0)
{
return ip;
}
else
{
int i;
int nums = get_if_nums();
for (i = 0; i < nums; i++)
{
ip = get_if_ip(i);
if (ip != 0 && ip != inet_addr("127.0.0.l"))
{
return ip;
}
}
}
return 0;
}
HT_API const char * get_local_ip()
{
uint32 ip = get_default_if_ip();
if (ip != 0)
{
return get_ip_str(ip);
}
return "127.0.0.1";
}
HT_API uint32 get_if_mask(int index)
{
#if __WINDOWS_OS__
char ipt_buf[1024];
DWORD i;
MIB_IPADDRTABLE * ipt = (MIB_IPADDRTABLE *)ipt_buf;
ULONG ipt_len = sizeof(ipt_buf);
DWORD fr = GetIpAddrTable(ipt, &ipt_len, FALSE);
if (fr != NO_ERROR)
{
return inet_addr("255.255.255.255");
}
for (i=0; i<ipt->dwNumEntries; i++)
{
if (i == index)
{
return ipt->table[i].dwMask;
}
}
#elif defined(IOS)
int count = 0;
struct ifaddrs *if_addrs = NULL;
struct ifaddrs *if_addr = NULL;
struct sockaddr_in * sin;
uint32 mask = inet_addr("255.255.255.255");
if (0 == getifaddrs(&if_addrs))
{
for (if_addr = if_addrs; if_addr != NULL; if_addr = if_addr->ifa_next)
{
if (NULL == if_addr->ifa_addr || if_addr->ifa_addr->sa_family != AF_INET)
{
continue;
}
if (count++ == index)
{
sin = (struct sockaddr_in *)if_addr->ifa_netmask;
mask = sin->sin_addr.s_addr;
break;
}
}
freeifaddrs(if_addrs);
if_addrs = NULL;
}
return mask;
#elif __LINUX_OS__
int i;
SOCKET socket_fd;
struct ifreq *ifr;
struct ifconf conf;
char buff[BUFSIZ];
int num, count = 0;
uint32 mask = inet_addr("255.255.255.255");
socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
conf.ifc_len = BUFSIZ;
conf.ifc_buf = buff;
ioctl(socket_fd, SIOCGIFCONF, &conf);
num = conf.ifc_len / sizeof(struct ifreq);
ifr = conf.ifc_req;
for (i=0; i<num; i++)
{
if (ifr->ifr_addr.sa_family != AF_INET)
{
ifr++;
continue;
}
if (count++ == index)
{
struct sockaddr_in *sin = (struct sockaddr_in *)(&ifr->ifr_netmask);
ioctl(socket_fd, SIOCGIFNETMASK, ifr);
mask = sin->sin_addr.s_addr;
break;
}
ifr++;
}
closesocket(socket_fd);
return mask;
#endif
return inet_addr("255.255.255.255");
}
HT_API uint32 get_route_if_mask(uint32 dst_ip)
{
#if __WINDOWS_OS__
DWORD i;
DWORD dwIfIndex,fr;
char ipt_buf[1024];
MIB_IPADDRTABLE *ipt;
ULONG ipt_len;
fr = GetBestInterface(dst_ip, &dwIfIndex);
if (fr != NO_ERROR)
{
return inet_addr("255.255.255.255");
}
ipt = (MIB_IPADDRTABLE *)ipt_buf;
ipt_len = sizeof(ipt_buf);
fr = GetIpAddrTable(ipt,&ipt_len,FALSE);
if (fr != NO_ERROR)
{
return inet_addr("255.255.255.255");
}
for (i=0; i<ipt->dwNumEntries; i++)
{
if (ipt->table[i].dwIndex == dwIfIndex)
{
return ipt->table[i].dwMask;
}
}
#elif defined(IOS)
struct ifaddrs *if_addrs = NULL;
struct ifaddrs *if_addr = NULL;
struct sockaddr_in * sin;
uint32 mask = inet_addr("255.255.255.255");
if (0 == getifaddrs(&if_addrs))
{
for (if_addr = if_addrs; if_addr != NULL; if_addr = if_addr->ifa_next)
{
if (NULL == if_addr->ifa_addr || if_addr->ifa_addr->sa_family != AF_INET)
{
continue;
}
sin = (struct sockaddr_in *)if_addr->ifa_netmask;
if (((if_addr->ifa_flags & IFF_LOOPBACK) == 0) && (if_addr->ifa_flags & IFF_UP))
{
mask = sin->sin_addr.s_addr;
break;
}
}
freeifaddrs(if_addrs);
if_addrs = NULL;
}
return mask;
#elif __LINUX_OS__
int i;
SOCKET socket_fd;
struct ifreq *ifr;
struct ifconf conf;
char buff[BUFSIZ];
int num;
uint32 mask = inet_addr("255.255.255.255");
socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
conf.ifc_len = BUFSIZ;
conf.ifc_buf = buff;
ioctl(socket_fd, SIOCGIFCONF, &conf);
num = conf.ifc_len / sizeof(struct ifreq);
ifr = conf.ifc_req;
for (i=0; i<num; i++)
{
if (ifr->ifr_addr.sa_family != AF_INET)
{
ifr++;
continue;
}
ioctl(socket_fd, SIOCGIFFLAGS, ifr);
if (((ifr->ifr_flags & IFF_LOOPBACK) == 0) && (ifr->ifr_flags & IFF_UP))
{
struct sockaddr_in *sin = (struct sockaddr_in *)(&ifr->ifr_netmask);
ioctl(socket_fd, SIOCGIFNETMASK, ifr);
mask = sin->sin_addr.s_addr;
break;
}
ifr++;
}
closesocket(socket_fd);
return mask;
#endif
return inet_addr("255.255.255.255");
}
HT_API uint32 get_default_if_mask()
{
return get_route_if_mask(0);
}
HT_API int is_local_if_net(uint32 destip)
{
int i;
int nums;
if (destip == inet_addr("127.0.0.1"))
{
return 1;
}
nums = get_if_nums();
for (i = 0; i < nums; i++)
{
uint32 ip = get_if_ip(i);
uint32 mask = get_if_mask(i);
if ((ip & mask) == (destip & mask))
{
return 1;
}
}
return 0;
}
HT_API int get_default_if_mac(uint8 * mac)
{
#ifdef IOS
#elif __WINDOWS_OS__
IP_ADAPTER_INFO AdapterInfo[16]; // Allocate information for up to 16 NICs
DWORD dwBufLen = sizeof(AdapterInfo); // Save the memory size of buffer
DWORD dwStatus = GetAdaptersInfo( // Call GetAdapterInfo
AdapterInfo, // [out] buffer to receive data
&dwBufLen); // [in] size of receive data buffer
PIP_ADAPTER_INFO pAdapterInfo = AdapterInfo;// Contains pointer to current adapter info
if (pAdapterInfo)
{
memcpy(mac, pAdapterInfo->Address, 6);
return 0;
}
#elif __LINUX_OS__
int i;
SOCKET socket_fd;
struct ifreq *ifr;
struct ifreq ifreq;
struct ifconf conf;
char buff[BUFSIZ];
int num;
socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
conf.ifc_len = BUFSIZ;
conf.ifc_buf = buff;
ioctl(socket_fd, SIOCGIFCONF, &conf);
num = conf.ifc_len / sizeof(struct ifreq);
ifr = conf.ifc_req;
for (i=0; i<num; i++)
{
if (ifr->ifr_addr.sa_family != AF_INET)
{
ifr++;
continue;
}
ioctl(socket_fd, SIOCGIFFLAGS, ifr);
if ((ifr->ifr_flags & IFF_LOOPBACK) != 0)
{
ifr++;
continue;
}
strcpy(ifreq.ifr_name, ifr->ifr_name);
if (ioctl(socket_fd, SIOCGIFHWADDR, &ifreq) < 0)
{
ifr++;
continue;
}
memcpy(mac, &ifreq.ifr_hwaddr.sa_data, 6);
close(socket_fd);
return 0;
}
close(socket_fd);
#endif
return -1;
}
HT_API const char * get_default_gateway()
{
static char gateway[32];
#if __WINDOWS_OS__
IP_ADAPTER_INFO AdapterInfo[16]; // Allocate information for up to 16 NICs
DWORD dwBufLen = sizeof(AdapterInfo); // Save the memory size of buffer
DWORD dwStatus = GetAdaptersInfo( // Call GetAdapterInfo
AdapterInfo, // [out] buffer to receive data
&dwBufLen); // [in] size of receive data buffer
PIP_ADAPTER_INFO pAdapterInfo = AdapterInfo;// Contains pointer to current adapter info
if (NULL == pAdapterInfo)
{
return NULL;
}
memset(gateway, 0, sizeof(gateway));
while (pAdapterInfo)
{
if (strcmp(pAdapterInfo->GatewayList.IpAddress.String, "0.0.0.0"))
{
strncpy(gateway, pAdapterInfo->GatewayList.IpAddress.String, sizeof(gateway)-1);
break;
}
pAdapterInfo = pAdapterInfo->Next;
}
#elif __LINUX_OS__
char line[100], *p, *c, *g, *saveptr;
int ret = 0;
FILE *fp = fopen("/proc/net/route" , "r");
if (NULL == fp)
{
return NULL;
}
memset(gateway, 0, sizeof(gateway));
while (fgets(line, 100, fp))
{
p = strtok_r(line, " \t", &saveptr);
c = strtok_r(NULL, " \t", &saveptr);
g = strtok_r(NULL, " \t", &saveptr);
if (p != NULL && c != NULL)
{
if (strcmp(c, "00000000") == 0)
{
if (g)
{
char *p_end;
int gw = strtol(g, &p_end, 16);
struct in_addr addr;
addr.s_addr = gw;
strcpy(gateway, inet_ntoa(addr));
ret = 1;
}
break;
}
}
}
fclose(fp);
if (ret == 0)
{
return NULL;
}
#endif
return gateway;
}
HT_API const char * get_dns_server()
{
static char dns[32] = {'\0'};
#if __WINDOWS_OS__
IP_ADAPTER_ADDRESSES addr[16], *paddr;
DWORD len = sizeof(addr);
memset(dns, 0, sizeof(dns));
if (NO_ERROR == GetAdaptersAddresses(AF_INET, 0, 0, addr, &len) && len >= sizeof(IP_ADAPTER_ADDRESSES))
{
paddr = addr;
while (paddr)
{
PIP_ADAPTER_DNS_SERVER_ADDRESS p_ipaddr;
if (paddr->IfType & IF_TYPE_SOFTWARE_LOOPBACK)
{
paddr = paddr->Next;
continue;
}
p_ipaddr = paddr->FirstDnsServerAddress;
if (p_ipaddr)
{
struct sockaddr_in * p_inaddr = (struct sockaddr_in *)p_ipaddr->Address.lpSockaddr;
strcpy(dns, inet_ntoa(p_inaddr->sin_addr));
break;
}
paddr = paddr->Next;
}
}
#elif __LINUX_OS__
uint32 i;
char line[100] = {'\0'};
char * p;
FILE * fp;
memset(dns, 0, sizeof(dns));
fp = fopen("/etc/resolv.conf" , "r");
if (NULL == fp)
{
log_print(HT_LOG_ERR, "open file /etc/resolv.conf failed\r\n");
return dns;
}
while (fgets(line, 100, fp))
{
p = line;
while (*p == ' ') p++; // skip space
if (strncasecmp(p, "nameserver", 10) != 0)
{
continue;
}
p += 10;
while (*p == ' ') p++; // skip space
i = 0;
while (*p != '\0')
{
if (*p == ' ' || *p == '\n')
{
break;
}
if (i < sizeof(dns) - 1)
{
dns[i++] = *p++;
}
else
{
break;
}
}
dns[i] = '\0';
if (is_ip_address(dns))
{
break;
}
else
{
dns[0] = '\0';
}
}
#endif
return dns;
}
HT_API const char * get_mask_by_prefix_len(int len)
{
int i;
static char mask_str[32] = {'\0'};
uint32 mask = 0;
len = (len > 32 ? 32 : len);
for (i = 0; i < len; i++)
{
mask |= (1 << (31 - i));
}
memset(mask_str, 0, sizeof(mask_str));
snprintf(mask_str, sizeof(mask_str), "%u.%u.%u.%u", (mask & 0xFF000000) >> 24, (mask & 0x00FF0000) >> 16,
(mask & 0x0000FF00) >> 8, (mask & 0x000000FF));
return mask_str;
}
HT_API int get_prefix_len_by_mask(const char * mask)
{
int i;
int len = 0;
uint32 n = inet_addr(mask);
n = ntohl(n);
for (i = 0; i < 32; i++)
{
if (n & ((uint32)1 << (31 - i)))
{
len++;
}
else
{
break;
}
}
return len;
}
HT_API const char * get_ip_str(uint32 ipaddr /* network byte order */)
{
struct in_addr addr;
addr.s_addr = ipaddr;
return inet_ntoa(addr);
}
HT_API uint32 get_address_by_name(const char * host_name)
{
uint32 addr = 0;
if (is_ip_address(host_name))
{
addr = inet_addr(host_name);
}
else
{
struct hostent * remoteHost = gethostbyname(host_name);
if (remoteHost)
{
addr = *(unsigned long *)(remoteHost->h_addr);
}
}
return addr;
}
HT_API char * lowercase(char * str)
{
uint32 i;
for (i = 0; i < strlen(str); ++i)
{
str[i] = tolower(str[i]);
}
return str;
}
HT_API char * uppercase(char * str)
{
uint32 i;
for (i = 0; i < strlen(str); ++i)
{
str[i] = toupper(str[i]);
}
return str;
}
HT_API int unicode(char ** dst, char * src)
{
char *ret;
int l, i;
if (!src)
{
*dst = NULL;
return 0;
}
l = MIN(64, (int)strlen(src));
ret = (char *)malloc(2*l);
if (NULL == ret)
{
*dst = NULL;
return 0;
}
for (i = 0; i < l; ++i)
{
ret[2*i] = src[i];
ret[2*i+1] = '\0';
}
*dst = ret;
return 2*l;
}
HT_API BOOL bin_to_hex_str(uint8 * bin, int binlen, char * hex, int hexlen)
{
uint16 i;
uint8 j;
if (hexlen <= binlen*2)
{
return FALSE;
}
for (i = 0; i < binlen; i++)
{
j = (bin[i] >> 4) & 0xf;
if (j <= 9)
{
hex[i*2] = (j + '0');
}
else
{
hex[i*2] = (j + 'a' - 10);
}
j = bin[i] & 0xf;
if (j <= 9)
{
hex[i*2+1] = (j + '0');
}
else
{
hex[i*2+1] = (j + 'a' - 10);
}
};
hex[binlen*2] = '\0';
return TRUE;
};
HT_API int hex_str_to_bin(char * hex, int hexlen, uint8 * bin, int binlen)
{
int i;
if (binlen < hexlen/2)
{
return 0;
}
for (i=0; i<hexlen/2; i++)
{
if (hex[i*2] >= '0' && hex[i*2] <= '9')
{
bin[i] = (hex[i*2] - '0') << 4;
}
else if (hex[i*2] >= 'a' && hex[i*2] <= 'z')
{
bin[i] = (hex[i*2] - 'a' + 10) << 4;
}
else if (hex[i*2] >= 'A' && hex[i*2] <= 'Z')
{
bin[i] = (hex[i*2] - 'A' + 10) << 4;
}
else
{
return 0;
}
if (hex[i*2+1] >= '0' && hex[i*2+1] <= '9')
{
bin[i] |= (hex[i*2+1] - '0');
}
else if (hex[i*2+1] >= 'a' && hex[i*2+1] <= 'z')
{
bin[i] |= hex[i*2+1] - 'a' + 10;
}
else if (hex[i*2+1] >= 'A' && hex[i*2+1] <= 'Z')
{
bin[i] |= hex[i*2+1] - 'A' + 10;
}
else
{
return 0;
}
}
return i;
}
static char hextab[17] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 0};
HT_API int url_encode(const char * src, const int srcsize, char * dst, const int dstsize)
{
int i;
int j;
char ch;
if ((NULL == src) || (NULL == dst) || (srcsize <= 0) || (dstsize <= 0))
{
return 0;
}
for (i = 0, j = 0; i < srcsize && j < dstsize; ++i)
{
ch = src[i];
if (((ch >= 'A') && (ch <= 'Z')) ||
((ch >= 'a') && (ch <= 'z')) ||
((ch >= '0') && (ch <= '9')) ||
ch == '.' || ch == '-' || ch == '_' || ch == '*')
{
dst[j++] = ch;
}
else if (ch == ' ')
{
dst[j++] = '+';
}
else
{
if (j+3 < dstsize)
{
dst[j] = '%';
dst[j+1] = hextab[ch >> 4];
dst[j+2] = hextab[ch & 15];
j+=3;
}
else
{
return 0;
}
}
}
dst[j] = '\0';
return j;
}
HT_API int url_decode(char * dst, char const * src, uint32 len)
{
char * p_dst = dst;
const char * p_src = src;
while (len > 0)
{
int before = 0;
int after = 0;
if (*p_src == '+')
{
++p_src;
--len;
*p_dst++ = ' ';
}
else if (*p_src == '%' && len >= 3 && sscanf(p_src+1, "%n%2hhx%n", &before, p_dst, &after) == 1)
{
uint32 size = after - before; // should be 1 or 2
++p_dst;
p_src += (1 + size);
len -= (1 + size);
}
else
{
*p_dst++ = *p_src++;
--len;
}
}
*p_dst = '\0';
return (int)(p_dst - dst);
}
void url_split(char const* url, char *proto, int proto_size,
char *user, int user_size,
char *pass, int pass_size,
char *host, int host_size,
int *port, char *path, int path_size)
{
uint32 len;
const char *p, *ls, *ls2, *at, *col, *brk;
if (port)
*port = -1;
if (proto_size > 0)
proto[0] = 0;
if (user_size > 0)
user[0] = 0;
if (pass_size > 0)
pass[0] = 0;
if (host_size > 0)
host[0] = 0;
if (path_size > 0)
path[0] = 0;
/* parse protocol */
if ((p = strchr(url, ':')))
{
if (proto)
{
len = MIN(proto_size - 1, p - url);
strncpy(proto, url, len);
proto[len] = '\0';
}
p++; /* skip ':' */
if (*p == '/')
p++;
if (*p == '/')
p++;
}
else if (path)
{
/* no protocol means plain filename */
len = MIN(path_size - 1, (int)strlen(url));
strncpy(path, url, len);
path[len] = '\0';
return;
}
if (NULL == p)
{
return;
}
/* separate path from hostname */
ls = strchr(p, '/');
ls2 = strchr(p, '?');
if (!ls)
ls = ls2;
else if (ls2)
ls = MIN(ls, ls2);
if (ls)
{
if (path)
{
len = MIN(path_size - 1, (int)strlen(ls));
strncpy(path, ls, len);
path[len] = '\0';
}
}
else
{
ls = &p[strlen(p)]; // XXX
}
/* the rest is hostname, use that to parse auth/port */
if (ls != p)
{
/* authorization (user[:pass]@hostname) */
while ((at = strchr(p, '@')) && at < ls)
{
if ((brk = strchr(p, ':')) && brk < ls)
{
if (user)
{
url_decode(user, p, MIN(user_size-1, brk - p));
}
if (pass)
{
url_decode(pass, brk + 1, MIN(pass_size-1, at - brk - 1));
}
}
p = at + 1; /* skip '@' */
}
if (*p == '[' && (brk = strchr(p, ']')) && brk < ls)
{
/* [host]:port */
if (host)
{
len = MIN(host_size - 1, brk - 1 - p);
strncpy(host, p + 1, len);
host[len] = '\0';
}
if (brk[1] == ':' && port)
{
*port = atoi(brk + 2);
}
}
else if ((col = strchr(p, ':')) && col < ls)
{
if (host)
{
len = MIN(host_size - 1, col - p);
strncpy(host, p, len);
host[len] = '\0';
}
if (port)
{
*port = atoi(col + 1);
}
}
else if (host)
{
len = MIN(host_size - 1, ls - p);
strncpy(host, p, len);
host[len] = '\0';
}
}
}
HT_API time_t get_time_by_string(char * p_time_str)
{
char * ptr_s;
struct tm st;
memset(&st, 0, sizeof(struct tm));
ptr_s = p_time_str;
while (*ptr_s == ' ' || *ptr_s == '\t')
{
ptr_s++;
}
sscanf(ptr_s, "%04d-%02d-%02d %02d:%02d:%02d",
&st.tm_year, &st.tm_mon, &st.tm_mday,
&st.tm_hour, &st.tm_min, &st.tm_sec);
st.tm_year -= 1900;
st.tm_mon -= 1;
return mktime(&st);
}
HT_API void get_time_str(char * buff, int len)
{
time_t nowtime;
struct tm *t1;
time(&nowtime);
t1 = localtime(&nowtime);
snprintf(buff, len, "%04d-%02d-%02d %02d:%02d:%02d",
t1->tm_year+1900, t1->tm_mon+1, t1->tm_mday,
t1->tm_hour, t1->tm_min, t1->tm_sec);
}
HT_API void get_time_str_day_off(time_t nt, char * buff, int len, int dayoff)
{
struct tm *t1;
time_t nt1 = nt + dayoff * 24 * 3600;
t1 = localtime(&nt1);
snprintf(buff, len, "%04d-%02d-%02d %02d:%02d:%02d",
t1->tm_year+1900, t1->tm_mon+1, t1->tm_mday,
t1->tm_hour, t1->tm_min, t1->tm_sec);
}
HT_API void get_time_str_mon_off(time_t nt, char * buff, int len, int moffset)
{
struct tm *t1;
int year;
int day_of_month[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
t1 = localtime(&nt);
t1->tm_mon += moffset;
t1->tm_year += t1->tm_mon / 12;
t1->tm_mon = t1->tm_mon % 12;
year = t1->tm_year + 1900;
if ((year % 400) == 0 || ((year % 100) != 0 && (year % 4) == 0))
{
day_of_month[1] = 29;
}
if (t1->tm_mday > day_of_month[t1->tm_mon])
{
t1->tm_mday = day_of_month[t1->tm_mon];
}
snprintf(buff, len, "%04d-%02d-%02d %02d:%02d:%02d",
t1->tm_year+1900, t1->tm_mon+1, t1->tm_mday,
t1->tm_hour, t1->tm_min, t1->tm_sec);
}
HT_API time_t get_time_by_tstring(const char * p_time_str)
{
const char * ptr_s;
struct tm st;
memset(&st, 0, sizeof(struct tm));
ptr_s = p_time_str;
while (*ptr_s == ' ' || *ptr_s == '\t')
{
ptr_s++;
}
sscanf(ptr_s, "%04d-%02d-%02dT%02d:%02d:%02d",
&st.tm_year, &st.tm_mon, &st.tm_mday,
&st.tm_hour, &st.tm_min, &st.tm_sec);
st.tm_year -= 1900;
st.tm_mon -= 1;
return mktime(&st);
}
HT_API void get_tstring_by_time(time_t t, char * buff, int len)
{
struct tm *t1;
t1 = localtime(&t);
snprintf(buff, len, "%04d-%02d-%02dT%02d:%02d:%02d",
t1->tm_year+1900, t1->tm_mon+1, t1->tm_mday,
t1->tm_hour, t1->tm_min, t1->tm_sec);
}
HT_API SOCKET tcp_connect(const char * hostname, int port, int timeout)
{
int ret;
SOCKET fd;
char portstr[10];
struct timeval tv;
struct addrinfo hints, *ai, *cur_ai;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
snprintf(portstr, sizeof(portstr), "%d", port);
ret = getaddrinfo(hostname, portstr, &hints, &ai);
if (ret)
{
log_print(HT_LOG_ERR, "Failed to resolve hostname %s\r\n", hostname);
return -1;
}
fd = -1;
for (cur_ai = ai; cur_ai; cur_ai = cur_ai->ai_next)
{
fd = socket(cur_ai->ai_family, cur_ai->ai_socktype, cur_ai->ai_protocol);
if (fd <= 0)
{
continue;
}
tv.tv_sec = timeout/1000;
tv.tv_usec = (timeout%1000) * 1000;
setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char*)&tv, sizeof(tv));
if (connect(fd, cur_ai->ai_addr, (int)(cur_ai->ai_addrlen)) < 0)
{
closesocket(fd);
fd = -1;
log_print(HT_LOG_ERR, "Connect hostname %s failed\r\n", hostname);
continue;
}
break; /* okay we got one */
}
freeaddrinfo(ai);
return fd;
}
HT_API SOCKET tcp_connect_timeout(uint32 rip, int port, int timeout)
{
SOCKET cfd;
struct sockaddr_in addr;
#if __LINUX_OS__
uint32 starttime = sys_os_get_ms();
struct timeval tv;
#elif __WINDOWS_OS__
int flag = 0;
unsigned long ul = 1;
#endif
cfd = socket(AF_INET, SOCK_STREAM, 0);
if (cfd <= 0)
{
log_print(HT_LOG_ERR, "%s, socket failed\n", __FUNCTION__);
return 0;
}
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = rip;
addr.sin_port = htons((uint16)port);
#if __LINUX_OS__
tv.tv_sec = timeout/1000;
tv.tv_usec = (timeout%1000) * 1000;
setsockopt(cfd, SOL_SOCKET, SO_SNDTIMEO, (char*)&tv, sizeof(tv));
while (connect(cfd, (struct sockaddr *)&addr, sizeof(addr)) == -1 && errno != EISCONN)
{
if (sys_os_get_ms() > starttime + timeout)
{
closesocket(cfd);
return -1;
}
if (errno != EINTR)
{
closesocket(cfd);
return -1;
}
}
return cfd;
#elif __WINDOWS_OS__
ioctlsocket(cfd, FIONBIO, &ul);
if (connect(cfd, (struct sockaddr *)&addr, sizeof(addr)) != 0)
{
fd_set set;
struct timeval tv;
tv.tv_sec = timeout/1000;
tv.tv_usec = (timeout%1000) * 1000;
FD_ZERO(&set);
FD_SET(cfd, &set);
if (select((int)(cfd+1), NULL, &set, NULL, &tv) > 0)
{
int err = 0, len = sizeof(int);
getsockopt(cfd, SOL_SOCKET, SO_ERROR, (char *)&err, (socklen_t*) &len);
if (err == 0)
{
flag = 1;
}
}
}
else
{
flag = 1;
}
ul = 0;
ioctlsocket(cfd, FIONBIO, &ul);
if (flag == 1)
{
return cfd;
}
else
{
closesocket(cfd);
return 0;
}
#endif
}
static int callCount = 0;
HT_API void network_init() {
callCount++;
log_print(HT_LOG_INFO, "Number of network_init called: %d,\n", callCount);
if (callCount == 1) { // Only initialize Winsock on the first call
log_print(HT_LOG_INFO, "Initialise network: %d,\n", callCount);
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
// Handle initialization failure
log_print(HT_LOG_ERR, "%s, network_init failed\n", __FUNCTION__);//HT_LOG_INFO
}
}
}
// Function to deinitialize network resources (e.g., Winsock)
HT_API void network_deinit() {
if (callCount > 0) { // Ensure network has been initialized before deinitialization
callCount--;
log_print(HT_LOG_INFO, "Number of network_deinit called: %d,\n", callCount);
if (callCount == 0) { // Deinitialize Winsock if it's the last deinitialization
log_print(HT_LOG_INFO, "Deinitialize network\n");
if (WSACleanup() != 0) {
// Handle deinitialization failure
log_print(HT_LOG_ERR, "%s, network_deinit failed\n", __FUNCTION__);
}
}
}
}
HT_API int daemon_init()
{
#if __LINUX_OS__
pid_t pid;
pid = fork();
if (pid == -1)
{
return -1;
}
else if (pid > 0)
{
exit(0);
}
setsid();
#endif
return 0;
}
#if __WINDOWS_OS__
#include <sys/timeb.h>
// used to make sure that static variables in gettimeofday() aren't
// initialized simultaneously by multiple threads
static long g_gettimeofday_lock = 0;
HT_API int gettimeofday(struct timeval * tp, int * tz)
{
static LARGE_INTEGER tickFrequency, epochOffset;
static BOOL isInitialized = FALSE;
LARGE_INTEGER tickNow;
QueryPerformanceCounter(&tickNow);
if (!isInitialized)
{
if (1 == InterlockedIncrement(&g_gettimeofday_lock))
{
// For our first call, use "ftime()", so that we get a time with a proper epoch.
// For subsequent calls, use "QueryPerformanceCount()", because it's more fine-grain.
struct timeb tb;
ftime(&tb);
tp->tv_sec = (long)tb.time;
tp->tv_usec = 1000*tb.millitm;
// Also get our counter frequency:
QueryPerformanceFrequency(&tickFrequency);
// compute an offset to add to subsequent counter times, so we get a proper epoch:
epochOffset.QuadPart = tp->tv_sec * tickFrequency.QuadPart + (tp->tv_usec * tickFrequency.QuadPart) / 1000000L - tickNow.QuadPart;
// next caller can use ticks for time calculation
isInitialized = TRUE;
return 0;
}
else
{
InterlockedDecrement(&g_gettimeofday_lock);
// wait until first caller has initialized static values
while (!isInitialized)
{
Sleep(1);
}
}
}
// adjust our tick count so that we get a proper epoch:
tickNow.QuadPart += epochOffset.QuadPart;
tp->tv_sec = (long)(tickNow.QuadPart / tickFrequency.QuadPart);
tp->tv_usec = (long)(((tickNow.QuadPart % tickFrequency.QuadPart) * 1000000L) / tickFrequency.QuadPart);
return 0;
}
#endif