/[svn]/vendor/pxys2-2.1.0/libopas/opas/opas.c
ViewVC logotype

Contents of /vendor/pxys2-2.1.0/libopas/opas/opas.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3253 - (show annotations)
Wed Apr 2 20:46:18 2014 UTC (6 years, 11 months ago) by michael
File MIME type: text/x-chdr
File size: 18678 byte(s)
- Imported pxys2-2.1.0

1 /* Copyright (C) 2003 Stephane Thiell
2 *
3 * This file is part of libopas (from pxys)
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 *
19 */
20 #define RCSID "$Id: opas.c,v 1.1.1.2 2004/01/15 14:18:23 mbuna Exp $"
21
22 #include "opas.h"
23
24 #ifdef HAVE_ALLOCA_H
25 #include <alloca.h>
26 #endif
27 #include <assert.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31
32 /* Internal includes */
33 #include "opas_msg.h"
34
35 #define OPAS_VERSION (((OPAS_MAJOR) << 24) + ((OPAS_MINOR) << 16))
36
37 #define MSG_USER_MAXSMALL (1024 - 12)
38
39 #define OPAS_HEADER_MAKE(serv, ping, ipv6, umsg, repl, prox, cach, erro) \
40 (OPAS_VERSION + ((serv) << 15) + ((ping) << 14) + ((ipv6) << 13) \
41 + ((umsg) << 12) + ((repl) << 11) + ((prox) << 10) \
42 + ((cach) << 9) + ((erro) << 8))
43
44 #define OPAS_HEADER_SETSIZE(h, siz) do { \
45 h = (h & ~0xff) + (unsigned char)(siz); } while (0)
46
47 /* After ntohl conversion:
48 */
49 #define OPAS_GET_VERSION(h) ((h) & 0xffff0000)
50 #define OPAS_GET_MSGSIZE(h) (4 + ((h) & 0xff))
51 #define OPAS_OK_VERSION(h) (((h) & 0xff000000) == ((OPAS_MAJOR) << 24) \
52 && (((h) & 0x00ff0000) >= ((OPAS_MINOR) << 16)))
53
54 /* Conversion macros
55 */
56 #define OPAS_QUERY_NTOH(qp) do { \
57 (qp)->head = ntohl((qp)->head); } while (0)
58
59 #define OPAS_QUERY_HTON(qp) do { \
60 (qp)->head = htonl((qp)->head); } while (0)
61
62 #define OPAS_REPLY_ERROR_NTOH(re) do { \
63 (re)->head = ntohl((re)->head); \
64 (re)->error = ntohl((re)->error); } while (0)
65
66 #define OPAS_REPLY_ERROR_HTON(re) do { \
67 (re)->head = htonl((re)->head); \
68 (re)->error = htonl((re)->error); } while (0)
69
70 #define OPAS_REPLY_PROXY_NTOH(rp) do { \
71 (rp)->head = ntohl((rp)->head); \
72 (rp)->timestamp = ntohl((rp)->timestamp); \
73 (rp)->proxy_type = ntohs((rp)->proxy_type); \
74 (rp)->proxy_port = ntohs((rp)->proxy_port); } while (0)
75
76 #define OPAS_REPLY_PROXY_HTON(rp) do { \
77 (rp)->head = htonl((rp)->head); \
78 (rp)->timestamp = htonl((rp)->timestamp); \
79 (rp)->proxy_type = htons((rp)->proxy_type); \
80 (rp)->proxy_port = htons((rp)->proxy_port); } while (0)
81
82 #define OPAS_MSG_USER_NTOH(mu) do { \
83 (mu)->head = ntohl((mu)->head); \
84 (mu)->data_length = ntohl((mu)->data_length); } while (0)
85
86 #define OPAS_MSG_USER_HTON(mu) do { \
87 (mu)->head = htonl((mu)->head); \
88 (mu)->data_length = htonl((mu)->data_length); } while (0)
89
90 struct opas_session_s
91 {
92 struct opas_callbacks cbs;
93 void *context;
94 void *ptr;
95 int size;
96 int end;
97 int minisize;
98 char minibuf[OPAS_MSG_MINSIZE];
99 };
100
101 #ifndef OPAS_VERSION_STRING
102 #define OPAS_VERSION_STRING "<Unknown>"
103 #endif
104
105 const char *
106 opas_get_version()
107 {
108 return OPAS_VERSION_STRING;
109 }
110
111 opas_session_t
112 opas_open_session(const struct opas_callbacks *callbacks, void *context)
113 {
114 opas_session_t session =
115 (opas_session_t)malloc(sizeof(struct opas_session_s));
116
117 if (session)
118 {
119 session->cbs = *callbacks;
120 session->context = context;
121 session->ptr = NULL;
122 session->size = 0;
123 session->end = 0;
124 session->minisize = 0;
125 session->minibuf[0] = '\0';
126 }
127
128 return session;
129 }
130
131 void
132 opas_close_session(opas_session_t session)
133 {
134 if (session->ptr)
135 free(session->ptr);
136 free(session);
137 }
138
139 void *
140 opas_get_context(opas_session_t session)
141 {
142 return session->context;
143 }
144
145 void
146 opas_set_context(opas_session_t session, void *context)
147 {
148 session->context = context;
149 }
150
151 static int
152 __opas_callout(opas_session_t session, uint32_t head, uint32_t msgsize,
153 void *data)
154 {
155 if (!(head & OPAS_FLAG_IPV6))
156 {
157 if (head & OPAS_FLAG_REPL)
158 {
159 if (head & OPAS_FLAG_ERRO)
160 {
161 if (msgsize == sizeof(struct opas_msg_reply_error))
162 {
163 struct opas_msg_reply_error *re = (struct opas_msg_reply_error*)data;
164 OPAS_REPLY_ERROR_NTOH(re);
165 if (session->cbs.reply_error_fun)
166 (*session->cbs.reply_error_fun)(re, session->context);
167 return 0;
168 }
169 }
170 else if (head & OPAS_FLAG_PROX)
171 {
172 if (msgsize >= sizeof(struct opas_msg_reply_proxy))
173 {
174 struct opas_msg_reply_proxy *rp = (struct opas_msg_reply_proxy*)data;
175 OPAS_REPLY_PROXY_NTOH(rp);
176 if (session->cbs.reply_proxy_fun)
177 (*session->cbs.reply_proxy_fun)(rp, session->context);
178 return 0;
179 }
180 }
181 else /* not an error nor a proxy... cool ! */
182 {
183 if (msgsize == sizeof(struct opas_msg_query))
184 {
185 OPAS_QUERY_NTOH((struct opas_msg_query *)data);
186 if (session->cbs.reply_noproxy_fun)
187 (*session->cbs.reply_noproxy_fun)((struct opas_msg_query *)data,
188 session->context);
189 return 0;
190 }
191 }
192 }
193 else /* OPAS_FLAG_REPL */
194 {
195 if (msgsize == sizeof(struct opas_msg_query))
196 {
197 OPAS_QUERY_NTOH((struct opas_msg_query *)data);
198 if (session->cbs.query_fun)
199 (*session->cbs.query_fun)((struct opas_msg_query *)data,
200 session->context);
201 return 0;
202 }
203 }
204 }
205 else
206 {
207 if (head & OPAS_FLAG_REPL)
208 {
209 if (head & OPAS_FLAG_ERRO)
210 {
211 if (msgsize == sizeof(struct opas_msg_reply6_error))
212 {
213 struct opas_msg_reply6_error *re
214 = (struct opas_msg_reply6_error*)data;
215 OPAS_REPLY_ERROR_NTOH(re);
216 if (session->cbs.reply6_error_fun)
217 (*session->cbs.reply6_error_fun)(re, session->context);
218 return 0;
219 }
220 }
221 else if (head & OPAS_FLAG_PROX)
222 {
223 if (msgsize >= sizeof(struct opas_msg_reply6_proxy))
224 {
225 OPAS_REPLY_PROXY_NTOH((struct opas_msg_reply6_proxy *)data);
226 if (session->cbs.reply6_proxy_fun)
227 (*session->cbs.reply6_proxy_fun)(
228 (struct opas_msg_reply6_proxy *)data,
229 session->context);
230 return 0;
231 }
232 }
233 else /* OPAS_FLAG_ERRO, OPAS_FLAG_PROX */
234 {
235 if (msgsize == sizeof(struct opas_msg_query6))
236 {
237 OPAS_QUERY_NTOH((struct opas_msg_query6 *)data);
238 if (session->cbs.reply6_noproxy_fun)
239 (*session->cbs.reply6_noproxy_fun)((struct opas_msg_query6 *)data,
240 session->context);
241 return 0;
242 }
243 }
244 }
245 else /* OPAS_FLAG_REPL */
246 {
247 if (msgsize == sizeof(struct opas_msg_query6))
248 {
249 OPAS_QUERY_NTOH((struct opas_msg_query6 *)data);
250 if (session->cbs.query6_fun)
251 (*session->cbs.query6_fun)((struct opas_msg_query6 *)data,
252 session->context);
253 return 0;
254 }
255 }
256 }
257 return -1;
258 }
259
260 static void
261 __opas_pong(opas_session_t session)
262 {
263 uint32_t head = htonl(OPAS_HEADER_MAKE(0,1,0,0,1,0,0,0));
264 (*session->cbs.send_fun)(&head, sizeof(head), session->context);
265 }
266
267 #define FEED_ERROR do { fprintf(stderr, "%s:%d feed error\n", \
268 __FILE__, __LINE__); \
269 result = -1; goto feed_error; } while (0)
270
271 #define VERIFY_HEADER(h) if (!OPAS_OK_VERSION(h)) FEED_ERROR
272
273 int
274 opas_feed(opas_session_t session, void *data, uint32_t size)
275 {
276 int result = 0;
277 uint32_t head, msgsize, umlen;
278 char *d = (char *)data;
279 char *dsave = NULL;
280
281 if (session->minisize > 0)
282 {
283 if (session->minisize + size < OPAS_MSG_MINSIZE)
284 {
285 memcpy(session->minibuf + session->minisize, data, size);
286 session->minisize += size;
287 return 0;
288 }
289 else
290 {
291 d = dsave = malloc(session->minisize + size);
292 if (!d)
293 return -1;
294 memcpy(d, session->minibuf, session->minisize);
295 memcpy((char *)d + session->minisize, data, size);
296 size += session->minisize;
297 session->minisize = 0;
298 }
299 }
300
301 while (size > 0)
302 {
303 if (session->end == 0)
304 {
305 if (size < OPAS_MSG_MINSIZE)
306 {
307 if (size >= sizeof(uint32_t))
308 {
309 head = ntohl(*((uint32_t *)d));
310 VERIFY_HEADER(head);
311 if (head & OPAS_FLAG_PING)
312 {
313 if (!(head & OPAS_FLAG_REPL))
314 __opas_pong(session);
315 size -= sizeof(uint32_t);
316 d += sizeof(uint32_t);
317 continue;
318 }
319 }
320 memcpy(session->minibuf, d, size);
321 session->minisize = size;
322 size = 0;
323 }
324 else
325 {
326 head = ntohl(*((uint32_t *)d));
327 VERIFY_HEADER(head);
328 if (head & OPAS_FLAG_PING)
329 {
330 if (!(head & OPAS_FLAG_REPL))
331 __opas_pong(session);
332 size -= sizeof(uint32_t);
333 d += sizeof(uint32_t);
334 continue;
335 }
336 msgsize = OPAS_GET_MSGSIZE(head);
337 if (!(head & OPAS_FLAG_UMSG))
338 {
339 if (msgsize <= size)
340 {
341 if (__opas_callout(session, head, msgsize, d) == -1)
342 FEED_ERROR;
343 size -= msgsize;
344 d += msgsize;
345 }
346 else
347 {
348 assert(msgsize <= OPAS_MSG_MAXSIZE);
349 if (session->size < OPAS_MSG_MAXSIZE)
350 {
351 if (session->ptr)
352 free(session->ptr);
353 session->ptr = malloc(OPAS_MSG_MAXSIZE);
354 if (!session->ptr)
355 return -1;
356 session->size = OPAS_MSG_MAXSIZE;
357 }
358 memcpy(session->ptr, d, size);
359 session->end = size;
360 size = 0;
361 }
362 }
363 else
364 {
365 /* User msg ! */
366 if (msgsize != sizeof(struct opas_msg_user_header))
367 FEED_ERROR;
368
369 umlen = ntohl(*((uint32_t *)((char *)d + 8)));
370 if (umlen > OPAS_UMSG_MAXSIZE)
371 FEED_ERROR;
372
373 if (msgsize + umlen <= size)
374 {
375 /* We are lucky */
376 OPAS_MSG_USER_NTOH((struct opas_msg_user_header *)d);
377 if (session->cbs.msg_user_fun)
378 (*session->cbs.msg_user_fun)((struct opas_msg_user_header *)d,
379 (void *)((char *)d + 12),
380 session->context);
381 size -= msgsize + umlen;
382 d += msgsize + umlen;
383 }
384 else
385 {
386 if (session->size < msgsize + umlen)
387 {
388 if (session->ptr)
389 free(session->ptr);
390 session->ptr = malloc(msgsize + umlen);
391 if (!session->ptr)
392 return -1;
393 session->size = msgsize + umlen;
394 }
395 memcpy(session->ptr, d, size);
396 session->end = size;
397 size = 0;
398 }
399 }
400 }
401 }
402 else /* if (session->end == 0) */
403 {
404 head = ntohl(*((uint32_t *)session->ptr));
405 VERIFY_HEADER(head);
406 msgsize = OPAS_GET_MSGSIZE(head);
407 umlen = ntohl(*((uint32_t *)((char *)session->ptr + 8)));
408
409 if (!(head & OPAS_FLAG_UMSG))
410 {
411 if (msgsize - session->end <= size)
412 {
413 /* full message */
414 memcpy((char *)session->ptr + session->end, d,
415 msgsize - session->end);
416
417 if (__opas_callout(session, head, msgsize, session->ptr) == -1)
418 FEED_ERROR;
419 size -= msgsize - session->end;
420 d += msgsize - session->end;
421 session->end = 0; /* flushed */
422 }
423 else
424 {
425 /* still partial */
426 memcpy((char *)session->ptr + session->end, d, size);
427 session->end += size;
428 size = 0;
429 }
430 }
431 else
432 {
433 /* User msg ! */
434 if (umlen - session->end <= size)
435 {
436 memcpy((char *)session->ptr + session->end, d, umlen - session->end);
437
438 OPAS_MSG_USER_NTOH((struct opas_msg_user_header *)session->ptr);
439 if (session->cbs.msg_user_fun)
440 (*session->cbs.msg_user_fun)(
441 (struct opas_msg_user_header *)session->ptr,
442 (void *)((char *)session->ptr + 12),
443 session->context);
444 size -= umlen - session->end;
445 d += umlen - session->end;
446 session->end = 0; /* flushed */
447 }
448 else
449 {
450 memcpy((char *)session->ptr + session->end, d, size);
451 session->end += size;
452 size = 0;
453 }
454 }
455 }
456 } /* while */
457
458 feed_error:
459 if (dsave)
460 free(dsave);
461 return result;
462 }
463
464 void
465 opas_ping(opas_session_t session)
466 {
467 uint32_t head = htonl(OPAS_HEADER_MAKE(0,1,0,0,0,0,0,0));
468 (*session->cbs.send_fun)(&head, sizeof(head), session->context);
469 }
470
471 void
472 opas_query(opas_session_t session, const struct in_addr *addr,
473 uint32_t user_data)
474 {
475 struct opas_msg_query msg;
476
477 msg.head = OPAS_HEADER_MAKE(0,0,0,0,0,0,0,0);
478 msg.user_data = user_data;
479 msg.addr = *addr;
480 OPAS_HEADER_SETSIZE(msg.head, 8);
481
482 OPAS_QUERY_HTON(&msg);
483 (*session->cbs.send_fun)(&msg, sizeof(msg), session->context);
484 }
485
486 void
487 opas_query6(opas_session_t session, const struct in6_addr *addr,
488 uint32_t user_data)
489 {
490 struct opas_msg_query6 msg;
491
492 msg.head = OPAS_HEADER_MAKE(0,0,1,0,0,0,0,0);
493 msg.user_data = user_data;
494 msg.addr = *addr;
495 OPAS_HEADER_SETSIZE(msg.head, 20);
496
497 OPAS_QUERY_HTON(&msg);
498 (*session->cbs.send_fun)(&msg, sizeof(msg), session->context);
499 }
500
501 void
502 opas_reply_noproxy(opas_session_t session, struct opas_msg_query *queryp,
503 int from_cache)
504 {
505 queryp->head |= OPAS_FLAG_REPL; /* Set reply bit */
506 if (from_cache)
507 queryp->head |= OPAS_FLAG_CACH;
508 OPAS_QUERY_HTON(queryp);
509 (*session->cbs.send_fun)(queryp, sizeof(*queryp), session->context);
510 }
511
512 void
513 opas_reply6_noproxy(opas_session_t session, struct opas_msg_query6 *queryp,
514 int from_cache)
515 {
516 queryp->head |= OPAS_FLAG_REPL; /* Reply bit */
517 if (from_cache)
518 queryp->head |= OPAS_FLAG_CACH;
519 OPAS_QUERY_HTON(queryp);
520 (*session->cbs.send_fun)(queryp, sizeof(*queryp), session->context);
521 }
522
523 void
524 opas_reply_proxy(opas_session_t session, struct opas_msg_query *queryp,
525 int from_cache, time_t ts, uint16_t type, uint16_t port,
526 const char *descr)
527 {
528 struct opas_msg_reply_proxy *replyp;
529 size_t len = sizeof(struct opas_msg_reply_proxy) + strlen(descr);
530
531 #ifdef HAVE_ALLOCA
532 replyp = (struct opas_msg_reply_proxy *)alloca(len);
533 #else
534 replyp = (struct opas_msg_reply_proxy *)malloc(len);
535 #endif
536
537 replyp->head = OPAS_HEADER_MAKE(0,0,0,0,1,1,from_cache,0);
538 replyp->user_data = queryp->user_data;
539 replyp->addr = queryp->addr;
540 replyp->timestamp = ts;
541 replyp->proxy_type = type;
542 replyp->proxy_port = port;
543 strcpy(replyp->proxy_descr, descr);
544 OPAS_HEADER_SETSIZE(replyp->head, len - 4);
545 OPAS_REPLY_PROXY_HTON(replyp);
546 (*session->cbs.send_fun)(replyp, len, session->context);
547
548 #ifndef HAVE_ALLOCA
549 free(replyp);
550 #endif
551 }
552
553 void
554 opas_reply6_proxy(opas_session_t session, struct opas_msg_query6 *queryp,
555 int from_cache, time_t ts, uint16_t type, uint16_t port,
556 const char *descr)
557 {
558 struct opas_msg_reply6_proxy *replyp;
559 size_t len = sizeof(struct opas_msg_reply6_proxy) + strlen(descr);
560
561 #ifdef HAVE_ALLOCA
562 replyp = (struct opas_msg_reply6_proxy *)alloca(len);
563 #else
564 replyp = (struct opas_msg_reply6_proxy *)malloc(len);
565 #endif
566
567 replyp->head = OPAS_HEADER_MAKE(0,0,1,0,1,1,from_cache,0);
568 replyp->user_data = queryp->user_data;
569 replyp->addr = queryp->addr;
570 replyp->timestamp = ts;
571 replyp->proxy_type = type;
572 replyp->proxy_port = port;
573 strcpy(replyp->proxy_descr, descr);
574 OPAS_HEADER_SETSIZE(replyp->head, len - 4);
575 OPAS_REPLY_PROXY_HTON(replyp);
576 (*session->cbs.send_fun)(replyp, len, session->context);
577
578 #ifndef HAVE_ALLOCA
579 free(replyp);
580 #endif
581 }
582
583 void
584 opas_reply_error(opas_session_t session, struct opas_msg_query *queryp,
585 uint32_t error)
586 {
587 struct opas_msg_reply_error reply;
588
589 reply.head = queryp->head | OPAS_FLAG_REPL | OPAS_FLAG_ERRO;
590 reply.user_data = queryp->user_data;
591 reply.addr = queryp->addr;
592 reply.error = error;
593 OPAS_HEADER_SETSIZE(reply.head, 12);
594
595 OPAS_REPLY_ERROR_HTON(&reply);
596 (*session->cbs.send_fun)(&reply, sizeof(reply), session->context);
597 }
598
599 void
600 opas_reply6_error(opas_session_t session, struct opas_msg_query6 *queryp,
601 uint32_t error)
602 {
603 struct opas_msg_reply6_error reply;
604
605 reply.head = queryp->head | OPAS_FLAG_REPL | OPAS_FLAG_ERRO;
606 reply.user_data = queryp->user_data;
607 reply.addr = queryp->addr;
608 reply.error = error;
609 OPAS_HEADER_SETSIZE(reply.head, 24);
610
611 OPAS_REPLY_ERROR_HTON(&reply);
612 (*session->cbs.send_fun)(&reply, sizeof(reply), session->context);
613 }
614
615 void
616 opas_send_msg_user(opas_session_t session, const void *msg_data,
617 uint32_t msg_length, int reply, uint32_t user_data)
618 {
619 struct opas_msg_user_header *ucheadp;
620
621 #ifdef HAVE_ALLOCA
622 if (msg_length <= MSG_USER_MAXSMALL)
623 {
624 ucheadp = (struct opas_msg_user_header *)alloca(sizeof(*ucheadp)
625 + msg_length);
626 }
627 else
628 {
629 #endif
630 ucheadp = (struct opas_msg_user_header *)malloc(sizeof(*ucheadp)
631 + msg_length);
632 #ifdef HAVE_ALLOCA
633 }
634 #endif
635
636 ucheadp->head = OPAS_HEADER_MAKE(0,0,0,1,reply,0,0,0);
637 ucheadp->user_data = user_data;
638 ucheadp->data_length = msg_length;
639 OPAS_HEADER_SETSIZE(ucheadp->head, 8);
640
641 if (msg_length > 0)
642 memcpy(ucheadp + 1, msg_data, msg_length);
643
644 OPAS_MSG_USER_HTON(ucheadp);
645 (*session->cbs.send_fun)(ucheadp, sizeof(*ucheadp) + msg_length,
646 session->context);
647
648 #ifdef HAVE_ALLOCA
649 if (msg_length > MSG_USER_MAXSMALL)
650 #endif
651 free(ucheadp);
652 }

svnadmin@ircd-hybrid.org
ViewVC Help
Powered by ViewVC 1.1.28