cf92ac7a0c
1.Subfolders in the Config/ directory now show up as submenus. 2.Added a way to run TunSafe as a Windows Service. Foreground Mode: The service will disconnect when TunSafe closes. Background Mode: The service will stay connected in the background. No longer required to run the TunSafe client as Admin as long as the service is running. 3.New config setting [Interface].ExcludedIPs to configure IPs that should not be routed through TunSafe. 4.Can now automatically start TunSafe when Windows starts 5.New UI with tabs and graphs 6.Cache DNS queries to ensure DNS will succeed if connection fails 7.Recreate tray icon when explorer.exe restarts 8.Renamed window title to TunSafe instead of TunSafe VPN Client 9.Main window is now resizable 10.Disallow roaming endpoint when using AllowedIPs=0.0.0.0/0 Only the original endpoint is added in the routing table so this would result in an endless loop of packets. 11.Display approximate Wireguard framing overhead in stats 12.Preparations for protocol handling with multiple threads 13.Delete the routes we made when disconnecting 14.Fix error message about unable to delete a route when connecting
175 lines
4.1 KiB
C++
175 lines
4.1 KiB
C++
// SPDX-License-Identifier: AGPL-1.0-only
|
|
// Copyright (C) 2018 Ludvig Strigeus <info@tunsafe.com>. All Rights Reserved.
|
|
#pragma once
|
|
#include "tunsafe_types.h"
|
|
#include <atomic>
|
|
#include <vector>
|
|
#include <assert.h>
|
|
#if !defined(OS_WIN)
|
|
#include <pthread.h>
|
|
#endif // !defined(OS_WIN)
|
|
|
|
#if defined(OS_WIN)
|
|
|
|
class ReaderWriterLock {
|
|
public:
|
|
ReaderWriterLock() : lock_(SRWLOCK_INIT) {}
|
|
void AcquireExclusive() { AcquireSRWLockExclusive(&lock_); }
|
|
void AcquireShared() { AcquireSRWLockShared(&lock_); }
|
|
void ReleaseExclusive() { ReleaseSRWLockExclusive(&lock_); }
|
|
void ReleaseShared() { ReleaseSRWLockShared(&lock_); }
|
|
private:
|
|
SRWLOCK lock_;
|
|
};
|
|
|
|
class Mutex {
|
|
public:
|
|
#if defined(_DEBUG)
|
|
bool locked_;
|
|
bool IsLocked() { return locked_; }
|
|
#define Mutex_SETLOCKED(x) locked_ = x;
|
|
#else
|
|
bool IsLocked() { return false; }
|
|
#define Mutex_SETLOCKED(x)
|
|
#endif
|
|
Mutex() : lock_(SRWLOCK_INIT) { Mutex_SETLOCKED(false); }
|
|
~Mutex() { }
|
|
void Acquire() {
|
|
AcquireSRWLockExclusive(&lock_);
|
|
Mutex_SETLOCKED(true);
|
|
}
|
|
void Release() {
|
|
Mutex_SETLOCKED(false);
|
|
ReleaseSRWLockExclusive(&lock_);
|
|
}
|
|
private:
|
|
SRWLOCK lock_;
|
|
};
|
|
|
|
typedef uint32 ThreadId;
|
|
|
|
static inline bool CurrentThreadIdEquals(ThreadId thread_id) {
|
|
return thread_id == GetCurrentThreadId();
|
|
}
|
|
|
|
#else // defined(OS_WIN)
|
|
|
|
class ReaderWriterLock {
|
|
public:
|
|
ReaderWriterLock() {
|
|
if (pthread_rwlock_init(&lock_, NULL) != 0)
|
|
tunsafe_die("pthread_rwlock_init failed");
|
|
}
|
|
~ReaderWriterLock() {
|
|
pthread_rwlock_destroy(&lock_);
|
|
}
|
|
void AcquireExclusive() { int rv = pthread_rwlock_wrlock(&lock_); assert(rv == 0); }
|
|
void AcquireShared() { int rv = pthread_rwlock_rdlock(&lock_); assert(rv == 0); }
|
|
void ReleaseExclusive() { int rv = pthread_rwlock_unlock(&lock_); assert(rv == 0); }
|
|
void ReleaseShared() { int rv = pthread_rwlock_unlock(&lock_); assert(rv == 0); }
|
|
private:
|
|
pthread_rwlock_t lock_;
|
|
};
|
|
|
|
class Mutex {
|
|
public:
|
|
#if defined(_DEBUG)
|
|
bool locked_;
|
|
bool IsLocked() { return locked_; }
|
|
#define Mutex_SETLOCKED(x) locked_ = x;
|
|
#else
|
|
bool IsLocked() { return false; }
|
|
#define Mutex_SETLOCKED(x)
|
|
#endif
|
|
Mutex() {
|
|
if (pthread_mutex_init(&lock_, NULL) != 0)
|
|
tunsafe_die("pthread_mutex_init failed");
|
|
Mutex_SETLOCKED(false);
|
|
}
|
|
~Mutex() {
|
|
pthread_mutex_destroy(&lock_);
|
|
}
|
|
void Acquire() {
|
|
int rv = pthread_mutex_lock(&lock_);
|
|
assert(rv == 0);
|
|
Mutex_SETLOCKED(true);
|
|
}
|
|
void Release() {
|
|
Mutex_SETLOCKED(false);
|
|
int rv = pthread_mutex_unlock(&lock_);
|
|
assert(rv == 0);
|
|
}
|
|
pthread_mutex_t *impl() { return &lock_; }
|
|
private:
|
|
pthread_mutex_t lock_;
|
|
};
|
|
|
|
typedef pthread_t ThreadId;
|
|
|
|
static inline bool CurrentThreadIdEquals(ThreadId thread_id) {
|
|
return pthread_equal(thread_id, pthread_self()) != 0;
|
|
}
|
|
|
|
static inline ThreadId GetCurrentThreadId() {
|
|
return pthread_self();
|
|
}
|
|
|
|
#endif // !defined(OS_WIN)
|
|
|
|
class ScopedLockShared {
|
|
public:
|
|
ScopedLockShared(ReaderWriterLock *lock) : lock_(lock) { lock->AcquireShared(); }
|
|
~ScopedLockShared() { lock_->ReleaseShared(); }
|
|
private:
|
|
ReaderWriterLock *lock_;
|
|
};
|
|
|
|
class ScopedLockExclusive {
|
|
public:
|
|
ScopedLockExclusive(ReaderWriterLock *lock) : lock_(lock) { lock->AcquireExclusive(); }
|
|
~ScopedLockExclusive() { lock_->ReleaseExclusive(); }
|
|
private:
|
|
ReaderWriterLock *lock_;
|
|
};
|
|
|
|
class ScopedLock {
|
|
public:
|
|
ScopedLock(Mutex *lock) : lock_(lock) { lock->Acquire(); }
|
|
~ScopedLock() { lock_->Release(); }
|
|
private:
|
|
Mutex *lock_;
|
|
};
|
|
|
|
// This class deletes objects delayed. All participating threads will call a function,
|
|
// and then once all threads did, all registered objects will get deleted.
|
|
class MultithreadedDelayedDelete {
|
|
public:
|
|
MultithreadedDelayedDelete();
|
|
~MultithreadedDelayedDelete();
|
|
|
|
typedef void DoDeleteFunc(void *x);
|
|
void Add(DoDeleteFunc *func, void *param);
|
|
|
|
void Initialize(uint32 num_threads);
|
|
|
|
void Checkpoint(uint32 thread_id);
|
|
|
|
void MainCheckpoint();
|
|
|
|
private:
|
|
struct Entry {
|
|
DoDeleteFunc *func;
|
|
void *param;
|
|
};
|
|
|
|
struct CheckpointData {
|
|
std::atomic<uint32> value;
|
|
uint8 align[60];
|
|
};
|
|
|
|
uint32 num_threads_;
|
|
|
|
std::vector<Entry> curr_, next_, to_delete_;
|
|
CheckpointData *table_;
|
|
Mutex lock_;
|
|
};
|