diff --git a/FTL.h b/FTL.h index 5623e0c2d..3cdc064ec 100644 --- a/FTL.h +++ b/FTL.h @@ -130,7 +130,7 @@ typedef struct { int forwarded_MAX; int clients_MAX; int domains_MAX; - int overTime_MAX; + int strings_MAX; int gravity; int gravity_conf; int querytype[TYPE_MAX-1]; @@ -221,6 +221,12 @@ typedef struct { char **domains; } whitelistStruct; +typedef struct { + int version; + unsigned int global_shm_counter; + unsigned int next_str_pos; +} ShmSettings; + // Prepare timers, used mainly for debugging purposes #define NUMTIMERS 5 diff --git a/shmem.c b/shmem.c index c49e057a9..61f5ce119 100644 --- a/shmem.c +++ b/shmem.c @@ -11,6 +11,9 @@ #include "FTL.h" #include "shmem.h" +/// The version of shared memory used +#define SHARED_MEMORY_VERSION 4 + /// The name of the shared memory. Use this when connecting to the shared memory. #define SHARED_LOCK_NAME "/FTL-lock" #define SHARED_STRINGS_NAME "/FTL-strings" @@ -20,6 +23,7 @@ #define SHARED_QUERIES_NAME "/FTL-queries" #define SHARED_FORWARDED_NAME "/FTL-forwarded" #define SHARED_OVERTIME_NAME "/FTL-overTime" +#define SHARED_SETTINGS_NAME "/FTL-settings" /// The pointer in shared memory to the shared string buffer static SharedMemory shm_lock = { 0 }; @@ -30,15 +34,17 @@ static SharedMemory shm_clients = { 0 }; static SharedMemory shm_queries = { 0 }; static SharedMemory shm_forwarded = { 0 }; static SharedMemory shm_overTime = { 0 }; +static SharedMemory shm_settings = { 0 }; typedef struct { pthread_mutex_t lock; bool waitingForLock; } ShmLock; static ShmLock *shmLock = NULL; +static ShmSettings *shmSettings = NULL; static int pagesize; -static unsigned int next_pos = 0; +static unsigned int local_shm_counter = 0; unsigned long long addstr(const char *str) { @@ -51,24 +57,28 @@ unsigned long long addstr(const char *str) // Get string length size_t len = strlen(str); - if(debug) logg("Adding \"%s\" (len %i) to buffer. next_pos is %i", str, len, next_pos); + if(debug) logg("Adding \"%s\" (len %i) to buffer. next_str_pos is %i", str, len, shmSettings->next_str_pos); // Reserve additional memory if necessary - size_t required_size = next_pos + len + 1; + size_t required_size = shmSettings->next_str_pos + len + 1; // Need to cast to long long because size_t calculations cannot be negative if((long long)required_size-(long long)shm_strings.size > 0 && - !realloc_shm(&shm_strings, shm_strings.size + pagesize)) + !realloc_shm(&shm_strings, shm_strings.size + pagesize, true)) return 0; + // Store new string buffer size in corresponding counters entry + // for re-using when we need to re-map shared memory objects + counters->strings_MAX = shm_strings.size; + // Copy the C string pointed by str into the shared string buffer - strncpy(&((char*)shm_strings.ptr)[next_pos], str, len); - ((char*)shm_strings.ptr)[next_pos + len] = '\0'; + strncpy(&((char*)shm_strings.ptr)[shmSettings->next_str_pos], str, len); + ((char*)shm_strings.ptr)[shmSettings->next_str_pos + len] = '\0'; // Increment string length counter - next_pos += len+1; + shmSettings->next_str_pos += len+1; // Return start of stored string - return (next_pos - (len + 1)); + return (shmSettings->next_str_pos - (len + 1)); } char *getstr(unsigned long long pos) @@ -99,6 +109,24 @@ pthread_mutex_t create_mutex() { return lock; } +void remap_shm(void) +{ + // Remap shared object pointers which might have changed + realloc_shm(&shm_queries, counters->queries_MAX*sizeof(queriesDataStruct), false); + queries = (queriesDataStruct*)shm_queries.ptr; + realloc_shm(&shm_domains, counters->domains_MAX*sizeof(domainsDataStruct), false); + domains = (domainsDataStruct*)shm_domains.ptr; + realloc_shm(&shm_clients, counters->clients_MAX*sizeof(clientsDataStruct), false); + clients = (clientsDataStruct*)shm_clients.ptr; + realloc_shm(&shm_forwarded, counters->forwarded_MAX*sizeof(forwardedDataStruct), false); + forwarded = (forwardedDataStruct*)shm_forwarded.ptr; + realloc_shm(&shm_strings, counters->strings_MAX, false); + // strings are not exposed by a global pointer + + // Update local counter to reflect that we absorbed this change + local_shm_counter = shmSettings->global_shm_counter; +} + void _lock_shm(const char* function, const int line, const char * file) { // Signal that FTL is waiting for a lock shmLock->waitingForLock = true; @@ -109,6 +137,15 @@ void _lock_shm(const char* function, const int line, const char * file) { if(debug) logg("Obtained lock for %s() (%s:%i)", function, file, line); + // Check if this process needs to remap the shared memory objects + if(shmSettings != NULL && + local_shm_counter != shmSettings->global_shm_counter) + { + if(debug) logg("Remapping shared memory for current process %u %u", + local_shm_counter, shmSettings->global_shm_counter); + remap_shm(); + } + // Turn off the waiting for lock signal to notify everyone who was // deferring to FTL that they can jump in the lock queue. shmLock->waitingForLock = false; @@ -144,18 +181,26 @@ bool init_shmem(void) shmLock->lock = create_mutex(); shmLock->waitingForLock = false; + /****************************** shared counters struct ******************************/ + // Try to create shared memory object + shm_counters = create_shm(SHARED_COUNTERS_NAME, sizeof(countersStruct)); + counters = (countersStruct*)shm_counters.ptr; + + /****************************** shared settings struct ******************************/ + // Try to create shared memory object + shm_settings = create_shm(SHARED_SETTINGS_NAME, sizeof(ShmSettings)); + shmSettings = (ShmSettings*)shm_settings.ptr; + shmSettings->version = SHARED_MEMORY_VERSION; + shmSettings->global_shm_counter = 0; + /****************************** shared strings buffer ******************************/ // Try to create shared memory object shm_strings = create_shm(SHARED_STRINGS_NAME, pagesize); + counters->strings_MAX = pagesize; // Initialize shared string object with an empty string at position zero ((char*)shm_strings.ptr)[0] = '\0'; - next_pos = 1; - - /****************************** shared counters struct ******************************/ - // Try to create shared memory object - shm_counters = create_shm(SHARED_COUNTERS_NAME, sizeof(countersStruct)); - counters = (countersStruct*)shm_counters.ptr; + shmSettings->next_str_pos = 1; /****************************** shared domains struct ******************************/ // Try to create shared memory object @@ -186,7 +231,6 @@ bool init_shmem(void) // Try to create shared memory object shm_overTime = create_shm(SHARED_OVERTIME_NAME, size); overTime = (overTimeDataStruct*)shm_overTime.ptr; - counters->overTime_MAX = (int) size; initOverTime(); return true; @@ -205,6 +249,7 @@ void destroy_shmem(void) delete_shm(&shm_queries); delete_shm(&shm_forwarded); delete_shm(&shm_overTime); + delete_shm(&shm_settings); } SharedMemory create_shm(char *name, size_t size) @@ -303,7 +348,7 @@ void *enlarge_shmem_struct(char type) } // Reallocate enough space for 4096 instances of requested object - realloc_shm(sharedMemory, sharedMemory->size + pagesize*sizeofobj); + realloc_shm(sharedMemory, sharedMemory->size + pagesize*sizeofobj, true); // Add allocated memory to corresponding counter *counter += pagesize; @@ -311,32 +356,47 @@ void *enlarge_shmem_struct(char type) return sharedMemory->ptr; } -bool realloc_shm(SharedMemory *sharedMemory, size_t size) { - logg("Resizing \"%s\" from %zu to %zu", sharedMemory->name, sharedMemory->size, size); - - int result = munmap(sharedMemory->ptr, sharedMemory->size); - if(result != 0) - logg("realloc_shm(): munmap(%p, %zu) failed: %s", sharedMemory->ptr, sharedMemory->size, strerror(errno)); - - // Open shared memory object - int fd = shm_open(sharedMemory->name, O_RDWR, S_IRUSR | S_IWUSR); - if(fd == -1) +bool realloc_shm(SharedMemory *sharedMemory, size_t size, bool resize) +{ + // Check if we can skip this routine as nothing is to be done + // when an object is not to be resized and its size didn't + // change elsewhere + if(!resize && size == sharedMemory->size) + return true; + + // Log that we are doing something here + logg("%s \"%s\" from %zu to %zu", resize ? "Resizing" : "Remapping", sharedMemory->name, sharedMemory->size, size); + + // Resize shard memory object if requested + // If not, we only remap a shared memory object which might have changed + // in another process. This happens when pihole-FTL forks due to incoming + // TCP requests. + int fd = -1; + if(resize) { - logg("FATAL: realloc_shm(): Failed to open shared memory object \"%s\": %s", - sharedMemory->name, strerror(errno)); - exit(EXIT_FAILURE); + // Open shared memory object + fd = shm_open(sharedMemory->name, O_RDWR, S_IRUSR | S_IWUSR); + if(fd == -1) + { + logg("FATAL: realloc_shm(): Failed to open shared memory object \"%s\": %s", + sharedMemory->name, strerror(errno)); + exit(EXIT_FAILURE); + } + + // Truncate shared memory object to specified size + int result = ftruncate(fd, size); + if(result == -1) { + logg("FATAL: realloc_shm(): ftruncate(%i, %zu): Failed to resize \"%s\": %s", + fd, size, sharedMemory->name, strerror(errno)); + exit(EXIT_FAILURE); + } + + // Update shm counters to indicate that at least one shared memory object changed + shmSettings->global_shm_counter++; + local_shm_counter++; } - // Resize shard memory object to requested size - result = ftruncate(fd, size); - if(result == -1) { - logg("FATAL: realloc_shm(): ftruncate(%i, %zu): Failed to resize \"%s\": %s", - fd, size, sharedMemory->name, strerror(errno)); - exit(EXIT_FAILURE); - } - -// void *new_ptr = mremap(sharedMemory->ptr, sharedMemory->size, size, MREMAP_MAYMOVE); - void *new_ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + void *new_ptr = mremap(sharedMemory->ptr, sharedMemory->size, size, MREMAP_MAYMOVE); if(new_ptr == MAP_FAILED) { logg("FATAL: realloc_shm(): mremap(%p, %zu, %zu, MREMAP_MAYMOVE): Failed to reallocate \"%s\" (%i): %s", @@ -346,8 +406,9 @@ bool realloc_shm(SharedMemory *sharedMemory, size_t size) { } // Close shared memory object file descriptor as it is no longer - // needed after having called mmap() - close(fd); + // needed after having called ftruncate() + if(resize) + close(fd); sharedMemory->ptr = new_ptr; sharedMemory->size = size; diff --git a/shmem.h b/shmem.h index 9f9b1f902..d6d793f8a 100644 --- a/shmem.h +++ b/shmem.h @@ -33,8 +33,9 @@ SharedMemory create_shm(char *name, size_t size); /// /// \param sharedMemory the shared memory struct /// \param size the new size +/// \param resize whether the object should be resized or only remapped /// \return if reallocation was successful -bool realloc_shm(SharedMemory *sharedMemory, size_t size); +bool realloc_shm(SharedMemory *sharedMemory, size_t size, bool resize); /// Disconnect from shared memory. If there are no other connections to shared memory, it will be deleted. ///