diff options
| author | fusion32 <marcopuzziello@gmail.com> | 2025-08-05 03:39:51 -0300 |
|---|---|---|
| committer | fusion32 <marcopuzziello@gmail.com> | 2025-08-08 12:11:36 -0300 |
| commit | 20ca1cf66123c110cc14aa452a840e5f62cd74ff (patch) | |
| tree | 5ce43bf569d54e04b5d0fab3dc9ec0708d061529 /src/hostcache.cc | |
| parent | 634554a0df8dfd35630f17b5fee44c54b7af73a5 (diff) | |
| download | querymanager-20ca1cf66123c110cc14aa452a840e5f62cd74ff.tar.gz querymanager-20ca1cf66123c110cc14aa452a840e5f62cd74ff.zip | |
store world hostname and resolve at runtime
Diffstat (limited to 'src/hostcache.cc')
| -rw-r--r-- | src/hostcache.cc | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/src/hostcache.cc b/src/hostcache.cc new file mode 100644 index 0000000..5d5d46a --- /dev/null +++ b/src/hostcache.cc @@ -0,0 +1,105 @@ +#include "querymanager.hh" + +// TODO(fusion): Support windows eventually? +#if OS_LINUX +# include <netdb.h> +#else +# error "Operating system not currently supported." +#endif + +struct THostCacheEntry{ + char HostName[100]; + bool Resolved; + int IPAddress; + int ResolveTime; +}; + +static THostCacheEntry *g_CachedHostNames; + +bool InitHostCache(void){ + ASSERT(g_CachedHostNames == NULL); + LOG("Max cached host names: %d", g_MaxCachedHostNames); + LOG("Host name expire time: %dms", g_HostNameExpireTime); + g_CachedHostNames = (THostCacheEntry*)calloc( + g_MaxCachedHostNames, sizeof(THostCacheEntry)); + return true; +} + +void ExitHostCache(void){ + if(g_CachedHostNames != NULL){ + free(g_CachedHostNames); + g_CachedHostNames = NULL; + } +} + +static bool DoResolveHostName(const char *HostName, int *OutAddr){ + ASSERT(HostName != NULL && OutAddr != NULL); + addrinfo *Result = NULL; + addrinfo Hints = {}; + Hints.ai_family = AF_INET; + Hints.ai_socktype = SOCK_STREAM; + int ErrCode = getaddrinfo(HostName, NULL, &Hints, &Result); + if(ErrCode != 0){ + LOG_ERR("Failed to resolve hostname \"%s\": %s", HostName, gai_strerror(ErrCode)); + return false; + } + + bool Resolved = false; + for(addrinfo *AddrInfo = Result; + AddrInfo != NULL; + AddrInfo = AddrInfo->ai_next){ + if(AddrInfo->ai_family == AF_INET && AddrInfo->ai_socktype == SOCK_STREAM){ + ASSERT(AddrInfo->ai_addrlen == sizeof(sockaddr_in)); + *OutAddr = ntohl(((sockaddr_in*)AddrInfo->ai_addr)->sin_addr.s_addr); + Resolved = true; + break; + } + } + freeaddrinfo(Result); + return Resolved; +} + +bool ResolveHostName(const char *HostName, int *OutAddr){ + ASSERT(HostName != NULL && !StringEmpty(HostName)); + THostCacheEntry *Entry = NULL; + int LeastRecentlyUsedIndex = 0; + int LeastRecentlyUsedTime = g_CachedHostNames[0].ResolveTime; + for(int i = 0; i < g_MaxCachedHostNames; i += 1){ + THostCacheEntry *Current = &g_CachedHostNames[i]; + + if((g_MonotonicTimeMS - Current->ResolveTime) >= g_HostNameExpireTime){ + memset(Current, 0, sizeof(THostCacheEntry)); + } + + if(Current->ResolveTime < LeastRecentlyUsedTime){ + LeastRecentlyUsedIndex = i; + LeastRecentlyUsedTime = Current->ResolveTime; + } + + if(StringEq(HostName, Current->HostName)){ + Entry = Current; + break; + } + } + + if(Entry == NULL){ + // NOTE(fusion): We also cache failures. + Entry = &g_CachedHostNames[LeastRecentlyUsedIndex]; + if(!StringCopy(Entry->HostName, sizeof(Entry->HostName), HostName)){ + LOG_WARN("Hostname \"%s\" was improperly cached because it was" + " too long (Length: %d, MaxLength: %d)", HostName, + (int)strlen(HostName), (int)sizeof(Entry->HostName)); + } + Entry->Resolved = DoResolveHostName(HostName, &Entry->IPAddress); + Entry->ResolveTime = g_MonotonicTimeMS; + } + + if(Entry && Entry->Resolved){ + if(OutAddr){ + *OutAddr = Entry->IPAddress; + } + return true; + }else{ + return false; + } +} |
