30m version
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
bin/
|
18
Makefile
Normal file
18
Makefile
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
SRC=main.c
|
||||||
|
TARGET=n
|
||||||
|
BUILDDIR=bin/
|
||||||
|
PREFIX=/usr/local/bin/
|
||||||
|
override CFLAGS+=-O3
|
||||||
|
|
||||||
|
all:
|
||||||
|
mkdir -p $(BUILDDIR)
|
||||||
|
$(CC) $(CFLAGS) $(SRC) -o $(BUILDDIR)$(TARGET)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -r $(BUILDDIR)
|
||||||
|
|
||||||
|
install: all
|
||||||
|
install $(BUILDDIR)$(TARGET) $(PREFIX)$(TARGET)
|
||||||
|
|
||||||
|
uninstall:
|
||||||
|
rm -rf $(PREFIX)$(TARGET)
|
28
README.md
Normal file
28
README.md
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# n
|
||||||
|
|
||||||
|
A simple NTP client.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Don’t use mine, because it will explode, launch missiles, and rain on your
|
||||||
|
porch.
|
||||||
|
|
||||||
|
If you still want to, `make install` will install this utility to
|
||||||
|
`/usr/local/bin`. You can change the installation directory by providing the
|
||||||
|
`PREFIX` option to `make install`.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
Usage: bin/n [options]
|
||||||
|
Options:
|
||||||
|
-h HOST, --host=HOST NTP server to use
|
||||||
|
defaults to 'europe.pool.ntp.org'
|
||||||
|
-p PORT, --port=PORT NTP server port to use (must be numerical)
|
||||||
|
defaults to '123'
|
||||||
|
--help Display this message and exit
|
||||||
|
```
|
||||||
|
|
||||||
|
<hr/>
|
||||||
|
|
||||||
|
Have fun!
|
129
main.c
Normal file
129
main.c
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
#include <getopt.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
#define EPOCH 2208988800ull
|
||||||
|
|
||||||
|
// assumes either little or big endian. pdp-endian, youre out of luck
|
||||||
|
#define NLITTLE 0x41424344UL
|
||||||
|
#define NENDIAN ('ABCD')
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
#if NENDIAN == NLITTLE
|
||||||
|
unsigned int mode: 3;
|
||||||
|
unsigned int vn: 3;
|
||||||
|
unsigned int li: 2;
|
||||||
|
#else
|
||||||
|
unsigned int li: 2;
|
||||||
|
unsigned int vn: 3;
|
||||||
|
unsigned int mode: 3;
|
||||||
|
#endif
|
||||||
|
uint8_t stratum;
|
||||||
|
uint8_t poll;
|
||||||
|
uint8_t prec;
|
||||||
|
uint32_t delay;
|
||||||
|
uint32_t dispersion;
|
||||||
|
uint32_t refid;
|
||||||
|
uint32_t rtms;
|
||||||
|
uint32_t rtmf;
|
||||||
|
uint32_t otms;
|
||||||
|
uint32_t otmf;
|
||||||
|
uint32_t rctms;
|
||||||
|
uint32_t rctmf;
|
||||||
|
uint32_t ttms;
|
||||||
|
uint32_t ttmf;
|
||||||
|
} __attribute__((packed, aligned(1))) ntp;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char* host;
|
||||||
|
int port;
|
||||||
|
} ntp_info;
|
||||||
|
|
||||||
|
ntp_info NDEFAULT = {.host="europe.pool.ntp.org", .port = 123};
|
||||||
|
|
||||||
|
void err(char* msg) {
|
||||||
|
fprintf(stderr, "Error %s.\n", msg);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void usage(char* program, int code) {
|
||||||
|
fprintf(stderr, "Usage: %s [options]\n", program);
|
||||||
|
fputs("Options:\n", stderr);
|
||||||
|
fputs(" -h HOST, --host=HOST NTP server to use\n", stderr);
|
||||||
|
fputs(" defaults to 'europe.pool.ntp.org'\n", stderr);
|
||||||
|
fputs(" -p PORT, --port=PORT NTP server port to use (must be numerical)\n", stderr);
|
||||||
|
fputs(" defaults to '123'\n", stderr);
|
||||||
|
fputs(" --help Display this message and exit\n", stderr);
|
||||||
|
exit(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
ntp_info args(int argc, char** argv) {
|
||||||
|
char c;
|
||||||
|
ntp_info res = NDEFAULT;
|
||||||
|
static struct option long_options[] = {
|
||||||
|
{"host", required_argument, 0, 'h'},
|
||||||
|
{"port", required_argument, 0, 'p'},
|
||||||
|
{"help", no_argument, 0, 'u'},
|
||||||
|
{NULL, 0, NULL, 0}
|
||||||
|
};
|
||||||
|
while ((c = getopt_long(argc, argv, "t:a:", long_options, 0)) != -1) {
|
||||||
|
switch (c) {
|
||||||
|
case 'h': res.host = optarg; break;
|
||||||
|
case 'p': {
|
||||||
|
char* end;
|
||||||
|
res.port = strtol(optarg, &end, 10);
|
||||||
|
if (end[0] != 0) {
|
||||||
|
fputs("Port is not numerical.\n", stderr);
|
||||||
|
usage(argv[0], 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'u': usage(argv[0], 0);
|
||||||
|
default: usage(argv[0], 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
int sock;
|
||||||
|
ntp n;
|
||||||
|
struct sockaddr_in a;
|
||||||
|
struct hostent* s;
|
||||||
|
ntp_info i = args(argc, argv);
|
||||||
|
|
||||||
|
memset(&n, 0, sizeof(ntp));
|
||||||
|
n.vn = 3;
|
||||||
|
n.mode = 3;
|
||||||
|
|
||||||
|
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||||
|
if (sock < 0) err("opening socket");
|
||||||
|
|
||||||
|
s = gethostbyname(i.host);
|
||||||
|
if (!s) err("resolving host");
|
||||||
|
|
||||||
|
bzero(&a, sizeof(a));
|
||||||
|
a.sin_family = AF_INET;
|
||||||
|
a.sin_port = htons(i.port);
|
||||||
|
bcopy(s->h_addr, &a.sin_addr.s_addr, s->h_length);
|
||||||
|
|
||||||
|
if (connect(sock, (struct sockaddr *) &a, sizeof(a)) < 0) err("connecting");
|
||||||
|
if (write(sock, &n, sizeof(ntp)) < 0) err("writing to network");
|
||||||
|
if (read(sock, &n, sizeof(ntp)) < 0) err("reading from network");
|
||||||
|
|
||||||
|
n.ttms = ntohl(n.ttms);
|
||||||
|
|
||||||
|
time_t tm = n.ttms - EPOCH;
|
||||||
|
|
||||||
|
fputs(ctime(&tm), stdout);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Reference in New Issue
Block a user