Simple NTP (Network Time Protocol) client — C library with a Python wrapper. Tested on Linux and OS X.
NTPSync runs a background thread that periodically queries an NTP server and keeps a monotonic, drift-corrected clock available to your application. It's designed for use cases where you need a precise, continuously-updated offset between your local clock and "true" NTP time — for example, synchronizing timestamps across distributed processes or measuring clock drift.
- Lightweight C core (
NtpSync.c/NtpSync.h) with no external dependencies beyond standard sockets. - Background synchronization thread with a configurable re-sync interval.
- Configurable maximum tolerated clock offset, with error reporting when synchronization accuracy is broken.
- Optional error callback for handling send/receive/version/KOD ("kiss of death") failures.
- Monotonic time accessor, independent of NTP corrections, for measuring elapsed time reliably.
- Python bindings generated with SWIG (
NtpSyncPy), so the C library can be driven directly from Python scripts.
| File | Description |
|---|---|
NtpSync.h / NtpSync.c |
Core NTP client library. |
UdpConn.h / UdpConn.c |
UDP socket helper used to talk to the NTP server. |
ByteOrder.h |
Byte-order (endianness) helpers for parsing NTP packets. |
DebugUtil.h / DebugUtil.c |
Debug/logging utilities. |
NtpSyncPy.i |
SWIG interface file used to generate the Python wrapper. |
NtpSyncPy.py |
Generated Python module (produced by SWIG). |
NtpSyncPy_wrap.c |
Generated SWIG C wrapper code. |
setup.py |
Python distutils/setup.py build script for the wrapper. |
makeit.sh |
Convenience script to build the Python extension. |
NtpSyncTest.py |
Example/test script showing how to use the Python API. |
- A C compiler (gcc/clang) and standard build tools.
- Python 2 with development headers (the Python wrapper and test script use
Python 2 syntax, e.g.
printstatements). - SWIG to (re)generate the Python bindings.
- NumPy — only needed to run
NtpSyncTest.py, which uses it to compute basic statistics.
On Debian/Ubuntu-based systems you can install the prerequisites with:
sudo apt-get install build-essential swig python2 python2-dev python-pip
pip2 install numpyThe makeit.sh script wraps the SWIG + setup.py build steps:
./makeit.shThis will:
- Remove any previous build artifacts (
_NtpSyncPy.so,build/,*.pyc). - Run SWIG against
NtpSyncPy.ito (re)generate the Python wrapper source. - Run
python setup.py buildto compile the C extension. - Copy the resulting
_NtpSyncPy.sointo the repository root, next toNtpSyncPy.py, so it can be imported directly.
To just clean the build artifacts without rebuilding:
./makeit.sh removeInclude NtpSync.h and link against NtpSync.c (and its UdpConn.c /
ByteOrder.h / DebugUtil.c dependencies). The public API is:
int ntp_sync_start(char *ip_address, double max_offset_ms, int inter_sync_delay_ms);
void ntp_sync_stop();
void ntp_sync_set_time(double ms);
double ntp_sync_get_time();
double ntp_sync_start_time();
int ntp_sync_error();
void ntp_sync_on_error(tCbOnErr cb, void *prm);
double ntp_sync_monotonic_time();| Function | Description |
|---|---|
ntp_sync_start(ip_address, max_offset_ms, inter_sync_delay_ms) |
Starts the background sync thread against the given NTP server IP, tolerating up to max_offset_ms of error and re-syncing every inter_sync_delay_ms milliseconds. Returns 0 on success. |
ntp_sync_stop() |
Stops the background sync thread. |
ntp_sync_set_time(ms) |
Sets/resets the internal reference timestamp. |
ntp_sync_get_time() |
Returns the current NTP-corrected time, in milliseconds. |
ntp_sync_start_time() |
Returns the timestamp recorded when synchronization started. |
ntp_sync_error() |
Returns the current error state (see eNtpSyncError), 0 meaning no error. |
ntp_sync_on_error(cb, prm) |
Registers a callback invoked whenever a sync error occurs. |
ntp_sync_monotonic_time() |
Returns a monotonic clock reading, unaffected by NTP corrections — useful for measuring elapsed time. |
Possible error codes (eNtpSyncError):
eNtpSyncError_no— no erroreNtpSyncError_send— failed to send the NTP requesteNtpSyncError_receive— failed to receive the NTP responseeNtpSyncError_version— unexpected NTP protocol versioneNtpSyncError_kod— server sent a "kiss of death" responseeNtpSyncError_unexpected— unexpected/malformed responseeNtpSyncError_accuracy_broken— offset exceeded the configured tolerance
After building the extension (./makeit.sh), import NtpSyncPy and call the
same functions from Python:
import NtpSyncPy as nsp
# Start syncing against an NTP server, allowing up to 0.5ms offset,
# re-synchronizing every 5000ms.
nsp.ntp_sync_start("127.0.0.1", 0.5, 5000)
# Read the current NTP-corrected time and check for errors.
if nsp.ntp_sync_error():
raise Exception("Synchronisation error (%d)" % nsp.ntp_sync_error())
current_time_ms = nsp.ntp_sync_get_time()
nsp.ntp_sync_stop()NtpSyncTest.py is a small command-line tool that continuously syncs against
an NTP server and prints delay statistics:
python2 NtpSyncTest.py --server 127.0.0.1 --offset 0.5 --synch-period 5000 --stats-period 5000Options:
| Flag | Description | Default |
|---|---|---|
-a, --server |
NTP server IP address | 127.0.0.1 |
-o, --offset |
Max clock offset tolerated, in ms | 0.5 |
-s, --synch-period |
Interval between re-syncs, in ms | 5000 |
-p, --stats-period |
Interval at which statistics are printed, in ms | 5000 |
Luca Filippin — luca.filippin@gmail.com
No license file is currently included in this repository. Please contact the author before reusing this code in your own projects.