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