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