Mercurial > pidgin.yaz
annotate src/protocols/zephyr/Zinternal.c @ 6160:7416a43dc786
[gaim-migrate @ 6635]
Hold it.. Nobody said anything about _three_ books. Oh that stinkin' wise
man. He was so busy filling me full of his secret little workds and his
phrases and his BALONEY that he never said anything about this...
committer: Tailor Script <tailor@pidgin.im>
author | Christian Hammond <chipx86@chipx86.com> |
---|---|
date | Wed, 16 Jul 2003 22:43:27 +0000 |
parents | 381da05cb5ed |
children | 08ce2a94d9c7 |
rev | line source |
---|---|
2086 | 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 * $Source$ | |
5136 | 7 * $Author: faceprint $ |
2086 | 8 * |
9 * Copyright (c) 1987,1988,1991 by the Massachusetts Institute of | |
10 * Technology. | |
11 * For copying and distribution information, see the file | |
12 * "mit-copyright.h". | |
13 */ | |
14 /* $Header$ */ | |
15 | |
16 #include <internal.h> | |
17 #include <arpa/inet.h> | |
18 #include <sys/socket.h> | |
19 #include <utmp.h> | |
20 | |
21 #ifndef lint | |
22 static const char rcsid_Zinternal_c[] = | |
5136 | 23 "$Id: Zinternal.c 5500 2003-04-15 04:18:00Z faceprint $"; |
2086 | 24 static const char copyright[] = |
25 "Copyright (c) 1987,1988,1991 by the Massachusetts Institute of Technology."; | |
26 #endif | |
27 | |
28 extern char *inet_ntoa (); | |
29 | |
30 int __Zephyr_fd = -1; | |
31 int __Zephyr_open; | |
32 int __Zephyr_port = -1; | |
2419
7ba69b8e0de5
[gaim-migrate @ 2432]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
33 struct in_addr __My_addr; |
2086 | 34 int __Q_CompleteLength; |
35 int __Q_Size; | |
36 struct _Z_InputQ *__Q_Head, *__Q_Tail; | |
37 struct sockaddr_in __HM_addr; | |
38 struct sockaddr_in __HM_addr_real; | |
39 int __HM_set; | |
40 int __Zephyr_server; | |
41 ZLocations_t *__locate_list; | |
42 int __locate_num; | |
43 int __locate_next; | |
44 ZSubscription_t *__subscriptions_list; | |
45 int __subscriptions_num; | |
46 int __subscriptions_next; | |
2419
7ba69b8e0de5
[gaim-migrate @ 2432]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
47 int Z_discarded_packets = 0; |
2086 | 48 |
49 #ifdef ZEPHYR_USES_KERBEROS | |
50 C_Block __Zephyr_session; | |
2419
7ba69b8e0de5
[gaim-migrate @ 2432]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
51 #endif |
2086 | 52 char __Zephyr_realm[REALM_SZ]; |
53 | |
54 #ifdef Z_DEBUG | |
55 void (*__Z_debug_print) __P((const char *fmt, va_list args, void *closure)); | |
56 void *__Z_debug_print_closure; | |
57 #endif | |
58 | |
59 #define min(a,b) ((a)<(b)?(a):(b)) | |
60 | |
5136 | 61 static int Z_AddField __P((char **ptr, const char *field, char *end)); |
2086 | 62 static int find_or_insert_uid __P((ZUnique_Id_t *uid, ZNotice_Kind_t kind)); |
63 | |
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) | |
70 ZUnique_Id_t *uid; | |
71 ZNotice_Kind_t kind; | |
72 { | |
73 static struct _filter { | |
74 ZUnique_Id_t uid; | |
75 ZNotice_Kind_t kind; | |
76 time_t t; | |
77 } *buffer; | |
78 static long size; | |
79 static long start; | |
80 static long num; | |
81 | |
82 time_t now; | |
83 struct _filter *new; | |
84 long i, j, new_size; | |
85 int result; | |
86 | |
87 /* Initialize the uid buffer if it hasn't been done already. */ | |
88 if (!buffer) { | |
89 size = Z_INITFILTERSIZE; | |
90 buffer = (struct _filter *) malloc(size * sizeof(*buffer)); | |
91 if (!buffer) | |
92 return 0; | |
93 } | |
94 | |
95 /* Age the uid buffer, discarding any uids older than the clock skew. */ | |
96 time(&now); | |
97 while (num && (now - buffer[start % size].t) > CLOCK_SKEW) | |
98 start++, num--; | |
99 start %= size; | |
100 | |
101 /* Make room for a new uid, since we'll probably have to insert one. */ | |
102 if (num == size) { | |
103 new_size = size * 2 + 2; | |
104 new = (struct _filter *) malloc(new_size * sizeof(*new)); | |
105 if (!new) | |
106 return 0; | |
107 for (i = 0; i < num; i++) | |
108 new[i] = buffer[(start + i) % size]; | |
109 free(buffer); | |
110 buffer = new; | |
111 size = new_size; | |
112 start = 0; | |
113 } | |
114 | |
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) | |
119 return 1; | |
120 if (result > 0) | |
121 break; | |
122 } | |
123 | |
124 /* We didn't find it; insert the uid into the buffer after i. */ | |
125 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; | |
131 num++; | |
132 | |
133 return 0; | |
134 } | |
135 | |
136 | |
137 /* Return 1 if there is a packet waiting, 0 otherwise */ | |
138 | |
139 int Z_PacketWaiting() | |
140 { | |
141 struct timeval tv; | |
142 fd_set read; | |
143 | |
144 tv.tv_sec = tv.tv_usec = 0; | |
145 FD_ZERO(&read); | |
146 FD_SET(ZGetFD(), &read); | |
147 return (select(ZGetFD() + 1, &read, NULL, NULL, &tv)); | |
148 } | |
149 | |
150 | |
151 /* Wait for a complete notice to become available */ | |
152 | |
153 Code_t Z_WaitForComplete() | |
154 { | |
155 Code_t retval; | |
156 | |
157 if (__Q_CompleteLength) | |
158 return (Z_ReadEnqueue()); | |
159 | |
160 while (!__Q_CompleteLength) | |
161 if ((retval = Z_ReadWait()) != ZERR_NONE) | |
162 return (retval); | |
163 | |
164 return (ZERR_NONE); | |
165 } | |
166 | |
167 | |
168 /* Read any available packets and enqueue them */ | |
169 | |
170 Code_t Z_ReadEnqueue() | |
171 { | |
172 Code_t retval; | |
173 | |
174 if (ZGetFD() < 0) | |
175 return (ZERR_NOPORT); | |
176 | |
177 while (Z_PacketWaiting()) | |
178 if ((retval = Z_ReadWait()) != ZERR_NONE) | |
179 return (retval); | |
180 | |
181 return (ZERR_NONE); | |
182 } | |
183 | |
184 | |
185 /* | |
186 * Search the queue for a notice with the proper multiuid - remove any | |
187 * notices that haven't been touched in a while | |
188 */ | |
189 | |
190 struct _Z_InputQ *Z_SearchQueue(uid, kind) | |
191 ZUnique_Id_t *uid; | |
192 ZNotice_Kind_t kind; | |
193 { | |
194 register struct _Z_InputQ *qptr; | |
195 struct _Z_InputQ *next; | |
196 struct timeval tv; | |
197 | |
198 (void) gettimeofday(&tv, (struct timezone *)0); | |
199 | |
200 qptr = __Q_Head; | |
201 | |
202 while (qptr) { | |
203 if (ZCompareUID(uid, &qptr->uid) && qptr->kind == kind) | |
204 return (qptr); | |
205 next = qptr->next; | |
206 if (qptr->timep && (qptr->timep+Z_NOTICETIMELIMIT < tv.tv_sec)) | |
207 Z_RemQueue(qptr); | |
208 qptr = next; | |
209 } | |
210 return (NULL); | |
211 } | |
212 | |
213 /* | |
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... | |
217 * | |
218 * This routine does NOT guarantee a complete packet will be ready when it | |
219 * returns. | |
220 */ | |
221 | |
222 Code_t Z_ReadWait() | |
223 { | |
224 register struct _Z_InputQ *qptr; | |
225 ZNotice_t notice; | |
226 ZPacket_t packet; | |
227 struct sockaddr_in olddest, from; | |
2419
7ba69b8e0de5
[gaim-migrate @ 2432]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
228 int from_len, packet_len, zvlen, part, partof; |
2086 | 229 char *slash; |
230 Code_t retval; | |
2419
7ba69b8e0de5
[gaim-migrate @ 2432]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
231 fd_set fds; |
7ba69b8e0de5
[gaim-migrate @ 2432]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
232 struct timeval tv; |
2086 | 233 |
234 if (ZGetFD() < 0) | |
235 return (ZERR_NOPORT); | |
236 | |
2419
7ba69b8e0de5
[gaim-migrate @ 2432]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
237 FD_ZERO(&fds); |
7ba69b8e0de5
[gaim-migrate @ 2432]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
238 FD_SET(ZGetFD(), &fds); |
7ba69b8e0de5
[gaim-migrate @ 2432]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
239 tv.tv_sec = 60; |
7ba69b8e0de5
[gaim-migrate @ 2432]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
240 tv.tv_usec = 0; |
7ba69b8e0de5
[gaim-migrate @ 2432]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
241 |
7ba69b8e0de5
[gaim-migrate @ 2432]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
242 if (select(ZGetFD() + 1, &fds, NULL, NULL, &tv) < 0) |
7ba69b8e0de5
[gaim-migrate @ 2432]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
243 return (errno); |
7ba69b8e0de5
[gaim-migrate @ 2432]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
244 if (!FD_ISSET(ZGetFD(), &fds)) |
7ba69b8e0de5
[gaim-migrate @ 2432]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
245 return ETIMEDOUT; |
7ba69b8e0de5
[gaim-migrate @ 2432]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
246 |
2086 | 247 from_len = sizeof(struct sockaddr_in); |
248 | |
249 packet_len = recvfrom(ZGetFD(), packet, sizeof(packet), 0, | |
250 (struct sockaddr *)&from, &from_len); | |
251 | |
252 if (packet_len < 0) | |
253 return (errno); | |
254 | |
255 if (!packet_len) | |
256 return (ZERR_EOF); | |
257 | |
2419
7ba69b8e0de5
[gaim-migrate @ 2432]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
258 /* Ignore obviously non-Zephyr packets. */ |
7ba69b8e0de5
[gaim-migrate @ 2432]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
259 zvlen = sizeof(ZVERSIONHDR) - 1; |
7ba69b8e0de5
[gaim-migrate @ 2432]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
260 if (packet_len < zvlen || memcmp(packet, ZVERSIONHDR, zvlen) != 0) { |
7ba69b8e0de5
[gaim-migrate @ 2432]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
261 Z_discarded_packets++; |
7ba69b8e0de5
[gaim-migrate @ 2432]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
262 return (ZERR_NONE); |
7ba69b8e0de5
[gaim-migrate @ 2432]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
263 } |
2086 | 264 |
265 /* Parse the notice */ | |
266 if ((retval = ZParseNotice(packet, packet_len, ¬ice)) != ZERR_NONE) | |
267 return (retval); | |
268 | |
269 /* | |
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. | |
272 */ | |
273 if (!__Zephyr_server) { | |
274 if (notice.z_kind != HMACK && notice.z_kind != SERVACK && | |
275 notice.z_kind != SERVNAK && notice.z_kind != CLIENTACK) { | |
276 ZNotice_t tmpnotice; | |
277 ZPacket_t pkt; | |
278 int len; | |
279 | |
280 tmpnotice = notice; | |
281 tmpnotice.z_kind = CLIENTACK; | |
282 tmpnotice.z_message_len = 0; | |
283 olddest = __HM_addr; | |
284 __HM_addr = from; | |
285 if ((retval = ZFormatSmallRawNotice(&tmpnotice, pkt, &len)) | |
286 != ZERR_NONE) | |
287 return(retval); | |
288 if ((retval = ZSendPacket(pkt, len, 0)) != ZERR_NONE) | |
289 return (retval); | |
290 __HM_addr = olddest; | |
291 } | |
292 if (find_or_insert_uid(¬ice.z_uid, notice.z_kind)) | |
293 return(ZERR_NONE); | |
294 | |
295 /* Check authentication on the notice. */ | |
296 notice.z_checked_auth = ZCheckAuthentication(¬ice, &from); | |
297 } | |
298 | |
299 | |
300 /* | |
301 * Parse apart the z_multinotice field - if the field is blank for | |
302 * some reason, assume this packet stands by itself. | |
303 */ | |
304 slash = strchr(notice.z_multinotice, '/'); | |
305 if (slash) { | |
306 part = atoi(notice.z_multinotice); | |
307 partof = atoi(slash+1); | |
308 if (part > partof || partof == 0) { | |
309 part = 0; | |
310 partof = notice.z_message_len; | |
311 } | |
312 } | |
313 else { | |
314 part = 0; | |
315 partof = notice.z_message_len; | |
316 } | |
317 | |
318 /* Too big a packet...just ignore it! */ | |
319 if (partof > Z_MAXNOTICESIZE) | |
320 return (ZERR_NONE); | |
321 | |
322 /* | |
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 | |
325 * appropriate. | |
326 */ | |
327 switch (notice.z_kind) { | |
328 case SERVACK: | |
329 case SERVNAK: | |
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) | |
338 */ | |
339 if (!__Zephyr_server && | |
340 !ZCompareUID(¬ice.z_multiuid, ¬ice.z_uid)) | |
341 /* they're not the same... throw away this packet. */ | |
342 return(ZERR_NONE); | |
343 /* fall thru & process it */ | |
344 default: | |
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, | |
349 notice.z_kind))) { | |
350 /* | |
351 * If this is the first fragment, and we haven't already | |
352 * gotten a first fragment, grab the header from it. | |
353 */ | |
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); | |
357 if (!qptr->header) | |
358 return (ENOMEM); | |
359 (void) memcpy(qptr->header, packet, qptr->header_len); | |
360 } | |
361 return (Z_AddNoticeToEntry(qptr, ¬ice, part)); | |
362 } | |
363 } | |
364 | |
365 /* | |
366 * We'll have to create a new entry...make sure the queue isn't | |
367 * going to get too big. | |
368 */ | |
369 if (__Q_Size+(__Zephyr_server ? notice.z_message_len : partof) > Z_MAXQUEUESIZE) | |
370 return (ZERR_NONE); | |
371 | |
372 /* | |
373 * This is a notice we haven't heard of, so create a new queue | |
374 * entry for it and zero it out. | |
375 */ | |
376 qptr = (struct _Z_InputQ *)malloc(sizeof(struct _Z_InputQ)); | |
377 if (!qptr) | |
378 return (ENOMEM); | |
379 (void) memset((char *)qptr, 0, sizeof(struct _Z_InputQ)); | |
380 | |
381 /* Insert the entry at the end of the queue */ | |
382 qptr->next = NULL; | |
383 qptr->prev = __Q_Tail; | |
384 if (__Q_Tail) | |
385 __Q_Tail->next = qptr; | |
386 __Q_Tail = qptr; | |
387 | |
388 if (!__Q_Head) | |
389 __Q_Head = qptr; | |
390 | |
391 | |
392 /* Copy the from field, multiuid, kind, and checked authentication. */ | |
393 qptr->from = from; | |
394 qptr->uid = notice.z_multiuid; | |
395 qptr->kind = notice.z_kind; | |
396 qptr->auth = notice.z_checked_auth; | |
397 | |
398 /* | |
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. | |
402 * | |
403 * If a Zephyr Server, we always take the header. | |
404 */ | |
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); | |
408 if (!qptr->header) | |
409 return ENOMEM; | |
410 (void) memcpy(qptr->header, packet, qptr->header_len); | |
411 } | |
412 | |
413 /* | |
414 * If this is not a fragmented notice, then don't bother with a | |
415 * hole list. | |
416 * If we are a Zephyr server, all notices are treated as complete. | |
417 */ | |
418 if (__Zephyr_server || (part == 0 && notice.z_message_len == partof)) { | |
419 __Q_CompleteLength++; | |
420 qptr->holelist = (struct _Z_Hole *) 0; | |
421 qptr->complete = 1; | |
422 /* allocate a msg buf for this piece */ | |
423 if (notice.z_message_len == 0) | |
424 qptr->msg = 0; | |
425 else if (!(qptr->msg = (char *) malloc((unsigned) notice.z_message_len))) | |
426 return(ENOMEM); | |
427 else | |
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))) | |
433 return (ENOMEM); | |
434 (void) memcpy(qptr->packet, qptr->header, qptr->header_len); | |
435 if(qptr->msg) | |
436 (void) memcpy(qptr->packet+qptr->header_len, qptr->msg, | |
437 qptr->msg_len); | |
438 return (ZERR_NONE); | |
439 } | |
440 | |
441 /* | |
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. | |
444 */ | |
445 if (!(qptr->msg = (char *) malloc((unsigned) partof)) && partof) | |
446 return (ENOMEM); | |
447 qptr->msg_len = partof; | |
448 __Q_Size += partof; | |
449 | |
450 /* | |
451 * Well, it's a fragmented notice...allocate a hole list and | |
452 * initialize it to the full packet size. Then insert the | |
453 * current fragment. | |
454 */ | |
455 if (!(qptr->holelist = (struct _Z_Hole *) | |
456 malloc(sizeof(struct _Z_Hole)))) | |
457 return (ENOMEM); | |
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)); | |
462 } | |
463 | |
464 | |
465 /* Fragment management routines - compliments, more or less, of RFC815 */ | |
466 | |
467 Code_t Z_AddNoticeToEntry(qptr, notice, part) | |
468 struct _Z_InputQ *qptr; | |
469 ZNotice_t *notice; | |
470 int part; | |
471 { | |
472 int last, oldfirst, oldlast; | |
473 struct _Z_Hole *hole, *lasthole; | |
474 struct timeval tv; | |
475 | |
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; | |
481 | |
482 (void) gettimeofday(&tv, (struct timezone *)0); | |
483 qptr->timep = tv.tv_sec; | |
484 | |
485 last = part+notice->z_message_len-1; | |
486 | |
487 hole = qptr->holelist; | |
488 lasthole = (struct _Z_Hole *) 0; | |
489 | |
490 /* copy in the message body */ | |
491 (void) memcpy(qptr->msg+part, notice->z_message, notice->z_message_len); | |
492 | |
493 /* Search for a hole that overlaps with the current fragment */ | |
494 while (hole) { | |
495 if (part <= hole->last && last >= hole->first) | |
496 break; | |
497 lasthole = hole; | |
498 hole = hole->next; | |
499 } | |
500 | |
501 /* If we found one, delete it and reconstruct a new hole */ | |
502 if (hole) { | |
503 oldfirst = hole->first; | |
504 oldlast = hole->last; | |
505 if (lasthole) | |
506 lasthole->next = hole->next; | |
507 else | |
508 qptr->holelist = hole->next; | |
509 free((char *)hole); | |
510 /* | |
511 * Now create a new hole that is the original hole without the | |
512 * current fragment. | |
513 */ | |
514 if (part > oldfirst) { | |
515 /* Search for the end of the hole list */ | |
516 hole = qptr->holelist; | |
517 lasthole = (struct _Z_Hole *) 0; | |
518 while (hole) { | |
519 lasthole = hole; | |
520 hole = hole->next; | |
521 } | |
522 if (lasthole) { | |
523 if (!(lasthole->next = (struct _Z_Hole *) | |
524 malloc(sizeof(struct _Z_InputQ)))) | |
525 return (ENOMEM); | |
526 hole = lasthole->next; | |
527 } | |
528 else { | |
529 if (!(qptr->holelist = (struct _Z_Hole *) | |
530 malloc(sizeof(struct _Z_InputQ)))) | |
531 return (ENOMEM); | |
532 hole = qptr->holelist; | |
533 } | |
534 hole->next = NULL; | |
535 hole->first = oldfirst; | |
536 hole->last = part-1; | |
537 } | |
538 if (last < oldlast) { | |
539 /* Search for the end of the hole list */ | |
540 hole = qptr->holelist; | |
541 lasthole = (struct _Z_Hole *) 0; | |
542 while (hole) { | |
543 lasthole = hole; | |
544 hole = hole->next; | |
545 } | |
546 if (lasthole) { | |
547 if (!(lasthole->next = (struct _Z_Hole *) | |
548 malloc(sizeof(struct _Z_InputQ)))) | |
549 return (ENOMEM); | |
550 hole = lasthole->next; | |
551 } | |
552 else { | |
553 if (!(qptr->holelist = (struct _Z_Hole *) | |
554 malloc(sizeof(struct _Z_InputQ)))) | |
555 return (ENOMEM); | |
556 hole = qptr->holelist; | |
557 } | |
558 hole->next = (struct _Z_Hole *) 0; | |
559 hole->first = last+1; | |
560 hole->last = oldlast; | |
561 } | |
562 } | |
563 | |
564 if (!qptr->holelist) { | |
565 if (!qptr->complete) | |
566 __Q_CompleteLength++; | |
567 qptr->complete = 1; | |
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))) | |
571 return (ENOMEM); | |
572 (void) memcpy(qptr->packet, qptr->header, qptr->header_len); | |
573 (void) memcpy(qptr->packet+qptr->header_len, qptr->msg, | |
574 qptr->msg_len); | |
575 } | |
576 | |
577 return (ZERR_NONE); | |
578 } | |
579 | |
580 Code_t Z_FormatHeader(notice, buffer, buffer_len, len, cert_routine) | |
581 ZNotice_t *notice; | |
582 char *buffer; | |
583 int buffer_len; | |
584 int *len; | |
585 Z_AuthProc cert_routine; | |
586 { | |
587 Code_t retval; | |
588 static char version[BUFSIZ]; /* default init should be all \0 */ | |
589 struct sockaddr_in name; | |
590 int namelen = sizeof(name); | |
591 | |
592 if (!notice->z_sender) | |
593 notice->z_sender = ZGetSender(); | |
594 | |
595 if (notice->z_port == 0) { | |
596 if (ZGetFD() < 0) { | |
597 retval = ZOpenPort((u_short *)0); | |
598 if (retval != ZERR_NONE) | |
599 return (retval); | |
600 } | |
601 retval = getsockname(ZGetFD(), (struct sockaddr *) &name, &namelen); | |
602 if (retval != 0) | |
603 return (retval); | |
604 notice->z_port = name.sin_port; | |
605 } | |
606 | |
607 notice->z_multinotice = ""; | |
608 | |
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); | |
612 | |
2419
7ba69b8e0de5
[gaim-migrate @ 2432]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
613 (void) memcpy(¬ice->z_uid.zuid_addr, &__My_addr, sizeof(__My_addr)); |
2086 | 614 |
615 notice->z_multiuid = notice->z_uid; | |
616 | |
617 if (!version[0]) | |
618 (void) sprintf(version, "%s%d.%d", ZVERSIONHDR, ZVERSIONMAJOR, | |
619 ZVERSIONMINOR); | |
620 notice->z_version = version; | |
621 | |
622 return Z_FormatAuthHeader(notice, buffer, buffer_len, len, cert_routine); | |
623 } | |
624 | |
625 Code_t Z_FormatAuthHeader(notice, buffer, buffer_len, len, cert_routine) | |
626 ZNotice_t *notice; | |
627 char *buffer; | |
628 int buffer_len; | |
629 int *len; | |
630 Z_AuthProc cert_routine; | |
631 { | |
632 if (!cert_routine) { | |
633 notice->z_auth = 0; | |
634 notice->z_authent_len = 0; | |
635 notice->z_ascii_authent = ""; | |
636 notice->z_checksum = 0; | |
637 return (Z_FormatRawHeader(notice, buffer, buffer_len, | |
638 len, NULL, NULL)); | |
639 } | |
640 | |
641 return ((*cert_routine)(notice, buffer, buffer_len, len)); | |
642 } | |
643 | |
644 Code_t Z_FormatRawHeader(notice, buffer, buffer_len, len, cstart, cend) | |
645 ZNotice_t *notice; | |
646 char *buffer; | |
647 int buffer_len; | |
648 int *len; | |
649 char **cstart, **cend; | |
650 { | |
651 char newrecip[BUFSIZ]; | |
652 char *ptr, *end; | |
653 int i; | |
654 | |
655 if (!notice->z_class) | |
656 notice->z_class = ""; | |
657 | |
658 if (!notice->z_class_inst) | |
659 notice->z_class_inst = ""; | |
660 | |
661 if (!notice->z_opcode) | |
662 notice->z_opcode = ""; | |
663 | |
664 if (!notice->z_recipient) | |
665 notice->z_recipient = ""; | |
666 | |
667 if (!notice->z_default_format) | |
668 notice->z_default_format = ""; | |
669 | |
670 ptr = buffer; | |
671 end = buffer+buffer_len; | |
672 | |
673 if (buffer_len < strlen(notice->z_version)+1) | |
674 return (ZERR_HEADERLEN); | |
675 | |
676 (void) strcpy(ptr, notice->z_version); | |
677 ptr += strlen(ptr)+1; | |
678 | |
679 if (ZMakeAscii32(ptr, end-ptr, Z_NUMFIELDS + notice->z_num_other_fields) | |
680 == ZERR_FIELDLEN) | |
681 return (ZERR_HEADERLEN); | |
682 ptr += strlen(ptr)+1; | |
683 | |
684 if (ZMakeAscii32(ptr, end-ptr, notice->z_kind) == ZERR_FIELDLEN) | |
685 return (ZERR_HEADERLEN); | |
686 ptr += strlen(ptr)+1; | |
687 | |
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; | |
692 | |
693 if (ZMakeAscii16(ptr, end-ptr, ntohs(notice->z_port)) == ZERR_FIELDLEN) | |
694 return (ZERR_HEADERLEN); | |
695 ptr += strlen(ptr)+1; | |
696 | |
697 if (ZMakeAscii32(ptr, end-ptr, notice->z_auth) == ZERR_FIELDLEN) | |
698 return (ZERR_HEADERLEN); | |
699 ptr += strlen(ptr)+1; | |
700 | |
701 if (ZMakeAscii32(ptr, end-ptr, notice->z_authent_len) == ZERR_FIELDLEN) | |
702 return (ZERR_HEADERLEN); | |
703 ptr += strlen(ptr)+1; | |
704 | |
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); | |
718 } | |
719 else { | |
720 if (strlen(notice->z_recipient) + strlen(__Zephyr_realm) + 2 > | |
2419
7ba69b8e0de5
[gaim-migrate @ 2432]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
721 sizeof(newrecip)) |
7ba69b8e0de5
[gaim-migrate @ 2432]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
722 return (ZERR_HEADERLEN); |
2086 | 723 (void) sprintf(newrecip, "%s@%s", notice->z_recipient, __Zephyr_realm); |
724 if (Z_AddField(&ptr, newrecip, end)) | |
725 return (ZERR_HEADERLEN); | |
726 } | |
727 if (Z_AddField(&ptr, notice->z_default_format, end)) | |
728 return (ZERR_HEADERLEN); | |
729 | |
730 /* copy back the end pointer location for crypto checksum */ | |
731 if (cstart) | |
732 *cstart = ptr; | |
733 if (ZMakeAscii32(ptr, end-ptr, notice->z_checksum) == ZERR_FIELDLEN) | |
734 return (ZERR_HEADERLEN); | |
735 ptr += strlen(ptr)+1; | |
736 if (cend) | |
737 *cend = ptr; | |
738 | |
739 if (Z_AddField(&ptr, notice->z_multinotice, end)) | |
740 return (ZERR_HEADERLEN); | |
741 | |
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; | |
746 | |
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); | |
750 | |
751 *len = ptr-buffer; | |
752 | |
753 return (ZERR_NONE); | |
754 } | |
755 | |
756 static int | |
5136 | 757 Z_AddField(char **ptr, const char *field, char *end) |
2086 | 758 { |
759 register int len; | |
760 | |
761 len = field ? strlen (field) + 1 : 1; | |
762 | |
763 if (*ptr+len > end) | |
764 return 1; | |
765 if (field) | |
766 (void) strcpy(*ptr, field); | |
767 else | |
768 **ptr = '\0'; | |
769 *ptr += len; | |
770 | |
771 return 0; | |
772 } | |
773 | |
774 struct _Z_InputQ *Z_GetFirstComplete() | |
775 { | |
776 struct _Z_InputQ *qptr; | |
777 | |
778 qptr = __Q_Head; | |
779 | |
780 while (qptr) { | |
781 if (qptr->complete) | |
782 return (qptr); | |
783 qptr = qptr->next; | |
784 } | |
785 | |
786 return ((struct _Z_InputQ *)0); | |
787 } | |
788 | |
789 struct _Z_InputQ *Z_GetNextComplete(qptr) | |
790 struct _Z_InputQ *qptr; | |
791 { | |
792 qptr = qptr->next; | |
793 while (qptr) { | |
794 if (qptr->complete) | |
795 return (qptr); | |
796 qptr = qptr->next; | |
797 } | |
798 | |
799 return ((struct _Z_InputQ *)0); | |
800 } | |
801 | |
802 void Z_RemQueue(qptr) | |
803 struct _Z_InputQ *qptr; | |
804 { | |
805 struct _Z_Hole *hole, *nexthole; | |
806 | |
807 if (qptr->complete) | |
808 __Q_CompleteLength--; | |
809 | |
810 __Q_Size -= qptr->msg_len; | |
811 | |
812 if (qptr->header) | |
813 free(qptr->header); | |
814 if (qptr->msg) | |
815 free(qptr->msg); | |
816 if (qptr->packet) | |
817 free(qptr->packet); | |
818 | |
819 hole = qptr->holelist; | |
820 while (hole) { | |
821 nexthole = hole->next; | |
822 free((char *)hole); | |
823 hole = nexthole; | |
824 } | |
825 | |
826 if (qptr == __Q_Head && __Q_Head == __Q_Tail) { | |
827 free ((char *)qptr); | |
828 __Q_Head = (struct _Z_InputQ *)0; | |
829 __Q_Tail = (struct _Z_InputQ *)0; | |
830 return; | |
831 } | |
832 | |
833 if (qptr == __Q_Head) { | |
834 __Q_Head = qptr->next; | |
835 __Q_Head->prev = (struct _Z_InputQ *)0; | |
836 free ((char *)qptr); | |
837 return; | |
838 } | |
839 if (qptr == __Q_Tail) { | |
840 __Q_Tail = qptr->prev; | |
841 __Q_Tail->next = (struct _Z_InputQ *)0; | |
842 free ((char *)qptr); | |
843 return; | |
844 } | |
845 qptr->prev->next = qptr->next; | |
846 qptr->next->prev = qptr->prev; | |
847 free ((char *)qptr); | |
848 return; | |
849 } | |
850 | |
851 Code_t Z_SendFragmentedNotice(notice, len, cert_func, send_func) | |
852 ZNotice_t *notice; | |
853 int len; | |
854 Z_AuthProc cert_func; | |
855 Z_SendProc send_func; | |
856 { | |
857 ZNotice_t partnotice; | |
858 ZPacket_t buffer; | |
859 char multi[64]; | |
860 int offset, hdrsize, fragsize, ret_len, message_len, waitforack; | |
861 Code_t retval; | |
862 | |
863 hdrsize = len-notice->z_message_len; | |
864 fragsize = Z_MAXPKTLEN-hdrsize-Z_FRAGFUDGE; | |
865 | |
866 offset = 0; | |
867 | |
868 waitforack = ((notice->z_kind == UNACKED || notice->z_kind == ACKED) | |
869 && !__Zephyr_server); | |
870 | |
871 partnotice = *notice; | |
872 | |
873 while (offset < notice->z_message_len || !notice->z_message_len) { | |
874 (void) sprintf(multi, "%d/%d", offset, notice->z_message_len); | |
875 partnotice.z_multinotice = multi; | |
876 if (offset > 0) { | |
877 (void) gettimeofday(&partnotice.z_uid.tv, | |
878 (struct timezone *)0); | |
879 partnotice.z_uid.tv.tv_sec = | |
880 htonl((u_long) partnotice.z_uid.tv.tv_sec); | |
881 partnotice.z_uid.tv.tv_usec = | |
882 htonl((u_long) partnotice.z_uid.tv.tv_usec); | |
2419
7ba69b8e0de5
[gaim-migrate @ 2432]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
883 (void) memcpy((char *)&partnotice.z_uid.zuid_addr, &__My_addr, |
7ba69b8e0de5
[gaim-migrate @ 2432]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
884 sizeof(__My_addr)); |
2086 | 885 } |
886 message_len = min(notice->z_message_len-offset, fragsize); | |
887 partnotice.z_message = notice->z_message+offset; | |
888 partnotice.z_message_len = message_len; | |
889 if ((retval = Z_FormatAuthHeader(&partnotice, buffer, Z_MAXHEADERLEN, | |
890 &ret_len, cert_func)) != ZERR_NONE) { | |
891 return (retval); | |
892 } | |
893 memcpy(buffer + ret_len, partnotice.z_message, message_len); | |
894 if ((retval = (*send_func)(&partnotice, buffer, ret_len+message_len, | |
895 waitforack)) != ZERR_NONE) { | |
896 return (retval); | |
897 } | |
898 offset += fragsize; | |
899 if (!notice->z_message_len) | |
900 break; | |
901 } | |
902 | |
903 return (ZERR_NONE); | |
904 } | |
905 | |
906 /*ARGSUSED*/ | |
907 Code_t Z_XmitFragment(notice, buf, len, wait) | |
908 ZNotice_t *notice; | |
909 char *buf; | |
910 int len; | |
911 int wait; | |
912 { | |
913 return(ZSendPacket(buf, len, wait)); | |
914 } | |
915 | |
916 #ifdef Z_DEBUG | |
917 /* For debugging printing */ | |
918 const char *const ZNoticeKinds[] = { | |
919 "UNSAFE", "UNACKED", "ACKED", "HMACK", "HMCTL", "SERVACK", "SERVNAK", | |
920 "CLIENTACK", "STAT" | |
921 }; | |
922 #endif | |
923 | |
924 #ifdef Z_DEBUG | |
925 | |
926 #undef Z_debug | |
927 #ifdef HAVE_STDARG_H | |
928 void Z_debug (const char *format, ...) | |
929 { | |
930 va_list pvar; | |
931 if (!__Z_debug_print) | |
932 return; | |
933 va_start (pvar, format); | |
934 (*__Z_debug_print) (format, pvar, __Z_debug_print_closure); | |
935 va_end (pvar); | |
936 } | |
937 #else /* stdarg */ | |
938 void Z_debug (va_alist) va_dcl | |
939 { | |
940 va_list pvar; | |
941 char *format; | |
942 if (!__Z_debug_print) | |
943 return; | |
944 va_start (pvar); | |
945 format = va_arg (pvar, char *); | |
946 (*__Z_debug_print) (format, pvar, __Z_debug_print_closure); | |
947 va_end (pvar); | |
948 } | |
949 #endif | |
950 | |
951 void Z_debug_stderr (format, args, closure) | |
952 const char *format; | |
953 va_list args; | |
954 void *closure; | |
955 { | |
956 #ifdef HAVE_VPRINTF | |
957 vfprintf (stderr, format, args); | |
958 #else | |
959 _doprnt (format, args, stderr); | |
960 #endif | |
961 putc ('\n', stderr); | |
962 } | |
963 | |
964 #undef ZGetFD | |
965 int ZGetFD () { return __Zephyr_fd; } | |
966 | |
967 #undef ZQLength | |
968 int ZQLength () { return __Q_CompleteLength; } | |
969 | |
970 #undef ZGetDestAddr | |
971 struct sockaddr_in ZGetDestAddr () { return __HM_addr; } | |
972 | |
973 #undef ZGetRealm | |
974 Zconst char * ZGetRealm () { return __Zephyr_realm; } | |
975 | |
976 #undef ZSetDebug | |
977 void ZSetDebug(proc, arg) | |
978 void (*proc) __P((const char *, va_list, void *)); | |
979 char *arg; | |
980 { | |
981 __Z_debug_print = proc; | |
982 __Z_debug_print_closure = arg; | |
983 } | |
984 #endif /* Z_DEBUG */ | |
985 |