1 /*
2  ** ex: set tabstop=4 ai expandtab softtabstop=4 shiftwidth=4:
3  **      $Id: addr.c 210 2010-01-14 13:20:02Z aaron $
4  */
5 /************************************************************************
6  *                                                                       *
7  *                       Copyright (C)  2005                             *
8  *                           Internet2                                   *
9  *                       All Rights Reserved                             *
10  *                                                                       *
11  ************************************************************************/
12 /*
13  **    File:        addr.c
14  **
15  **    Author:      Jeff W. Boote
16  **
17  **    Date:        Tue Dec 20 11:55:21 MST 2005
18  **
19  **    Description:
20  **                 Address abstraction API. (Everybody needs one, right?)
21  */
22 
23 #include <I2util/utilP.h>
24 
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <string.h>
28 #include <assert.h>
29 
30 
31 /*
32  * Data structures
33  */
34 typedef struct I2AddrRec I2AddrRec;
35 
36 struct I2AddrRec{
37     I2ErrHandle      eh;
38 
39     I2Boolean       node_set;
40     char            node[NI_MAXHOST+1];
41 
42     I2Boolean       port_set;
43     uint16_t        port_value;
44     char            port[NI_MAXSERV+1];
45 
46     I2Boolean       ai_free;    /* free ai list directly...*/
47     struct addrinfo *ai;
48 
49     struct sockaddr *saddr;
50     socklen_t       saddrlen;
51     int             so_type;    /* socktype saddr works with    */
52     int             so_protocol;    /* protocol saddr works with    */
53     I2Boolean       passive;
54 
55     I2Boolean       fd_user;
56     int             fd;
57 };
58 
59 static void
_I2AddrClearAI(I2Addr addr)60 _I2AddrClearAI(
61         I2Addr  addr
62         )
63 {
64     if(!addr)
65         return;
66 
67     if(addr->ai){
68         if(!addr->ai_free){
69             freeaddrinfo(addr->ai);
70         }else{
71             struct addrinfo    *ai, *next;
72 
73             ai = addr->ai;
74             while(ai){
75                 next = ai->ai_next;
76 
77                 if(ai->ai_addr) free(ai->ai_addr);
78                 if(ai->ai_canonname) free(ai->ai_canonname);
79                 free(ai);
80 
81                 ai = next;
82             }
83         }
84     }
85 
86     addr->ai = NULL;
87     addr->saddr = NULL;
88     addr->saddrlen = 0;
89     addr->ai_free = False;
90 
91     return;
92 }
93 
94 void
I2AddrFree(I2Addr addr)95 I2AddrFree(
96         I2Addr    addr
97         )
98 {
99     if(!addr)
100         return;
101 
102     _I2AddrClearAI(addr);
103 
104     if((addr->fd >= 0) && !addr->fd_user){
105         if(close(addr->fd) < 0){
106             I2ErrLogT(addr->eh,LOG_WARNING,
107                     errno,":close(%d)",addr->fd);
108         }
109     }
110 
111     free(addr);
112 
113     return;
114 }
115 
116 I2Addr
_I2AddrAlloc(I2ErrHandle eh)117 _I2AddrAlloc(
118         I2ErrHandle eh
119         )
120 {
121     I2Addr    addr = calloc(1,sizeof(struct I2AddrRec));
122 
123     if(!addr){
124         I2ErrLogT(eh,LOG_ERR,I2EUNKNOWN,
125                 ": calloc(1,%d): %M",sizeof(struct I2AddrRec));
126         return NULL;
127     }
128 
129     addr->eh = eh;
130 
131     addr->node_set = 0;
132     strncpy(addr->node,"unknown",sizeof(addr->node));
133     addr->port_set = addr->port_value = 0;
134     strncpy(addr->port,"unknown",sizeof(addr->port));
135     addr->ai_free = 0;
136     addr->ai = NULL;
137 
138     addr->saddr = NULL;
139     addr->saddrlen = 0;
140 
141     addr->fd_user = 0;
142     addr->fd= -1;
143 
144     return addr;
145 }
146 
147 static struct addrinfo*
CopyAddrRec(I2ErrHandle eh,const struct addrinfo * src)148 CopyAddrRec(
149         I2ErrHandle eh,
150         const struct addrinfo   *src
151         )
152 {
153     struct addrinfo    *dst = calloc(1,sizeof(struct addrinfo));
154 
155     if(!dst){
156         I2ErrLogT(eh,LOG_ERR,errno,
157                 ": calloc(1,sizeof(struct addrinfo))");
158         return NULL;
159     }
160 
161     *dst = *src;
162 
163     if(src->ai_addr){
164         dst->ai_addr = malloc(src->ai_addrlen);
165         if(!dst->ai_addr){
166             I2ErrLogT(eh,LOG_ERR,errno,
167                     "malloc(%u): %s",src->ai_addrlen,
168                     strerror(errno));
169             free(dst);
170             return NULL;
171         }
172         memcpy(dst->ai_addr,src->ai_addr,src->ai_addrlen);
173         dst->ai_addrlen = src->ai_addrlen;
174     }
175     else
176         dst->ai_addrlen = 0;
177 
178     if(src->ai_canonname){
179         int    len = strlen(src->ai_canonname);
180 
181         if(len > NI_MAXHOST){
182             I2ErrLogT(eh,LOG_WARNING,
183                     I2EUNKNOWN,
184                     ":Invalid canonname!");
185             dst->ai_canonname = NULL;
186         }else{
187             dst->ai_canonname = malloc(sizeof(char)*(len+1));
188             if(!dst->ai_canonname){
189                 I2ErrLogT(eh,LOG_WARNING,
190                         errno,": malloc(sizeof(%d)",len+1);
191                 dst->ai_canonname = NULL;
192             }else
193                 strcpy(dst->ai_canonname,src->ai_canonname);
194         }
195     }
196 
197     dst->ai_next = NULL;
198 
199     return dst;
200 }
201 
202 I2Addr
I2AddrCopy(I2Addr from)203 I2AddrCopy(
204         I2Addr from
205         )
206 {
207     I2Addr          to;
208     struct addrinfo **aip;
209     struct addrinfo *ai;
210 
211     if(!from)
212         return NULL;
213 
214     if( !(to = _I2AddrAlloc(from->eh)))
215         return NULL;
216 
217     if(from->node_set){
218         strncpy(to->node,from->node,sizeof(to->node));
219         to->node_set = True;
220     }
221 
222     if(from->port_set){
223         strncpy(to->port,from->port,sizeof(to->port));
224         to->port_value = from->port_value;
225         to->port_set = True;
226     }
227 
228     aip = &to->ai;
229     ai = from->ai;
230 
231     while(ai){
232         to->ai_free = 1;
233         *aip = CopyAddrRec(from->eh,ai);
234         if(!*aip){
235             I2AddrFree(to);
236             return NULL;
237         }
238         if(ai->ai_addr == from->saddr){
239             to->saddr = (*aip)->ai_addr;
240             to->saddrlen = (*aip)->ai_addrlen;
241         }
242 
243         aip = &(*aip)->ai_next;
244         ai = ai->ai_next;
245     }
246 
247     to->fd = from->fd;
248 
249     if(to->fd > -1)
250         to->fd_user = True;
251 
252     return to;
253 }
254 
255 I2Addr
I2AddrByNode(I2ErrHandle eh,const char * node)256 I2AddrByNode(
257         I2ErrHandle eh,
258         const char    *node
259         )
260 {
261     I2Addr      addr;
262     char        buff[NI_MAXHOST+1];
263     const char  *nptr=node;
264     char        *pptr=NULL;
265     char        *s1,*s2;
266 
267     if(!node)
268         return NULL;
269 
270     if(!(addr=_I2AddrAlloc(eh)))
271         return NULL;
272 
273     strncpy(buff,node,sizeof(buff));
274 
275     /*
276      * Pull off port if specified. If syntax doesn't match URL like
277      * node:port - ipv6( [node]:port) - then just assume whole string
278      * is nodename and let getaddrinfo report problems later.
279      * (This service syntax is specified by rfc2396 and rfc2732.)
280      */
281 
282     /*
283      * First try ipv6 syntax since it is more restrictive.
284      */
285     if( (s1 = strchr(buff,'['))){
286         s1++;
287         if(strchr(s1,'[')) goto NOPORT;
288         if(!(s2 = strchr(s1,']'))) goto NOPORT;
289         *s2++='\0';
290         if(strchr(s2,']')) goto NOPORT;
291         if(*s2++ != ':') goto NOPORT;
292         nptr = s1;
293         pptr = s2;
294     }
295     /*
296      * Now try ipv4 style.
297      */
298     else if( (s1 = strchr(buff,':'))){
299         *s1++='\0';
300         /* second ':' indicates a v6 address with no port specified */
301         if(strchr(s1,':')) goto NOPORT;
302         nptr = buff;
303         pptr = s1;
304     }
305 
306 
307 NOPORT:
308     /*
309      * Set hostname if it was specified.
310      */
311     if(nptr && strlen(nptr)){
312         strncpy(addr->node,nptr,sizeof(addr->node));
313         addr->node_set = 1;
314     }
315 
316     if(pptr && strlen(pptr)){
317         int     tint;
318         char    *tstr=NULL;
319 
320         tint = strtol(pptr,&tstr,10);
321         if(!tstr || (pptr == tstr) || (tint < 0) || (tint > (int)0xffff)){
322             addr->port_set = addr->port_value = 0;
323         }
324         else{
325             addr->port_set = True;
326             addr->port_value = (uint16_t)tint;
327             strncpy(addr->port,pptr,sizeof(addr->port));
328         }
329     }
330 
331     return addr;
332 }
333 
334 I2Addr
I2AddrByWildcard(I2ErrHandle eh,int socktype,const char * servname)335 I2AddrByWildcard(
336         I2ErrHandle eh,
337         int         socktype,
338         const char  *servname
339         )
340 {
341     struct addrinfo *ai=NULL;
342     struct addrinfo hints;
343     I2Addr          addr;
344     int             ai_err;
345 
346 
347     memset(&hints,0,sizeof(struct addrinfo));
348     hints.ai_family = AF_UNSPEC;
349     hints.ai_socktype = socktype;
350     hints.ai_flags = AI_PASSIVE;
351 
352     if( (ai_err = getaddrinfo(NULL,servname,&hints,&ai)!=0)
353             || !ai){
354         I2ErrLogT(eh,LOG_ERR,I2EUNKNOWN,
355                 "getaddrinfo(): %s",gai_strerror(ai_err));
356         return NULL;
357     }
358 
359     if( !(addr = _I2AddrAlloc(eh))){
360         freeaddrinfo(ai);
361         return NULL;
362     }
363 
364     addr->ai = ai;
365     addr->passive = True;
366 
367     return addr;
368 }
369 
370 static void
_I2AddrSetNodePort(I2Addr addr)371 _I2AddrSetNodePort(
372         I2Addr  addr
373         )
374 {
375     int     gai;
376     char    *pptr=NULL;
377     char    *tstr=NULL;
378     int     tint;
379 
380     if(!addr->saddr || (addr->node_set && addr->port_set)){
381         return;
382     }
383 
384     if(addr->saddr->sa_family == AF_UNIX){
385         strncpy(addr->node,"unixsock",sizeof(addr->node));
386         strncpy(addr->port,"unnamed",sizeof(addr->port));
387 
388         addr->node_set = True;
389         addr->port_set = True;
390         addr->port_value = 0;
391     }
392     else{
393         if( (gai = getnameinfo(addr->saddr,addr->saddrlen,
394                         addr->node,sizeof(addr->node),
395                         addr->port,sizeof(addr->port),
396                         NI_NUMERICSERV)) != 0){
397             I2ErrLogT(addr->eh,LOG_WARNING,I2EUNKNOWN,
398                     "getnameinfo(): %s",gai_strerror(gai));
399             strncpy(addr->node,"unknown",sizeof(addr->node));
400             strncpy(addr->port,"unknown",sizeof(addr->port));
401         }
402         else{
403 
404             addr->node_set = True;
405 
406             pptr = addr->port;
407             tstr = NULL;
408             tint = strtol(pptr,&tstr,10);
409             if(!tstr || (pptr == tstr) || (tint < 0) || (tint > (int)0xffff)){
410                 addr->port_set = addr->port_value = 0;
411             }
412             else{
413                 addr->port_set = True;
414                 addr->port_value = (uint16_t)tint;
415             }
416         }
417     }
418 
419     return;
420 }
421 
422 /*
423  * Function:    I2AddrBySAddr
424  *
425  * Description:
426  *     Construct an I2Addr record given a sockaddr struct.
427  *
428  * In Args:
429  *              Set socktype == 0 if it doesn't matter. (but realize
430  *              this is here because the saddr will probably by used
431  *              to create a socket...
432  *
433  * Out Args:
434  *
435  * Scope:
436  * Returns:
437  * Side Effect:
438  */
439 I2Addr
I2AddrBySAddr(I2ErrHandle eh,struct sockaddr * saddr,socklen_t saddrlen,int socktype,int protocol)440 I2AddrBySAddr(
441         I2ErrHandle eh,
442         struct sockaddr *saddr,
443         socklen_t       saddrlen,
444         int             socktype,
445         int             protocol
446         )
447 {
448     I2Addr               addr;
449     struct addrinfo     *ai=NULL;
450     struct sockaddr_in  v4addr;
451 
452     if(!saddr){
453         return NULL;
454     }
455 
456     switch(saddr->sa_family){
457 #ifdef    AF_INET6
458         struct sockaddr_in6    v6addr;
459 
460         case AF_INET6:
461         if(saddrlen < sizeof(v6addr)){
462             I2ErrLogT(eh,LOG_ERR,EINVAL,"invalid saddrlen for addr family");
463             return NULL;
464         }
465 
466         /*
467          * If this is a mapped addr - create a sockaddr_in
468          * instead of the sockaddr_in6. (This is so addr
469          * matching will work in other parts of the code, and
470          * users of v4 will not be confused by security limits
471          * on v6 addresses causing problems.)
472          */
473         memcpy(&v6addr,saddr,sizeof(v6addr));
474         if(IN6_IS_ADDR_V4MAPPED(&v6addr.sin6_addr)){
475             memset(&v4addr,0,sizeof(v4addr));
476 #ifdef    HAVE_STRUCT_SOCKADDR_SA_LEN
477             v4addr.sin_len = sizeof(v4addr);
478 #endif
479             v4addr.sin_family = AF_INET;
480             v4addr.sin_port = v6addr.sin6_port;
481             memcpy(&v4addr.sin_addr.s_addr,
482                     &v6addr.sin6_addr.s6_addr[12],4);
483             saddr = (struct sockaddr*)&v4addr;
484             saddrlen = sizeof(v4addr);
485         }
486         break;
487 #endif
488 
489         /* fall through */
490         case AF_INET:
491         case AF_UNIX:
492         break;
493 
494         default:
495         I2ErrLogT(eh,LOG_ERR,EINVAL,"Invalid addr family");
496         return NULL;
497         break;
498     }
499 
500     if(!(addr = _I2AddrAlloc(eh)))
501         return NULL;
502 
503     if(!(ai = calloc(1,sizeof(struct addrinfo)))){
504         I2ErrLogT(addr->eh,LOG_ERR,I2EUNKNOWN,
505                 "malloc():%s",strerror(errno));
506         (void)I2AddrFree(addr);
507         return NULL;
508     }
509 
510     if(!(addr->saddr = calloc(1,saddrlen))){
511         I2ErrLogT(addr->eh,LOG_ERR,I2EUNKNOWN,
512                 "malloc():%s",strerror(errno));
513         (void)I2AddrFree(addr);
514         (void)free(ai);
515         return NULL;
516     }
517     memcpy(addr->saddr,saddr,saddrlen);
518     ai->ai_addr = addr->saddr;
519     addr->saddrlen = saddrlen;
520     ai->ai_addrlen = saddrlen;
521 
522     ai->ai_flags = 0;
523     ai->ai_family = saddr->sa_family;
524     ai->ai_socktype = socktype;
525     ai->ai_protocol = protocol;
526     ai->ai_canonname = NULL;
527     ai->ai_next = NULL;
528 
529     addr->ai = ai;
530     addr->ai_free = True;
531     addr->so_type = socktype;
532     addr->so_protocol = protocol;
533 
534     _I2AddrSetNodePort(addr);
535 
536     return addr;
537 }
538 
539 static I2Addr
ByAnySockFD(I2ErrHandle eh,int fd,I2Boolean close_on_free,struct sockaddr * saddr,socklen_t saddrlen)540 ByAnySockFD(
541         I2ErrHandle     eh,
542         int             fd,
543         I2Boolean       close_on_free,
544         struct sockaddr *saddr,
545         socklen_t       saddrlen)
546 {
547     int                     so_type;
548     socklen_t               so_typesize = sizeof(so_type);
549     I2Addr                  addr;
550 
551     /*
552      * *BSD getsockname/getpeername returns 0 size for AF_UNIX.
553      * fake a sockaddr to describe this.
554      */
555     if(!saddrlen){
556         saddr->sa_family = AF_UNIX;
557         /*
558          * Set the size of this "fake" sockaddr to include
559          * the sa_family member. (and possibly the sa_len member)
560          */
561         saddrlen = (char*)&saddr->sa_family - (char*)saddr;
562         saddrlen += sizeof(saddr->sa_family);
563 #ifdef    HAVE_STRUCT_SOCKADDR_SA_LEN
564         if(saddrlen <= (socklen_t)((char*)&saddr->sa_len - (char*)saddr)){
565             saddrlen = (char*)&saddr->sa_len - (char*)saddr;
566             saddrlen += sizeof(saddr->sa_len);
567         }
568         saddr->sa_len = saddrlen;
569 #endif
570     }
571 
572     if(getsockopt(fd,SOL_SOCKET,SO_TYPE,
573                 (void*)&so_type,&so_typesize) != 0){
574         I2ErrLogT(eh,LOG_ERR,errno,"getsockopt(): %M");
575         return NULL;
576     }
577 
578     addr = I2AddrBySAddr(eh,saddr,saddrlen,so_type,0);
579     if(!addr)
580         return NULL;
581 
582     addr->fd_user = !close_on_free;
583     addr->fd = fd;
584 
585     return addr;
586 }
587 
588 I2Addr
I2AddrBySockFD(I2ErrHandle eh,int fd,I2Boolean close_on_free)589 I2AddrBySockFD(
590         I2ErrHandle eh,
591         int         fd,
592         I2Boolean   close_on_free
593         )
594 {
595     struct sockaddr_storage sbuff;
596     socklen_t               saddrlen = sizeof(sbuff);
597 
598     if(getpeername(fd,(void*)&sbuff,&saddrlen) != 0){
599         I2ErrLogT(eh,LOG_ERR,errno,"getpeername(): %M");
600         return NULL;
601     }
602 
603     return ByAnySockFD(eh,fd,close_on_free,(struct sockaddr *)&sbuff,saddrlen);
604 }
605 
606 I2Addr
I2AddrByLocalSockFD(I2ErrHandle eh,int fd,I2Boolean close_on_free)607 I2AddrByLocalSockFD(
608         I2ErrHandle eh,
609         int         fd,
610         I2Boolean   close_on_free
611         )
612 {
613     struct sockaddr_storage sbuff;
614     socklen_t               saddrlen = sizeof(sbuff);
615 
616     if(getsockname(fd,(void*)&sbuff,&saddrlen) != 0){
617         I2ErrLogT(eh,LOG_ERR,errno,"getsockname(): %M");
618         return NULL;
619     }
620 
621     return ByAnySockFD(eh,fd,close_on_free,(struct sockaddr *)&sbuff,saddrlen);
622 }
623 
624 
625 /*
626  * Function:    I2AddrSetSAddr
627  *
628  * Description:
629  *
630  * In Args:
631  *
632  * Out Args:
633  *
634  * Scope:
635  * Returns:
636  * Side Effect:
637  *              Does not copy the memory and does not directly free it.
638  *              (It is expected that this memory points at the saddr
639  *              portion of one of the getaddrinfo structures returned
640  *              from I2AddrAddrInfo.)
641  */
642 I2Boolean
I2AddrSetSAddr(I2Addr addr,struct sockaddr * saddr,socklen_t saddr_len)643 I2AddrSetSAddr(
644         I2Addr addr,
645         struct sockaddr *saddr,
646         socklen_t       saddr_len
647         )
648 {
649     if(addr->fd > -1){
650         I2ErrLogT(addr->eh,LOG_ERR,EINVAL,
651                 "I2AddrSetSAddr: Addr already associated with socket: %M");
652         return False;
653     }
654 
655     if(!addr->ai){
656         I2ErrLogT(addr->eh,LOG_ERR,EINVAL,
657                 "I2AddrSetSAddr: AddrInfo not set: %M");
658         return False;
659     }
660 
661     addr->saddr = saddr;
662     addr->saddrlen = saddr_len;
663 
664     /*
665      * reset node/port based on new saddr
666      */
667     addr->node_set = False;
668     addr->port_set = addr->port_value = 0;
669     _I2AddrSetNodePort(addr);
670 
671     return True;
672 }
673 
674 /*
675  * Function:    I2AddrSetFD
676  *
677  * Description:
678  *
679  * In Args:
680  *
681  * Out Args:
682  *
683  * Scope:
684  * Returns:
685  * Side Effect:
686  */
687 I2Boolean
I2AddrSetFD(I2Addr addr,int fd,I2Boolean close_on_free)688 I2AddrSetFD(
689         I2Addr      addr,
690         int         fd,
691         I2Boolean   close_on_free
692         )
693 {
694     if(!addr)
695         return False;
696 
697     if((fd > -1) && (fd != addr->fd) && (addr->fd > -1)){
698         I2ErrLogT(addr->eh,LOG_ERR,EINVAL,
699                 "I2AddrSetFD: Addr already associated with socket: %M");
700         return False;
701     }
702 
703     addr->fd = fd;
704     addr->fd_user = !close_on_free;
705 
706     return True;
707 }
708 
709 /*
710  * Function:    I2AddrSetPort
711  *
712  * Description:
713  *
714  * In Args:
715  *
716  * Out Args:
717  *
718  * Scope:
719  * Returns:
720  * Side Effect:
721  */
722 I2Boolean
I2AddrSetPort(I2Addr addr,uint16_t port)723 I2AddrSetPort(
724         I2Addr     addr,
725         uint16_t   port
726         )
727 {
728     if(!addr)
729         return False;
730 
731     if(addr->fd > -1){
732         I2ErrLogT(addr->eh,LOG_ERR,EINVAL,
733                 "I2AddrSetPort: Addr already associated with socket: %M");
734         return False;
735     }
736 
737     /*
738      * If saddr is already set - than modify the port.
739      */
740     if(addr->saddr){
741         I2SockUnion sau_mem;
742         I2SockUnion *sau;
743 
744         if( !(sau = I2SockAddrToSockUnion(addr->saddr,
745                         addr->saddrlen,&sau_mem))){
746             I2ErrLogT(addr->eh,LOG_ERR,EINVAL,
747                     "I2AddrSetPort: Unable to decode sockaddr");
748             return False;
749         }
750 
751         /*
752          * decode v4 and v6 sockaddrs.
753          */
754         switch(sau->sa.sa_family){
755 #ifdef    AF_INET6
756 
757             case AF_INET6:
758             sau->sin6.sin6_port = htons(port);
759             break;
760 #endif
761             case AF_INET:
762             sau->sin.sin_port = htons(port);
763             break;
764             default:
765             I2ErrLogT(addr->eh,LOG_ERR,EINVAL,
766                     "I2AddrSetPort: Invalid address family");
767             return False;
768         }
769 
770         if( !I2SockUnionToSockAddr(sau,&addr->saddrlen,addr->saddr)){
771             return False;
772         }
773     }
774 
775     snprintf(addr->port,sizeof(addr->port),"%u",port);
776     addr->port_set = True;
777     addr->port_value = port;
778 
779     return True;
780 }
781 
782 /*
783  * Function:    I2AddrPort
784  *
785  * Description:
786  *
787  * In Args:
788  *
789  * Out Args:
790  *
791  * Scope:
792  * Returns:
793  * Side Effect:
794  */
795 uint16_t
I2AddrPort(I2Addr addr)796 I2AddrPort(
797         I2Addr     addr
798         )
799 {
800 
801     if(!addr)
802         return 0;
803 
804     return addr->port_value;
805 }
806 
807 /*
808  * Function:    I2AddrSetProtocol
809  *
810  * Description:
811  *
812  * In Args:
813  *
814  * Out Args:
815  *
816  * Scope:
817  * Returns:
818  * Side Effect:
819  */
820 I2Boolean
I2AddrSetProtocol(I2Addr addr,int protocol)821 I2AddrSetProtocol(
822         I2Addr  addr,
823         int     protocol
824         )
825 {
826     if(!addr)
827         return False;
828 
829     if(addr->so_protocol == protocol)
830         return True;
831 
832     /*
833      * If so_protocol was "unset" before, then this is a simple assignment
834      * even for an associated socket.
835      */
836     if(!addr->so_protocol){
837         addr->so_protocol = protocol;
838         return True;
839     }
840 
841     /*
842      * Otherwise, make sure this assignment is happening *before* actual
843      * association with a socket/saddr.
844      */
845     if(addr->fd > -1){
846         I2ErrLogT(addr->eh,LOG_ERR,EINVAL,
847                 "I2AddrSetProtocol: Addr already associated with socket: %M");
848         return False;
849     }
850     if(addr->saddr){
851         I2ErrLogT(addr->eh,LOG_ERR,EINVAL,
852                 "I2AddrSetProtocol: Addr already associated with saddr: %M");
853         return False;
854     }
855 
856     _I2AddrClearAI(addr);
857 
858     addr->so_protocol = protocol;
859 
860     return True;
861 }
862 
863 /*
864  * Function:    I2AddrProtocol
865  *
866  * Description:
867  *
868  * In Args:
869  *
870  * Out Args:
871  *
872  * Scope:
873  * Returns:
874  * Side Effect:
875  */
876 int
I2AddrProtocol(I2Addr addr)877 I2AddrProtocol(
878         I2Addr  addr
879         )
880 {
881     if(!addr)
882         return 0;
883 
884     return addr->so_protocol;
885 }
886 
887 /*
888  * Function:    I2AddrSetSocktype
889  *
890  * Description:
891  *
892  * In Args:
893  *
894  * Out Args:
895  *
896  * Scope:
897  * Returns:
898  * Side Effect:
899  */
900 I2Boolean
I2AddrSetSocktype(I2Addr addr,int so_type)901 I2AddrSetSocktype(
902         I2Addr     addr,
903         int         so_type
904         )
905 {
906     if(!addr)
907         return False;
908 
909     if(addr->so_type == so_type)
910         return True;
911 
912     /*
913      * If so_type was "unset" before, then this is a simple assignment
914      * even for an associated socket.
915      */
916     if(!addr->so_type){
917         addr->so_type = so_type;
918         return True;
919     }
920 
921     if(addr->fd > -1){
922         I2ErrLogT(addr->eh,LOG_ERR,EINVAL,
923                 "I2AddrSetSocktype: Addr already associated with socket: %M");
924         return False;
925     }
926     if(addr->saddr){
927         I2ErrLogT(addr->eh,LOG_ERR,EINVAL,
928                 "I2AddrSetSocktype: Addr already associated with saddr: %M");
929         return False;
930     }
931 
932     _I2AddrClearAI(addr);
933 
934     addr->so_type = so_type;
935 
936     return True;
937 }
938 
939 /*
940  * Function:    I2AddrSocktype
941  *
942  * Description:
943  *          Retrieves so_socktype.
944  *
945  * In Args:
946  *
947  * Out Args:
948  *
949  * Scope:
950  * Returns:
951  * Side Effect:
952  */
953 int
I2AddrSocktype(I2Addr addr)954 I2AddrSocktype(
955         I2Addr  addr
956         )
957 {
958     if(!addr)
959         return 0;
960 
961     return addr->so_type;
962 }
963 
964 /*
965  * Function:    I2AddrSetPassive
966  *
967  * Description:
968  *
969  * In Args:
970  *
971  * Out Args:
972  *
973  * Scope:
974  * Returns:
975  * Side Effect:
976  */
977 I2Boolean
I2AddrSetPassive(I2Addr addr,I2Boolean passive)978 I2AddrSetPassive(
979         I2Addr     addr,
980         I2Boolean  passive
981         )
982 {
983     if(!addr)
984         return False;
985 
986     if(addr->passive == passive)
987         return True;
988 
989     if(addr->fd > -1){
990         I2ErrLogT(addr->eh,LOG_ERR,EINVAL,
991                 "I2AddrSetPassive: Addr already associated with socket: %M");
992         return False;
993     }
994     if(addr->saddr){
995         I2ErrLogT(addr->eh,LOG_ERR,EINVAL,
996                 "I2AddrSetPassive: Addr already associated with saddr: %M");
997         return False;
998     }
999 
1000     _I2AddrClearAI(addr);
1001 
1002     addr->passive = passive;
1003 
1004     return True;
1005 }
1006 
1007 /*
1008  * Function:    I2AddrFD
1009  *
1010  * Description:
1011  *      Retrieves the fd associated with the I2Addr.
1012  *
1013  * In Args:
1014  *
1015  * Out Args:
1016  *
1017  * Scope:
1018  * Returns:
1019  * Side Effect:
1020  */
1021 int
I2AddrFD(I2Addr addr)1022 I2AddrFD(
1023         I2Addr addr
1024         )
1025 {
1026     if(!addr || (addr->fd < 0))
1027         return -1;
1028 
1029     return addr->fd;
1030 }
1031 
1032 /*
1033  * Function:    I2AddrSAddr
1034  *
1035  * Description:
1036  *          This function retrieves the sockaddr associated with the given
1037  *          I2Addr. (If the saddr has not been set, it returns null.)
1038  *
1039  * In Args:
1040  *
1041  * Out Args:
1042  *
1043  * Scope:
1044  * Returns:
1045  * Side Effect:
1046  */
1047 struct sockaddr *
I2AddrSAddr(I2Addr addr,socklen_t * saddr_len)1048 I2AddrSAddr(
1049         I2Addr      addr,
1050         socklen_t   *saddr_len
1051         )
1052 {
1053     socklen_t   len_mem;
1054     socklen_t   *len = &len_mem;
1055 
1056     if(saddr_len){
1057         len = saddr_len;
1058     }
1059 
1060     if(addr && addr->saddr){
1061         *len = addr->saddrlen;
1062         return addr->saddr;
1063     }
1064 
1065     *len = 0;
1066     return NULL;
1067 }
1068 
1069 /*
1070  * Function:    I2AddrNodeName
1071  *
1072  * Description:
1073  *              This function gets a char* node name for a given I2Addr.
1074  *              The len parameter is an in/out parameter.
1075  *
1076  * In Args:
1077  *
1078  * Out Args:
1079  *
1080  * Scope:
1081  * Returns:
1082  * Side Effect:
1083  */
1084 char *
I2AddrNodeName(I2Addr addr,char * buf,size_t * len)1085 I2AddrNodeName(
1086         I2Addr addr,
1087         char    *buf,
1088         size_t  *len
1089         )
1090 {
1091     int i;
1092 
1093     assert(buf);
1094     assert(len);
1095     assert(*len > 0);
1096 
1097     if(!addr){
1098         goto bail;
1099     }
1100 
1101     if(!addr->node_set){
1102         _I2AddrSetNodePort(addr);
1103     }
1104 
1105     if(addr->node_set){
1106         *len = MIN(*len,sizeof(addr->node));
1107         strncpy(buf,addr->node,*len);
1108 
1109         for(i = 0; i < strlen(buf); i++) {
1110              if (buf[i] == '%') {
1111                  buf[i] = '\0';
1112                  *len = i;
1113              }
1114         }
1115 
1116         return buf;
1117     }
1118 
1119 bail:
1120     *len = 0;
1121     buf[0] = '\0';
1122     return NULL;
1123 }
1124 
1125 /*
1126  * Function:    I2AddrServName
1127  *
1128  * Description:
1129  *              This function gets a char* service name for a given I2Addr.
1130  *              The len parameter is an in/out parameter.
1131  *
1132  * In Args:
1133  *
1134  * Out Args:
1135  *
1136  * Scope:
1137  * Returns:
1138  * Side Effect:
1139  */
1140 char *
I2AddrServName(I2Addr addr,char * buf,size_t * len)1141 I2AddrServName(
1142         I2Addr addr,
1143         char    *buf,
1144         size_t  *len
1145         )
1146 {
1147     assert(buf);
1148     assert(len);
1149     assert(*len > 0);
1150 
1151     if(!addr){
1152         goto bail;
1153     }
1154 
1155     if(!addr->port_set){
1156         _I2AddrSetNodePort(addr);
1157     }
1158 
1159     if(addr->port_set){
1160         *len = MIN(*len,sizeof(addr->port));
1161         strncpy(buf,addr->port,*len);
1162         return buf;
1163     }
1164 
1165 bail:
1166     *len = 0;
1167     buf[0] = '\0';
1168     return NULL;
1169 }
1170 
1171 /*
1172  * Function:    I2AddrNodeServName
1173  *
1174  * Description:
1175  *              This function gets a char* complete IP:port name for a given
1176  *              I2Addr. The len parameter is an in/out parameter.
1177  *
1178  * In Args:
1179  *
1180  * Out Args:
1181  *
1182  * Scope:
1183  * Returns:
1184  * Side Effect:
1185  */
1186 char *
I2AddrNodeServName(I2Addr addr,char * buf,size_t * len)1187 I2AddrNodeServName(
1188         I2Addr addr,
1189         char    *buf,
1190         size_t  *len
1191         )
1192 {
1193     size_t  newlen;
1194 
1195     assert(buf);
1196     assert(len);
1197     assert(*len > 0);
1198 
1199     if(!addr){
1200         goto bail;
1201     }
1202 
1203     if(!addr->node_set || !addr->port_set){
1204         _I2AddrSetNodePort(addr);
1205     }
1206 
1207     if(!addr->node_set || !addr->port_set){
1208         goto bail;
1209     }
1210 
1211     newlen = strlen("[]:") + strlen(addr->node) + strlen(addr->port);
1212     *len = MIN(*len,newlen);
1213 
1214     strncpy(buf,"[",*len);
1215     strncat(buf,addr->node,*len);
1216     strncat(buf,"]:",*len);
1217     strncat(buf,addr->port,*len);
1218 
1219     return buf;
1220 
1221 bail:
1222     *len = 0;
1223     buf[0] = '\0';
1224     return NULL;
1225 }
1226 
1227 /*
1228  * Function:    I2AddrAddrInfo
1229  *
1230  * Description:
1231  *
1232  * In Args:
1233  *              def_node:   only used if internal node is not set
1234  *              def_serv:   only used if internal port not set
1235  *
1236  * Out Args:
1237  *
1238  * Scope:
1239  * Returns:
1240  * Side Effect:
1241  */
1242 struct addrinfo
I2AddrAddrInfo(I2Addr addr,char * def_node,char * def_serv)1243 *I2AddrAddrInfo(
1244         I2Addr     addr,
1245         char        *def_node,
1246         char        *def_serv
1247         )
1248 {
1249     struct addrinfo hints;
1250     char            *host=NULL;
1251     char            *port=NULL;
1252     int             gai;
1253 
1254     if(!addr){
1255         return NULL;
1256     }
1257 
1258     if(addr->ai)
1259         return addr->ai;
1260 
1261     memset(&hints,0,sizeof(hints));
1262     hints.ai_family = AF_UNSPEC;
1263 
1264     if(addr->so_type){
1265         hints.ai_socktype = addr->so_type;
1266     }
1267     else{
1268         hints.ai_socktype = SOCK_STREAM;
1269     }
1270 
1271     if(addr->so_protocol){
1272         hints.ai_protocol = addr->so_protocol;
1273     }
1274 
1275     if(addr->passive){
1276         hints.ai_flags = AI_PASSIVE;
1277     }
1278 
1279     if(addr->node_set && (strncmp(addr->node,"unknown",sizeof(addr->node)))){
1280         host = addr->node;
1281     }
1282     else if(def_node){
1283         host = def_node;
1284     }
1285 
1286     if(addr->port_set && (strncmp(addr->port,"unknown",sizeof(addr->port)))){
1287         port = addr->port;
1288     }
1289     else if(def_serv){
1290         port = def_serv;
1291     }
1292 
1293     /*
1294      * Some implementations allow this and give you a bogus connection
1295      * to localhost. I prefer the quick fail.
1296      */
1297     if(!host && !addr->passive){
1298         return NULL;
1299     }
1300 
1301     if(((gai = getaddrinfo(host,port,&hints,&addr->ai)) != 0) || !addr->ai){
1302         I2ErrLogT(addr->eh,LOG_ERR,I2EUNKNOWN,"getaddrinfo(): %s",
1303                 gai_strerror(gai));
1304         return NULL;
1305     }
1306     addr->ai_free = 0;
1307 
1308     return addr->ai;
1309 }
1310 
1311 /*
1312  * Function:    I2AddrSockLen
1313  *
1314  * Description:
1315  *              Return socket address length (for use in calling accept etc...)
1316  *              or 0 if it doesn't refer to a socket yet.
1317  *
1318  * In Args:
1319  *
1320  * Out Args:
1321  *
1322  * Scope:
1323  * Returns:
1324  * Side Effect:
1325  */
1326 extern socklen_t
I2AddrSockLen(I2Addr addr)1327 I2AddrSockLen(
1328         I2Addr    addr
1329         )
1330 {
1331     if(addr && addr->saddr){
1332         return addr->saddrlen;
1333     }
1334     return 0;
1335 }
1336 
1337 /*
1338  * TODO: optimize byte swapping by using BYTE_ORDER macro
1339  * i.e.
1340  * #if (BYTE_ORDER == BIG_ENDIAN)
1341  *  do_nothing
1342  * #else
1343  *  do_this
1344  * #endif
1345  */
1346 
1347 /*
1348  * Deal with network ordering of 64 bit int's.
1349  */
1350 uint64_t
I2htonll(uint64_t h64)1351 I2htonll(
1352         uint64_t    h64
1353       )
1354 {
1355     uint64_t    n64=0;
1356     uint32_t    l32;
1357     uint32_t    h32;
1358     uint8_t     *t8;
1359 
1360     /* Use t8 to byte address the n64 */
1361     t8 = (uint8_t *)&n64;
1362 
1363     /* set low-order bytes */
1364     l32 = htonl(h64 & 0xFFFFFFFFUL);
1365 
1366     /* set high-order bytes */
1367     h64 >>=32;
1368     h32 = htonl(h64 & 0xFFFFFFFFUL);
1369 
1370     memcpy(&t8[0],&h32,4);
1371     memcpy(&t8[4],&l32,4);
1372 
1373     return n64;
1374 }
1375 
1376 uint64_t
I2ntohll(uint64_t n64)1377 I2ntohll(
1378         uint64_t    n64
1379       )
1380 {
1381     uint64_t    h64;
1382     char        *t8 = (char *)&n64;
1383     uint32_t    t32;
1384 
1385     /* High order bytes */
1386     memcpy(&t32,&t8[0],4);
1387     h64 = ntohl(t32);
1388     h64 <<= 32;
1389 
1390     /* Low order bytes */
1391     memcpy(&t32,&t8[4],4);
1392     h64 |= ntohl(t32);
1393 
1394     return h64;
1395 }
1396