ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/vendor/pxys2-2.1.0/libopas/opas/opas.c
Revision: 3253
Committed: Wed Apr 2 20:46:18 2014 UTC (12 years, 3 months ago) by michael
Content type: text/x-csrc
File size: 18678 byte(s)
Log Message:
- Imported pxys2-2.1.0

File Contents

# User Rev Content
1 michael 3253 /* 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     }