Showing 29 changed files with 377 additions and 4 deletions
+37 -2
Makefile
... ...
@@ -68,8 +68,24 @@ ifeq ($(MACHINE),riscv64)
68 68
   STRIP = $(PREFIX)-strip
69 69
 endif
70 70
 
71
+$(warning MACHINE: $(MACHINE))
72
+$(warning ARCH: $(ARCH))
73
+$(warning TARGET: $(TARGET))
74
+$(warning CFLAGS: $(CFLAGS))
75
+
71 76
 # Source files
72
-SRCS = ntpprint.c ntpset.c set_time_back.c
77
+SRCS = ntpprint.c ntpset.c set_time_back.c ntpsetfile.c ntp-server-minimal.c
78
+ifeq ($(MACHINE),cosmocc)
79
+	SRCS = ntpprint.c ntpset.c set_time_back.c ntpsetfile.c
80
+else
81
+ifeq ($(MACHINE),win64)
82
+	SRCS = ntpprint-win.c
83
+else
84
+ifeq ($(MACHINE),win32)
85
+	SRCS = ntpprint-win.c
86
+endif
87
+endif
88
+endif
73 89
 
74 90
 # Output directory based on ARCH
75 91
 OUTDIR = $(ARCH)
... ...
@@ -88,8 +104,21 @@ $(OUTDIR):
88 104
 	mkdir -p $(OUTDIR)
89 105
 
90 106
 # Pattern rule: compile each source file to output directory with naming scheme
107
+ifeq ($(MACHINE),win64)
91 108
 $(OUTDIR)/%-$(_TARGET)-$(ARCH): %.c | $(OUTDIR)
109
+	$(warning Compiling: $(@))
110
+	$(CC) $(CFLAGS) -o $@ $< -lws2_32
111
+else
112
+ifeq ($(MACHINE),win32)
113
+$(OUTDIR)/%-$(_TARGET)-$(ARCH): %.c | $(OUTDIR)
114
+	$(warning Compiling: $(@))
115
+	$(CC) $(CFLAGS) -o $@ $< -lws2_32
116
+else
117
+$(OUTDIR)/%-$(_TARGET)-$(ARCH): %.c | $(OUTDIR)
118
+	$(warning Compiling: $(@))
92 119
 	$(CC) $(CFLAGS) -o $@ $<
120
+endif
121
+endif
93 122
 
94 123
 ifdef STRIP
95 124
 	$(STRIP) $@
... ...
@@ -98,9 +127,15 @@ ifeq ($(MACHINE),cosmocc)
98 127
 	$(RM) -fv $@.aarch64.elf $@.com.dbg
99 128
 endif
100 129
 
130
+ifeq ($(MACHINE),win32)
131
+	mv win32/ntpprint-win-windows.exe-win32 win32/ntpprint-win32.exe
132
+endif
133
+ifeq ($(MACHINE),win64)
134
+	mv win64/ntpprint-win-windows.exe-win64 win64/ntpprint-win64.exe
135
+endif
101 136
 
102 137
 clean:
103
-	rm -rf arm6 arm7 win64 win32 multi aarch64 riscv64 x86_64
138
+	rm -rf $(OUTDIR)
104 139
 
105 140
 .PHONY: all clean
106 141
 
+27
Makefile.windows
... ...
@@ -0,0 +1,27 @@
1
+CC=gcc
2
+WIN64=x86_64-w64-mingw32-gcc
3
+WIN32=i686-w64-mingw32-gcc
4
+CFLAGS=-static -O2 -Wall -Wextra
5
+
6
+SRC=ntp-server-minimal.c
7
+WINDIR=win
8
+WIN64_BIN=win64/ntp-server-minimal-win64.exe
9
+WIN32_BIN=win32/ntp-server-minimal-win32.exe
10
+
11
+all: $(WIN64_BIN) $(WIN32_BIN)
12
+
13
+$(WIN64_BIN): $(SRC) | win64
14
+	$(WIN64) $(CFLAGS) -o $@ $< -lws2_32
15
+
16
+$(WIN32_BIN): $(SRC) | win32
17
+	$(WIN32) $(CFLAGS) -o $@ $< -lws2_32
18
+
19
+win32:
20
+	mkdir -p win32
21
+
22
+win64:
23
+	mkdir -p win64
24
+
25
+clean:
26
+	rm -f $(LINUX_BIN)
27
+	rm -rf $(WINDIR)
BIN
aarch64/ntp-server-minimal-linux-aarch64
Binary file not shown.
BIN
aarch64/ntpset-linux-aarch64
Binary file not shown.
BIN
aarch64/ntpsetfile-linux-aarch64
Binary file not shown.
BIN
arm6/ntp-server-minimal-linux-arm6
Binary file not shown.
BIN
arm6/ntpset-linux-arm6
Binary file not shown.
BIN
arm6/ntpsetfile-linux-arm6
Binary file not shown.
BIN
arm7/ntp-server-minimal-linux-arm7
Binary file not shown.
BIN
arm7/ntpset-linux-arm7
Binary file not shown.
BIN
arm7/ntpsetfile-linux-arm7
Binary file not shown.
+11
build.sh
... ...
@@ -34,3 +34,14 @@ else
34 34
   echo "cosmocc not found"
35 35
 fi
36 36
 
37
+echo "-----------------------------------------------------------------"
38
+echo "Machine: win32"
39
+echo "-----------------------------------------------------------------"
40
+make MACHINE=win32 > /dev/null
41
+
42
+echo "-----------------------------------------------------------------"
43
+echo "Machine: win64"
44
+echo "-----------------------------------------------------------------"
45
+make MACHINE=win64 > /dev/null
46
+
47
+make -f Makefile.windows
+9
clean.sh
... ...
@@ -29,3 +29,12 @@ echo "Cleaning: cosmocc"
29 29
 echo "-----------------------------------------------------------------"
30 30
 make MACHINE=cosmocc clean > /dev/null
31 31
 
32
+echo "-----------------------------------------------------------------"
33
+echo "Cleaning: win32 linux"
34
+echo "-----------------------------------------------------------------"
35
+make MACHINE=win32 clean > /dev/null
36
+
37
+echo "-----------------------------------------------------------------"
38
+echo "Cleaning: win64 linux"
39
+echo "-----------------------------------------------------------------"
40
+make MACHINE=win64 clean > /dev/null
BIN
multi/ntpset-cosmocc-multi
Binary file not shown.
BIN
multi/ntpsetfile-cosmocc-multi
Binary file not shown.
+183
ntp-server-minimal.c
... ...
@@ -0,0 +1,183 @@
1
+// ntp_server.c
2
+// Minimal NTP server, cross-platform (Linux/Windows)
3
+
4
+#include <stdio.h>
5
+#include <stdlib.h>
6
+#include <string.h>
7
+#include <time.h>
8
+#include <stdint.h>
9
+#include <sys/time.h>
10
+
11
+#ifdef _WIN32
12
+  #include <basetsd.h>
13
+  #include <windef.h> 
14
+  #include <winsock2.h>
15
+  #include <windows.h> 
16
+  #include <ws2tcpip.h>
17
+  //#pragma comment(lib, "ws2_32.lib")
18
+  #define CLOSESOCK closesocket
19
+  // Provide localtime_r compatibility using localtime_s
20
+  #define localtime_r(timep, result) ( localtime_s((result), (timep)) == 0 ? (result) : NULL )
21
+  #define gmtime_r(timep, result)    ( gmtime_s((result), (timep)) == 0 ? (result) : NULL )
22
+#else
23
+  #include <unistd.h>
24
+  #include <arpa/inet.h>
25
+  #include <netinet/in.h>
26
+  #include <sys/socket.h>
27
+  #define CLOSESOCK close
28
+#endif
29
+
30
+#define NTP_PORT 123
31
+#define NTP_TIMESTAMP_DELTA 2208988800ull  // 1900 to 1970
32
+
33
+typedef struct {
34
+    uint8_t li_vn_mode;
35
+    uint8_t stratum;
36
+    uint8_t poll;
37
+    int8_t  precision;
38
+    uint32_t root_delay;
39
+    uint32_t root_dispersion;
40
+    uint32_t ref_id;
41
+    uint32_t ref_ts_sec;
42
+    uint32_t ref_ts_frac;
43
+    uint32_t orig_ts_sec;
44
+    uint32_t orig_ts_frac;
45
+    uint32_t recv_ts_sec;
46
+    uint32_t recv_ts_frac;
47
+    uint32_t tx_ts_sec;
48
+    uint32_t tx_ts_frac;
49
+} ntp_packet;
50
+
51
+#ifdef _WIN32
52
+static void get_ntp_time(uint32_t *sec, uint32_t *frac) {
53
+    FILETIME ft;
54
+    GetSystemTimeAsFileTime(&ft);
55
+    ULARGE_INTEGER uli;
56
+    uli.LowPart  = ft.dwLowDateTime;
57
+    uli.HighPart = ft.dwHighDateTime;
58
+
59
+    // Convert 100ns intervals since 1601 → Unix epoch (seconds)
60
+    uint64_t seconds_since_1601 = uli.QuadPart / 10000000ULL;
61
+    uint64_t usec_part = (uli.QuadPart / 10ULL) % 1000000ULL;
62
+    time_t tv_sec = (time_t)(seconds_since_1601 - 11644473600ULL);
63
+    long tv_usec = (long)usec_part;
64
+
65
+    // Convert timeval → NTP
66
+    *sec  = htonl((uint32_t)((uint64_t)tv_sec + NTP_TIMESTAMP_DELTA));
67
+    *frac = htonl((uint32_t)((double)tv_usec * (1ULL << 32) / 1.0e6));
68
+}
69
+#else
70
+static void timeval_to_ntp(struct timeval *tv, uint32_t *sec, uint32_t *frac) {
71
+    // Cast tv_sec to uint64_t to avoid overflow
72
+    uint64_t ntp_sec = (uint64_t)tv->tv_sec + NTP_TIMESTAMP_DELTA;
73
+    *sec  = htonl((uint32_t)ntp_sec);
74
+    *frac = htonl((uint32_t)((double)tv->tv_usec * (1ULL<<32) / 1.0e6));
75
+}
76
+#endif 
77
+
78
+static void log_request(struct sockaddr_in *cliaddr) {
79
+    char ip[INET_ADDRSTRLEN];
80
+    inet_ntop(AF_INET, &(cliaddr->sin_addr), ip, sizeof(ip));
81
+
82
+    time_t now = time(NULL);
83
+    struct tm local_tm, gmt_tm;
84
+
85
+    // Get local time + UTC time
86
+    localtime_r(&now, &local_tm);
87
+    gmtime_r(&now, &gmt_tm);
88
+
89
+    // Compute offset in seconds
90
+    int offset = (int)difftime(mktime(&local_tm), mktime(&gmt_tm));
91
+
92
+    // Convert offset to ±hhmm
93
+    char tzbuf[10];
94
+    int hours = offset / 3600;
95
+    int mins  = abs(offset % 3600) / 60;
96
+    snprintf(tzbuf, sizeof(tzbuf), "%+03d%02d", hours, mins);
97
+
98
+    // Format datetime
99
+    char timebuf[64];
100
+    strftime(timebuf, sizeof(timebuf), "%Y-%m-%dT%H:%M:%S", &local_tm);
101
+
102
+    printf("%s%s Request from %s:%d\n",
103
+           timebuf, tzbuf,
104
+           ip,
105
+           ntohs(cliaddr->sin_port));
106
+    fflush(stdout);
107
+}
108
+
109
+int main() {
110
+#ifdef _WIN32
111
+    WSADATA wsa;
112
+    if (WSAStartup(MAKEWORD(2,2), &wsa) != 0) {
113
+        fprintf(stderr, "WSAStartup failed\n");
114
+        return 1;
115
+    }
116
+#endif
117
+
118
+    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
119
+    if (sockfd < 0) {
120
+        perror("socket");
121
+        return 1;
122
+    }
123
+
124
+    struct sockaddr_in servaddr, cliaddr;
125
+    socklen_t len = sizeof(cliaddr);
126
+    memset(&servaddr, 0, sizeof(servaddr));
127
+    servaddr.sin_family = AF_INET;
128
+    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
129
+    servaddr.sin_port = htons(NTP_PORT);
130
+
131
+    if (bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
132
+        perror("bind");
133
+        CLOSESOCK(sockfd);
134
+        return 1;
135
+    }
136
+
137
+    printf("NTP server listening on UDP port %d...\n", NTP_PORT);
138
+
139
+    ntp_packet packet;
140
+    while (1) {
141
+        memset(&packet, 0, sizeof(packet));
142
+        if (recvfrom(sockfd, (char *)&packet, sizeof(packet), 0,
143
+                     (struct sockaddr *)&cliaddr, &len) < 0) {
144
+            perror("recvfrom");
145
+            continue;
146
+        }
147
+
148
+        log_request(&cliaddr);
149
+
150
+        ntp_packet reply;
151
+        memset(&reply, 0, sizeof(reply));
152
+        reply.li_vn_mode = (0 << 6) | (4 << 3) | 4; // LI=0, VN=4, Mode=4 (server)
153
+        reply.stratum = 1;
154
+        reply.poll = 4;
155
+        reply.precision = -20;
156
+
157
+#ifdef _WIN32
158
+		get_ntp_time(&reply.ref_ts_sec, &reply.ref_ts_frac);
159
+        get_ntp_time(&reply.recv_ts_sec, &reply.recv_ts_frac);
160
+        get_ntp_time(&reply.tx_ts_sec, &reply.tx_ts_frac);
161
+#else
162
+        struct timeval tv;
163
+        gettimeofday(&tv, NULL);
164
+    		timeval_to_ntp(&tv, &reply.ref_ts_sec, &reply.ref_ts_frac);
165
+        reply.orig_ts_sec = packet.tx_ts_sec;
166
+        reply.orig_ts_frac = packet.tx_ts_frac;
167
+        timeval_to_ntp(&tv, &reply.recv_ts_sec, &reply.recv_ts_frac);
168
+        timeval_to_ntp(&tv, &reply.tx_ts_sec, &reply.tx_ts_frac);
169
+#endif
170
+        
171
+
172
+        if (sendto(sockfd, (char *)&reply, sizeof(reply), 0,
173
+                   (struct sockaddr *)&cliaddr, len) < 0) {
174
+            perror("sendto");
175
+        }
176
+    }
177
+
178
+    CLOSESOCK(sockfd);
179
+#ifdef _WIN32
180
+    WSACleanup();
181
+#endif
182
+    return 0;
183
+}
+3 -2
ntpprint-win.c
... ...
@@ -1,11 +1,12 @@
1 1
 #include <stdio.h>
2 2
 #include <stdlib.h>
3 3
 #include <string.h>
4
+#include <basetsd.h>
5
+#include <windef.h>
4 6
 #include <winsock2.h>
5
-#include <windows.h>
6 7
 #include <time.h>
7 8
 
8
-#pragma comment(lib, "ws2_32.lib")
9
+//#pragma comment(lib, "ws2_32.lib")
9 10
 
10 11
 #define NTP_TIMESTAMP_DELTA 2208988800ull
11 12
 
+1
ntpset.c
... ...
@@ -90,6 +90,7 @@ int main(int argc, char *argv[]) {
90 90
         .tv_sec = time_recv,
91 91
         .tv_usec = 0
92 92
     };
93
+    printf("%lld\n", (long long)tv.tv_sec);
93 94
 
94 95
     if (settimeofday(&tv, NULL) < 0) {
95 96
         perror("settimeofday (are you root?)");
+106
ntpsetfile.c
... ...
@@ -0,0 +1,106 @@
1
+#include <stdio.h>
2
+#include <stdlib.h>
3
+#include <stdint.h>
4
+#include <string.h>
5
+#include <unistd.h>
6
+#include <time.h>
7
+#include <sys/socket.h>
8
+#include <arpa/inet.h>
9
+#include <netdb.h>
10
+#include <sys/time.h>
11
+#include <errno.h>
12
+
13
+#define NTP_TIMESTAMP_DELTA 2208988800ull
14
+#define NTP_PORT 123
15
+#define NTP_PACKET_SIZE 48
16
+
17
+static long max_delta=120;
18
+
19
+int main(int argc, char *argv[]) {
20
+    if ((argc != 2) && (argc != 3)) {
21
+        fprintf(stderr, "Usage: %s <time file> <max delta>\n", argv[0]);
22
+        return 1;
23
+    }
24
+
25
+    time_t now = time(NULL);
26
+    if (now == (time_t)-1) {
27
+        perror("Cannot get time");
28
+        return EXIT_FAILURE;
29
+    }
30
+    
31
+    FILE *fp = fopen(argv[1], "r");
32
+    if (!fp) {
33
+        perror("Error opening file, creating it. Please re-run");
34
+        FILE *fp = fopen(argv[1], "w");
35
+        fprintf(fp, "%ld\n", (long)now);
36
+        fclose(fp);
37
+        return EXIT_FAILURE;
38
+    }
39
+    
40
+    if( NULL != argv[2]) {
41
+		max_delta=atoi(argv[2]);
42
+	}
43
+    
44
+
45
+    char buffer[64];  // enough for a 32-bit int in ASCII
46
+    if (!fgets(buffer, sizeof(buffer), fp)) {
47
+        fprintf(stderr, "Error reading integer from file\n");
48
+        fclose(fp);
49
+        return EXIT_FAILURE;
50
+    }
51
+    fclose(fp);
52
+
53
+    // Convert ASCII string to integer
54
+    char *endptr;
55
+    long value = strtol(buffer, &endptr, 10);
56
+
57
+    if (*endptr != '\0' && *endptr != '\n') {
58
+        fprintf(stderr, "Invalid integer in file: %s\n", buffer);
59
+        return EXIT_FAILURE;
60
+    }
61
+
62
+    if (value < INT32_MIN || value > INT32_MAX) {
63
+        fprintf(stderr, "Value out of 32-bit range: %ld\n", value);
64
+        return EXIT_FAILURE;
65
+    }
66
+    
67
+    //printf("Max delta : %ld\n", (long)max_delta);
68
+    printf("Epoch time: %ld\n", (long)now);
69
+    long delta=now-value;
70
+    printf("Delta     : %ld\n", (long)delta);
71
+    
72
+    long do_change=0; 
73
+    if(delta<0) {
74
+		//printf("Current time is before file\n");
75
+		if(-delta > max_delta) do_change=1;
76
+	} else {
77
+		//printf("Current time is after file\n");
78
+		if(delta > max_delta) do_change=1;
79
+	}
80
+    
81
+    if(do_change) {	
82
+		// Set system time
83
+		struct timeval tv = {
84
+			.tv_sec = value,
85
+			.tv_usec = 0
86
+		};
87
+		printf("Time difference %ld > %ld, forcing\n",delta,max_delta);
88
+		if (settimeofday(&tv, NULL) < 0) {
89
+			perror("settimeofday (are you root?)");
90
+			return 1;
91
+		}
92
+
93
+		//~ printf("System time set successfully to: %s", ctime(&tv.tv_sec));
94
+    } else {
95
+		printf("Time difference is acceptable, updating %s\n",
96
+			argv[1]);
97
+		FILE *fp = fopen(argv[1], "w");
98
+		if (!fp) {
99
+			perror("Error opening file");
100
+			return EXIT_FAILURE;
101
+		}
102
+		fprintf(fp, "%ld\n", (long)now);
103
+        fclose(fp);
104
+	}
105
+    return 0;
106
+}
BIN
riscv64/ntp-server-minimal-linux-riscv64
Binary file not shown.
BIN
riscv64/ntpset-linux-riscv64
Binary file not shown.
BIN
riscv64/ntpsetfile-linux-riscv64
Binary file not shown.
BIN
win32/ntp-server-minimal-win32.exe
Binary file not shown.
BIN
win32/ntpprint-win32.exe
Binary file not shown.
BIN
win64/ntp-server-minimal-win64.exe
Binary file not shown.
BIN
win64/ntpprint-win64.exe
Binary file not shown.
BIN
x86_64/ntp-server-minimal-linux-x86_64
Binary file not shown.
BIN
x86_64/ntpset-linux-x86_64
Binary file not shown.
BIN
x86_64/ntpsetfile-linux-x86_64
Binary file not shown.