Replace functions which called once with their bodies
[pidgin-git.git] / libpurple / protocols / zephyr / Zinternal.c
blob6fea6ddf8ca00221afb88629a1194ed4c253e076
1 /* This file is part of the Project Athena Zephyr Notification System.
2 * It contains source for the internal Zephyr routines.
4 * Created by: Robert French
6 * Copyright (c) 1987,1988,1991 by the Massachusetts Institute of
7 * Technology.
8 * For copying and distribution information, see the file
9 * "mit-copyright.h".
12 #include "internal.h"
13 #ifdef WIN32
14 #include <winsock2.h>
16 #ifndef ZEPHYR_USES_KERBEROS
17 int gettimeofday(struct timeval* p, struct timezone* tz ){
18 union {
19 long long ns100; /*time since 1 Jan 1601 in 100ns units */
20 FILETIME ft;
21 } _now;
23 GetSystemTimeAsFileTime( &(_now.ft) );
24 p->tv_usec=(long)((_now.ns100 / 10LL) % 1000000LL );
25 p->tv_sec= (long)((_now.ns100-(116444736000000000LL))/10000000LL);
26 return 0;
28 #endif
30 #else
31 #include <arpa/inet.h>
32 #include <sys/socket.h>
33 #endif
35 int __Zephyr_fd = -1;
36 int __Zephyr_open;
37 int __Zephyr_port = -1;
38 struct in_addr __My_addr;
39 int __Q_CompleteLength;
40 int __Q_Size;
41 struct _Z_InputQ *__Q_Head, *__Q_Tail;
42 struct sockaddr_in __HM_addr;
43 struct sockaddr_in __HM_addr_real;
44 int __HM_set;
45 int __Zephyr_server;
46 ZLocations_t *__locate_list;
47 int __locate_num;
48 int __locate_next;
49 ZSubscription_t *__subscriptions_list;
50 int __subscriptions_num;
51 int __subscriptions_next;
52 int Z_discarded_packets = 0;
54 #ifdef ZEPHYR_USES_KERBEROS
55 C_Block __Zephyr_session;
56 #endif
57 char __Zephyr_realm[REALM_SZ];
59 #ifdef Z_DEBUG
60 void (*__Z_debug_print)(const char *fmt, va_list args, void *closure);
61 void *__Z_debug_print_closure;
62 #endif
64 static int Z_AddField(char **ptr, const char *field, char *end);
65 static int find_or_insert_uid(ZUnique_Id_t *uid, ZNotice_Kind_t kind);
67 /* Find or insert uid in the old uids buffer. The buffer is a sorted
68 * circular queue. We make the assumption that most packets arrive in
69 * order, so we can usually search for a uid or insert it into the buffer
70 * by looking back just a few entries from the end. Since this code is
71 * only executed by the client, the implementation isn't microoptimized. */
72 static int find_or_insert_uid(uid, kind)
73 ZUnique_Id_t *uid;
74 ZNotice_Kind_t kind;
76 static struct _filter {
77 ZUnique_Id_t uid;
78 ZNotice_Kind_t kind;
79 time_t t;
80 } *buffer;
81 static long size;
82 static long start;
83 static long num;
85 time_t now;
86 struct _filter *new;
87 long i, j, new_size;
88 int result;
90 /* Initialize the uid buffer if it hasn't been done already. */
91 if (!buffer) {
92 size = Z_INITFILTERSIZE;
93 buffer = (struct _filter *) malloc(size * sizeof(*buffer));
94 if (!buffer)
95 return 0;
98 /* Age the uid buffer, discarding any uids older than the clock skew. */
99 time(&now);
100 while (num && (now - buffer[start % size].t) > CLOCK_SKEW)
101 start++, num--;
102 start %= size;
104 /* Make room for a new uid, since we'll probably have to insert one. */
105 if (num == size) {
106 new_size = size * 2 + 2;
107 new = (struct _filter *) malloc(new_size * sizeof(*new));
108 if (!new)
109 return 0;
110 for (i = 0; i < num; i++)
111 new[i] = buffer[(start + i) % size];
112 free(buffer);
113 buffer = new;
114 size = new_size;
115 start = 0;
118 /* Search for this uid in the buffer, starting from the end. */
119 for (i = start + num - 1; i >= start; i--) {
120 result = memcmp(uid, &buffer[i % size].uid, sizeof(*uid));
121 if (result == 0 && buffer[i % size].kind == kind)
122 return 1;
123 if (result > 0)
124 break;
127 /* We didn't find it; insert the uid into the buffer after i. */
128 i++;
129 for (j = start + num; j > i; j--)
130 buffer[j % size] = buffer[(j - 1) % size];
131 buffer[i % size].uid = *uid;
132 buffer[i % size].kind = kind;
133 buffer[i % size].t = now;
134 num++;
136 return 0;
140 /* Return 1 if there is a packet waiting, 0 otherwise */
142 static int Z_PacketWaiting(void)
144 struct timeval tv;
145 fd_set read;
147 tv.tv_sec = tv.tv_usec = 0;
148 FD_ZERO(&read);
149 FD_SET(ZGetFD(), &read);
150 return (select(ZGetFD() + 1, &read, NULL, NULL, &tv));
154 /* Wait for a complete notice to become available */
156 Code_t Z_WaitForComplete(void)
158 Code_t retval;
160 if (__Q_CompleteLength)
161 return (Z_ReadEnqueue());
163 while (!__Q_CompleteLength)
164 if ((retval = Z_ReadWait()) != ZERR_NONE)
165 return (retval);
167 return (ZERR_NONE);
171 /* Read any available packets and enqueue them */
173 Code_t Z_ReadEnqueue()
175 Code_t retval;
177 if (ZGetFD() < 0)
178 return (ZERR_NOPORT);
180 while (Z_PacketWaiting())
181 if ((retval = Z_ReadWait()) != ZERR_NONE)
182 return (retval);
184 return (ZERR_NONE);
189 * Search the queue for a notice with the proper multiuid - remove any
190 * notices that haven't been touched in a while
193 static struct _Z_InputQ *Z_SearchQueue(ZUnique_Id_t *uid, ZNotice_Kind_t kind)
195 register struct _Z_InputQ *qptr;
196 struct _Z_InputQ *next;
197 struct timeval tv;
199 (void) gettimeofday(&tv, (struct timezone *)0);
201 qptr = __Q_Head;
203 while (qptr) {
204 if (ZCompareUID(uid, &qptr->uid) && qptr->kind == kind)
205 return (qptr);
206 next = qptr->next;
207 if (qptr->timep && ((time_t)qptr->timep+Z_NOTICETIMELIMIT < tv.tv_sec))
208 Z_RemQueue(qptr);
209 qptr = next;
211 return (NULL);
215 * Now we delve into really convoluted queue handling and
216 * fragmentation reassembly algorithms and other stuff you probably
217 * don't want to look at...
219 * This routine does NOT guarantee a complete packet will be ready when it
220 * returns.
223 Code_t Z_ReadWait()
225 register struct _Z_InputQ *qptr;
226 ZNotice_t notice;
227 ZPacket_t packet;
228 struct sockaddr_in olddest, from;
229 int packet_len, zvlen, part, partof;
230 socklen_t from_len;
231 char *slash;
232 Code_t retval;
233 fd_set fds;
234 struct timeval tv;
236 if (ZGetFD() < 0)
237 return (ZERR_NOPORT);
239 FD_ZERO(&fds);
240 FD_SET(ZGetFD(), &fds);
241 tv.tv_sec = 60;
242 tv.tv_usec = 0;
244 if (select(ZGetFD() + 1, &fds, NULL, NULL, &tv) < 0)
245 return (errno);
246 if (!FD_ISSET(ZGetFD(), &fds))
247 return ETIMEDOUT;
249 from_len = sizeof(struct sockaddr_in);
251 packet_len = recvfrom(ZGetFD(), packet, sizeof(packet) - 1, 0,
252 (struct sockaddr *)&from, &from_len);
254 if (packet_len < 0)
255 return (errno);
257 if (!packet_len)
258 return (ZERR_EOF);
260 packet[packet_len] = '\0';
262 /* Ignore obviously non-Zephyr packets. */
263 zvlen = sizeof(ZVERSIONHDR) - 1;
264 if (packet_len < zvlen || memcmp(packet, ZVERSIONHDR, zvlen) != 0) {
265 Z_discarded_packets++;
266 return (ZERR_NONE);
269 /* Parse the notice */
270 if ((retval = ZParseNotice(packet, packet_len, &notice)) != ZERR_NONE)
271 return (retval);
274 * If we're not a server and the notice is of an appropriate kind,
275 * send back a CLIENTACK to whoever sent it to say we got it.
277 if (!__Zephyr_server) {
278 if (notice.z_kind != HMACK && notice.z_kind != SERVACK &&
279 notice.z_kind != SERVNAK && notice.z_kind != CLIENTACK) {
280 ZNotice_t tmpnotice;
281 ZPacket_t pkt;
282 int len;
284 tmpnotice = notice;
285 tmpnotice.z_kind = CLIENTACK;
286 tmpnotice.z_message_len = 0;
287 olddest = __HM_addr;
288 __HM_addr = from;
289 if ((retval = ZFormatSmallRawNotice(&tmpnotice, pkt, &len))
290 != ZERR_NONE)
291 return(retval);
292 if ((retval = ZSendPacket(pkt, len, 0)) != ZERR_NONE)
293 return (retval);
294 __HM_addr = olddest;
296 if (find_or_insert_uid(&notice.z_uid, notice.z_kind))
297 return(ZERR_NONE);
299 /* Check authentication on the notice. */
300 notice.z_checked_auth = ZCheckAuthentication(&notice, &from);
305 * Parse apart the z_multinotice field - if the field is blank for
306 * some reason, assume this packet stands by itself.
308 slash = strchr(notice.z_multinotice, '/');
309 if (slash) {
310 part = atoi(notice.z_multinotice);
311 partof = atoi(slash+1);
312 if (part > partof || partof == 0) {
313 part = 0;
314 partof = notice.z_message_len;
317 else {
318 part = 0;
319 partof = notice.z_message_len;
322 /* Too big a packet...just ignore it! */
323 if (partof > Z_MAXNOTICESIZE)
324 return (ZERR_NONE);
327 * If we aren't a server and we can find a notice in the queue
328 * with the same multiuid field, insert the current fragment as
329 * appropriate.
331 switch (notice.z_kind) {
332 case SERVACK:
333 case SERVNAK:
334 /* The SERVACK and SERVNAK replies shouldn't be reassembled
335 (they have no parts). Instead, we should hold on to the reply
336 ONLY if it's the first part of a fragmented message, i.e.
337 multi_uid == uid. This allows programs to wait for the uid
338 of the first packet, and get a response when that notice
339 arrives. Acknowledgements of the other fragments are discarded
340 (XXX we assume here that they all carry the same information
341 regarding failure/success)
343 if (!__Zephyr_server &&
344 !ZCompareUID(&notice.z_multiuid, &notice.z_uid))
345 /* they're not the same... throw away this packet. */
346 return(ZERR_NONE);
347 /* fall thru & process it */
348 default:
349 /* for HMACK types, we assume no packet loss (local loopback
350 connections). The other types can be fragmented and MUST
351 run through this code. */
352 if (!__Zephyr_server && (qptr = Z_SearchQueue(&notice.z_multiuid,
353 notice.z_kind))) {
355 * If this is the first fragment, and we haven't already
356 * gotten a first fragment, grab the header from it.
358 if (part == 0 && !qptr->header) {
359 qptr->header_len = packet_len-notice.z_message_len;
360 qptr->header = (char *) malloc((unsigned) qptr->header_len);
361 if (!qptr->header)
362 return (ENOMEM);
363 (void) memcpy(qptr->header, packet, qptr->header_len);
365 return (Z_AddNoticeToEntry(qptr, &notice, part));
370 * We'll have to create a new entry...make sure the queue isn't
371 * going to get too big.
373 if (__Q_Size+(__Zephyr_server ? notice.z_message_len : partof) > Z_MAXQUEUESIZE)
374 return (ZERR_NONE);
377 * This is a notice we haven't heard of, so create a new queue
378 * entry for it and zero it out.
380 qptr = (struct _Z_InputQ *)malloc(sizeof(struct _Z_InputQ));
381 if (!qptr)
382 return (ENOMEM);
383 (void) memset((char *)qptr, 0, sizeof(struct _Z_InputQ));
385 /* Insert the entry at the end of the queue */
386 qptr->next = NULL;
387 qptr->prev = __Q_Tail;
388 if (__Q_Tail)
389 __Q_Tail->next = qptr;
390 __Q_Tail = qptr;
392 if (!__Q_Head)
393 __Q_Head = qptr;
396 /* Copy the from field, multiuid, kind, and checked authentication. */
397 qptr->from = from;
398 qptr->uid = notice.z_multiuid;
399 qptr->kind = notice.z_kind;
400 qptr->auth = notice.z_checked_auth;
403 * If this is the first part of the notice, we take the header
404 * from it. We only take it if this is the first fragment so that
405 * the Unique ID's will be predictable.
407 * If a Zephyr Server, we always take the header.
409 if (__Zephyr_server || part == 0) {
410 qptr->header_len = packet_len-notice.z_message_len;
411 qptr->header = (char *) malloc((unsigned) qptr->header_len);
412 if (!qptr->header)
413 return ENOMEM;
414 (void) memcpy(qptr->header, packet, qptr->header_len);
418 * If this is not a fragmented notice, then don't bother with a
419 * hole list.
420 * If we are a Zephyr server, all notices are treated as complete.
422 if (__Zephyr_server || (part == 0 && notice.z_message_len == partof)) {
423 __Q_CompleteLength++;
424 qptr->holelist = (struct _Z_Hole *) 0;
425 qptr->complete = 1;
426 /* allocate a msg buf for this piece */
427 if (notice.z_message_len == 0)
428 qptr->msg = 0;
429 else if (!(qptr->msg = (char *) malloc((unsigned) notice.z_message_len)))
430 return(ENOMEM);
431 else
432 (void) memcpy(qptr->msg, notice.z_message, notice.z_message_len);
433 qptr->msg_len = notice.z_message_len;
434 __Q_Size += notice.z_message_len;
435 qptr->packet_len = qptr->header_len+qptr->msg_len;
436 if (!(qptr->packet = (char *) malloc((unsigned) qptr->packet_len)))
437 return (ENOMEM);
438 (void) memcpy(qptr->packet, qptr->header, qptr->header_len);
439 if(qptr->msg)
440 (void) memcpy(qptr->packet+qptr->header_len, qptr->msg,
441 qptr->msg_len);
442 return (ZERR_NONE);
446 * We know how long the message is going to be (this is better
447 * than IP fragmentation...), so go ahead and allocate it all.
449 if (!(qptr->msg = (char *) malloc((unsigned) partof)) && partof)
450 return (ENOMEM);
451 qptr->msg_len = partof;
452 __Q_Size += partof;
455 * Well, it's a fragmented notice...allocate a hole list and
456 * initialize it to the full packet size. Then insert the
457 * current fragment.
459 if (!(qptr->holelist = (struct _Z_Hole *)
460 malloc(sizeof(struct _Z_Hole))))
461 return (ENOMEM);
462 qptr->holelist->next = (struct _Z_Hole *) 0;
463 qptr->holelist->first = 0;
464 qptr->holelist->last = partof-1;
465 return (Z_AddNoticeToEntry(qptr, &notice, part));
469 /* Fragment management routines - compliments, more or less, of RFC815 */
471 Code_t Z_AddNoticeToEntry(qptr, notice, part)
472 struct _Z_InputQ *qptr;
473 ZNotice_t *notice;
474 int part;
476 int last, oldfirst, oldlast;
477 struct _Z_Hole *hole, *lasthole;
478 struct timeval tv;
480 /* Incorporate this notice's checked authentication. */
481 if (notice->z_checked_auth == ZAUTH_FAILED)
482 qptr->auth = ZAUTH_FAILED;
483 else if (notice->z_checked_auth == ZAUTH_NO && qptr->auth != ZAUTH_FAILED)
484 qptr->auth = ZAUTH_NO;
486 (void) gettimeofday(&tv, (struct timezone *)0);
487 qptr->timep = tv.tv_sec;
489 last = part+notice->z_message_len-1;
491 hole = qptr->holelist;
492 lasthole = (struct _Z_Hole *) 0;
494 /* copy in the message body */
495 (void) memcpy(qptr->msg+part, notice->z_message, notice->z_message_len);
497 /* Search for a hole that overlaps with the current fragment */
498 while (hole) {
499 if (part <= hole->last && last >= hole->first)
500 break;
501 lasthole = hole;
502 hole = hole->next;
505 /* If we found one, delete it and reconstruct a new hole */
506 if (hole) {
507 oldfirst = hole->first;
508 oldlast = hole->last;
509 if (lasthole)
510 lasthole->next = hole->next;
511 else
512 qptr->holelist = hole->next;
513 free((char *)hole);
515 * Now create a new hole that is the original hole without the
516 * current fragment.
518 if (part > oldfirst) {
519 /* Search for the end of the hole list */
520 hole = qptr->holelist;
521 lasthole = (struct _Z_Hole *) 0;
522 while (hole) {
523 lasthole = hole;
524 hole = hole->next;
526 if (lasthole) {
527 struct _Z_InputQ *inputq = malloc(sizeof(struct _Z_InputQ));
528 if (!inputq)
529 return (ENOMEM);
530 lasthole->next = (struct _Z_Hole *)inputq;
531 hole = lasthole->next;
533 else {
534 struct _Z_InputQ *inputq = malloc(sizeof(struct _Z_InputQ));
535 if (!inputq)
536 return (ENOMEM);
537 qptr->holelist = (struct _Z_Hole *)inputq;
538 hole = qptr->holelist;
540 hole->next = NULL;
541 hole->first = oldfirst;
542 hole->last = part-1;
544 if (last < oldlast) {
545 /* Search for the end of the hole list */
546 hole = qptr->holelist;
547 lasthole = (struct _Z_Hole *) 0;
548 while (hole) {
549 lasthole = hole;
550 hole = hole->next;
552 if (lasthole) {
553 struct _Z_InputQ *inputq = malloc(sizeof(struct _Z_InputQ));
554 if (!inputq)
555 return (ENOMEM);
556 lasthole->next = (struct _Z_Hole *)inputq;
557 hole = lasthole->next;
559 else {
560 struct _Z_InputQ *inputq = malloc(sizeof(struct _Z_InputQ));
561 if (!inputq)
562 return (ENOMEM);
563 qptr->holelist = (struct _Z_Hole *)inputq;
564 hole = qptr->holelist;
566 hole->next = (struct _Z_Hole *) 0;
567 hole->first = last+1;
568 hole->last = oldlast;
572 if (!qptr->holelist) {
573 if (!qptr->complete)
574 __Q_CompleteLength++;
575 qptr->complete = 1;
576 qptr->timep = 0; /* don't time out anymore */
577 qptr->packet_len = qptr->header_len+qptr->msg_len;
578 if (!(qptr->packet = (char *) malloc((unsigned) qptr->packet_len)))
579 return (ENOMEM);
580 (void) memcpy(qptr->packet, qptr->header, qptr->header_len);
581 (void) memcpy(qptr->packet+qptr->header_len, qptr->msg,
582 qptr->msg_len);
585 return (ZERR_NONE);
588 Code_t Z_FormatHeader(notice, buffer, buffer_len, len, cert_routine)
589 ZNotice_t *notice;
590 char *buffer;
591 int buffer_len;
592 int *len;
593 Z_AuthProc cert_routine;
595 Code_t retval;
596 static char version[BUFSIZ]; /* default init should be all \0 */
597 struct sockaddr_in name;
598 socklen_t namelen = sizeof(name);
600 if (!notice->z_sender)
601 notice->z_sender = ZGetSender();
603 if (notice->z_port == 0) {
604 if (ZGetFD() < 0) {
605 retval = ZOpenPort((unsigned short *)0);
606 if (retval != ZERR_NONE)
607 return (retval);
609 retval = getsockname(ZGetFD(), (struct sockaddr *) &name, &namelen);
610 if (retval != 0)
611 return (retval);
612 notice->z_port = name.sin_port;
615 notice->z_multinotice = "";
617 (void) gettimeofday(&notice->z_uid.tv, (struct timezone *)0);
618 notice->z_uid.tv.tv_sec = htonl((unsigned long) notice->z_uid.tv.tv_sec);
619 notice->z_uid.tv.tv_usec = htonl((unsigned long) notice->z_uid.tv.tv_usec);
621 (void) memcpy(&notice->z_uid.zuid_addr, &__My_addr, sizeof(__My_addr));
623 notice->z_multiuid = notice->z_uid;
625 if (!version[0])
626 (void) sprintf(version, "%s%d.%d", ZVERSIONHDR, ZVERSIONMAJOR,
627 ZVERSIONMINOR);
628 notice->z_version = version;
630 return Z_FormatAuthHeader(notice, buffer, buffer_len, len, cert_routine);
633 Code_t Z_FormatAuthHeader(notice, buffer, buffer_len, len, cert_routine)
634 ZNotice_t *notice;
635 char *buffer;
636 int buffer_len;
637 int *len;
638 Z_AuthProc cert_routine;
640 if (!cert_routine) {
641 notice->z_auth = 0;
642 notice->z_authent_len = 0;
643 notice->z_ascii_authent = "";
644 notice->z_checksum = 0;
645 return (Z_FormatRawHeader(notice, buffer, buffer_len,
646 len, NULL, NULL));
649 return ((*cert_routine)(notice, buffer, buffer_len, len));
652 Code_t Z_FormatRawHeader(notice, buffer, buffer_len, len, cstart, cend)
653 ZNotice_t *notice;
654 char *buffer;
655 gsize buffer_len;
656 int *len;
657 char **cstart, **cend;
659 char newrecip[BUFSIZ];
660 char *ptr, *end;
661 int i;
663 if (!notice->z_class)
664 notice->z_class = "";
666 if (!notice->z_class_inst)
667 notice->z_class_inst = "";
669 if (!notice->z_opcode)
670 notice->z_opcode = "";
672 if (!notice->z_recipient)
673 notice->z_recipient = "";
675 if (!notice->z_default_format)
676 notice->z_default_format = "";
678 ptr = buffer;
679 end = buffer+buffer_len;
681 if (buffer_len < strlen(notice->z_version)+1)
682 return (ZERR_HEADERLEN);
684 g_strlcpy(ptr, notice->z_version, buffer_len);
685 ptr += strlen(ptr)+1;
687 if (ZMakeAscii32(ptr, end-ptr, Z_NUMFIELDS + notice->z_num_other_fields)
688 == ZERR_FIELDLEN)
689 return (ZERR_HEADERLEN);
690 ptr += strlen(ptr)+1;
692 if (ZMakeAscii32(ptr, end-ptr, notice->z_kind) == ZERR_FIELDLEN)
693 return (ZERR_HEADERLEN);
694 ptr += strlen(ptr)+1;
696 if (ZMakeAscii(ptr, end-ptr, (unsigned char *)&notice->z_uid,
697 sizeof(ZUnique_Id_t)) == ZERR_FIELDLEN)
698 return (ZERR_HEADERLEN);
699 ptr += strlen(ptr)+1;
701 if (ZMakeAscii16(ptr, end-ptr, ntohs(notice->z_port)) == ZERR_FIELDLEN)
702 return (ZERR_HEADERLEN);
703 ptr += strlen(ptr)+1;
705 if (ZMakeAscii32(ptr, end-ptr, notice->z_auth) == ZERR_FIELDLEN)
706 return (ZERR_HEADERLEN);
707 ptr += strlen(ptr)+1;
709 if (ZMakeAscii32(ptr, end-ptr, notice->z_authent_len) == ZERR_FIELDLEN)
710 return (ZERR_HEADERLEN);
711 ptr += strlen(ptr)+1;
713 if (Z_AddField(&ptr, notice->z_ascii_authent, end))
714 return (ZERR_HEADERLEN);
715 if (Z_AddField(&ptr, notice->z_class, end))
716 return (ZERR_HEADERLEN);
717 if (Z_AddField(&ptr, notice->z_class_inst, end))
718 return (ZERR_HEADERLEN);
719 if (Z_AddField(&ptr, notice->z_opcode, end))
720 return (ZERR_HEADERLEN);
721 if (Z_AddField(&ptr, notice->z_sender, end))
722 return (ZERR_HEADERLEN);
723 if (strchr(notice->z_recipient, '@') || !*notice->z_recipient) {
724 if (Z_AddField(&ptr, notice->z_recipient, end))
725 return (ZERR_HEADERLEN);
727 else {
728 if (strlen(notice->z_recipient) + strlen(__Zephyr_realm) + 2 >
729 sizeof(newrecip))
730 return (ZERR_HEADERLEN);
731 (void) sprintf(newrecip, "%s@%s", notice->z_recipient, __Zephyr_realm);
732 if (Z_AddField(&ptr, newrecip, end))
733 return (ZERR_HEADERLEN);
735 if (Z_AddField(&ptr, notice->z_default_format, end))
736 return (ZERR_HEADERLEN);
738 /* copy back the end pointer location for crypto checksum */
739 if (cstart)
740 *cstart = ptr;
741 if (ZMakeAscii32(ptr, end-ptr, notice->z_checksum) == ZERR_FIELDLEN)
742 return (ZERR_HEADERLEN);
743 ptr += strlen(ptr)+1;
744 if (cend)
745 *cend = ptr;
747 if (Z_AddField(&ptr, notice->z_multinotice, end))
748 return (ZERR_HEADERLEN);
750 if (ZMakeAscii(ptr, end-ptr, (unsigned char *)&notice->z_multiuid,
751 sizeof(ZUnique_Id_t)) == ZERR_FIELDLEN)
752 return (ZERR_HEADERLEN);
753 ptr += strlen(ptr)+1;
755 for (i=0;i<notice->z_num_other_fields;i++)
756 if (Z_AddField(&ptr, notice->z_other_fields[i], end))
757 return (ZERR_HEADERLEN);
759 *len = ptr-buffer;
761 return (ZERR_NONE);
764 static int
765 Z_AddField(char **ptr, const char *field, char *end)
767 register int len;
769 len = field ? strlen (field) + 1 : 1;
771 if (*ptr+len > end)
772 return 1;
773 if (field)
774 strcpy(*ptr, field);
775 else
776 **ptr = '\0';
777 *ptr += len;
779 return 0;
782 struct _Z_InputQ *Z_GetFirstComplete()
784 struct _Z_InputQ *qptr;
786 qptr = __Q_Head;
788 while (qptr) {
789 if (qptr->complete)
790 return (qptr);
791 qptr = qptr->next;
794 return ((struct _Z_InputQ *)0);
797 struct _Z_InputQ *Z_GetNextComplete(qptr)
798 struct _Z_InputQ *qptr;
800 qptr = qptr->next;
801 while (qptr) {
802 if (qptr->complete)
803 return (qptr);
804 qptr = qptr->next;
807 return ((struct _Z_InputQ *)0);
810 void Z_RemQueue(qptr)
811 struct _Z_InputQ *qptr;
813 struct _Z_Hole *hole, *nexthole;
815 if (qptr->complete)
816 __Q_CompleteLength--;
818 __Q_Size -= qptr->msg_len;
820 free(qptr->header);
821 free(qptr->msg);
822 free(qptr->packet);
824 hole = qptr->holelist;
825 while (hole) {
826 nexthole = hole->next;
827 free((char *)hole);
828 hole = nexthole;
831 if (qptr == __Q_Head && __Q_Head == __Q_Tail) {
832 free ((char *)qptr);
833 __Q_Head = (struct _Z_InputQ *)0;
834 __Q_Tail = (struct _Z_InputQ *)0;
835 return;
838 if (qptr == __Q_Head) {
839 __Q_Head = qptr->next;
840 __Q_Head->prev = (struct _Z_InputQ *)0;
841 free ((char *)qptr);
842 return;
844 if (qptr == __Q_Tail) {
845 __Q_Tail = qptr->prev;
846 __Q_Tail->next = (struct _Z_InputQ *)0;
847 free ((char *)qptr);
848 return;
850 qptr->prev->next = qptr->next;
851 qptr->next->prev = qptr->prev;
852 free ((char *)qptr);
853 return;
856 Code_t Z_SendFragmentedNotice(notice, len, cert_func, send_func)
857 ZNotice_t *notice;
858 int len;
859 Z_AuthProc cert_func;
860 Z_SendProc send_func;
862 ZNotice_t partnotice;
863 ZPacket_t buffer;
864 char multi[64];
865 int offset, hdrsize, fragsize, ret_len, message_len, waitforack;
866 Code_t retval;
868 hdrsize = len-notice->z_message_len;
869 fragsize = Z_MAXPKTLEN-hdrsize-Z_FRAGFUDGE;
871 offset = 0;
873 waitforack = ((notice->z_kind == UNACKED || notice->z_kind == ACKED)
874 && !__Zephyr_server);
876 partnotice = *notice;
878 while (offset < notice->z_message_len || !notice->z_message_len) {
879 (void) sprintf(multi, "%d/%d", offset, notice->z_message_len);
880 partnotice.z_multinotice = multi;
881 if (offset > 0) {
882 (void) gettimeofday(&partnotice.z_uid.tv,
883 (struct timezone *)0);
884 partnotice.z_uid.tv.tv_sec =
885 htonl((unsigned long) partnotice.z_uid.tv.tv_sec);
886 partnotice.z_uid.tv.tv_usec =
887 htonl((unsigned long) partnotice.z_uid.tv.tv_usec);
888 (void) memcpy((char *)&partnotice.z_uid.zuid_addr, &__My_addr,
889 sizeof(__My_addr));
891 message_len = MIN(notice->z_message_len - offset, fragsize);
892 partnotice.z_message = (char*)notice->z_message+offset;
893 partnotice.z_message_len = message_len;
894 if ((retval = Z_FormatAuthHeader(&partnotice, buffer, Z_MAXHEADERLEN,
895 &ret_len, cert_func)) != ZERR_NONE) {
896 return (retval);
898 memcpy(buffer + ret_len, partnotice.z_message, message_len);
899 if ((retval = (*send_func)(&partnotice, buffer, ret_len+message_len,
900 waitforack)) != ZERR_NONE) {
901 return (retval);
903 offset += fragsize;
904 if (!notice->z_message_len)
905 break;
908 return (ZERR_NONE);
911 /*ARGSUSED*/
912 Code_t Z_XmitFragment(notice, buf, len, wait)
913 ZNotice_t *notice;
914 char *buf;
915 int len;
916 int wait;
918 return(ZSendPacket(buf, len, wait));
921 #ifdef Z_DEBUG
922 /* For debugging printing */
923 const char *const ZNoticeKinds[] = {
924 "UNSAFE", "UNACKED", "ACKED", "HMACK", "HMCTL", "SERVACK", "SERVNAK",
925 "CLIENTACK", "STAT"
927 #endif
929 #ifdef Z_DEBUG
931 #undef Z_debug
932 void Z_debug (const char *format, ...)
934 va_list pvar;
935 if (!__Z_debug_print)
936 return;
937 va_start (pvar, format);
938 (*__Z_debug_print) (format, pvar, __Z_debug_print_closure);
939 va_end (pvar);
942 void Z_debug_stderr (format, args, closure)
943 const char *format;
944 va_list args;
945 void *closure;
947 vfprintf (stderr, format, args);
948 putc ('\n', stderr);
951 #undef ZGetFD
952 int ZGetFD () { return __Zephyr_fd; }
954 #undef ZQLength
955 int ZQLength () { return __Q_CompleteLength; }
957 #undef ZGetDestAddr
958 struct sockaddr_in ZGetDestAddr () { return __HM_addr; }
960 #undef ZGetRealm
961 Zconst char * ZGetRealm () { return __Zephyr_realm; }
963 #undef ZSetDebug
964 void ZSetDebug(proc, arg)
965 void (*proc)(const char *, va_list, void *);
966 char *arg;
968 __Z_debug_print = proc;
969 __Z_debug_print_closure = arg;
971 #endif /* Z_DEBUG */