Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pi-hole FTL v5.8.1 #1116

Merged
merged 8 commits into from
Apr 21, 2021
39 changes: 27 additions & 12 deletions src/api/socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -313,8 +313,8 @@ static void *telnet_connection_handler_thread(void *socket_desc)

// Set thread name
char threadname[16];
sprintf(threadname,"telnet-%i",sock);
prctl(PR_SET_NAME,threadname,0,0,0);
sprintf(threadname, "telnet-%i", sock);
prctl(PR_SET_NAME, threadname, 0, 0, 0);
//Receive from client
ssize_t n;
while((n = recv(sock,client_message,SOCKETBUFFERLEN-1, 0)))
Expand Down Expand Up @@ -364,8 +364,8 @@ static void *socket_connection_handler_thread(void *socket_desc)

// Set thread name
char threadname[16];
sprintf(threadname,"socket-%i",sock);
prctl(PR_SET_NAME,threadname,0,0,0);
sprintf(threadname, "socket-%i", sock);
prctl(PR_SET_NAME, threadname, 0, 0, 0);

// Receive from client
ssize_t n;
Expand Down Expand Up @@ -414,15 +414,18 @@ void *telnet_listening_thread_IPv4(void *args)
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

// Set thread name
prctl(PR_SET_NAME,"telnet-IPv4",0,0,0);
thread_names[TELNETv4] = "telnet-IPv4";
prctl(PR_SET_NAME, thread_names[TELNETv4], 0, 0, 0);

// Initialize IPv4 telnet socket
ipv4telnet = bind_to_telnet_port_IPv4(&telnetfd4);
if(!ipv4telnet)
return NULL;

thread_cancellable[TELNETv4] = true;

// Listen as long as this thread is not canceled
while(true)
while(!killed)
{
// Look for new clients that want to connect
const int csck = listener(telnetfd4, 4);
Expand All @@ -446,7 +449,9 @@ void *telnet_listening_thread_IPv4(void *args)
logg("WARNING: Unable to open telnet processing thread: %s", strerror(errno));
}
}
return false;

logg("Terminating IPv4 telnet thread");
return NULL;
}

void *telnet_listening_thread_IPv6(void *args)
Expand All @@ -460,7 +465,8 @@ void *telnet_listening_thread_IPv6(void *args)
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

// Set thread name
prctl(PR_SET_NAME,"telnet-IPv6",0,0,0);
thread_names[TELNETv6] = "telnet-IPv6";
prctl(PR_SET_NAME, thread_names[TELNETv6], 0, 0, 0);

// Initialize IPv6 telnet socket but only if IPv6 interfaces are available
if(!ipv6_available())
Expand All @@ -470,8 +476,10 @@ void *telnet_listening_thread_IPv6(void *args)
if(!ipv6telnet)
return NULL;

thread_cancellable[TELNETv6] = true;

// Listen as long as this thread is not canceled
while(true)
while(!killed)
{
// Look for new clients that want to connect
const int csck = listener(telnetfd6, 6);
Expand All @@ -495,7 +503,9 @@ void *telnet_listening_thread_IPv6(void *args)
logg("WARNING: Unable to open telnet processing thread: %s", strerror(errno));
}
}
return false;

logg("Terminating IPv6 telnet thread");
return NULL;
}

void *socket_listening_thread(void *args)
Expand All @@ -509,7 +519,8 @@ void *socket_listening_thread(void *args)
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

// Set thread name
prctl(PR_SET_NAME,"socket listener",0,0,0);
thread_names[SOCKET] = "telnet-socket";
prctl(PR_SET_NAME, thread_names[SOCKET], 0, 0, 0);

// Return early to avoid CPU spinning if Unix socket is not available
sock_avail = bind_to_unix_socket(&socketfd);
Expand All @@ -519,8 +530,10 @@ void *socket_listening_thread(void *args)
return NULL;
}

thread_cancellable[SOCKET] = true;

// Listen as long as this thread is not canceled
while(true)
while(!killed)
{
// Look for new clients that want to connect
const int csck = listener(socketfd, 0);
Expand All @@ -541,6 +554,8 @@ void *socket_listening_thread(void *args)
logg("WARNING: Unable to open socket processing thread: %s", strerror(errno));
}
}

logg("Terminating socket thread");
return NULL;
}

Expand Down
49 changes: 32 additions & 17 deletions src/daemon.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
#include "database/common.h"
// destroy_shmem()
#include "shmem.h"
// killed
#include "signals.h"

pthread_t threads[THREADS_MAX] = { 0 };
bool resolver_ready = false;
Expand Down Expand Up @@ -168,24 +170,27 @@ pid_t FTL_gettid(void)
#endif // SYS_gettid
}

// Clean up on exit
void cleanup(const int ret)
static void terminate_threads(void)
{
int s;
struct timespec ts;
// Terminate threads before closing database connections and finishing shared memory
logg("Asking threads to cancel");
for(int i = 0; i < THREADS_MAX; i++)
{
pthread_cancel(threads[i]);
}
// Try to join threads to ensure cancelation has succeeded
killed = true;
// Try to join threads to ensure cancellation has succeeded
logg("Waiting for threads to join");
for(int i = 0; i < THREADS_MAX; i++)
{
if(thread_cancellable[i])
{
logg("Thread %s (%d) is idle, terminating it.",
thread_names[i], i);
pthread_cancel(threads[i]);
}

if (clock_gettime(CLOCK_REALTIME, &ts) == -1)
{
logg("Cannot get clock time, canceling thread instead of joining");
logg("Thread %s (%d) is busy, cancelling it (cannot set timout).",
thread_names[i], i);
pthread_cancel(threads[i]);
continue;
}
Expand All @@ -195,25 +200,35 @@ void cleanup(const int ret)

if((s = pthread_timedjoin_np(threads[i], NULL, &ts)) != 0)
{
logg("Thread %d (%ld) timed out (%s), canceling it.",
i, (long)threads[i], strerror(s));
logg("Thread %s (%d) is still busy, cancelling it.",
thread_names[i], i);
pthread_cancel(threads[i]);
continue;
}
}
logg("All threads joined");
}

// Clean up on exit
void cleanup(const int ret)
{
// Do proper cleanup only if FTL started successfully
if(resolver_ready)
{
terminate_threads();

// Close database connection
gravityDB_close();
// Close database connection
gravityDB_close();

// Close sockets and delete Unix socket file handle
close_telnet_socket();
close_unix_socket(true);
// Close sockets and delete Unix socket file handle
close_telnet_socket();
close_unix_socket(true);
}

// Empty API port file, port 0 = truncate file
saveport(0);

//Remove PID file
// Remove PID file
removepid();

// Remove shared memory objects
Expand Down
7 changes: 4 additions & 3 deletions src/database/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
#include "sqlite3-ext.h"
// import_aliasclients()
#include "aliasclients.h"
// add_additional_info_column()
#include "query-table.h"

bool DBdeleteoldqueries = false;
long int lastdbindex = 0;
Expand Down Expand Up @@ -300,10 +302,9 @@ void db_init(void)
// Update to version 7 if lower
if(dbversion < 7)
{
// Update to version 7: Create message table
// Update to version 7: Add additional_info column to queries table
logg("Updating long-term database to version 7");
if(dbquery(db, "ALTER TABLE queries ADD COLUMN additional_info TEXT;") != SQLITE_OK ||
!dbquery(db, "INSERT OR REPLACE INTO ftl (id, value) VALUES ( %u, %i );", DB_VERSION, 7) != SQLITE_OK)
if(!add_additional_info_column(db))
{
logg("Column additional_info not initialized, database not available");
dbclose(&db);
Expand Down
56 changes: 50 additions & 6 deletions src/database/database-thread.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,21 @@
void *DB_thread(void *val)
{
// Set thread name
prctl(PR_SET_NAME,"database",0,0,0);
thread_names[DB] = "database";
prctl(PR_SET_NAME, thread_names[DB], 0, 0, 0);

// Save timestamp as we do not want to store immediately
// to the database
time_t lastDBsave = time(NULL) - time(NULL)%config.DBinterval;

// Run as long as this thread is not canceled
while(true)
// Run until shutdown of the process
while(!killed)
{
sqlite3 *db = dbopen(false);
if(db == NULL)
{
// Sleep 5 seconds and try again
sleepms(5000);
thread_sleepms(DB, 5000);
continue;
}
time_t now = time(NULL);
Expand All @@ -59,6 +60,13 @@ void *DB_thread(void *val)
DB_save_queries(db);
unlock_shm();

// Intermediate cancellation-point
if(killed)
{
dbclose(&db);
break;
}

// Check if GC should be done on the database
if(DBdeleteoldqueries && config.maxDBdays != -1)
{
Expand All @@ -73,22 +81,57 @@ void *DB_thread(void *val)
set_event(PARSE_NEIGHBOR_CACHE);
}

// Intermediate cancellation-point
if(killed)
{
dbclose(&db);
break;
}

// Update MAC vendor strings once a month (the MAC vendor
// database is not updated very often)
if(now % 2592000L == 0)
updateMACVendorRecords(db);

// Intermediate cancellation-point
if(killed)
{
dbclose(&db);
break;
}

if(get_and_clear_event(PARSE_NEIGHBOR_CACHE))
parse_neighbor_cache(db);

// Intermediate cancellation-point
if(killed)
{
dbclose(&db);
break;
}

// Process database related event queue elements
if(get_and_clear_event(RELOAD_GRAVITY))
FTL_reload_all_domainlists();

// Intermediate cancellation-point
if(killed)
{
dbclose(&db);
break;
}

// Reload privacy level from pihole-FTL.conf
if(get_and_clear_event(RELOAD_PRIVACY_LEVEL))
get_privacy_level(NULL);

// Intermediate cancellation-point
if(killed)
{
dbclose(&db);
break;
}

// Import alias-clients
if(get_and_clear_event(REIMPORT_ALIASCLIENTS))
{
Expand All @@ -100,9 +143,10 @@ void *DB_thread(void *val)
// Close database connection
dbclose(&db);

// Sleep 1 second
sleepms(1000);
// Sleep 1 sec
thread_sleepms(DB, 1000);
}

logg("Terminating database thread");
return NULL;
}