winverbs/nd: do not convert timeout status value
[mirror/winof/.git] / etc / user / inet.c
1 /*\r
2  * Copyright (c) 2009 Intel Corp., Inc.\r
3  *\r
4  * This software is available to you under a choice of one of two\r
5  * licenses.  You may choose to be licensed under the terms of the GNU\r
6  * General Public License (GPL) Version 2, available from the file\r
7  * COPYING in the main directory of this source tree, or the\r
8  * OpenIB.org BSD license below:\r
9  *\r
10  *     Redistribution and use in source and binary forms, with or\r
11  *     without modification, are permitted provided that the following\r
12  *     conditions are met:\r
13  *\r
14  *      - Redistributions of source code must retain the above\r
15  *        copyright notice, this list of conditions and the following\r
16  *        disclaimer.\r
17  *\r
18  *      - Redistributions in binary form must reproduce the above\r
19  *        copyright notice, this list of conditions and the following\r
20  *        disclaimer in the documentation and/or other materials\r
21  *        provided with the distribution.\r
22  *\r
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
24  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
25  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
26  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
27  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
28  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
29  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
30  * SOFTWARE.\r
31  *\r
32  */\r
33 \r
34 #include <arpa/inet.h>\r
35 #include <stdlib.h>\r
36 #include <stdio.h>\r
37 \r
38 static int inet_pton4(const char *src, struct in_addr *addr)\r
39 {\r
40         unsigned long ip;\r
41 \r
42         ip = inet_addr(src);\r
43         if (ip == INADDR_NONE)\r
44                 return 0;\r
45 \r
46         addr->S_un.S_addr = ip;\r
47         return 1;\r
48 }\r
49 \r
50 enum in6_addr_format_state\r
51 {\r
52         in6_fs_num,\r
53         in6_fs_colon,\r
54         in6_fs_0_colon,\r
55         in6_fs_0_num\r
56 };\r
57 \r
58 static int inet_check_groups(const char *src)\r
59 {\r
60         int i;\r
61         int digits = 0, groups = 0;\r
62         enum in6_addr_format_state state;\r
63 \r
64         if (src[0] == ':') {\r
65                 if (src[1] == ':') {\r
66                         i = 2;\r
67                         state = in6_fs_0_colon;\r
68                 } else {\r
69                         return -1;\r
70                 }\r
71         } else {\r
72                 i = 0;\r
73                 state = in6_fs_num;\r
74         }\r
75 \r
76         for (; src[i] != '\0'; i++) {\r
77                 if (src[i] == ':') {\r
78 \r
79                         switch (state) {\r
80                         case in6_fs_num:\r
81                                 state = in6_fs_colon;\r
82                                 break;\r
83                         case in6_fs_colon:\r
84                         case in6_fs_0_num:\r
85                                 state = in6_fs_0_colon;\r
86                                 break;\r
87                         default:\r
88                                 return -1;\r
89                         }\r
90                         digits = 0;\r
91 \r
92                 } else if (isxdigit(src[i]) && digits++ < 4) {\r
93 \r
94                         switch (state) {\r
95                         case in6_fs_colon:\r
96                                 state = in6_fs_num;\r
97                                 groups++;\r
98                                 break;\r
99                         case in6_fs_0_colon:\r
100                                 state = in6_fs_0_num;\r
101                                 groups++;\r
102                                 break;\r
103                         default:\r
104                                 break;\r
105                         }\r
106                 } else {\r
107                         return -1;\r
108                 }\r
109         }\r
110 \r
111         if (groups > 8 || state == in6_fs_colon)\r
112                 return -1;\r
113         \r
114         return groups;\r
115 }\r
116 \r
117 /*\r
118  * We don't handle the format x:x:x:x:x:x:d.d.d.d\r
119  */\r
120 static int inet_pton6(const char *src, struct in6_addr *addr)\r
121 {\r
122         const char *pos;\r
123         int i, skip;\r
124 \r
125         skip = 8 - inet_check_groups(src);\r
126         if (skip > 8)\r
127                 return -1;\r
128 \r
129         memset(addr, 0, sizeof(*addr));\r
130         if (src[0] == ':') {\r
131                 pos = src + 2;\r
132                 i = skip;\r
133         } else {\r
134                 pos = src;\r
135                 i = 0;\r
136         }\r
137 \r
138         for (; i < 8; i++) {\r
139                 addr->u.Word[i] = htons((u_short) strtoul(pos, (char **) &pos, 16));\r
140                 pos++;\r
141                 if (*pos == ':') {\r
142                         pos++;\r
143                         i += skip;\r
144                 }\r
145         }\r
146 \r
147         return 1;\r
148 }\r
149 \r
150 #if WINVER < 0x600\r
151 int inet_pton(int af, const char *src, void *dst)\r
152 {\r
153         switch (af) {\r
154         case AF_INET:\r
155                 return inet_pton4(src, (struct in_addr *) dst);\r
156         case AF_INET6:\r
157                 return inet_pton6(src, (struct in6_addr *) dst);\r
158         default:\r
159                 return -1;\r
160         }\r
161 }\r
162 #endif\r
163 \r
164 static const char *inet_ntop4(const void *src, char *dst, socklen_t cnt)\r
165 {\r
166         struct sockaddr_in in;\r
167 \r
168         in.sin_family = AF_INET;\r
169         memcpy(&in.sin_addr, src, 4);\r
170         if (getnameinfo((struct sockaddr *) &in,\r
171                                         (socklen_t) sizeof(struct sockaddr_in),\r
172                                         dst, cnt, NULL, 0, NI_NUMERICHOST))\r
173                 return NULL;\r
174 \r
175         return dst;\r
176 }\r
177 \r
178 static const char *inet_ntop6(const void *src, char *dst, socklen_t cnt)\r
179 {\r
180         struct sockaddr_in6 in6;\r
181         char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"];\r
182         int i, n = 0;\r
183 \r
184         memset(&in6, 0, sizeof in6);\r
185         in6.sin6_family = AF_INET6;\r
186         memcpy(&in6.sin6_addr, src, sizeof(struct in_addr6));\r
187 \r
188         /*\r
189          * If no ipv6 support return simple IPv6 format rule:\r
190          * A series of "0's in a 16bit block can be represented by "0" \r
191          */\r
192         if (getnameinfo((struct sockaddr *) &in6, (socklen_t) (sizeof in6),\r
193                                         dst, cnt, NULL, 0, NI_NUMERICHOST)) \r
194         {\r
195                                 \r
196                 if (cnt < sizeof(tmp))\r
197                         return NULL;\r
198 \r
199                 for (i = 0; i < 8; i++) \r
200                         n += sprintf(tmp+n, "%s%x", i ? ":" : "",\r
201                                                  ntohs(((unsigned short*) src)[i]));\r
202                 tmp[n] = '\0';\r
203                 strcpy(dst, tmp);\r
204         }\r
205         return dst;\r
206 }\r
207 \r
208 #if WINVER < 0x600\r
209 const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt)\r
210 {\r
211         switch (af) {\r
212         case AF_INET:\r
213                 return inet_ntop4(src, dst, cnt);\r
214         case AF_INET6:\r
215                 return inet_ntop6(src, dst, cnt);\r
216         default:\r
217                 return NULL;\r
218         }\r
219 }\r
220 #endif\r