Merge commit 'origin/ser_modules'
[sip-router] / ip_addr.h
1 /* $Id$
2  *
3  * ip address family related structures
4  *
5  * Copyright (C) 2001-2003 FhG Fokus
6  *
7  * This file is part of ser, a free SIP server.
8  *
9  * ser is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version
13  *
14  * For a license to use the ser software under conditions
15  * other than those described here, or to purchase support for this
16  * software, please contact iptel.org by e-mail at the following addresses:
17  *    info@iptel.org
18  *
19  * ser is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License 
25  * along with this program; if not, write to the Free Software 
26  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27  */
28 /*
29  * History:
30  * --------
31  *  2003-02-13  added struct dest_info (andrei)
32  *  2003-04-06  all ports are stored/passed in host byte order now (andrei)
33  *  2006-04-20  comp support in recv_info and dest_info (andrei)
34  *  2006-04-21  added init_dst_from_rcv (andrei)
35  *  2007-06-26  added ip_addr_mk_any() (andrei)
36  *  2008-05-21  added su2a(), ip_addr2sbuf(), ip4tosbuf(), ip62sbuf() (andrei)
37  */
38
39 #ifndef ip_addr_h
40 #define ip_addr_h
41
42 #include <string.h>
43 #include <sys/types.h>
44 #include <sys/socket.h>
45 #include <netinet/in.h>
46 #include <netdb.h>
47 #include "str.h"
48 #include "compiler_opt.h"
49 #include "ut.h"
50
51
52 #include "dprint.h"
53
54 enum sip_protos { PROTO_NONE, PROTO_UDP, PROTO_TCP, PROTO_TLS, PROTO_SCTP };
55 #define PROTO_LAST PROTO_SCTP
56
57 #ifdef USE_COMP
58 enum comp_methods { COMP_NONE, COMP_SIGCOMP, COMP_SERGZ };
59 #endif
60
61 struct ip_addr{
62         unsigned int af; /* address family: AF_INET6 or AF_INET */
63         unsigned int len;    /* address len, 16 or 4 */
64         
65         /* 64 bits aligned address */
66         union {
67                 unsigned long  addrl[16/sizeof(long)]; /* long format*/
68                 unsigned int   addr32[4];
69                 unsigned short addr16[8];
70                 unsigned char  addr[16];
71         }u;
72 };
73
74
75
76 struct net{
77         struct ip_addr ip;
78         struct ip_addr mask;
79 };
80
81 union sockaddr_union{
82                 struct sockaddr     s;
83                 struct sockaddr_in  sin;
84         #ifdef USE_IPV6
85                 struct sockaddr_in6 sin6;
86         #endif
87 };
88
89
90
91 enum si_flags { SI_NONE=0, SI_IS_IP=1, SI_IS_LO=2, SI_IS_MCAST=4,
92                                  SI_IS_ANY=8, SI_IS_MHOMED=16 };
93
94 struct addr_info{
95         str name; /* name - eg.: foo.bar or 10.0.0.1 */
96         struct ip_addr address; /*ip address */
97         str address_str;        /*ip address converted to string -- optimization*/
98         enum si_flags flags; /* SI_IS_IP | SI_IS_LO | SI_IS_MCAST */
99         union sockaddr_union su;
100         struct addr_info* next;
101         struct addr_info* prev;
102 };
103
104 struct socket_info{
105         int socket;
106         str name; /* name - eg.: foo.bar or 10.0.0.1 */
107         struct ip_addr address; /* ip address */
108         str address_str;        /*ip address converted to string -- optimization*/
109         str port_no_str; /* port number converted to string -- optimization*/
110         enum si_flags flags; /* SI_IS_IP | SI_IS_LO | SI_IS_MCAST */
111         union sockaddr_union su; 
112         struct socket_info* next;
113         struct socket_info* prev;
114         unsigned short port_no;  /* port number */
115         char proto; /* tcp or udp*/
116         str sock_str; /* Socket proto, ip, and port as string */
117         struct addr_info* addr_info_lst; /* extra addresses (e.g. SCTP mh) */
118 };
119
120
121 struct receive_info{
122         struct ip_addr src_ip;
123         struct ip_addr dst_ip;
124         unsigned short src_port; /* host byte order */
125         unsigned short dst_port; /* host byte order */
126         int proto_reserved1; /* tcp stores the connection id here */
127         int proto_reserved2;
128         union sockaddr_union src_su; /* useful for replies*/
129         struct socket_info* bind_address; /* sock_info structure on which 
130                                                                           the msg was received*/
131         char proto;
132 #ifdef USE_COMP
133         short comp; /* compression */
134 #endif
135         /* no need for dst_su yet */
136 };
137
138
139 struct dest_info{
140         struct socket_info* send_sock;
141         union sockaddr_union to;
142         int id; /* tcp stores the connection id here */ 
143         char proto;
144 #ifdef USE_COMP
145         short comp;
146 #endif
147 };
148
149
150 /* list of names for multi-homed sockets that need to bind on
151  * multiple addresses in the same time (sctp ) */
152 struct name_lst{
153         char* name;
154         struct name_lst* next;
155         int flags;
156 };
157
158
159 struct socket_id{
160         struct name_lst* addr_lst; /* address list, the first one must
161                                                                   be present and is the main one
162                                                                   (in case of multihoming sctp)*/
163         int flags;
164         int proto;
165         int port;
166         struct socket_id* next;
167 };
168
169
170
171 /* len of the sockaddr */
172 #ifdef HAVE_SOCKADDR_SA_LEN
173 #define sockaddru_len(su)       ((su).s.sa_len)
174 #else
175 #ifdef USE_IPV6
176 #define sockaddru_len(su)       \
177                         (((su).s.sa_family==AF_INET6)?sizeof(struct sockaddr_in6):\
178                                         sizeof(struct sockaddr_in))
179 #else
180 #define sockaddru_len(su)       sizeof(struct sockaddr_in)
181 #endif /*USE_IPV6*/
182 #endif /* HAVE_SOCKADDR_SA_LEN*/
183         
184 /* inits an ip_addr with the addr. info from a hostent structure
185  * ip = struct ip_addr*
186  * he= struct hostent*
187  */
188 #define hostent2ip_addr(ip, he, addr_no) \
189         do{ \
190                 (ip)->af=(he)->h_addrtype; \
191                 (ip)->len=(he)->h_length;  \
192                 memcpy((ip)->u.addr, (he)->h_addr_list[(addr_no)], (ip)->len); \
193         }while(0)
194         
195
196
197
198 /* gets the protocol family corresponding to a specific address family
199  * ( PF_INET - AF_INET, PF_INET6 - AF_INET6, af for others)
200  */
201 #ifdef USE_IPV6
202 #define AF2PF(af)   (((af)==AF_INET)?PF_INET:((af)==AF_INET6)?PF_INET6:(af))
203 #else
204 #define AF2PF(af)   (((af)==AF_INET)?PF_INET:(af))
205 #endif
206
207
208
209
210 struct net* mk_net(struct ip_addr* ip, struct ip_addr* mask);
211 struct net* mk_net_bitlen(struct ip_addr* ip, unsigned int bitlen);
212
213 void print_ip(char* prefix, struct ip_addr* ip, char* suffix);
214 void stdout_print_ip(struct ip_addr* ip);
215 void print_net(struct net* net);
216
217 #ifdef USE_MCAST
218 /* Returns 1 if the given address is a multicast address */
219 int is_mcast(struct ip_addr* ip);
220 #endif /* USE_MCAST */
221
222 /* returns 1 if the given ip address is INADDR_ANY or IN6ADDR_ANY,
223  * 0 otherwise */
224 inline static int ip_addr_any(struct ip_addr* ip)
225 {
226         int r;
227         int l;
228         
229         l=ip->len/4;
230         for (r=0; r<l; r++)
231                 if (ip->u.addr32[r]!=0)
232                         return 0;
233         return 1;
234 }
235
236
237
238 /* returns 1 if the given ip address is a loopback address
239  * 0 otherwise */
240 inline static int ip_addr_loopback(struct ip_addr* ip)
241 {
242         if (ip->af==AF_INET)
243                 return ip->u.addr32[0]==htonl(INADDR_LOOPBACK);
244 #ifdef USE_IPV6
245         else if (ip->af==AF_INET6)
246                 return IN6_IS_ADDR_LOOPBACK((struct in6_addr*)ip->u.addr32);
247 #endif /* USE_IPV6 */
248         return 0;
249 }
250
251
252
253 /* creates an ANY ip_addr (filled with 0, af and len properly set) */
254 inline static void ip_addr_mk_any(int af, struct ip_addr* ip)
255 {
256         ip->af=af;
257         if (likely(af==AF_INET)){
258                 ip->len=4;
259                 ip->u.addr32[0]=0;
260         }
261 #ifdef USE_IPV6
262         else{
263                 ip->len=16;
264 #if (defined (ULONG_MAX) && ULONG_MAX > 4294967295) || defined LP64
265                 /* long is 64 bits */
266                 ip->u.addrl[0]=0;
267                 ip->u.addrl[1]=0;
268 #else
269                 ip->u.addr32[0]=0;
270                 ip->u.addr32[1]=0;
271                 ip->u.addr32[2]=0;
272                 ip->u.addr32[3]=0;
273 #endif /* ULONG_MAX */
274         }
275 #endif
276 }
277
278 /* returns 1 if ip & net.mask == net.ip ; 0 otherwise & -1 on error 
279         [ diff. address families ]) */
280 inline static int matchnet(struct ip_addr* ip, struct net* net)
281 {
282         unsigned int r;
283
284         if (ip->af == net->ip.af){
285                 for(r=0; r<ip->len/4; r++){ /* ipv4 & ipv6 addresses are
286                                                                            all multiple of 4*/
287                         if ((ip->u.addr32[r]&net->mask.u.addr32[r])!=
288                                                                                                                  net->ip.u.addr32[r]){
289                                 return 0;
290                         }
291                 }
292                 return 1;
293         };
294         return -1;
295 }
296
297
298
299
300 /* inits an ip_addr pointer from a sockaddr structure*/
301 static inline void sockaddr2ip_addr(struct ip_addr* ip, struct sockaddr* sa)
302 {
303         switch(sa->sa_family){
304         case AF_INET:
305                         ip->af=AF_INET;
306                         ip->len=4;
307                         memcpy(ip->u.addr, &((struct sockaddr_in*)sa)->sin_addr, 4);
308                         break;
309 #ifdef USE_IPV6
310         case AF_INET6:
311                         ip->af=AF_INET6;
312                         ip->len=16;
313                         memcpy(ip->u.addr, &((struct sockaddr_in6*)sa)->sin6_addr, 16);
314                         break;
315 #endif
316         default:
317                         LOG(L_CRIT, "sockaddr2ip_addr: BUG: unknown address family %d\n",
318                                         sa->sa_family);
319         }
320 }
321
322
323
324 /* compare 2 ip_addrs (both args are pointers)*/
325 #define ip_addr_cmp(ip1, ip2) \
326         (((ip1)->af==(ip2)->af)&& \
327                 (memcmp((ip1)->u.addr, (ip2)->u.addr, (ip1)->len)==0))
328
329
330
331 /* compare 2 sockaddr_unions */
332 static inline int su_cmp(union sockaddr_union* s1, union sockaddr_union* s2)
333 {
334         if (s1->s.sa_family!=s2->s.sa_family) return 0;
335         switch(s1->s.sa_family){
336                 case AF_INET:
337                         return (s1->sin.sin_port==s2->sin.sin_port)&&
338                                         (memcmp(&s1->sin.sin_addr, &s2->sin.sin_addr, 4)==0);
339 #ifdef USE_IPV6
340                 case AF_INET6:
341                         return (s1->sin6.sin6_port==s2->sin6.sin6_port)&&
342                                         (memcmp(&s1->sin6.sin6_addr, &s2->sin6.sin6_addr, 16)==0);
343 #endif
344                 default:
345                         LOG(L_CRIT,"su_cmp: BUG: unknown address family %d\n",
346                                                 s1->s.sa_family);
347                         return 0;
348         }
349 }
350
351
352
353 /* gets the port number (host byte order) */
354 static inline unsigned short su_getport(union sockaddr_union* su)
355 {
356         switch(su->s.sa_family){
357                 case AF_INET:
358                         return ntohs(su->sin.sin_port);
359 #ifdef USE_IPV6
360                 case AF_INET6:
361                         return ntohs(su->sin6.sin6_port);
362 #endif
363                 default:
364                         LOG(L_CRIT,"su_get_port: BUG: unknown address family %d\n",
365                                                 su->s.sa_family);
366                         return 0;
367         }
368 }
369
370
371
372 /* sets the port number (host byte order) */
373 static inline void su_setport(union sockaddr_union* su, unsigned short port)
374 {
375         switch(su->s.sa_family){
376                 case AF_INET:
377                         su->sin.sin_port=htons(port);
378                         break;
379 #ifdef USE_IPV6
380                 case AF_INET6:
381                          su->sin6.sin6_port=htons(port);
382                          break;
383 #endif
384                 default:
385                         LOG(L_CRIT,"su_set_port: BUG: unknown address family %d\n",
386                                                 su->s.sa_family);
387         }
388 }
389
390
391
392 /* inits an ip_addr pointer from a sockaddr_union ip address */
393 static inline void su2ip_addr(struct ip_addr* ip, union sockaddr_union* su)
394 {
395         switch(su->s.sa_family){
396         case AF_INET: 
397                                         ip->af=AF_INET;
398                                         ip->len=4;
399                                         memcpy(ip->u.addr, &su->sin.sin_addr, 4);
400                                         break;
401 #ifdef USE_IPV6
402         case AF_INET6:
403                                         ip->af=AF_INET6;
404                                         ip->len=16;
405                                         memcpy(ip->u.addr, &su->sin6.sin6_addr, 16);
406                                         break;
407 #endif
408         default:
409                                         LOG(L_CRIT,"su2ip_addr: BUG: unknown address family %d\n",
410                                                         su->s.sa_family);
411         }
412 }
413
414
415 /* ip_addr2su -> the same as init_su*/
416 #define ip_addr2su init_su
417
418 /* inits a struct sockaddr_union from a struct ip_addr and a port no 
419  * returns 0 if ok, -1 on error (unknown address family)
420  * the port number is in host byte order */
421 static inline int init_su( union sockaddr_union* su,
422                                                         struct ip_addr* ip,
423                                                         unsigned short   port ) 
424 {
425         memset(su, 0, sizeof(union sockaddr_union));/*needed on freebsd*/
426         su->s.sa_family=ip->af;
427         switch(ip->af){
428 #ifdef USE_IPV6
429         case    AF_INET6:
430                 memcpy(&su->sin6.sin6_addr, ip->u.addr, ip->len); 
431                 #ifdef HAVE_SOCKADDR_SA_LEN
432                         su->sin6.sin6_len=sizeof(struct sockaddr_in6);
433                 #endif
434                 su->sin6.sin6_port=htons(port);
435                 break;
436 #endif
437         case AF_INET:
438                 memcpy(&su->sin.sin_addr, ip->u.addr, ip->len);
439                 #ifdef HAVE_SOCKADDR_SA_LEN
440                         su->sin.sin_len=sizeof(struct sockaddr_in);
441                 #endif
442                 su->sin.sin_port=htons(port);
443                 break;
444         default:
445                 LOG(L_CRIT, "init_ss: BUG: unknown address family %d\n", ip->af);
446                 return -1;
447         }
448         return 0;
449 }
450
451
452
453 /* inits a struct sockaddr_union from a struct hostent, an address index in
454  * the hostent structure and a port no. (host byte order)
455  * WARNING: no index overflow  checks!
456  * returns 0 if ok, -1 on error (unknown address family) */
457 static inline int hostent2su( union sockaddr_union* su,
458                                                                 struct hostent* he,
459                                                                 unsigned int idx,
460                                                                 unsigned short   port ) 
461 {
462         memset(su, 0, sizeof(union sockaddr_union)); /*needed on freebsd*/
463         su->s.sa_family=he->h_addrtype;
464         switch(he->h_addrtype){
465 #ifdef USE_IPV6
466         case    AF_INET6:
467                 memcpy(&su->sin6.sin6_addr, he->h_addr_list[idx], he->h_length);
468                 #ifdef HAVE_SOCKADDR_SA_LEN
469                         su->sin6.sin6_len=sizeof(struct sockaddr_in6);
470                 #endif
471                 su->sin6.sin6_port=htons(port);
472                 break;
473 #endif
474         case AF_INET:
475                 memcpy(&su->sin.sin_addr, he->h_addr_list[idx], he->h_length);
476                 #ifdef HAVE_SOCKADDR_SA_LEN
477                         su->sin.sin_len=sizeof(struct sockaddr_in);
478                 #endif
479                 su->sin.sin_port=htons(port);
480                 break;
481         default:
482                 LOG(L_CRIT, "hostent2su: BUG: unknown address family %d\n", 
483                                 he->h_addrtype);
484                 return -1;
485         }
486         return 0;
487 }
488
489
490
491 /* maximum size of a str returned by ip_addr2str */
492 #define IP6_MAX_STR_SIZE 39 /*1234:5678:9012:3456:7890:1234:5678:9012*/
493 #define IP4_MAX_STR_SIZE 15 /*123.456.789.012*/
494
495 #ifdef USE_IPV6
496 /* converts a raw ipv6 addr (16 bytes) to ascii */
497 static inline int ip6tosbuf(unsigned char* ip6, char* buff, int len)
498 {
499         int offset;
500         register unsigned char a,b,c;
501         register unsigned char d;
502         register unsigned short hex4;
503         int r;
504         #define HEXDIG(x) (((x)>=10)?(x)-10+'A':(x)+'0')
505         
506         
507         offset=0;
508         if (unlikely(len<IP6_MAX_STR_SIZE))
509                 return 0;
510         for(r=0;r<7;r++){
511                 hex4=((unsigned char)ip6[r*2]<<8)+(unsigned char)ip6[r*2+1];
512                 a=hex4>>12;
513                 b=(hex4>>8)&0xf;
514                 c=(hex4>>4)&0xf;
515                 d=hex4&0xf;
516                 if (a){
517                         buff[offset]=HEXDIG(a);
518                         buff[offset+1]=HEXDIG(b);
519                         buff[offset+2]=HEXDIG(c);
520                         buff[offset+3]=HEXDIG(d);
521                         buff[offset+4]=':';
522                         offset+=5;
523                 }else if(b){
524                         buff[offset]=HEXDIG(b);
525                         buff[offset+1]=HEXDIG(c);
526                         buff[offset+2]=HEXDIG(d);
527                         buff[offset+3]=':';
528                         offset+=4;
529                 }else if(c){
530                         buff[offset]=HEXDIG(c);
531                         buff[offset+1]=HEXDIG(d);
532                         buff[offset+2]=':';
533                         offset+=3;
534                 }else{
535                         buff[offset]=HEXDIG(d);
536                         buff[offset+1]=':';
537                         offset+=2;
538                 }
539         }
540         /* last int16*/
541         hex4=((unsigned char)ip6[r*2]<<8)+(unsigned char)ip6[r*2+1];
542         a=hex4>>12;
543         b=(hex4>>8)&0xf;
544         c=(hex4>>4)&0xf;
545         d=hex4&0xf;
546         if (a){
547                 buff[offset]=HEXDIG(a);
548                 buff[offset+1]=HEXDIG(b);
549                 buff[offset+2]=HEXDIG(c);
550                 buff[offset+3]=HEXDIG(d);
551                 offset+=4;
552         }else if(b){
553                 buff[offset]=HEXDIG(b);
554                 buff[offset+1]=HEXDIG(c);
555                 buff[offset+2]=HEXDIG(d);
556                 offset+=3;
557         }else if(c){
558                 buff[offset]=HEXDIG(c);
559                 buff[offset+1]=HEXDIG(d);
560                 offset+=2;
561         }else{
562                 buff[offset]=HEXDIG(d);
563                 offset+=1;
564         }
565         
566         return offset;
567 }
568 #endif /* USE_IPV6 */
569
570
571
572 /* converts a raw ipv4 addr (4 bytes) to ascii */
573 static inline int ip4tosbuf(unsigned char* ip4, char* buff, int len)
574 {
575         int offset;
576         register unsigned char a,b,c;
577         int r;
578         
579         
580         offset=0;
581         if (unlikely(len<IP4_MAX_STR_SIZE))
582                 return 0;
583         for(r=0;r<3;r++){
584                 a=(unsigned char)ip4[r]/100;
585                 c=(unsigned char)ip4[r]%10;
586                 b=(unsigned char)ip4[r]%100/10;
587                 if (a){
588                         buff[offset]=a+'0';
589                         buff[offset+1]=b+'0';
590                         buff[offset+2]=c+'0';
591                         buff[offset+3]='.';
592                         offset+=4;
593                 }else if (b){
594                         buff[offset]=b+'0';
595                         buff[offset+1]=c+'0';
596                         buff[offset+2]='.';
597                         offset+=3;
598                 }else{
599                         buff[offset]=c+'0';
600                         buff[offset+1]='.';
601                         offset+=2;
602                 }
603         }
604         /* last number */
605         a=(unsigned char)ip4[r]/100;
606         c=(unsigned char)ip4[r]%10;
607         b=(unsigned char)ip4[r]%100/10;
608         if (a){
609                 buff[offset]=a+'0';
610                 buff[offset+1]=b+'0';
611                 buff[offset+2]=c+'0';
612                 offset+=3;
613         }else if (b){
614                 buff[offset]=b+'0';
615                 buff[offset+1]=c+'0';
616                 offset+=2;
617         }else{
618                 buff[offset]=c+'0';
619                 offset+=1;
620         }
621         
622         return offset;
623 }
624
625
626
627 /* fast ip_addr -> string converter;
628  * returns number of bytes written in buf on success, <=0 on error
629  * The buffer must have enough space to hold the maximum size ip address
630  *  of the corresponding address (see IP[46] above) or else the function
631  *  will return error (no detailed might fit checks are made, for example
632  *   if len==7 the function will fail even for 1.2.3.4).
633  */
634 static inline int ip_addr2sbuf(struct ip_addr* ip, char* buff, int len)
635 {
636         switch(ip->af){
637         #ifdef USE_IPV6
638                 case AF_INET6:
639                         return ip6tosbuf(ip->u.addr, buff, len);
640                         break;
641         #endif /* USE_IPV6 */
642                 case AF_INET:
643                         return ip4tosbuf(ip->u.addr, buff, len);
644                         break;
645                 default:
646                         LOG(L_CRIT, "BUG: ip_addr2sbuf: unknown address family %d\n",
647                                         ip->af);
648                         return 0;
649         }
650         return 0;
651 }
652
653
654
655 /* maximum size of a str returned by ip_addr2a (including \0) */
656 #define IP_ADDR_MAX_STR_SIZE (IP6_MAX_STR_SIZE+1) /* ip62ascii +  \0*/
657 /* fast ip_addr -> string converter;
658  * it uses an internal buffer
659  */
660 static inline char* ip_addr2a(struct ip_addr* ip)
661 {
662
663         static char buff[IP_ADDR_MAX_STR_SIZE];
664         int len;
665         
666         
667         len=ip_addr2sbuf(ip, buff, sizeof(buff)-1);
668         buff[len]=0;
669
670         return buff;
671 }
672
673
674
675 #define SU2A_MAX_STR_SIZE  (IP6_MAX_STR_SIZE + 2 /* [] */+\
676                                                                 1 /* : */ + USHORT2SBUF_MAX_LEN + 1 /* \0 */)
677 /* returns an asciiz string containing the ip and the port
678  *  (<ip_addr>:port or [<ipv6_addr>]:port)
679  */
680 static inline char* su2a(union sockaddr_union* su, int su_len)
681 {
682         static char buf[SU2A_MAX_STR_SIZE];
683         int offs;
684         
685 #ifdef USE_IPV6
686         if (unlikely(su->s.sa_family==AF_INET6)){
687                 if (unlikely(su_len<sizeof(su->sin6)))
688                         return "<addr. error>";
689                 buf[0]='[';
690                 offs=1+ip6tosbuf((unsigned char*)&su->sin6.sin6_addr, &buf[1],
691                                                         sizeof(buf)-4);
692                 buf[offs]=']';
693                 offs++;
694         }else
695 #endif /* USE_IPV6*/
696         if (unlikely(su_len<sizeof(su->sin)))
697                 return "<addr. error>";
698         else
699                 offs=ip4tosbuf((unsigned char*)&su->sin.sin_addr, buf, sizeof(buf)-2);
700         buf[offs]=':';
701         offs+=1+ushort2sbuf(su_getport(su), &buf[offs+1], sizeof(buf)-(offs+1)-1);
702         buf[offs]=0;
703         return buf;
704 }
705
706
707
708 /* converts an ip_addr structure to a hostent, returns pointer to internal
709  * statical structure */
710 static inline struct hostent* ip_addr2he(str* name, struct ip_addr* ip)
711 {
712         static struct hostent he;
713         static char hostname[256];
714         static char* p_aliases[1];
715         static char* p_addr[2];
716         static char address[16];
717         
718         p_aliases[0]=0; /* no aliases*/
719         p_addr[1]=0; /* only one address*/
720         p_addr[0]=address;
721         strncpy(hostname, name->s, (name->len<256)?(name->len)+1:256);
722         if (ip->len>16) return 0;
723         memcpy(address, ip->u.addr, ip->len);
724         
725         he.h_addrtype=ip->af;
726         he.h_length=ip->len;
727         he.h_addr_list=p_addr;
728         he.h_aliases=p_aliases;
729         he.h_name=hostname;
730         return &he;
731 }
732
733
734
735 /* init a dest_info structure */
736 #define init_dest_info(dst) \
737         do{ \
738                 memset((dst), 0, sizeof(struct dest_info)); \
739         } while(0) 
740
741
742
743 /* init a dest_info structure from a recv_info structure */
744 inline static void init_dst_from_rcv(struct dest_info* dst,
745                                                                         struct receive_info* rcv)
746 {
747                 dst->send_sock=rcv->bind_address;
748                 dst->to=rcv->src_su;
749                 dst->id=rcv->proto_reserved1;
750                 dst->proto=rcv->proto;
751 #ifdef USE_COMP
752                 dst->comp=rcv->comp;
753 #endif
754 }
755
756
757 #endif