print-wb.c revision 17680
1/*
2 * Copyright (c) 1993, 1994, 1995, 1996
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the University of California,
13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
16 * written permission.
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 */
21
22#ifndef lint
23static char rcsid[] =
24    "@(#) $Header: print-wb.c,v 1.20 96/07/14 19:39:05 leres Exp $ (LBL)";
25#endif
26
27#include <sys/types.h>
28#include <sys/time.h>
29
30#include <netinet/in.h>
31
32#include <stdio.h>
33
34#include "interface.h"
35#include "addrtoname.h"
36
37/* XXX need to add byte-swapping macros! */
38
39/*
40 * Largest packet size.  Everything should fit within this space.
41 * For instance, multiline objects are sent piecewise.
42 */
43#define MAXFRAMESIZE 1024
44
45/*
46 * Multiple drawing ops can be sent in one packet.  Each one starts on a
47 * an even multiple of DOP_ALIGN bytes, which must be a power of two.
48 */
49#define DOP_ALIGN 4
50#define DOP_ROUNDUP(x)	((((int)(x)) + (DOP_ALIGN - 1)) & ~(DOP_ALIGN - 1))
51#define DOP_NEXT(d)\
52	((struct dophdr*)((u_char *)(d) + \
53			  DOP_ROUNDUP(ntohs((d)->dh_len) + sizeof(*(d)))))
54
55/*
56 * Format of the whiteboard packet header.
57 * The transport level header.
58 */
59struct pkt_hdr {
60	u_int32_t ph_src;		/* site id of source */
61	u_int32_t ph_ts;		/* time stamp (for skew computation) */
62	u_short ph_version;	/* version number */
63	u_char ph_type;		/* message type */
64	u_char ph_flags;	/* message flags */
65};
66
67/* Packet types */
68#define PT_DRAWOP	0	/* drawing operation */
69#define PT_ID		1	/* announcement packet */
70#define PT_RREQ		2	/* repair request */
71#define PT_RREP		3	/* repair reply */
72#define PT_KILL		4	/* terminate participation */
73#define PT_PREQ         5       /* page vector request */
74#define PT_PREP         7       /* page vector reply */
75
76/* flags */
77#define PF_USER		0x01	/* hint that packet has interactive data */
78#define PF_VIS		0x02	/* only visible ops wanted */
79
80struct PageID {
81	u_int32_t p_sid;		/* session id of initiator */
82	u_int32_t p_uid;		/* page number */
83};
84
85struct dophdr {
86	u_int32_t  dh_ts;		/* sender's timestamp */
87	u_short	dh_len;		/* body length */
88	u_char	dh_flags;
89	u_char	dh_type;	/* body type */
90	/* body follows */
91};
92/*
93 * Drawing op sub-types.
94 */
95#define DT_RECT         2
96#define DT_LINE         3
97#define DT_ML           4
98#define DT_DEL          5
99#define DT_XFORM        6
100#define DT_ELL          7
101#define DT_CHAR         8
102#define DT_STR          9
103#define DT_NOP          10
104#define DT_PSCODE       11
105#define DT_PSCOMP       12
106#define DT_REF          13
107#define DT_SKIP         14
108#define DT_HOLE         15
109#define DT_MAXTYPE      15
110
111/*
112 * A drawing operation.
113 */
114struct pkt_dop {
115	struct PageID pd_page;	/* page that operations apply to */
116	u_int32_t	pd_sseq;	/* start sequence number */
117	u_int32_t	pd_eseq;	/* end sequence number */
118	/* drawing ops follow */
119};
120
121/*
122 * A repair request.
123 */
124struct pkt_rreq {
125        u_int32_t pr_id;           /* source id of drawops to be repaired */
126        struct PageID pr_page;           /* page of drawops */
127        u_int32_t pr_sseq;         /* start seqno */
128        u_int32_t pr_eseq;         /* end seqno*/
129};
130
131/*
132 * A repair reply.
133 */
134struct pkt_rrep {
135	u_int32_t pr_id;	/* original site id of ops  */
136	struct pkt_dop pr_dop;
137	/* drawing ops follow */
138};
139
140struct id_off {
141        u_int32_t id;
142        u_int32_t off;
143};
144
145struct pgstate {
146	u_int32_t slot;
147	struct PageID page;
148	u_short nid;
149	u_short rsvd;
150        /* seqptr's */
151};
152
153/*
154 * An announcement packet.
155 */
156struct pkt_id {
157	u_int32_t pi_mslot;
158        struct PageID    pi_mpage;        /* current page */
159	struct pgstate pi_ps;
160        /* seqptr's */
161        /* null-terminated site name */
162};
163
164struct pkt_preq {
165        struct PageID  pp_page;
166        u_int32_t  pp_low;
167        u_int32_t  pp_high;
168};
169
170struct pkt_prep {
171        u_int32_t  pp_n;           /* size of pageid array */
172        /* pgstate's follow */
173};
174
175static int
176wb_id(const struct pkt_id *id, u_int len)
177{
178	int i;
179	const char *cp;
180	const struct id_off *io;
181	char c;
182	int nid;
183
184	printf(" wb-id:");
185	len -= sizeof(*id);
186	if (len < 0 || (u_char *)(id + 1) > snapend)
187		return (-1);
188
189	printf(" %u/%s:%u (max %u/%s:%u) ",
190	       (u_int32_t)ntohl(id->pi_ps.slot),
191	       ipaddr_string(&id->pi_ps.page.p_sid),
192	       (u_int32_t)ntohl(id->pi_ps.page.p_uid),
193	       (u_int32_t)ntohl(id->pi_mslot),
194	       ipaddr_string(&id->pi_mpage.p_sid),
195	       (u_int32_t)ntohl(id->pi_mpage.p_uid));
196
197	nid = ntohs(id->pi_ps.nid);
198	len -= sizeof(*io) * nid;
199	io = (struct id_off *)(id + 1);
200	cp = (char *)(io + nid);
201	if ((u_char *)cp + len <= snapend) {
202		putchar('"');
203		(void)fn_print((u_char *)cp, (u_char *)cp + len);
204		putchar('"');
205	}
206
207	c = '<';
208	for (i = 0; i < nid && (u_char*)io < snapend; ++io, ++i) {
209		printf("%c%s:%u",
210		    c, ipaddr_string(&io->id), (u_int32_t)ntohl(io->off));
211		c = ',';
212	}
213	if (i >= nid) {
214		printf(">");
215		return (0);
216	}
217	return (-1);
218}
219
220static int
221wb_rreq(const struct pkt_rreq *rreq, u_int len)
222{
223	printf(" wb-rreq:");
224	if (len < sizeof(*rreq) || (u_char *)(rreq + 1) > snapend)
225		return (-1);
226
227	printf(" please repair %s %s:%u<%u:%u>",
228	       ipaddr_string(&rreq->pr_id),
229	       ipaddr_string(&rreq->pr_page.p_sid),
230	       (u_int32_t)ntohl(rreq->pr_page.p_uid),
231	       (u_int32_t)ntohl(rreq->pr_sseq),
232	       (u_int32_t)ntohl(rreq->pr_eseq));
233	return (0);
234}
235
236static int
237wb_preq(const struct pkt_preq *preq, u_int len)
238{
239	printf(" wb-preq:");
240	if (len < sizeof(*preq) || (u_char *)(preq + 1) > snapend)
241		return (-1);
242
243	printf(" need %u/%s:%u",
244	       (u_int32_t)ntohl(preq->pp_low),
245	       ipaddr_string(&preq->pp_page.p_sid),
246	       (u_int32_t)ntohl(preq->pp_page.p_uid));
247	return (0);
248}
249
250static int
251wb_prep(const struct pkt_prep *prep, u_int len)
252{
253	int n;
254	const struct pgstate* ps;
255	const u_char* ep = snapend;
256
257	printf(" wb-prep:");
258	if (len < sizeof(*prep)) {
259		return (-1);
260	}
261	n = ntohl(prep->pp_n);
262	ps = (const struct pgstate*)(prep + 1);
263	while (--n >= 0 && (u_char*)ps < ep) {
264		const struct id_off *io, *ie;
265		char c = '<';
266
267		printf(" %u/%s:%u",
268		    (u_int32_t)ntohl(ps->slot),
269		    ipaddr_string(&ps->page.p_sid),
270		    (u_int32_t)ntohl(ps->page.p_uid));
271		io = (struct id_off*)(ps + 1);
272		for (ie = io + ps->nid; io < ie && (u_char*)io < ep; ++io) {
273			printf("%c%s:%u", c, ipaddr_string(&io->id),
274			    (u_int32_t)ntohl(io->off));
275			c = ',';
276		}
277		printf(">");
278		ps = (struct pgstate*)io;
279	}
280	return ((u_char*)ps <= ep? 0 : -1);
281}
282
283
284char *dopstr[] = {
285	"dop-0!",
286	"dop-1!",
287	"RECT",
288	"LINE",
289	"ML",
290	"DEL",
291	"XFORM",
292	"ELL",
293	"CHAR",
294	"STR",
295	"NOP",
296	"PSCODE",
297	"PSCOMP",
298	"REF",
299	"SKIP",
300	"HOLE",
301};
302
303static int
304wb_dops(const struct dophdr *dh, u_int32_t ss, u_int32_t es)
305{
306	printf(" <");
307	for ( ; ss <= es; ++ss) {
308		register int t = dh->dh_type;
309
310		if (t > DT_MAXTYPE)
311			printf(" dop-%d!", t);
312		else {
313			printf(" %s", dopstr[t]);
314			if (t == DT_SKIP || t == DT_HOLE) {
315				int ts = ntohl(dh->dh_ts);
316				printf("%d", ts - ss + 1);
317				if (ss > ts || ts > es) {
318					printf("[|]");
319					if (ts < ss)
320						return (0);
321				}
322				ss = ts;
323			}
324		}
325		dh = DOP_NEXT(dh);
326		if ((u_char*)dh >= snapend) {
327			printf("[|wb]");
328			break;
329		}
330	}
331	printf(" >");
332	return (0);
333}
334
335static int
336wb_rrep(const struct pkt_rrep *rrep, u_int len)
337{
338	const struct pkt_dop *dop = &rrep->pr_dop;
339
340	printf(" wb-rrep:");
341	len -= sizeof(*rrep);
342	if (len < 0 || (u_char *)(rrep + 1) > snapend)
343		return (-1);
344
345	printf(" for %s %s:%u<%u:%u>",
346	    ipaddr_string(&rrep->pr_id),
347	    ipaddr_string(&dop->pd_page.p_sid),
348	    (u_int32_t)ntohl(dop->pd_page.p_uid),
349	    (u_int32_t)ntohl(dop->pd_sseq),
350	    (u_int32_t)ntohl(dop->pd_eseq));
351
352	if (vflag)
353		return (wb_dops((const struct dophdr*)(dop + 1),
354		    ntohl(dop->pd_sseq), ntohl(dop->pd_eseq)));
355	return (0);
356}
357
358static int
359wb_drawop(const struct pkt_dop *dop, u_int len)
360{
361	printf(" wb-dop:");
362	len -= sizeof(*dop);
363	if (len < 0 || (u_char *)(dop + 1) > snapend)
364		return (-1);
365
366	printf(" %s:%u<%u:%u>",
367	    ipaddr_string(&dop->pd_page.p_sid),
368	    (u_int32_t)ntohl(dop->pd_page.p_uid),
369	    (u_int32_t)ntohl(dop->pd_sseq),
370	    (u_int32_t)ntohl(dop->pd_eseq));
371
372	if (vflag)
373		return (wb_dops((const struct dophdr*)(dop + 1),
374				ntohl(dop->pd_sseq), ntohl(dop->pd_eseq)));
375	return (0);
376}
377
378/*
379 * Print whiteboard multicast packets.
380 */
381void
382wb_print(register const void *hdr, register u_int len)
383{
384	register const struct pkt_hdr* ph;
385
386	ph = (const struct pkt_hdr*)hdr;
387	len -= sizeof(*ph);
388	if (len < 0 || (u_char *)(ph + 1) <= snapend) {
389		if (ph->ph_flags)
390			printf("*");
391		switch (ph->ph_type) {
392
393		case PT_KILL:
394			printf(" wb-kill");
395			return;
396
397		case PT_ID:
398			if (wb_id((struct pkt_id *)(ph + 1), len) >= 0)
399				return;
400			break;
401
402		case PT_RREQ:
403			if (wb_rreq((struct pkt_rreq *)(ph + 1), len) >= 0)
404				return;
405			break;
406
407		case PT_RREP:
408			if (wb_rrep((struct pkt_rrep *)(ph + 1), len) >= 0)
409				return;
410			break;
411
412		case PT_DRAWOP:
413			if (wb_drawop((struct pkt_dop *)(ph + 1), len) >= 0)
414				return;
415			break;
416
417		case PT_PREQ:
418			if (wb_preq((struct pkt_preq *)(ph + 1), len) >= 0)
419				return;
420			break;
421
422		case PT_PREP:
423			if (wb_prep((struct pkt_prep *)(ph + 1), len) >= 0)
424				return;
425			break;
426
427		default:
428			printf(" wb-%d!", ph->ph_type);
429			return;
430		}
431	}
432	printf("[|wb]");
433}
434