imapext-2007

annotate src/osdep/unix/ip6_unix.c @ 0:ada5e610ab86

imap-2007e
author yuuji@gentei.org
date Mon, 14 Sep 2009 15:17:45 +0900
parents
children
rev   line source
yuuji@0 1 /* ========================================================================
yuuji@0 2 * Copyright 1988-2006 University of Washington
yuuji@0 3 *
yuuji@0 4 * Licensed under the Apache License, Version 2.0 (the "License");
yuuji@0 5 * you may not use this file except in compliance with the License.
yuuji@0 6 * You may obtain a copy of the License at
yuuji@0 7 *
yuuji@0 8 * http://www.apache.org/licenses/LICENSE-2.0
yuuji@0 9 *
yuuji@0 10 *
yuuji@0 11 * ========================================================================
yuuji@0 12 */
yuuji@0 13
yuuji@0 14 /*
yuuji@0 15 * Program: UNIX IPv6 routines
yuuji@0 16 *
yuuji@0 17 * Author: Mark Crispin
yuuji@0 18 * Networks and Distributed Computing
yuuji@0 19 * Computing & Communications
yuuji@0 20 * University of Washington
yuuji@0 21 * Administration Building, AG-44
yuuji@0 22 * Seattle, WA 98195
yuuji@0 23 * Internet: MRC@CAC.Washington.EDU
yuuji@0 24 *
yuuji@0 25 * Date: 18 December 2003
yuuji@0 26 * Last Edited: 30 August 2006
yuuji@0 27 */
yuuji@0 28
yuuji@0 29
yuuji@0 30 /*
yuuji@0 31 * There is some amazingly bad design in IPv6 sockets.
yuuji@0 32 *
yuuji@0 33 * Supposedly, the new getnameinfo() and getaddrinfo() functions create an
yuuji@0 34 * abstraction that is not dependent upon IPv4 or IPv6. However, the
yuuji@0 35 * definition of getnameinfo() requires that the caller pass the length of
yuuji@0 36 * the sockaddr instead of deriving it from sa_family. The man page says
yuuji@0 37 * that there's an sa_len member in the sockaddr, but actually there isn't.
yuuji@0 38 * This means that any caller to getnameinfo() and getaddrinfo() has to know
yuuji@0 39 * the size for the protocol family used by that sockaddr.
yuuji@0 40 *
yuuji@0 41 * The new sockaddr_in6 is bigger than the generic sockaddr (which is what
yuuji@0 42 * connect(), accept(), bind(), getpeername(), getsockname(), etc. expect).
yuuji@0 43 * Rather than increase the size of sockaddr, there's a new sockaddr_storage
yuuji@0 44 * which is only usable for allocating space.
yuuji@0 45 */
yuuji@0 46
yuuji@0 47 #define SADRLEN sizeof (struct sockaddr_storage)
yuuji@0 48
yuuji@0 49 #define SADR4(sadr) ((struct sockaddr_in *) sadr)
yuuji@0 50 #define SADR4LEN sizeof (struct sockaddr_in)
yuuji@0 51 #define SADR4ADR(sadr) SADR4 (sadr)->sin_addr
yuuji@0 52 #define ADR4LEN sizeof (struct in_addr)
yuuji@0 53 #define SADR4PORT(sadr) SADR4 (sadr)->sin_port
yuuji@0 54
yuuji@0 55 #define SADR6(sadr) ((struct sockaddr_in6 *) sadr)
yuuji@0 56 #define SADR6LEN sizeof (struct sockaddr_in6)
yuuji@0 57 #define SADR6ADR(sadr) SADR6 (sadr)->sin6_addr
yuuji@0 58 #define ADR6LEN sizeof (struct in6_addr)
yuuji@0 59 #define SADR6PORT(sadr) SADR6 (sadr)->sin6_port
yuuji@0 60
yuuji@0 61
yuuji@0 62 /* IP abstraction layer */
yuuji@0 63
yuuji@0 64 char *ip_sockaddrtostring (struct sockaddr *sadr);
yuuji@0 65 long ip_sockaddrtoport (struct sockaddr *sadr);
yuuji@0 66 void *ip_stringtoaddr (char *text,size_t *len,int *family);
yuuji@0 67 struct sockaddr *ip_newsockaddr (size_t *len);
yuuji@0 68 struct sockaddr *ip_sockaddr (int family,void *adr,size_t adrlen,
yuuji@0 69 unsigned short port,size_t *len);
yuuji@0 70 char *ip_sockaddrtoname (struct sockaddr *sadr);
yuuji@0 71 void *ip_nametoaddr (char *name,size_t *len,int *family,char **canonical,
yuuji@0 72 void **next);
yuuji@0 73
yuuji@0 74 /* Return IP address string from socket address
yuuji@0 75 * Accepts: socket address
yuuji@0 76 * Returns: IP address as name string
yuuji@0 77 */
yuuji@0 78
yuuji@0 79 char *ip_sockaddrtostring (struct sockaddr *sadr)
yuuji@0 80 {
yuuji@0 81 static char tmp[NI_MAXHOST];
yuuji@0 82 switch (sadr->sa_family) {
yuuji@0 83 case PF_INET: /* IPv4 */
yuuji@0 84 if (!getnameinfo (sadr,SADR4LEN,tmp,NI_MAXHOST,NIL,NIL,NI_NUMERICHOST))
yuuji@0 85 return tmp;
yuuji@0 86 break;
yuuji@0 87 case PF_INET6: /* IPv6 */
yuuji@0 88 if (!getnameinfo (sadr,SADR6LEN,tmp,NI_MAXHOST,NIL,NIL,NI_NUMERICHOST))
yuuji@0 89 return tmp;
yuuji@0 90 break;
yuuji@0 91 }
yuuji@0 92 return "NON-IP";
yuuji@0 93 }
yuuji@0 94
yuuji@0 95
yuuji@0 96 /* Return port from socket address
yuuji@0 97 * Accepts: socket address
yuuji@0 98 * Returns: port number or -1 if can't determine it
yuuji@0 99 */
yuuji@0 100
yuuji@0 101 long ip_sockaddrtoport (struct sockaddr *sadr)
yuuji@0 102 {
yuuji@0 103 switch (sadr->sa_family) {
yuuji@0 104 case PF_INET:
yuuji@0 105 return ntohs (SADR4PORT (sadr));
yuuji@0 106 case PF_INET6:
yuuji@0 107 return ntohs (SADR6PORT (sadr));
yuuji@0 108 }
yuuji@0 109 return -1;
yuuji@0 110 }
yuuji@0 111
yuuji@0 112 /* Return IP address from string
yuuji@0 113 * Accepts: name string
yuuji@0 114 * pointer to returned length
yuuji@0 115 * pointer to returned address family
yuuji@0 116 * Returns: address if valid, length and family updated, or NIL
yuuji@0 117 */
yuuji@0 118
yuuji@0 119 void *ip_stringtoaddr (char *text,size_t *len,int *family)
yuuji@0 120
yuuji@0 121 {
yuuji@0 122 char tmp[MAILTMPLEN];
yuuji@0 123 static struct addrinfo *hints;
yuuji@0 124 struct addrinfo *ai;
yuuji@0 125 void *adr = NIL;
yuuji@0 126 if (!hints) { /* hints set up yet? */
yuuji@0 127 hints = (struct addrinfo *) /* one-time setup */
yuuji@0 128 memset (fs_get (sizeof (struct addrinfo)),0,sizeof (struct addrinfo));
yuuji@0 129 hints->ai_family = AF_UNSPEC;/* allow any address family */
yuuji@0 130 hints->ai_socktype = SOCK_STREAM;
yuuji@0 131 /* numeric name only */
yuuji@0 132 hints->ai_flags = AI_NUMERICHOST;
yuuji@0 133 }
yuuji@0 134 /* case-independent lookup */
yuuji@0 135 if (text && (strlen (text) < MAILTMPLEN) &&
yuuji@0 136 (!getaddrinfo (lcase (strcpy (tmp,text)),NIL,hints,&ai))) {
yuuji@0 137 switch (*family = ai->ai_family) {
yuuji@0 138 case AF_INET: /* IPv4 */
yuuji@0 139 adr = fs_get (*len = ADR4LEN);
yuuji@0 140 memcpy (adr,(void *) &SADR4ADR (ai->ai_addr),*len);
yuuji@0 141 break;
yuuji@0 142 case AF_INET6: /* IPv6 */
yuuji@0 143 adr = fs_get (*len = ADR6LEN);
yuuji@0 144 memcpy (adr,(void *) &SADR6ADR (ai->ai_addr),*len);
yuuji@0 145 break;
yuuji@0 146 }
yuuji@0 147 freeaddrinfo (ai); /* free addrinfo */
yuuji@0 148 }
yuuji@0 149 return adr;
yuuji@0 150 }
yuuji@0 151
yuuji@0 152 /* Create a maximum-size socket address
yuuji@0 153 * Accepts: pointer to return maximum socket address length
yuuji@0 154 * Returns: new, empty socket address of maximum size
yuuji@0 155 */
yuuji@0 156
yuuji@0 157 struct sockaddr *ip_newsockaddr (size_t *len)
yuuji@0 158 {
yuuji@0 159 return (struct sockaddr *) memset (fs_get (SADRLEN),0,*len = SADRLEN);
yuuji@0 160 }
yuuji@0 161
yuuji@0 162
yuuji@0 163 /* Stuff a socket address
yuuji@0 164 * Accepts: address family
yuuji@0 165 * IPv4 address
yuuji@0 166 * length of address
yuuji@0 167 * port number
yuuji@0 168 * pointer to return socket address length
yuuji@0 169 * Returns: socket address
yuuji@0 170 */
yuuji@0 171
yuuji@0 172 struct sockaddr *ip_sockaddr (int family,void *adr,size_t adrlen,
yuuji@0 173 unsigned short port,size_t *len)
yuuji@0 174 {
yuuji@0 175 struct sockaddr *sadr = ip_newsockaddr (len);
yuuji@0 176 switch (family) { /* build socket address based upon family */
yuuji@0 177 case AF_INET: /* IPv4 */
yuuji@0 178 sadr->sa_family = PF_INET;
yuuji@0 179 /* copy host address */
yuuji@0 180 memcpy (&SADR4ADR (sadr),adr,adrlen);
yuuji@0 181 /* copy port number in network format */
yuuji@0 182 SADR4PORT (sadr) = htons (port);
yuuji@0 183 *len = SADR4LEN;
yuuji@0 184 break;
yuuji@0 185 case AF_INET6: /* IPv6 */
yuuji@0 186 sadr->sa_family = PF_INET6;
yuuji@0 187 /* copy host address */
yuuji@0 188 memcpy (&SADR6ADR (sadr),adr,adrlen);
yuuji@0 189 /* copy port number in network format */
yuuji@0 190 SADR6PORT (sadr) = htons (port);
yuuji@0 191 *len = SADR6LEN;
yuuji@0 192 break;
yuuji@0 193 default: /* non-IP?? */
yuuji@0 194 sadr->sa_family = PF_UNSPEC;
yuuji@0 195 break;
yuuji@0 196 }
yuuji@0 197 return sadr;
yuuji@0 198 }
yuuji@0 199
yuuji@0 200 /* Return name from socket address
yuuji@0 201 * Accepts: socket address
yuuji@0 202 * Returns: canonical name for that address or NIL if none
yuuji@0 203 */
yuuji@0 204
yuuji@0 205 char *ip_sockaddrtoname (struct sockaddr *sadr)
yuuji@0 206 {
yuuji@0 207 static char tmp[NI_MAXHOST];
yuuji@0 208 switch (sadr->sa_family) {
yuuji@0 209 case PF_INET: /* IPv4 */
yuuji@0 210 if (!getnameinfo (sadr,SADR4LEN,tmp,NI_MAXHOST,NIL,NIL,NI_NAMEREQD))
yuuji@0 211 return tmp;
yuuji@0 212 break;
yuuji@0 213 case PF_INET6: /* IPv6 */
yuuji@0 214 if (!getnameinfo (sadr,SADR6LEN,tmp,NI_MAXHOST,NIL,NIL,NI_NAMEREQD))
yuuji@0 215 return tmp;
yuuji@0 216 break;
yuuji@0 217 }
yuuji@0 218 return NIL;
yuuji@0 219 }
yuuji@0 220
yuuji@0 221 /* Return address from name
yuuji@0 222 * Accepts: name or NIL to return next address
yuuji@0 223 * pointer to previous/returned length
yuuji@0 224 * pointer to previous/returned address family
yuuji@0 225 * pointer to previous/returned canonical name
yuuji@0 226 * pointer to previous/return state for next-address calls
yuuji@0 227 * Returns: address with length/family/canonical updated if needed, or NIL
yuuji@0 228 */
yuuji@0 229
yuuji@0 230 void *ip_nametoaddr (char *name,size_t *len,int *family,char **canonical,
yuuji@0 231 void **next)
yuuji@0 232 {
yuuji@0 233 struct addrinfo *cur = NIL;
yuuji@0 234 static struct addrinfo *hints;
yuuji@0 235 static struct addrinfo *ai = NIL;
yuuji@0 236 static char lcname[MAILTMPLEN];
yuuji@0 237 if (!hints) { /* hints set up yet? */
yuuji@0 238 hints = (struct addrinfo *) /* one-time setup */
yuuji@0 239 memset (fs_get (sizeof (struct addrinfo)),0,sizeof (struct addrinfo));
yuuji@0 240 /* allow any address family */
yuuji@0 241 hints->ai_family = AF_UNSPEC;
yuuji@0 242 hints->ai_socktype = SOCK_STREAM;
yuuji@0 243 /* need canonical name */
yuuji@0 244 hints->ai_flags = AI_CANONNAME;
yuuji@0 245 }
yuuji@0 246 if (name) { /* name supplied? */
yuuji@0 247 if (ai) {
yuuji@0 248 freeaddrinfo (ai); /* free old addrinfo */
yuuji@0 249 ai = NIL;
yuuji@0 250 }
yuuji@0 251 /* case-independent lookup */
yuuji@0 252 if ((strlen (name) < MAILTMPLEN) &&
yuuji@0 253 (!getaddrinfo (lcase (strcpy (lcname,name)),NIL,hints,&ai))) {
yuuji@0 254 cur = ai; /* current block */
yuuji@0 255 if (canonical) /* set canonical name */
yuuji@0 256 *canonical = cur->ai_canonname ? cur->ai_canonname : lcname;
yuuji@0 257 /* remember as next block */
yuuji@0 258 if (next) *next = (void *) ai;
yuuji@0 259 }
yuuji@0 260 else { /* error */
yuuji@0 261 cur = NIL;
yuuji@0 262 if (len) *len = 0;
yuuji@0 263 if (family) *family = 0;
yuuji@0 264 if (canonical) *canonical = NIL;
yuuji@0 265 if (next) *next = NIL;
yuuji@0 266 }
yuuji@0 267 }
yuuji@0 268 /* return next in series */
yuuji@0 269 else if (next && (cur = ((struct addrinfo *) *next)->ai_next)) {
yuuji@0 270 *next = cur; /* set as last address */
yuuji@0 271 /* set canonical in case changed */
yuuji@0 272 if (canonical && cur->ai_canonname) *canonical = cur->ai_canonname;
yuuji@0 273 }
yuuji@0 274
yuuji@0 275 if (cur) { /* got data? */
yuuji@0 276 if (family) *family = cur->ai_family;
yuuji@0 277 switch (cur->ai_family) {
yuuji@0 278 case AF_INET:
yuuji@0 279 if (len) *len = ADR4LEN;
yuuji@0 280 return (void *) &SADR4ADR (cur->ai_addr);
yuuji@0 281 case AF_INET6:
yuuji@0 282 if (len) *len = ADR6LEN;
yuuji@0 283 return (void *) &SADR6ADR (cur->ai_addr);
yuuji@0 284 }
yuuji@0 285 }
yuuji@0 286 if (len) *len = 0; /* error return */
yuuji@0 287 return NIL;
yuuji@0 288 }

UW-IMAP'd extensions by yuuji