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
7 * $Author: warmenhoven $
9 * Copyright (c) 1987,1988,1991 by the Massachusetts Institute of
11 * For copying and distribution information, see the file
17 #include <arpa/inet.h>
18 #include <sys/socket.h>
22 static const char rcsid_Zinternal_c
[] =
23 "$Id: Zinternal.c 2432 2001-10-03 19:38:28Z warmenhoven $";
24 static const char copyright
[] =
25 "Copyright (c) 1987,1988,1991 by the Massachusetts Institute of Technology.";
28 extern char *inet_ntoa ();
32 int __Zephyr_port
= -1;
33 struct in_addr __My_addr
;
34 int __Q_CompleteLength
;
36 struct _Z_InputQ
*__Q_Head
, *__Q_Tail
;
37 struct sockaddr_in __HM_addr
;
38 struct sockaddr_in __HM_addr_real
;
41 ZLocations_t
*__locate_list
;
44 ZSubscription_t
*__subscriptions_list
;
45 int __subscriptions_num
;
46 int __subscriptions_next
;
47 int Z_discarded_packets
= 0;
49 #ifdef ZEPHYR_USES_KERBEROS
50 C_Block __Zephyr_session
;
52 char __Zephyr_realm
[REALM_SZ
];
55 void (*__Z_debug_print
) __P((const char *fmt
, va_list args
, void *closure
));
56 void *__Z_debug_print_closure
;
59 #define min(a,b) ((a)<(b)?(a):(b))
61 static int Z_AddField
__P((char **ptr
, char *field
, char *end
));
62 static int find_or_insert_uid
__P((ZUnique_Id_t
*uid
, ZNotice_Kind_t kind
));
64 /* Find or insert uid in the old uids buffer. The buffer is a sorted
65 * circular queue. We make the assumption that most packets arrive in
66 * order, so we can usually search for a uid or insert it into the buffer
67 * by looking back just a few entries from the end. Since this code is
68 * only executed by the client, the implementation isn't microoptimized. */
69 static int find_or_insert_uid(uid
, kind
)
73 static struct _filter
{
87 /* Initialize the uid buffer if it hasn't been done already. */
89 size
= Z_INITFILTERSIZE
;
90 buffer
= (struct _filter
*) malloc(size
* sizeof(*buffer
));
95 /* Age the uid buffer, discarding any uids older than the clock skew. */
97 while (num
&& (now
- buffer
[start
% size
].t
) > CLOCK_SKEW
)
101 /* Make room for a new uid, since we'll probably have to insert one. */
103 new_size
= size
* 2 + 2;
104 new = (struct _filter
*) malloc(new_size
* sizeof(*new));
107 for (i
= 0; i
< num
; i
++)
108 new[i
] = buffer
[(start
+ i
) % size
];
115 /* Search for this uid in the buffer, starting from the end. */
116 for (i
= start
+ num
- 1; i
>= start
; i
--) {
117 result
= memcmp(uid
, &buffer
[i
% size
].uid
, sizeof(*uid
));
118 if (result
== 0 && buffer
[i
% size
].kind
== kind
)
124 /* We didn't find it; insert the uid into the buffer after i. */
126 for (j
= start
+ num
; j
> i
; j
--)
127 buffer
[j
% size
] = buffer
[(j
- 1) % size
];
128 buffer
[i
% size
].uid
= *uid
;
129 buffer
[i
% size
].kind
= kind
;
130 buffer
[i
% size
].t
= now
;
137 /* Return 1 if there is a packet waiting, 0 otherwise */
139 int Z_PacketWaiting()
144 tv
.tv_sec
= tv
.tv_usec
= 0;
146 FD_SET(ZGetFD(), &read
);
147 return (select(ZGetFD() + 1, &read
, NULL
, NULL
, &tv
));
151 /* Wait for a complete notice to become available */
153 Code_t
Z_WaitForComplete()
157 if (__Q_CompleteLength
)
158 return (Z_ReadEnqueue());
160 while (!__Q_CompleteLength
)
161 if ((retval
= Z_ReadWait()) != ZERR_NONE
)
168 /* Read any available packets and enqueue them */
170 Code_t
Z_ReadEnqueue()
175 return (ZERR_NOPORT
);
177 while (Z_PacketWaiting())
178 if ((retval
= Z_ReadWait()) != ZERR_NONE
)
186 * Search the queue for a notice with the proper multiuid - remove any
187 * notices that haven't been touched in a while
190 struct _Z_InputQ
*Z_SearchQueue(uid
, kind
)
194 register struct _Z_InputQ
*qptr
;
195 struct _Z_InputQ
*next
;
198 (void) gettimeofday(&tv
, (struct timezone
*)0);
203 if (ZCompareUID(uid
, &qptr
->uid
) && qptr
->kind
== kind
)
206 if (qptr
->timep
&& (qptr
->timep
+Z_NOTICETIMELIMIT
< tv
.tv_sec
))
214 * Now we delve into really convoluted queue handling and
215 * fragmentation reassembly algorithms and other stuff you probably
216 * don't want to look at...
218 * This routine does NOT guarantee a complete packet will be ready when it
224 register struct _Z_InputQ
*qptr
;
227 struct sockaddr_in olddest
, from
;
228 int from_len
, packet_len
, zvlen
, part
, partof
;
235 return (ZERR_NOPORT
);
238 FD_SET(ZGetFD(), &fds
);
242 if (select(ZGetFD() + 1, &fds
, NULL
, NULL
, &tv
) < 0)
244 if (!FD_ISSET(ZGetFD(), &fds
))
247 from_len
= sizeof(struct sockaddr_in
);
249 packet_len
= recvfrom(ZGetFD(), packet
, sizeof(packet
), 0,
250 (struct sockaddr
*)&from
, &from_len
);
258 /* Ignore obviously non-Zephyr packets. */
259 zvlen
= sizeof(ZVERSIONHDR
) - 1;
260 if (packet_len
< zvlen
|| memcmp(packet
, ZVERSIONHDR
, zvlen
) != 0) {
261 Z_discarded_packets
++;
265 /* Parse the notice */
266 if ((retval
= ZParseNotice(packet
, packet_len
, ¬ice
)) != ZERR_NONE
)
270 * If we're not a server and the notice is of an appropriate kind,
271 * send back a CLIENTACK to whoever sent it to say we got it.
273 if (!__Zephyr_server
) {
274 if (notice
.z_kind
!= HMACK
&& notice
.z_kind
!= SERVACK
&&
275 notice
.z_kind
!= SERVNAK
&& notice
.z_kind
!= CLIENTACK
) {
281 tmpnotice
.z_kind
= CLIENTACK
;
282 tmpnotice
.z_message_len
= 0;
285 if ((retval
= ZFormatSmallRawNotice(&tmpnotice
, pkt
, &len
))
288 if ((retval
= ZSendPacket(pkt
, len
, 0)) != ZERR_NONE
)
292 if (find_or_insert_uid(¬ice
.z_uid
, notice
.z_kind
))
295 /* Check authentication on the notice. */
296 notice
.z_checked_auth
= ZCheckAuthentication(¬ice
, &from
);
301 * Parse apart the z_multinotice field - if the field is blank for
302 * some reason, assume this packet stands by itself.
304 slash
= strchr(notice
.z_multinotice
, '/');
306 part
= atoi(notice
.z_multinotice
);
307 partof
= atoi(slash
+1);
308 if (part
> partof
|| partof
== 0) {
310 partof
= notice
.z_message_len
;
315 partof
= notice
.z_message_len
;
318 /* Too big a packet...just ignore it! */
319 if (partof
> Z_MAXNOTICESIZE
)
323 * If we aren't a server and we can find a notice in the queue
324 * with the same multiuid field, insert the current fragment as
327 switch (notice
.z_kind
) {
330 /* The SERVACK and SERVNAK replies shouldn't be reassembled
331 (they have no parts). Instead, we should hold on to the reply
332 ONLY if it's the first part of a fragmented message, i.e.
333 multi_uid == uid. This allows programs to wait for the uid
334 of the first packet, and get a response when that notice
335 arrives. Acknowledgements of the other fragments are discarded
336 (XXX we assume here that they all carry the same information
337 regarding failure/success)
339 if (!__Zephyr_server
&&
340 !ZCompareUID(¬ice
.z_multiuid
, ¬ice
.z_uid
))
341 /* they're not the same... throw away this packet. */
343 /* fall thru & process it */
345 /* for HMACK types, we assume no packet loss (local loopback
346 connections). The other types can be fragmented and MUST
347 run through this code. */
348 if (!__Zephyr_server
&& (qptr
= Z_SearchQueue(¬ice
.z_multiuid
,
351 * If this is the first fragment, and we haven't already
352 * gotten a first fragment, grab the header from it.
354 if (part
== 0 && !qptr
->header
) {
355 qptr
->header_len
= packet_len
-notice
.z_message_len
;
356 qptr
->header
= (char *) malloc((unsigned) qptr
->header_len
);
359 (void) memcpy(qptr
->header
, packet
, qptr
->header_len
);
361 return (Z_AddNoticeToEntry(qptr
, ¬ice
, part
));
366 * We'll have to create a new entry...make sure the queue isn't
367 * going to get too big.
369 if (__Q_Size
+(__Zephyr_server
? notice
.z_message_len
: partof
) > Z_MAXQUEUESIZE
)
373 * This is a notice we haven't heard of, so create a new queue
374 * entry for it and zero it out.
376 qptr
= (struct _Z_InputQ
*)malloc(sizeof(struct _Z_InputQ
));
379 (void) memset((char *)qptr
, 0, sizeof(struct _Z_InputQ
));
381 /* Insert the entry at the end of the queue */
383 qptr
->prev
= __Q_Tail
;
385 __Q_Tail
->next
= qptr
;
392 /* Copy the from field, multiuid, kind, and checked authentication. */
394 qptr
->uid
= notice
.z_multiuid
;
395 qptr
->kind
= notice
.z_kind
;
396 qptr
->auth
= notice
.z_checked_auth
;
399 * If this is the first part of the notice, we take the header
400 * from it. We only take it if this is the first fragment so that
401 * the Unique ID's will be predictable.
403 * If a Zephyr Server, we always take the header.
405 if (__Zephyr_server
|| part
== 0) {
406 qptr
->header_len
= packet_len
-notice
.z_message_len
;
407 qptr
->header
= (char *) malloc((unsigned) qptr
->header_len
);
410 (void) memcpy(qptr
->header
, packet
, qptr
->header_len
);
414 * If this is not a fragmented notice, then don't bother with a
416 * If we are a Zephyr server, all notices are treated as complete.
418 if (__Zephyr_server
|| (part
== 0 && notice
.z_message_len
== partof
)) {
419 __Q_CompleteLength
++;
420 qptr
->holelist
= (struct _Z_Hole
*) 0;
422 /* allocate a msg buf for this piece */
423 if (notice
.z_message_len
== 0)
425 else if (!(qptr
->msg
= (char *) malloc((unsigned) notice
.z_message_len
)))
428 (void) memcpy(qptr
->msg
, notice
.z_message
, notice
.z_message_len
);
429 qptr
->msg_len
= notice
.z_message_len
;
430 __Q_Size
+= notice
.z_message_len
;
431 qptr
->packet_len
= qptr
->header_len
+qptr
->msg_len
;
432 if (!(qptr
->packet
= (char *) malloc((unsigned) qptr
->packet_len
)))
434 (void) memcpy(qptr
->packet
, qptr
->header
, qptr
->header_len
);
436 (void) memcpy(qptr
->packet
+qptr
->header_len
, qptr
->msg
,
442 * We know how long the message is going to be (this is better
443 * than IP fragmentation...), so go ahead and allocate it all.
445 if (!(qptr
->msg
= (char *) malloc((unsigned) partof
)) && partof
)
447 qptr
->msg_len
= partof
;
451 * Well, it's a fragmented notice...allocate a hole list and
452 * initialize it to the full packet size. Then insert the
455 if (!(qptr
->holelist
= (struct _Z_Hole
*)
456 malloc(sizeof(struct _Z_Hole
))))
458 qptr
->holelist
->next
= (struct _Z_Hole
*) 0;
459 qptr
->holelist
->first
= 0;
460 qptr
->holelist
->last
= partof
-1;
461 return (Z_AddNoticeToEntry(qptr
, ¬ice
, part
));
465 /* Fragment management routines - compliments, more or less, of RFC815 */
467 Code_t
Z_AddNoticeToEntry(qptr
, notice
, part
)
468 struct _Z_InputQ
*qptr
;
472 int last
, oldfirst
, oldlast
;
473 struct _Z_Hole
*hole
, *lasthole
;
476 /* Incorporate this notice's checked authentication. */
477 if (notice
->z_checked_auth
== ZAUTH_FAILED
)
478 qptr
->auth
= ZAUTH_FAILED
;
479 else if (notice
->z_checked_auth
== ZAUTH_NO
&& qptr
->auth
!= ZAUTH_FAILED
)
480 qptr
->auth
= ZAUTH_NO
;
482 (void) gettimeofday(&tv
, (struct timezone
*)0);
483 qptr
->timep
= tv
.tv_sec
;
485 last
= part
+notice
->z_message_len
-1;
487 hole
= qptr
->holelist
;
488 lasthole
= (struct _Z_Hole
*) 0;
490 /* copy in the message body */
491 (void) memcpy(qptr
->msg
+part
, notice
->z_message
, notice
->z_message_len
);
493 /* Search for a hole that overlaps with the current fragment */
495 if (part
<= hole
->last
&& last
>= hole
->first
)
501 /* If we found one, delete it and reconstruct a new hole */
503 oldfirst
= hole
->first
;
504 oldlast
= hole
->last
;
506 lasthole
->next
= hole
->next
;
508 qptr
->holelist
= hole
->next
;
511 * Now create a new hole that is the original hole without the
514 if (part
> oldfirst
) {
515 /* Search for the end of the hole list */
516 hole
= qptr
->holelist
;
517 lasthole
= (struct _Z_Hole
*) 0;
523 if (!(lasthole
->next
= (struct _Z_Hole
*)
524 malloc(sizeof(struct _Z_InputQ
))))
526 hole
= lasthole
->next
;
529 if (!(qptr
->holelist
= (struct _Z_Hole
*)
530 malloc(sizeof(struct _Z_InputQ
))))
532 hole
= qptr
->holelist
;
535 hole
->first
= oldfirst
;
538 if (last
< oldlast
) {
539 /* Search for the end of the hole list */
540 hole
= qptr
->holelist
;
541 lasthole
= (struct _Z_Hole
*) 0;
547 if (!(lasthole
->next
= (struct _Z_Hole
*)
548 malloc(sizeof(struct _Z_InputQ
))))
550 hole
= lasthole
->next
;
553 if (!(qptr
->holelist
= (struct _Z_Hole
*)
554 malloc(sizeof(struct _Z_InputQ
))))
556 hole
= qptr
->holelist
;
558 hole
->next
= (struct _Z_Hole
*) 0;
559 hole
->first
= last
+1;
560 hole
->last
= oldlast
;
564 if (!qptr
->holelist
) {
566 __Q_CompleteLength
++;
568 qptr
->timep
= 0; /* don't time out anymore */
569 qptr
->packet_len
= qptr
->header_len
+qptr
->msg_len
;
570 if (!(qptr
->packet
= (char *) malloc((unsigned) qptr
->packet_len
)))
572 (void) memcpy(qptr
->packet
, qptr
->header
, qptr
->header_len
);
573 (void) memcpy(qptr
->packet
+qptr
->header_len
, qptr
->msg
,
580 Code_t
Z_FormatHeader(notice
, buffer
, buffer_len
, len
, cert_routine
)
585 Z_AuthProc cert_routine
;
588 static char version
[BUFSIZ
]; /* default init should be all \0 */
589 struct sockaddr_in name
;
590 int namelen
= sizeof(name
);
592 if (!notice
->z_sender
)
593 notice
->z_sender
= ZGetSender();
595 if (notice
->z_port
== 0) {
597 retval
= ZOpenPort((u_short
*)0);
598 if (retval
!= ZERR_NONE
)
601 retval
= getsockname(ZGetFD(), (struct sockaddr
*) &name
, &namelen
);
604 notice
->z_port
= name
.sin_port
;
607 notice
->z_multinotice
= "";
609 (void) gettimeofday(¬ice
->z_uid
.tv
, (struct timezone
*)0);
610 notice
->z_uid
.tv
.tv_sec
= htonl((u_long
) notice
->z_uid
.tv
.tv_sec
);
611 notice
->z_uid
.tv
.tv_usec
= htonl((u_long
) notice
->z_uid
.tv
.tv_usec
);
613 (void) memcpy(¬ice
->z_uid
.zuid_addr
, &__My_addr
, sizeof(__My_addr
));
615 notice
->z_multiuid
= notice
->z_uid
;
618 (void) sprintf(version
, "%s%d.%d", ZVERSIONHDR
, ZVERSIONMAJOR
,
620 notice
->z_version
= version
;
622 return Z_FormatAuthHeader(notice
, buffer
, buffer_len
, len
, cert_routine
);
625 Code_t
Z_FormatAuthHeader(notice
, buffer
, buffer_len
, len
, cert_routine
)
630 Z_AuthProc cert_routine
;
634 notice
->z_authent_len
= 0;
635 notice
->z_ascii_authent
= "";
636 notice
->z_checksum
= 0;
637 return (Z_FormatRawHeader(notice
, buffer
, buffer_len
,
641 return ((*cert_routine
)(notice
, buffer
, buffer_len
, len
));
644 Code_t
Z_FormatRawHeader(notice
, buffer
, buffer_len
, len
, cstart
, cend
)
649 char **cstart
, **cend
;
651 char newrecip
[BUFSIZ
];
655 if (!notice
->z_class
)
656 notice
->z_class
= "";
658 if (!notice
->z_class_inst
)
659 notice
->z_class_inst
= "";
661 if (!notice
->z_opcode
)
662 notice
->z_opcode
= "";
664 if (!notice
->z_recipient
)
665 notice
->z_recipient
= "";
667 if (!notice
->z_default_format
)
668 notice
->z_default_format
= "";
671 end
= buffer
+buffer_len
;
673 if (buffer_len
< strlen(notice
->z_version
)+1)
674 return (ZERR_HEADERLEN
);
676 (void) strcpy(ptr
, notice
->z_version
);
677 ptr
+= strlen(ptr
)+1;
679 if (ZMakeAscii32(ptr
, end
-ptr
, Z_NUMFIELDS
+ notice
->z_num_other_fields
)
681 return (ZERR_HEADERLEN
);
682 ptr
+= strlen(ptr
)+1;
684 if (ZMakeAscii32(ptr
, end
-ptr
, notice
->z_kind
) == ZERR_FIELDLEN
)
685 return (ZERR_HEADERLEN
);
686 ptr
+= strlen(ptr
)+1;
688 if (ZMakeAscii(ptr
, end
-ptr
, (unsigned char *)¬ice
->z_uid
,
689 sizeof(ZUnique_Id_t
)) == ZERR_FIELDLEN
)
690 return (ZERR_HEADERLEN
);
691 ptr
+= strlen(ptr
)+1;
693 if (ZMakeAscii16(ptr
, end
-ptr
, ntohs(notice
->z_port
)) == ZERR_FIELDLEN
)
694 return (ZERR_HEADERLEN
);
695 ptr
+= strlen(ptr
)+1;
697 if (ZMakeAscii32(ptr
, end
-ptr
, notice
->z_auth
) == ZERR_FIELDLEN
)
698 return (ZERR_HEADERLEN
);
699 ptr
+= strlen(ptr
)+1;
701 if (ZMakeAscii32(ptr
, end
-ptr
, notice
->z_authent_len
) == ZERR_FIELDLEN
)
702 return (ZERR_HEADERLEN
);
703 ptr
+= strlen(ptr
)+1;
705 if (Z_AddField(&ptr
, notice
->z_ascii_authent
, end
))
706 return (ZERR_HEADERLEN
);
707 if (Z_AddField(&ptr
, notice
->z_class
, end
))
708 return (ZERR_HEADERLEN
);
709 if (Z_AddField(&ptr
, notice
->z_class_inst
, end
))
710 return (ZERR_HEADERLEN
);
711 if (Z_AddField(&ptr
, notice
->z_opcode
, end
))
712 return (ZERR_HEADERLEN
);
713 if (Z_AddField(&ptr
, notice
->z_sender
, end
))
714 return (ZERR_HEADERLEN
);
715 if (strchr(notice
->z_recipient
, '@') || !*notice
->z_recipient
) {
716 if (Z_AddField(&ptr
, notice
->z_recipient
, end
))
717 return (ZERR_HEADERLEN
);
720 if (strlen(notice
->z_recipient
) + strlen(__Zephyr_realm
) + 2 >
722 return (ZERR_HEADERLEN
);
723 (void) sprintf(newrecip
, "%s@%s", notice
->z_recipient
, __Zephyr_realm
);
724 if (Z_AddField(&ptr
, newrecip
, end
))
725 return (ZERR_HEADERLEN
);
727 if (Z_AddField(&ptr
, notice
->z_default_format
, end
))
728 return (ZERR_HEADERLEN
);
730 /* copy back the end pointer location for crypto checksum */
733 if (ZMakeAscii32(ptr
, end
-ptr
, notice
->z_checksum
) == ZERR_FIELDLEN
)
734 return (ZERR_HEADERLEN
);
735 ptr
+= strlen(ptr
)+1;
739 if (Z_AddField(&ptr
, notice
->z_multinotice
, end
))
740 return (ZERR_HEADERLEN
);
742 if (ZMakeAscii(ptr
, end
-ptr
, (unsigned char *)¬ice
->z_multiuid
,
743 sizeof(ZUnique_Id_t
)) == ZERR_FIELDLEN
)
744 return (ZERR_HEADERLEN
);
745 ptr
+= strlen(ptr
)+1;
747 for (i
=0;i
<notice
->z_num_other_fields
;i
++)
748 if (Z_AddField(&ptr
, notice
->z_other_fields
[i
], end
))
749 return (ZERR_HEADERLEN
);
757 Z_AddField(ptr
, field
, end
)
758 char **ptr
, *field
, *end
;
762 len
= field
? strlen (field
) + 1 : 1;
767 (void) strcpy(*ptr
, field
);
775 struct _Z_InputQ
*Z_GetFirstComplete()
777 struct _Z_InputQ
*qptr
;
787 return ((struct _Z_InputQ
*)0);
790 struct _Z_InputQ
*Z_GetNextComplete(qptr
)
791 struct _Z_InputQ
*qptr
;
800 return ((struct _Z_InputQ
*)0);
803 void Z_RemQueue(qptr
)
804 struct _Z_InputQ
*qptr
;
806 struct _Z_Hole
*hole
, *nexthole
;
809 __Q_CompleteLength
--;
811 __Q_Size
-= qptr
->msg_len
;
820 hole
= qptr
->holelist
;
822 nexthole
= hole
->next
;
827 if (qptr
== __Q_Head
&& __Q_Head
== __Q_Tail
) {
829 __Q_Head
= (struct _Z_InputQ
*)0;
830 __Q_Tail
= (struct _Z_InputQ
*)0;
834 if (qptr
== __Q_Head
) {
835 __Q_Head
= qptr
->next
;
836 __Q_Head
->prev
= (struct _Z_InputQ
*)0;
840 if (qptr
== __Q_Tail
) {
841 __Q_Tail
= qptr
->prev
;
842 __Q_Tail
->next
= (struct _Z_InputQ
*)0;
846 qptr
->prev
->next
= qptr
->next
;
847 qptr
->next
->prev
= qptr
->prev
;
852 Code_t
Z_SendFragmentedNotice(notice
, len
, cert_func
, send_func
)
855 Z_AuthProc cert_func
;
856 Z_SendProc send_func
;
858 ZNotice_t partnotice
;
861 int offset
, hdrsize
, fragsize
, ret_len
, message_len
, waitforack
;
864 hdrsize
= len
-notice
->z_message_len
;
865 fragsize
= Z_MAXPKTLEN
-hdrsize
-Z_FRAGFUDGE
;
869 waitforack
= ((notice
->z_kind
== UNACKED
|| notice
->z_kind
== ACKED
)
870 && !__Zephyr_server
);
872 partnotice
= *notice
;
874 while (offset
< notice
->z_message_len
|| !notice
->z_message_len
) {
875 (void) sprintf(multi
, "%d/%d", offset
, notice
->z_message_len
);
876 partnotice
.z_multinotice
= multi
;
878 (void) gettimeofday(&partnotice
.z_uid
.tv
,
879 (struct timezone
*)0);
880 partnotice
.z_uid
.tv
.tv_sec
=
881 htonl((u_long
) partnotice
.z_uid
.tv
.tv_sec
);
882 partnotice
.z_uid
.tv
.tv_usec
=
883 htonl((u_long
) partnotice
.z_uid
.tv
.tv_usec
);
884 (void) memcpy((char *)&partnotice
.z_uid
.zuid_addr
, &__My_addr
,
887 message_len
= min(notice
->z_message_len
-offset
, fragsize
);
888 partnotice
.z_message
= notice
->z_message
+offset
;
889 partnotice
.z_message_len
= message_len
;
890 if ((retval
= Z_FormatAuthHeader(&partnotice
, buffer
, Z_MAXHEADERLEN
,
891 &ret_len
, cert_func
)) != ZERR_NONE
) {
894 memcpy(buffer
+ ret_len
, partnotice
.z_message
, message_len
);
895 if ((retval
= (*send_func
)(&partnotice
, buffer
, ret_len
+message_len
,
896 waitforack
)) != ZERR_NONE
) {
900 if (!notice
->z_message_len
)
908 Code_t
Z_XmitFragment(notice
, buf
, len
, wait
)
914 return(ZSendPacket(buf
, len
, wait
));
918 /* For debugging printing */
919 const char *const ZNoticeKinds
[] = {
920 "UNSAFE", "UNACKED", "ACKED", "HMACK", "HMCTL", "SERVACK", "SERVNAK",
929 void Z_debug (const char *format
, ...)
932 if (!__Z_debug_print
)
934 va_start (pvar
, format
);
935 (*__Z_debug_print
) (format
, pvar
, __Z_debug_print_closure
);
939 void Z_debug (va_alist
) va_dcl
943 if (!__Z_debug_print
)
946 format
= va_arg (pvar
, char *);
947 (*__Z_debug_print
) (format
, pvar
, __Z_debug_print_closure
);
952 void Z_debug_stderr (format
, args
, closure
)
958 vfprintf (stderr
, format
, args
);
960 _doprnt (format
, args
, stderr
);
966 int ZGetFD () { return __Zephyr_fd
; }
969 int ZQLength () { return __Q_CompleteLength
; }
972 struct sockaddr_in
ZGetDestAddr () { return __HM_addr
; }
975 Zconst
char * ZGetRealm () { return __Zephyr_realm
; }
978 void ZSetDebug(proc
, arg
)
979 void (*proc
) __P((const char *, va_list, void *));
982 __Z_debug_print
= proc
;
983 __Z_debug_print_closure
= arg
;