ipfsyncd.c revision 1.2 1 1.2 darrenr /* $NetBSD: ipfsyncd.c,v 1.2 2012/07/22 14:27:51 darrenr Exp $ */
2 1.1 christos
3 1.1 christos /*
4 1.2 darrenr * Copyright (C) 2012 by Darren Reed.
5 1.1 christos *
6 1.1 christos * See the IPFILTER.LICENCE file for details on licencing.
7 1.1 christos */
8 1.1 christos #if !defined(lint)
9 1.1 christos static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed";
10 1.2 darrenr static const char rcsid[] = "@(#)Id: ipfsyncd.c,v 1.1.1.2 2012/07/22 13:44:55 darrenr Exp $";
11 1.1 christos #endif
12 1.1 christos #include <sys/types.h>
13 1.1 christos #include <sys/time.h>
14 1.1 christos #include <sys/socket.h>
15 1.1 christos #include <sys/ioctl.h>
16 1.1 christos #include <sys/sockio.h>
17 1.1 christos #include <sys/errno.h>
18 1.1 christos
19 1.1 christos #include <netinet/in.h>
20 1.1 christos #include <net/if.h>
21 1.1 christos
22 1.1 christos #include <arpa/inet.h>
23 1.1 christos
24 1.1 christos #include <stdio.h>
25 1.1 christos #include <stdlib.h>
26 1.1 christos #include <fcntl.h>
27 1.1 christos #include <unistd.h>
28 1.1 christos #include <string.h>
29 1.1 christos #include <syslog.h>
30 1.1 christos #include <signal.h>
31 1.1 christos
32 1.1 christos #include "ipf.h"
33 1.1 christos #include "opts.h"
34 1.1 christos
35 1.1 christos
36 1.1 christos #define R_IO_ERROR -1
37 1.1 christos #define R_OKAY 0
38 1.1 christos #define R_MORE 1
39 1.1 christos #define R_SKIP 2
40 1.1 christos #if defined(sun) && !defined(SOLARIS2)
41 1.1 christos # define STRERROR(x) sys_errlist[x]
42 1.1 christos extern char *sys_errlist[];
43 1.1 christos #else
44 1.1 christos # define STRERROR(x) strerror(x)
45 1.1 christos #endif
46 1.1 christos
47 1.1 christos
48 1.1 christos int main __P((int, char *[]));
49 1.1 christos void usage __P((char *));
50 1.1 christos void printsynchdr __P((synchdr_t *));
51 1.1 christos void printtable __P((int));
52 1.1 christos void printsmcproto __P((char *));
53 1.1 christos void printcommand __P((int));
54 1.1 christos int do_kbuff __P((int, char *, int *));
55 1.1 christos int do_packet __P((int, char *));
56 1.1 christos int buildsocket __P((char *, struct sockaddr_in *));
57 1.1 christos void do_io __P((void));
58 1.1 christos void handleterm __P((int));
59 1.1 christos
60 1.1 christos int terminate = 0;
61 1.1 christos int igmpfd = -1;
62 1.1 christos int nfd = -1;
63 1.1 christos int lfd = -1;
64 1.1 christos int opts = 0;
65 1.1 christos
66 1.1 christos void
67 1.1 christos usage(progname)
68 1.1 christos char *progname;
69 1.1 christos {
70 1.1 christos fprintf(stderr,
71 1.1 christos "Usage: %s [-d] [-p port] [-i address] -I <interface>\n",
72 1.1 christos progname);
73 1.1 christos }
74 1.1 christos
75 1.1 christos void
76 1.1 christos handleterm(sig)
77 1.1 christos int sig;
78 1.1 christos {
79 1.1 christos terminate = sig;
80 1.1 christos }
81 1.1 christos
82 1.1 christos
83 1.1 christos /* should be large enough to hold header + any datatype */
84 1.1 christos #define BUFFERLEN 1400
85 1.1 christos
86 1.1 christos int
87 1.1 christos main(argc, argv)
88 1.1 christos int argc;
89 1.1 christos char *argv[];
90 1.1 christos {
91 1.1 christos struct sockaddr_in sin;
92 1.1 christos char *interface;
93 1.1 christos char *progname;
94 1.1 christos int opt, tries;
95 1.1 christos
96 1.1 christos progname = strrchr(argv[0], '/');
97 1.1 christos if (progname) {
98 1.1 christos progname++;
99 1.1 christos } else {
100 1.1 christos progname = argv[0];
101 1.1 christos }
102 1.1 christos
103 1.1 christos opts = 0;
104 1.1 christos tries = 0;
105 1.1 christos interface = NULL;
106 1.1 christos
107 1.1 christos bzero((char *)&sin, sizeof(sin));
108 1.1 christos sin.sin_family = AF_INET;
109 1.1 christos sin.sin_port = htons(0xaf6c);
110 1.1 christos sin.sin_addr.s_addr = htonl(INADDR_UNSPEC_GROUP | 0x697066);
111 1.1 christos
112 1.1 christos while ((opt = getopt(argc, argv, "di:I:p:")) != -1)
113 1.1 christos switch (opt)
114 1.1 christos {
115 1.1 christos case 'd' :
116 1.1 christos debuglevel++;
117 1.1 christos break;
118 1.1 christos case 'I' :
119 1.1 christos interface = optarg;
120 1.1 christos break;
121 1.1 christos case 'i' :
122 1.1 christos sin.sin_addr.s_addr = inet_addr(optarg);
123 1.1 christos break;
124 1.1 christos case 'p' :
125 1.1 christos sin.sin_port = htons(atoi(optarg));
126 1.1 christos break;
127 1.1 christos }
128 1.1 christos
129 1.1 christos if (interface == NULL) {
130 1.1 christos usage(progname);
131 1.1 christos exit(1);
132 1.1 christos }
133 1.1 christos
134 1.1 christos if (!debuglevel) {
135 1.1 christos
136 1.1 christos #if BSD >= 199306
137 1.1 christos daemon(0, 0);
138 1.1 christos #else
139 1.1 christos int fd = open("/dev/null", O_RDWR);
140 1.1 christos
141 1.1 christos switch (fork())
142 1.1 christos {
143 1.1 christos case 0 :
144 1.1 christos break;
145 1.1 christos
146 1.1 christos case -1 :
147 1.1 christos fprintf(stderr, "%s: fork() failed: %s\n",
148 1.1 christos argv[0], STRERROR(errno));
149 1.1 christos exit(1);
150 1.1 christos /* NOTREACHED */
151 1.1 christos
152 1.1 christos default :
153 1.1 christos exit(0);
154 1.1 christos /* NOTREACHED */
155 1.1 christos }
156 1.1 christos
157 1.1 christos dup2(fd, 0);
158 1.1 christos dup2(fd, 1);
159 1.1 christos dup2(fd, 2);
160 1.1 christos close(fd);
161 1.1 christos
162 1.1 christos setsid();
163 1.1 christos #endif
164 1.1 christos }
165 1.1 christos
166 1.1 christos signal(SIGHUP, handleterm);
167 1.1 christos signal(SIGINT, handleterm);
168 1.1 christos signal(SIGTERM, handleterm);
169 1.1 christos
170 1.1 christos openlog(progname, LOG_PID, LOG_SECURITY);
171 1.1 christos
172 1.1 christos while (!terminate) {
173 1.1 christos if (lfd != -1) {
174 1.1 christos close(lfd);
175 1.1 christos lfd = -1;
176 1.1 christos }
177 1.1 christos if (nfd != -1) {
178 1.1 christos close(nfd);
179 1.1 christos nfd = -1;
180 1.1 christos }
181 1.1 christos if (igmpfd != -1) {
182 1.1 christos close(igmpfd);
183 1.1 christos igmpfd = -1;
184 1.1 christos }
185 1.1 christos
186 1.1 christos if (buildsocket(interface, &sin) == -1)
187 1.1 christos goto tryagain;
188 1.1 christos
189 1.1 christos lfd = open(IPSYNC_NAME, O_RDWR);
190 1.1 christos if (lfd == -1) {
191 1.1 christos syslog(LOG_ERR, "open(%s):%m", IPSYNC_NAME);
192 1.1 christos debug(1, "open(%s): %s\n", IPSYNC_NAME,
193 1.1 christos STRERROR(errno));
194 1.1 christos goto tryagain;
195 1.1 christos }
196 1.1 christos
197 1.1 christos tries = -1;
198 1.1 christos do_io();
199 1.1 christos tryagain:
200 1.1 christos tries++;
201 1.1 christos syslog(LOG_INFO, "retry in %d seconds", 1 << tries);
202 1.1 christos debug(1, "wait %d seconds\n", 1 << tries);
203 1.1 christos sleep(1 << tries);
204 1.1 christos }
205 1.1 christos
206 1.1 christos
207 1.1 christos /* terminate */
208 1.1 christos if (lfd != -1)
209 1.1 christos close(lfd);
210 1.1 christos if (nfd != -1)
211 1.1 christos close(nfd);
212 1.1 christos
213 1.1 christos syslog(LOG_ERR, "signal %d received, exiting...", terminate);
214 1.1 christos debug(1, "signal %d received, exiting...", terminate);
215 1.1 christos
216 1.1 christos exit(1);
217 1.1 christos }
218 1.1 christos
219 1.1 christos
220 1.1 christos void
221 1.1 christos do_io()
222 1.1 christos {
223 1.1 christos char nbuff[BUFFERLEN];
224 1.1 christos char buff[BUFFERLEN];
225 1.1 christos fd_set mrd, rd;
226 1.1 christos int maxfd;
227 1.1 christos int inbuf;
228 1.1 christos int n1;
229 1.1 christos int left;
230 1.1 christos
231 1.1 christos FD_ZERO(&mrd);
232 1.1 christos FD_SET(lfd, &mrd);
233 1.1 christos FD_SET(nfd, &mrd);
234 1.1 christos maxfd = nfd;
235 1.1 christos if (lfd > maxfd)
236 1.1 christos maxfd = lfd;
237 1.1 christos debug(2, "nfd %d lfd %d maxfd %d\n", nfd, lfd, maxfd);
238 1.1 christos
239 1.1 christos inbuf = 0;
240 1.1 christos /*
241 1.1 christos * A threaded approach to this loop would have one thread
242 1.1 christos * work on reading lfd (only) all the time and another thread
243 1.1 christos * working on reading nfd all the time.
244 1.1 christos */
245 1.1 christos while (!terminate) {
246 1.1 christos int n;
247 1.1 christos
248 1.1 christos rd = mrd;
249 1.1 christos
250 1.1 christos n = select(maxfd + 1, &rd, NULL, NULL, NULL);
251 1.1 christos if (n < 0) {
252 1.1 christos switch (errno)
253 1.1 christos {
254 1.1 christos case EINTR :
255 1.1 christos continue;
256 1.1 christos default :
257 1.1 christos syslog(LOG_ERR, "select error: %m");
258 1.1 christos debug(1, "select error: %s\n", STRERROR(errno));
259 1.1 christos return;
260 1.1 christos }
261 1.1 christos }
262 1.1 christos
263 1.1 christos if (FD_ISSET(lfd, &rd)) {
264 1.1 christos n1 = read(lfd, buff+inbuf, BUFFERLEN-inbuf);
265 1.1 christos
266 1.1 christos debug(3, "read(K):%d\n", n1);
267 1.1 christos
268 1.1 christos if (n1 <= 0) {
269 1.1 christos syslog(LOG_ERR, "read error (k-header): %m");
270 1.1 christos debug(1, "read error (k-header): %s\n",
271 1.1 christos STRERROR(errno));
272 1.1 christos return;
273 1.1 christos }
274 1.1 christos
275 1.1 christos left = 0;
276 1.1 christos
277 1.1 christos switch (do_kbuff(n1, buff, &left))
278 1.1 christos {
279 1.1 christos case R_IO_ERROR :
280 1.1 christos return;
281 1.1 christos case R_MORE :
282 1.1 christos inbuf += left;
283 1.1 christos break;
284 1.1 christos default :
285 1.1 christos inbuf = 0;
286 1.1 christos break;
287 1.1 christos }
288 1.1 christos }
289 1.1 christos
290 1.1 christos if (FD_ISSET(nfd, &rd)) {
291 1.1 christos n1 = recv(nfd, nbuff, sizeof(nbuff), 0);
292 1.1 christos
293 1.1 christos debug(3, "read(N):%d\n", n1);
294 1.1 christos
295 1.1 christos if (n1 <= 0) {
296 1.1 christos syslog(LOG_ERR, "read error (n-header): %m");
297 1.1 christos debug(1, "read error (n-header): %s\n",
298 1.1 christos STRERROR(errno));
299 1.1 christos return;
300 1.1 christos }
301 1.1 christos
302 1.1 christos switch (do_packet(n1, nbuff))
303 1.1 christos {
304 1.1 christos case R_IO_ERROR :
305 1.1 christos return;
306 1.1 christos default :
307 1.1 christos break;
308 1.1 christos }
309 1.1 christos }
310 1.1 christos }
311 1.1 christos }
312 1.1 christos
313 1.1 christos
314 1.1 christos int
315 1.1 christos buildsocket(nicname, sinp)
316 1.1 christos char *nicname;
317 1.1 christos struct sockaddr_in *sinp;
318 1.1 christos {
319 1.1 christos struct sockaddr_in *reqip;
320 1.1 christos struct ifreq req;
321 1.1 christos char opt;
322 1.1 christos
323 1.1 christos debug(2, "binding to %s:%s\n", nicname, inet_ntoa(sinp->sin_addr));
324 1.1 christos
325 1.1 christos if (IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) {
326 1.1 christos struct in_addr addr;
327 1.1 christos struct ip_mreq mreq;
328 1.1 christos
329 1.1 christos igmpfd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP);
330 1.1 christos if (igmpfd == -1) {
331 1.1 christos syslog(LOG_ERR, "socket:%m");
332 1.1 christos debug(1, "socket:%s\n", STRERROR(errno));
333 1.1 christos return -1;
334 1.1 christos }
335 1.1 christos
336 1.1 christos bzero((char *)&req, sizeof(req));
337 1.1 christos strncpy(req.ifr_name, nicname, sizeof(req.ifr_name));
338 1.1 christos req.ifr_name[sizeof(req.ifr_name) - 1] = '\0';
339 1.1 christos if (ioctl(igmpfd, SIOCGIFADDR, &req) == -1) {
340 1.1 christos syslog(LOG_ERR, "ioctl(SIOCGIFADDR):%m");
341 1.1 christos debug(1, "ioctl(SIOCGIFADDR):%s\n", STRERROR(errno));
342 1.1 christos close(igmpfd);
343 1.1 christos igmpfd = -1;
344 1.1 christos return -1;
345 1.1 christos }
346 1.1 christos reqip = (struct sockaddr_in *)&req.ifr_addr;
347 1.1 christos
348 1.1 christos addr = reqip->sin_addr;
349 1.1 christos if (setsockopt(igmpfd, IPPROTO_IP, IP_MULTICAST_IF,
350 1.1 christos (char *)&addr, sizeof(addr)) == -1) {
351 1.1 christos syslog(LOG_ERR, "setsockopt(IP_MULTICAST_IF(%s)):%m",
352 1.1 christos inet_ntoa(addr));
353 1.1 christos debug(1, "setsockopt(IP_MULTICAST_IF(%s)):%s\n",
354 1.1 christos inet_ntoa(addr), STRERROR(errno));
355 1.1 christos close(igmpfd);
356 1.1 christos igmpfd = -1;
357 1.1 christos return -1;
358 1.1 christos }
359 1.1 christos
360 1.1 christos opt = 0;
361 1.1 christos if (setsockopt(igmpfd, IPPROTO_IP, IP_MULTICAST_LOOP,
362 1.1 christos (char *)&opt, sizeof(opt)) == -1) {
363 1.1 christos syslog(LOG_ERR, "setsockopt(IP_MULTICAST_LOOP=0):%m");
364 1.1 christos debug(1, "setsockopt(IP_MULTICAST_LOOP=0):%s\n",
365 1.1 christos STRERROR(errno));
366 1.1 christos close(igmpfd);
367 1.1 christos igmpfd = -1;
368 1.1 christos return -1;
369 1.1 christos }
370 1.1 christos
371 1.1 christos opt = 63;
372 1.1 christos if (setsockopt(igmpfd, IPPROTO_IP, IP_MULTICAST_TTL,
373 1.1 christos (char *)&opt, sizeof(opt)) == -1) {
374 1.1 christos syslog(LOG_ERR, "setsockopt(IP_MULTICAST_TTL=%d):%m",
375 1.1 christos opt);
376 1.1 christos debug(1, "setsockopt(IP_MULTICAST_TTL=%d):%s\n", opt,
377 1.1 christos STRERROR(errno));
378 1.1 christos close(igmpfd);
379 1.1 christos igmpfd = -1;
380 1.1 christos return -1;
381 1.1 christos }
382 1.1 christos
383 1.1 christos mreq.imr_multiaddr.s_addr = sinp->sin_addr.s_addr;
384 1.1 christos mreq.imr_interface.s_addr = reqip->sin_addr.s_addr;
385 1.1 christos
386 1.1 christos if (setsockopt(igmpfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
387 1.1 christos (char *)&mreq, sizeof(mreq)) == -1) {
388 1.1 christos char buffer[80];
389 1.1 christos
390 1.1 christos sprintf(buffer, "%s,", inet_ntoa(sinp->sin_addr));
391 1.1 christos strcat(buffer, inet_ntoa(reqip->sin_addr));
392 1.1 christos
393 1.1 christos syslog(LOG_ERR,
394 1.1 christos "setsockpt(IP_ADD_MEMBERSHIP,%s):%m", buffer);
395 1.1 christos debug(1, "setsockpt(IP_ADD_MEMBERSHIP,%s):%s\n",
396 1.1 christos buffer, STRERROR(errno));
397 1.1 christos close(igmpfd);
398 1.1 christos igmpfd = -1;
399 1.1 christos return -1;
400 1.1 christos }
401 1.1 christos }
402 1.1 christos nfd = socket(AF_INET, SOCK_DGRAM, 0);
403 1.1 christos if (nfd == -1) {
404 1.1 christos syslog(LOG_ERR, "socket:%m");
405 1.1 christos if (igmpfd != -1) {
406 1.1 christos close(igmpfd);
407 1.1 christos igmpfd = -1;
408 1.1 christos }
409 1.1 christos return -1;
410 1.1 christos }
411 1.1 christos bzero((char *)&req, sizeof(req));
412 1.1 christos strncpy(req.ifr_name, nicname, sizeof(req.ifr_name));
413 1.1 christos req.ifr_name[sizeof(req.ifr_name) - 1] = '\0';
414 1.1 christos if (ioctl(nfd, SIOCGIFADDR, &req) == -1) {
415 1.1 christos syslog(LOG_ERR, "ioctl(SIOCGIFADDR):%m");
416 1.1 christos debug(1, "ioctl(SIOCGIFADDR):%s\n", STRERROR(errno));
417 1.1 christos close(igmpfd);
418 1.1 christos igmpfd = -1;
419 1.1 christos return -1;
420 1.1 christos }
421 1.1 christos
422 1.1 christos if (bind(nfd, (struct sockaddr *)&req.ifr_addr,
423 1.1 christos sizeof(req.ifr_addr)) == -1) {
424 1.1 christos syslog(LOG_ERR, "bind:%m");
425 1.1 christos debug(1, "bind:%s\n", STRERROR(errno));
426 1.1 christos close(nfd);
427 1.1 christos if (igmpfd != -1) {
428 1.1 christos close(igmpfd);
429 1.1 christos igmpfd = -1;
430 1.1 christos }
431 1.1 christos nfd = -1;
432 1.1 christos return -1;
433 1.1 christos }
434 1.1 christos
435 1.1 christos if (connect(nfd, (struct sockaddr *)sinp, sizeof(*sinp)) == -1) {
436 1.1 christos syslog(LOG_ERR, "connect:%m");
437 1.1 christos debug(1, "connect:%s\n", STRERROR(errno));
438 1.1 christos close(nfd);
439 1.1 christos if (igmpfd != -1) {
440 1.1 christos close(igmpfd);
441 1.1 christos igmpfd = -1;
442 1.1 christos }
443 1.1 christos nfd = -1;
444 1.1 christos return -1;
445 1.1 christos }
446 1.1 christos syslog(LOG_INFO, "Sending data to %s", inet_ntoa(sinp->sin_addr));
447 1.1 christos debug(3, "Sending data to %s\n", inet_ntoa(sinp->sin_addr));
448 1.1 christos
449 1.1 christos return nfd;
450 1.1 christos }
451 1.1 christos
452 1.1 christos
453 1.1 christos int
454 1.1 christos do_packet(pklen, buff)
455 1.1 christos int pklen;
456 1.1 christos char *buff;
457 1.1 christos {
458 1.1 christos synchdr_t *sh;
459 1.1 christos u_32_t magic;
460 1.1 christos int len;
461 1.1 christos int n2;
462 1.1 christos int n3;
463 1.1 christos
464 1.1 christos while (pklen > 0) {
465 1.1 christos if (pklen < sizeof(*sh)) {
466 1.1 christos syslog(LOG_ERR, "packet length too short:%d", pklen);
467 1.1 christos debug(2, "packet length too short:%d\n", pklen);
468 1.1 christos return R_SKIP;
469 1.1 christos }
470 1.1 christos
471 1.1 christos sh = (synchdr_t *)buff;
472 1.1 christos len = ntohl(sh->sm_len);
473 1.1 christos magic = ntohl(sh->sm_magic);
474 1.1 christos
475 1.1 christos if (magic != SYNHDRMAGIC) {
476 1.1 christos syslog(LOG_ERR, "invalid header magic %x", magic);
477 1.1 christos debug(2, "invalid header magic %x\n", magic);
478 1.1 christos return R_SKIP;
479 1.1 christos }
480 1.1 christos
481 1.1 christos if (pklen < len + sizeof(*sh)) {
482 1.1 christos syslog(LOG_ERR, "packet length too short:%d", pklen);
483 1.1 christos debug(2, "packet length too short:%d\n", pklen);
484 1.1 christos return R_SKIP;
485 1.1 christos }
486 1.1 christos
487 1.1 christos if (debuglevel > 3) {
488 1.1 christos printsynchdr(sh);
489 1.1 christos printcommand(sh->sm_cmd);
490 1.1 christos printtable(sh->sm_table);
491 1.1 christos printsmcproto(buff);
492 1.1 christos }
493 1.1 christos
494 1.1 christos n2 = sizeof(*sh) + len;
495 1.1 christos
496 1.1 christos do {
497 1.1 christos n3 = write(lfd, buff, n2);
498 1.1 christos if (n3 <= 0) {
499 1.1 christos syslog(LOG_ERR, "write error: %m");
500 1.1 christos debug(1, "write error: %s\n", STRERROR(errno));
501 1.1 christos return R_IO_ERROR;
502 1.1 christos }
503 1.1 christos
504 1.1 christos n2 -= n3;
505 1.1 christos buff += n3;
506 1.1 christos pklen -= n3;
507 1.1 christos } while (n3 != 0);
508 1.1 christos }
509 1.1 christos
510 1.1 christos return R_OKAY;
511 1.1 christos }
512 1.1 christos
513 1.1 christos
514 1.1 christos
515 1.1 christos int
516 1.1 christos do_kbuff(inbuf, buf, left)
517 1.1 christos int inbuf, *left;
518 1.1 christos char *buf;
519 1.1 christos {
520 1.1 christos synchdr_t *sh;
521 1.1 christos u_32_t magic;
522 1.1 christos int complete;
523 1.1 christos int sendlen;
524 1.1 christos int error;
525 1.1 christos int bytes;
526 1.1 christos int len;
527 1.1 christos int n2;
528 1.1 christos int n3;
529 1.1 christos
530 1.1 christos sendlen = 0;
531 1.1 christos bytes = inbuf;
532 1.1 christos error = R_OKAY;
533 1.1 christos sh = (synchdr_t *)buf;
534 1.1 christos
535 1.1 christos for (complete = 0; bytes > 0; complete++) {
536 1.1 christos len = ntohl(sh->sm_len);
537 1.1 christos magic = ntohl(sh->sm_magic);
538 1.1 christos
539 1.1 christos if (magic != SYNHDRMAGIC) {
540 1.1 christos syslog(LOG_ERR,
541 1.1 christos "read invalid header magic 0x%x, flushing",
542 1.1 christos magic);
543 1.1 christos debug(2, "read invalid header magic 0x%x, flushing\n",
544 1.1 christos magic);
545 1.1 christos n2 = SMC_RLOG;
546 1.1 christos (void) ioctl(lfd, SIOCIPFFL, &n2);
547 1.1 christos break;
548 1.1 christos }
549 1.1 christos
550 1.1 christos if (debuglevel > 3) {
551 1.1 christos printsynchdr(sh);
552 1.1 christos printcommand(sh->sm_cmd);
553 1.1 christos printtable(sh->sm_table);
554 1.1 christos putchar('\n');
555 1.1 christos }
556 1.1 christos
557 1.1 christos if (bytes < sizeof(*sh) + len) {
558 1.1 christos debug(3, "Not enough bytes %d < %d\n", bytes,
559 1.1 christos sizeof(*sh) + len);
560 1.1 christos error = R_MORE;
561 1.1 christos break;
562 1.1 christos }
563 1.1 christos
564 1.1 christos if (debuglevel > 3) {
565 1.1 christos printsmcproto(buf);
566 1.1 christos }
567 1.1 christos
568 1.1 christos sendlen += len + sizeof(*sh);
569 1.1 christos sh = (synchdr_t *)(buf + sendlen);
570 1.1 christos bytes -= sendlen;
571 1.1 christos }
572 1.1 christos
573 1.1 christos if (complete) {
574 1.1 christos n3 = send(nfd, buf, sendlen, 0);
575 1.1 christos if (n3 <= 0) {
576 1.1 christos syslog(LOG_ERR, "write error: %m");
577 1.1 christos debug(1, "write error: %s\n", STRERROR(errno));
578 1.1 christos return R_IO_ERROR;
579 1.1 christos }
580 1.1 christos debug(3, "send on %d len %d = %d\n", nfd, sendlen, n3);
581 1.1 christos error = R_OKAY;
582 1.1 christos }
583 1.1 christos
584 1.1 christos /* move buffer to the front,we might need to make
585 1.1 christos * this more efficient, by using a rolling pointer
586 1.1 christos * over the buffer and only copying it, when
587 1.1 christos * we are reaching the end
588 1.1 christos */
589 1.1 christos if (bytes > 0) {
590 1.1 christos bcopy(buf + bytes, buf, bytes);
591 1.1 christos error = R_MORE;
592 1.1 christos }
593 1.1 christos debug(4, "complete %d bytes %d error %d\n", complete, bytes, error);
594 1.1 christos
595 1.1 christos *left = bytes;
596 1.1 christos
597 1.1 christos return error;
598 1.1 christos }
599 1.1 christos
600 1.1 christos
601 1.1 christos void
602 1.1 christos printcommand(cmd)
603 1.1 christos int cmd;
604 1.1 christos {
605 1.1 christos
606 1.1 christos switch (cmd)
607 1.1 christos {
608 1.1 christos case SMC_CREATE :
609 1.1 christos printf(" cmd:CREATE");
610 1.1 christos break;
611 1.1 christos case SMC_UPDATE :
612 1.1 christos printf(" cmd:UPDATE");
613 1.1 christos break;
614 1.1 christos default :
615 1.1 christos printf(" cmd:Unknown(%d)", cmd);
616 1.1 christos break;
617 1.1 christos }
618 1.1 christos }
619 1.1 christos
620 1.1 christos
621 1.1 christos void
622 1.1 christos printtable(table)
623 1.1 christos int table;
624 1.1 christos {
625 1.1 christos switch (table)
626 1.1 christos {
627 1.1 christos case SMC_NAT :
628 1.1 christos printf(" table:NAT");
629 1.1 christos break;
630 1.1 christos case SMC_STATE :
631 1.1 christos printf(" table:STATE");
632 1.1 christos break;
633 1.1 christos default :
634 1.1 christos printf(" table:Unknown(%d)", table);
635 1.1 christos break;
636 1.1 christos }
637 1.1 christos }
638 1.1 christos
639 1.1 christos
640 1.1 christos void
641 1.1 christos printsmcproto(buff)
642 1.1 christos char *buff;
643 1.1 christos {
644 1.1 christos syncupdent_t *su;
645 1.1 christos synchdr_t *sh;
646 1.1 christos
647 1.1 christos sh = (synchdr_t *)buff;
648 1.1 christos
649 1.1 christos if (sh->sm_cmd == SMC_CREATE) {
650 1.1 christos ;
651 1.1 christos
652 1.1 christos } else if (sh->sm_cmd == SMC_UPDATE) {
653 1.1 christos su = (syncupdent_t *)buff;
654 1.1 christos if (sh->sm_p == IPPROTO_TCP) {
655 1.1 christos printf(" TCP Update: age %lu state %d/%d\n",
656 1.1 christos su->sup_tcp.stu_age,
657 1.1 christos su->sup_tcp.stu_state[0],
658 1.1 christos su->sup_tcp.stu_state[1]);
659 1.1 christos }
660 1.1 christos } else {
661 1.1 christos printf("Unknown command\n");
662 1.1 christos }
663 1.1 christos }
664 1.1 christos
665 1.1 christos
666 1.1 christos void
667 1.1 christos printsynchdr(sh)
668 1.1 christos synchdr_t *sh;
669 1.1 christos {
670 1.1 christos
671 1.1 christos printf("v:%d p:%d num:%d len:%d magic:%x", sh->sm_v, sh->sm_p,
672 1.1 christos ntohl(sh->sm_num), ntohl(sh->sm_len), ntohl(sh->sm_magic));
673 1.1 christos }
674