~liuxingcs/+junk/pidgin

« back to all changes in this revision

Viewing changes to libpurple/protocols/zephyr/Zinternal.c

  • Committer: liuxing
  • Date: 2013-04-25 11:10:17 UTC
  • Revision ID: liuxingcs@yeah.net-20130425111017-fm4mtfsuvhq0dbqd
pidgin

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* This file is part of the Project Athena Zephyr Notification System.
 
2
 * It contains source for the internal Zephyr routines.
 
3
 *
 
4
 *      Created by:     Robert French
 
5
 *
 
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".
 
10
 */
 
11
 
 
12
#include "internal.h"
 
13
#ifdef WIN32
 
14
#include <winsock2.h>
 
15
 
 
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;
 
22
 
 
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;
 
27
   }
 
28
#endif
 
29
 
 
30
#else
 
31
#include <arpa/inet.h>
 
32
#include <sys/socket.h>
 
33
#endif
 
34
 
 
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;
 
53
 
 
54
#ifdef ZEPHYR_USES_KERBEROS
 
55
C_Block __Zephyr_session;
 
56
#endif
 
57
char __Zephyr_realm[REALM_SZ];
 
58
 
 
59
#ifdef Z_DEBUG
 
60
void (*__Z_debug_print) __P((const char *fmt, va_list args, void *closure));
 
61
void *__Z_debug_print_closure;
 
62
#endif
 
63
 
 
64
#define min(a,b) ((a)<(b)?(a):(b))
 
65
 
 
66
static int Z_AddField __P((char **ptr, const char *field, char *end));
 
67
static int find_or_insert_uid __P((ZUnique_Id_t *uid, ZNotice_Kind_t kind));
 
68
 
 
69
/* Find or insert uid in the old uids buffer.  The buffer is a sorted
 
70
 * circular queue.  We make the assumption that most packets arrive in
 
71
 * order, so we can usually search for a uid or insert it into the buffer
 
72
 * by looking back just a few entries from the end.  Since this code is
 
73
 * only executed by the client, the implementation isn't microoptimized. */
 
74
static int find_or_insert_uid(uid, kind)
 
75
    ZUnique_Id_t *uid;
 
76
    ZNotice_Kind_t kind;
 
77
{
 
78
    static struct _filter {
 
79
        ZUnique_Id_t    uid;
 
80
        ZNotice_Kind_t  kind;
 
81
        time_t          t;
 
82
    } *buffer;
 
83
    static long size;
 
84
    static long start;
 
85
    static long num;
 
86
 
 
87
    time_t now;
 
88
    struct _filter *new;
 
89
    long i, j, new_size;
 
90
    int result;
 
91
 
 
92
    /* Initialize the uid buffer if it hasn't been done already. */
 
93
    if (!buffer) {
 
94
        size = Z_INITFILTERSIZE;
 
95
        buffer = (struct _filter *) malloc(size * sizeof(*buffer));
 
96
        if (!buffer)
 
97
            return 0;
 
98
    }
 
99
 
 
100
    /* Age the uid buffer, discarding any uids older than the clock skew. */
 
101
    time(&now);
 
102
    while (num && (now - buffer[start % size].t) > CLOCK_SKEW)
 
103
        start++, num--;
 
104
    start %= size;
 
105
 
 
106
    /* Make room for a new uid, since we'll probably have to insert one. */
 
107
    if (num == size) {
 
108
        new_size = size * 2 + 2;
 
109
        new = (struct _filter *) malloc(new_size * sizeof(*new));
 
110
        if (!new)
 
111
            return 0;
 
112
        for (i = 0; i < num; i++)
 
113
            new[i] = buffer[(start + i) % size];
 
114
        free(buffer);
 
115
        buffer = new;
 
116
        size = new_size;
 
117
        start = 0;
 
118
    }
 
119
 
 
120
    /* Search for this uid in the buffer, starting from the end. */
 
121
    for (i = start + num - 1; i >= start; i--) {
 
122
        result = memcmp(uid, &buffer[i % size].uid, sizeof(*uid));
 
123
        if (result == 0 && buffer[i % size].kind == kind)
 
124
            return 1;
 
125
        if (result > 0)
 
126
            break;
 
127
    }
 
128
 
 
129
    /* We didn't find it; insert the uid into the buffer after i. */
 
130
    i++;
 
131
    for (j = start + num; j > i; j--)
 
132
        buffer[j % size] = buffer[(j - 1) % size];
 
133
    buffer[i % size].uid = *uid;
 
134
    buffer[i % size].kind = kind;
 
135
    buffer[i % size].t = now;
 
136
    num++;
 
137
 
 
138
    return 0;
 
139
}
 
140
 
 
141
 
 
142
/* Return 1 if there is a packet waiting, 0 otherwise */
 
143
 
 
144
static int Z_PacketWaiting(void)
 
145
{
 
146
    struct timeval tv;
 
147
    fd_set read;
 
148
 
 
149
    tv.tv_sec = tv.tv_usec = 0;
 
150
    FD_ZERO(&read);
 
151
    FD_SET(ZGetFD(), &read);
 
152
    return (select(ZGetFD() + 1, &read, NULL, NULL, &tv));
 
153
}
 
154
 
 
155
 
 
156
/* Wait for a complete notice to become available */
 
157
 
 
158
Code_t Z_WaitForComplete(void)
 
159
{
 
160
    Code_t retval;
 
161
 
 
162
    if (__Q_CompleteLength)
 
163
        return (Z_ReadEnqueue());
 
164
 
 
165
    while (!__Q_CompleteLength)
 
166
        if ((retval = Z_ReadWait()) != ZERR_NONE)
 
167
            return (retval);
 
168
 
 
169
    return (ZERR_NONE);
 
170
}
 
171
 
 
172
 
 
173
/* Read any available packets and enqueue them */
 
174
 
 
175
Code_t Z_ReadEnqueue()
 
176
{
 
177
    Code_t retval;
 
178
 
 
179
    if (ZGetFD() < 0)
 
180
        return (ZERR_NOPORT);
 
181
 
 
182
    while (Z_PacketWaiting())
 
183
        if ((retval = Z_ReadWait()) != ZERR_NONE)
 
184
            return (retval);
 
185
 
 
186
    return (ZERR_NONE);
 
187
}
 
188
 
 
189
 
 
190
/*
 
191
 * Search the queue for a notice with the proper multiuid - remove any
 
192
 * notices that haven't been touched in a while
 
193
 */
 
194
 
 
195
static struct _Z_InputQ *Z_SearchQueue(ZUnique_Id_t *uid, ZNotice_Kind_t kind)
 
196
{
 
197
    register struct _Z_InputQ *qptr;
 
198
    struct _Z_InputQ *next;
 
199
    struct timeval tv;
 
200
 
 
201
    (void) gettimeofday(&tv, (struct timezone *)0);
 
202
 
 
203
    qptr = __Q_Head;
 
204
 
 
205
    while (qptr) {
 
206
        if (ZCompareUID(uid, &qptr->uid) && qptr->kind == kind)
 
207
            return (qptr);
 
208
        next = qptr->next;
 
209
        if (qptr->timep && (qptr->timep+Z_NOTICETIMELIMIT < tv.tv_sec))
 
210
            Z_RemQueue(qptr);
 
211
        qptr = next;
 
212
    }
 
213
    return (NULL);
 
214
}
 
215
 
 
216
/*
 
217
 * Now we delve into really convoluted queue handling and
 
218
 * fragmentation reassembly algorithms and other stuff you probably
 
219
 * don't want to look at...
 
220
 *
 
221
 * This routine does NOT guarantee a complete packet will be ready when it
 
222
 * returns.
 
223
 */
 
224
 
 
225
Code_t Z_ReadWait()
 
226
{
 
227
    register struct _Z_InputQ *qptr;
 
228
    ZNotice_t notice;
 
229
    ZPacket_t packet;
 
230
    struct sockaddr_in olddest, from;
 
231
    int packet_len, zvlen, part, partof;
 
232
    socklen_t from_len;
 
233
    char *slash;
 
234
    Code_t retval;
 
235
    fd_set fds;
 
236
    struct timeval tv;
 
237
 
 
238
    if (ZGetFD() < 0)
 
239
        return (ZERR_NOPORT);
 
240
 
 
241
    FD_ZERO(&fds);
 
242
    FD_SET(ZGetFD(), &fds);
 
243
    tv.tv_sec = 60;
 
244
    tv.tv_usec = 0;
 
245
 
 
246
    if (select(ZGetFD() + 1, &fds, NULL, NULL, &tv) < 0)
 
247
      return (errno);
 
248
    if (!FD_ISSET(ZGetFD(), &fds))
 
249
      return ETIMEDOUT;
 
250
 
 
251
    from_len = sizeof(struct sockaddr_in);
 
252
 
 
253
    packet_len = recvfrom(ZGetFD(), packet, sizeof(packet), 0,
 
254
                          (struct sockaddr *)&from, &from_len);
 
255
 
 
256
    if (packet_len < 0)
 
257
        return (errno);
 
258
 
 
259
    if (!packet_len)
 
260
        return (ZERR_EOF);
 
261
 
 
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);
 
267
    }
 
268
 
 
269
    /* Parse the notice */
 
270
    if ((retval = ZParseNotice(packet, packet_len, &notice)) != ZERR_NONE)
 
271
        return (retval);
 
272
 
 
273
    /*
 
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.
 
276
     */
 
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;
 
283
 
 
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;
 
295
        }
 
296
        if (find_or_insert_uid(&notice.z_uid, notice.z_kind))
 
297
            return(ZERR_NONE);
 
298
 
 
299
        /* Check authentication on the notice. */
 
300
        notice.z_checked_auth = ZCheckAuthentication(&notice, &from);
 
301
    }
 
302
 
 
303
 
 
304
    /*
 
305
     * Parse apart the z_multinotice field - if the field is blank for
 
306
     * some reason, assume this packet stands by itself.
 
307
     */
 
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;
 
315
        }
 
316
    }
 
317
    else {
 
318
        part = 0;
 
319
        partof = notice.z_message_len;
 
320
    }
 
321
 
 
322
    /* Too big a packet...just ignore it! */
 
323
    if (partof > Z_MAXNOTICESIZE)
 
324
        return (ZERR_NONE);
 
325
 
 
326
    /*
 
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.
 
330
     */
 
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)
 
342
         */
 
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))) {
 
354
            /*
 
355
             * If this is the first fragment, and we haven't already
 
356
             * gotten a first fragment, grab the header from it.
 
357
             */
 
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);
 
364
            }
 
365
            return (Z_AddNoticeToEntry(qptr, &notice, part));
 
366
        }
 
367
    }
 
368
 
 
369
    /*
 
370
     * We'll have to create a new entry...make sure the queue isn't
 
371
     * going to get too big.
 
372
     */
 
373
    if (__Q_Size+(__Zephyr_server ? notice.z_message_len : partof) > Z_MAXQUEUESIZE)
 
374
        return (ZERR_NONE);
 
375
 
 
376
    /*
 
377
     * This is a notice we haven't heard of, so create a new queue
 
378
     * entry for it and zero it out.
 
379
     */
 
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));
 
384
 
 
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;
 
391
 
 
392
    if (!__Q_Head)
 
393
        __Q_Head = qptr;
 
394
 
 
395
 
 
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;
 
401
 
 
402
    /*
 
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.
 
406
     *
 
407
     * If a Zephyr Server, we always take the header.
 
408
     */
 
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);
 
415
    }
 
416
 
 
417
    /*
 
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.
 
421
     */
 
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);
 
443
    }
 
444
 
 
445
    /*
 
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.
 
448
     */
 
449
    if (!(qptr->msg = (char *) malloc((unsigned) partof)) && partof)
 
450
        return (ENOMEM);
 
451
    qptr->msg_len = partof;
 
452
    __Q_Size += partof;
 
453
 
 
454
    /*
 
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.
 
458
     */
 
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));
 
466
}
 
467
 
 
468
 
 
469
/* Fragment management routines - compliments, more or less, of RFC815 */
 
470
 
 
471
Code_t Z_AddNoticeToEntry(qptr, notice, part)
 
472
    struct _Z_InputQ *qptr;
 
473
    ZNotice_t *notice;
 
474
    int part;
 
475
{
 
476
    int last, oldfirst, oldlast;
 
477
    struct _Z_Hole *hole, *lasthole;
 
478
    struct timeval tv;
 
479
 
 
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;
 
485
 
 
486
    (void) gettimeofday(&tv, (struct timezone *)0);
 
487
    qptr->timep = tv.tv_sec;
 
488
 
 
489
    last = part+notice->z_message_len-1;
 
490
 
 
491
    hole = qptr->holelist;
 
492
    lasthole = (struct _Z_Hole *) 0;
 
493
 
 
494
    /* copy in the message body */
 
495
    (void) memcpy(qptr->msg+part, notice->z_message, notice->z_message_len);
 
496
 
 
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;
 
503
    }
 
504
 
 
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);
 
514
        /*
 
515
         * Now create a new hole that is the original hole without the
 
516
         * current fragment.
 
517
         */
 
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;
 
525
            }
 
526
            if (lasthole) {
 
527
                if (!(lasthole->next = (struct _Z_Hole *)
 
528
                      malloc(sizeof(struct _Z_InputQ))))
 
529
                    return (ENOMEM);
 
530
                hole = lasthole->next;
 
531
            }
 
532
            else {
 
533
                if (!(qptr->holelist = (struct _Z_Hole *)
 
534
                      malloc(sizeof(struct _Z_InputQ))))
 
535
                    return (ENOMEM);
 
536
                hole = qptr->holelist;
 
537
            }
 
538
            hole->next = NULL;
 
539
            hole->first = oldfirst;
 
540
            hole->last = part-1;
 
541
        }
 
542
        if (last < oldlast) {
 
543
            /* Search for the end of the hole list */
 
544
            hole = qptr->holelist;
 
545
            lasthole = (struct _Z_Hole *) 0;
 
546
            while (hole) {
 
547
                lasthole = hole;
 
548
                hole = hole->next;
 
549
            }
 
550
            if (lasthole) {
 
551
                if (!(lasthole->next = (struct _Z_Hole *)
 
552
                      malloc(sizeof(struct _Z_InputQ))))
 
553
                    return (ENOMEM);
 
554
                hole = lasthole->next;
 
555
            }
 
556
            else {
 
557
                if (!(qptr->holelist = (struct _Z_Hole *)
 
558
                      malloc(sizeof(struct _Z_InputQ))))
 
559
                    return (ENOMEM);
 
560
                hole = qptr->holelist;
 
561
            }
 
562
            hole->next = (struct _Z_Hole *) 0;
 
563
            hole->first = last+1;
 
564
            hole->last = oldlast;
 
565
        }
 
566
    }
 
567
 
 
568
    if (!qptr->holelist) {
 
569
        if (!qptr->complete)
 
570
            __Q_CompleteLength++;
 
571
        qptr->complete = 1;
 
572
        qptr->timep = 0;                /* don't time out anymore */
 
573
        qptr->packet_len = qptr->header_len+qptr->msg_len;
 
574
        if (!(qptr->packet = (char *) malloc((unsigned) qptr->packet_len)))
 
575
            return (ENOMEM);
 
576
        (void) memcpy(qptr->packet, qptr->header, qptr->header_len);
 
577
        (void) memcpy(qptr->packet+qptr->header_len, qptr->msg,
 
578
                       qptr->msg_len);
 
579
    }
 
580
 
 
581
    return (ZERR_NONE);
 
582
}
 
583
 
 
584
Code_t Z_FormatHeader(notice, buffer, buffer_len, len, cert_routine)
 
585
    ZNotice_t *notice;
 
586
    char *buffer;
 
587
    int buffer_len;
 
588
    int *len;
 
589
    Z_AuthProc cert_routine;
 
590
{
 
591
    Code_t retval;
 
592
    static char version[BUFSIZ]; /* default init should be all \0 */
 
593
    struct sockaddr_in name;
 
594
    socklen_t namelen = sizeof(name);
 
595
 
 
596
    if (!notice->z_sender)
 
597
        notice->z_sender = ZGetSender();
 
598
 
 
599
    if (notice->z_port == 0) {
 
600
        if (ZGetFD() < 0) {
 
601
            retval = ZOpenPort((unsigned short *)0);
 
602
            if (retval != ZERR_NONE)
 
603
                return (retval);
 
604
        }
 
605
        retval = getsockname(ZGetFD(), (struct sockaddr *) &name, &namelen);
 
606
        if (retval != 0)
 
607
            return (retval);
 
608
        notice->z_port = name.sin_port;
 
609
    }
 
610
 
 
611
    notice->z_multinotice = "";
 
612
 
 
613
    (void) gettimeofday(&notice->z_uid.tv, (struct timezone *)0);
 
614
    notice->z_uid.tv.tv_sec = htonl((unsigned long) notice->z_uid.tv.tv_sec);
 
615
    notice->z_uid.tv.tv_usec = htonl((unsigned long) notice->z_uid.tv.tv_usec);
 
616
 
 
617
    (void) memcpy(&notice->z_uid.zuid_addr, &__My_addr, sizeof(__My_addr));
 
618
 
 
619
    notice->z_multiuid = notice->z_uid;
 
620
 
 
621
    if (!version[0])
 
622
            (void) sprintf(version, "%s%d.%d", ZVERSIONHDR, ZVERSIONMAJOR,
 
623
                           ZVERSIONMINOR);
 
624
    notice->z_version = version;
 
625
 
 
626
    return Z_FormatAuthHeader(notice, buffer, buffer_len, len, cert_routine);
 
627
}
 
628
 
 
629
Code_t Z_FormatAuthHeader(notice, buffer, buffer_len, len, cert_routine)
 
630
    ZNotice_t *notice;
 
631
    char *buffer;
 
632
    int buffer_len;
 
633
    int *len;
 
634
    Z_AuthProc cert_routine;
 
635
{
 
636
    if (!cert_routine) {
 
637
        notice->z_auth = 0;
 
638
        notice->z_authent_len = 0;
 
639
        notice->z_ascii_authent = "";
 
640
        notice->z_checksum = 0;
 
641
        return (Z_FormatRawHeader(notice, buffer, buffer_len,
 
642
                                  len, NULL, NULL));
 
643
    }
 
644
 
 
645
    return ((*cert_routine)(notice, buffer, buffer_len, len));
 
646
}
 
647
 
 
648
Code_t Z_FormatRawHeader(notice, buffer, buffer_len, len, cstart, cend)
 
649
    ZNotice_t *notice;
 
650
    char *buffer;
 
651
    int buffer_len;
 
652
    int *len;
 
653
    char **cstart, **cend;
 
654
{
 
655
    char newrecip[BUFSIZ];
 
656
    char *ptr, *end;
 
657
    int i;
 
658
 
 
659
    if (!notice->z_class)
 
660
            notice->z_class = "";
 
661
 
 
662
    if (!notice->z_class_inst)
 
663
            notice->z_class_inst = "";
 
664
 
 
665
    if (!notice->z_opcode)
 
666
            notice->z_opcode = "";
 
667
 
 
668
    if (!notice->z_recipient)
 
669
            notice->z_recipient = "";
 
670
 
 
671
    if (!notice->z_default_format)
 
672
            notice->z_default_format = "";
 
673
 
 
674
    ptr = buffer;
 
675
    end = buffer+buffer_len;
 
676
 
 
677
    if (buffer_len < strlen(notice->z_version)+1)
 
678
        return (ZERR_HEADERLEN);
 
679
 
 
680
    g_strlcpy(ptr, notice->z_version, buffer_len);
 
681
    ptr += strlen(ptr)+1;
 
682
 
 
683
    if (ZMakeAscii32(ptr, end-ptr, Z_NUMFIELDS + notice->z_num_other_fields)
 
684
        == ZERR_FIELDLEN)
 
685
        return (ZERR_HEADERLEN);
 
686
    ptr += strlen(ptr)+1;
 
687
 
 
688
    if (ZMakeAscii32(ptr, end-ptr, notice->z_kind) == ZERR_FIELDLEN)
 
689
        return (ZERR_HEADERLEN);
 
690
    ptr += strlen(ptr)+1;
 
691
 
 
692
    if (ZMakeAscii(ptr, end-ptr, (unsigned char *)&notice->z_uid,
 
693
                   sizeof(ZUnique_Id_t)) == ZERR_FIELDLEN)
 
694
        return (ZERR_HEADERLEN);
 
695
    ptr += strlen(ptr)+1;
 
696
 
 
697
    if (ZMakeAscii16(ptr, end-ptr, ntohs(notice->z_port)) == ZERR_FIELDLEN)
 
698
        return (ZERR_HEADERLEN);
 
699
    ptr += strlen(ptr)+1;
 
700
 
 
701
    if (ZMakeAscii32(ptr, end-ptr, notice->z_auth) == ZERR_FIELDLEN)
 
702
        return (ZERR_HEADERLEN);
 
703
    ptr += strlen(ptr)+1;
 
704
 
 
705
    if (ZMakeAscii32(ptr, end-ptr, notice->z_authent_len) == ZERR_FIELDLEN)
 
706
        return (ZERR_HEADERLEN);
 
707
    ptr += strlen(ptr)+1;
 
708
 
 
709
    if (Z_AddField(&ptr, notice->z_ascii_authent, end))
 
710
        return (ZERR_HEADERLEN);
 
711
    if (Z_AddField(&ptr, notice->z_class, end))
 
712
        return (ZERR_HEADERLEN);
 
713
    if (Z_AddField(&ptr, notice->z_class_inst, end))
 
714
        return (ZERR_HEADERLEN);
 
715
    if (Z_AddField(&ptr, notice->z_opcode, end))
 
716
        return (ZERR_HEADERLEN);
 
717
    if (Z_AddField(&ptr, notice->z_sender, end))
 
718
        return (ZERR_HEADERLEN);
 
719
    if (strchr(notice->z_recipient, '@') || !*notice->z_recipient) {
 
720
        if (Z_AddField(&ptr, notice->z_recipient, end))
 
721
            return (ZERR_HEADERLEN);
 
722
    }
 
723
    else {
 
724
        if (strlen(notice->z_recipient) + strlen(__Zephyr_realm) + 2 >
 
725
            sizeof(newrecip))
 
726
            return (ZERR_HEADERLEN);
 
727
        (void) sprintf(newrecip, "%s@%s", notice->z_recipient, __Zephyr_realm);
 
728
        if (Z_AddField(&ptr, newrecip, end))
 
729
            return (ZERR_HEADERLEN);
 
730
    }
 
731
    if (Z_AddField(&ptr, notice->z_default_format, end))
 
732
        return (ZERR_HEADERLEN);
 
733
 
 
734
    /* copy back the end pointer location for crypto checksum */
 
735
    if (cstart)
 
736
        *cstart = ptr;
 
737
    if (ZMakeAscii32(ptr, end-ptr, notice->z_checksum) == ZERR_FIELDLEN)
 
738
        return (ZERR_HEADERLEN);
 
739
    ptr += strlen(ptr)+1;
 
740
    if (cend)
 
741
        *cend = ptr;
 
742
 
 
743
    if (Z_AddField(&ptr, notice->z_multinotice, end))
 
744
        return (ZERR_HEADERLEN);
 
745
 
 
746
    if (ZMakeAscii(ptr, end-ptr, (unsigned char *)&notice->z_multiuid,
 
747
                   sizeof(ZUnique_Id_t)) == ZERR_FIELDLEN)
 
748
        return (ZERR_HEADERLEN);
 
749
    ptr += strlen(ptr)+1;
 
750
 
 
751
    for (i=0;i<notice->z_num_other_fields;i++)
 
752
        if (Z_AddField(&ptr, notice->z_other_fields[i], end))
 
753
            return (ZERR_HEADERLEN);
 
754
 
 
755
    *len = ptr-buffer;
 
756
 
 
757
    return (ZERR_NONE);
 
758
}
 
759
 
 
760
static int
 
761
Z_AddField(char **ptr, const char *field, char *end)
 
762
{
 
763
    register int len;
 
764
 
 
765
    len = field ? strlen (field) + 1 : 1;
 
766
 
 
767
    if (*ptr+len > end)
 
768
        return 1;
 
769
    if (field)
 
770
        strcpy(*ptr, field);
 
771
    else
 
772
      **ptr = '\0';
 
773
    *ptr += len;
 
774
 
 
775
    return 0;
 
776
}
 
777
 
 
778
struct _Z_InputQ *Z_GetFirstComplete()
 
779
{
 
780
    struct _Z_InputQ *qptr;
 
781
 
 
782
    qptr = __Q_Head;
 
783
 
 
784
    while (qptr) {
 
785
        if (qptr->complete)
 
786
            return (qptr);
 
787
        qptr = qptr->next;
 
788
    }
 
789
 
 
790
    return ((struct _Z_InputQ *)0);
 
791
}
 
792
 
 
793
struct _Z_InputQ *Z_GetNextComplete(qptr)
 
794
    struct _Z_InputQ *qptr;
 
795
{
 
796
    qptr = qptr->next;
 
797
    while (qptr) {
 
798
        if (qptr->complete)
 
799
            return (qptr);
 
800
        qptr = qptr->next;
 
801
    }
 
802
 
 
803
    return ((struct _Z_InputQ *)0);
 
804
}
 
805
 
 
806
void Z_RemQueue(qptr)
 
807
    struct _Z_InputQ *qptr;
 
808
{
 
809
    struct _Z_Hole *hole, *nexthole;
 
810
 
 
811
    if (qptr->complete)
 
812
        __Q_CompleteLength--;
 
813
 
 
814
    __Q_Size -= qptr->msg_len;
 
815
 
 
816
    if (qptr->header)
 
817
        free(qptr->header);
 
818
    if (qptr->msg)
 
819
        free(qptr->msg);
 
820
    if (qptr->packet)
 
821
        free(qptr->packet);
 
822
 
 
823
    hole = qptr->holelist;
 
824
    while (hole) {
 
825
        nexthole = hole->next;
 
826
        free((char *)hole);
 
827
        hole = nexthole;
 
828
    }
 
829
 
 
830
    if (qptr == __Q_Head && __Q_Head == __Q_Tail) {
 
831
        free ((char *)qptr);
 
832
        __Q_Head = (struct _Z_InputQ *)0;
 
833
        __Q_Tail = (struct _Z_InputQ *)0;
 
834
        return;
 
835
    }
 
836
 
 
837
    if (qptr == __Q_Head) {
 
838
        __Q_Head = qptr->next;
 
839
        __Q_Head->prev = (struct _Z_InputQ *)0;
 
840
        free ((char *)qptr);
 
841
        return;
 
842
    }
 
843
    if (qptr == __Q_Tail) {
 
844
        __Q_Tail = qptr->prev;
 
845
        __Q_Tail->next = (struct _Z_InputQ *)0;
 
846
        free ((char *)qptr);
 
847
        return;
 
848
    }
 
849
    qptr->prev->next = qptr->next;
 
850
    qptr->next->prev = qptr->prev;
 
851
    free ((char *)qptr);
 
852
    return;
 
853
}
 
854
 
 
855
Code_t Z_SendFragmentedNotice(notice, len, cert_func, send_func)
 
856
    ZNotice_t *notice;
 
857
    int len;
 
858
    Z_AuthProc cert_func;
 
859
    Z_SendProc send_func;
 
860
{
 
861
    ZNotice_t partnotice;
 
862
    ZPacket_t buffer;
 
863
    char multi[64];
 
864
    int offset, hdrsize, fragsize, ret_len, message_len, waitforack;
 
865
    Code_t retval;
 
866
 
 
867
    hdrsize = len-notice->z_message_len;
 
868
    fragsize = Z_MAXPKTLEN-hdrsize-Z_FRAGFUDGE;
 
869
 
 
870
    offset = 0;
 
871
 
 
872
    waitforack = ((notice->z_kind == UNACKED || notice->z_kind == ACKED)
 
873
                  && !__Zephyr_server);
 
874
 
 
875
    partnotice = *notice;
 
876
 
 
877
    while (offset < notice->z_message_len || !notice->z_message_len) {
 
878
        (void) sprintf(multi, "%d/%d", offset, notice->z_message_len);
 
879
        partnotice.z_multinotice = multi;
 
880
        if (offset > 0) {
 
881
            (void) gettimeofday(&partnotice.z_uid.tv,
 
882
                                (struct timezone *)0);
 
883
            partnotice.z_uid.tv.tv_sec =
 
884
                htonl((unsigned long) partnotice.z_uid.tv.tv_sec);
 
885
            partnotice.z_uid.tv.tv_usec =
 
886
                htonl((unsigned long) partnotice.z_uid.tv.tv_usec);
 
887
            (void) memcpy((char *)&partnotice.z_uid.zuid_addr, &__My_addr,
 
888
                          sizeof(__My_addr));
 
889
        }
 
890
        message_len = min(notice->z_message_len-offset, fragsize);
 
891
        partnotice.z_message = (char*)notice->z_message+offset;
 
892
        partnotice.z_message_len = message_len;
 
893
        if ((retval = Z_FormatAuthHeader(&partnotice, buffer, Z_MAXHEADERLEN,
 
894
                                         &ret_len, cert_func)) != ZERR_NONE) {
 
895
            return (retval);
 
896
        }
 
897
        memcpy(buffer + ret_len, partnotice.z_message, message_len);
 
898
        if ((retval = (*send_func)(&partnotice, buffer, ret_len+message_len,
 
899
                                   waitforack)) != ZERR_NONE) {
 
900
            return (retval);
 
901
        }
 
902
        offset += fragsize;
 
903
        if (!notice->z_message_len)
 
904
            break;
 
905
    }
 
906
 
 
907
    return (ZERR_NONE);
 
908
}
 
909
 
 
910
/*ARGSUSED*/
 
911
Code_t Z_XmitFragment(notice, buf, len, wait)
 
912
ZNotice_t *notice;
 
913
char *buf;
 
914
int len;
 
915
int wait;
 
916
{
 
917
        return(ZSendPacket(buf, len, wait));
 
918
}
 
919
 
 
920
#ifdef Z_DEBUG
 
921
/* For debugging printing */
 
922
const char *const ZNoticeKinds[] = {
 
923
    "UNSAFE", "UNACKED", "ACKED", "HMACK", "HMCTL", "SERVACK", "SERVNAK",
 
924
    "CLIENTACK", "STAT"
 
925
};
 
926
#endif
 
927
 
 
928
#ifdef Z_DEBUG
 
929
 
 
930
#undef Z_debug
 
931
#ifdef HAVE_STDARG_H
 
932
void Z_debug (const char *format, ...)
 
933
{
 
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);
 
940
}
 
941
#else /* stdarg */
 
942
void Z_debug (va_alist) va_dcl
 
943
{
 
944
    va_list pvar;
 
945
    char *format;
 
946
    if (!__Z_debug_print)
 
947
      return;
 
948
    va_start (pvar);
 
949
    format = va_arg (pvar, char *);
 
950
    (*__Z_debug_print) (format, pvar, __Z_debug_print_closure);
 
951
    va_end (pvar);
 
952
}
 
953
#endif
 
954
 
 
955
void Z_debug_stderr (format, args, closure)
 
956
     const char *format;
 
957
     va_list args;
 
958
     void *closure;
 
959
{
 
960
#ifdef HAVE_VPRINTF
 
961
    vfprintf (stderr, format, args);
 
962
#else
 
963
    _doprnt (format, args, stderr);
 
964
#endif
 
965
    putc ('\n', stderr);
 
966
}
 
967
 
 
968
#undef ZGetFD
 
969
int ZGetFD () { return __Zephyr_fd; }
 
970
 
 
971
#undef ZQLength
 
972
int ZQLength () { return __Q_CompleteLength; }
 
973
 
 
974
#undef ZGetDestAddr
 
975
struct sockaddr_in ZGetDestAddr () { return __HM_addr; }
 
976
 
 
977
#undef ZGetRealm
 
978
Zconst char * ZGetRealm () { return __Zephyr_realm; }
 
979
 
 
980
#undef ZSetDebug
 
981
void ZSetDebug(proc, arg)
 
982
    void (*proc) __P((const char *, va_list, void *));
 
983
    char *arg;
 
984
{
 
985
    __Z_debug_print = proc;
 
986
    __Z_debug_print_closure = arg;
 
987
}
 
988
#endif /* Z_DEBUG */
 
989