root/lang/c/kazuhiki/trunk/kazuhiki/network_impl.h @ 20958

Revision 20958, 11.1 kB (checked in by frsyuki, 5 years ago)

lang/c/kazuhiki: added Kazuhiki, an advanced command line parser for C++

Line 
1/*
2 * Kazuhiki
3 *
4 * Copyright (C) 2007-2008 FURUHASHI Sadayuki
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24
25#ifndef KAZUHIKI_NETWORK_IMPL_H__
26#define KAZUHIKI_NETWORK_IMPL_H__
27
28#include <arpa/inet.h>
29#include <netdb.h>
30#ifndef DISABLE_IFADDRS
31#include <ifaddrs.h>
32#endif
33
34namespace Kazuhiki {
35namespace Accept {
36
37namespace detail {
38
39template <typename Address>
40bool ConvertHostNameIMPL(const char* arg, Address& addr, bool resolve,
41                int family, int flags)
42{
43        Address v;
44        memset(&v, 0, sizeof(v));
45        if( !resolve ) {
46#ifndef DISABLE_IPV6
47                if( family == AF_UNSPEC ) {
48                        if( inet_pton(AF_INET,  arg, &((struct sockaddr_in* )&v)->sin_addr) > 0 ){
49                                ((struct sockaddr_in*)&v)->sin_family = AF_INET;
50                                //((struct sockaddr_in*)&v)->sin_len = sizeof(struct sockaddr_in);
51                        } else if( inet_pton(AF_INET6, arg, &((struct sockaddr_in6*)&v)->sin6_addr) > 0 ) {
52                                ((struct sockaddr_in6*)&v)->sin6_family = AF_INET6;
53                                //((struct sockaddr_in6*)&v)->sin6_len = sizeof(struct sockaddr_in6);
54                        } else {
55                                return false;
56                        }
57                } else if( family == AF_INET ) {
58                        if( inet_pton(AF_INET,  arg, &((struct sockaddr_in* )&v)->sin_addr) > 0 ){
59                                ((struct sockaddr_in*)&v)->sin_family = AF_INET;
60                                //((struct sockaddr_in*)&v)->sin_len = sizeof(struct sockaddr_in);
61                        } else {
62                                return false;
63                        }
64                } else {  // family == AF_INET6
65                        if( inet_pton(AF_INET6, arg, &((struct sockaddr_in6*)&v)->sin6_addr) > 0 ) {
66                                ((struct sockaddr_in6*)&v)->sin6_family = AF_INET6;
67                                //((struct sockaddr_in6*)&v)->sin6_len = sizeof(struct sockaddr_in6);
68                        } else {
69                                return false;
70                        }
71                }
72#else
73                return inet_aton(arg, &v.sin_addr);
74#endif
75        } else {
76#ifndef DISABLE_GETADDRINFO
77                struct addrinfo hints;
78                memset(&hints, 0, sizeof(hints));
79                hints.ai_family = family;
80                hints.ai_socktype = SOCK_STREAM;    // TODO: 指定する?
81                hints.ai_flags = flags;
82                struct addrinfo *res = NULL;
83                int err;
84                if( (err=getaddrinfo(arg, NULL, &hints, &res)) != 0 ) {
85                        return false;
86                }
87                struct addrinfo* rp(res);  // 最初の一つを使う
88                memcpy(&v, rp->ai_addr, rp->ai_addrlen);
89                freeaddrinfo(res);
90#else
91                struct hostent* ent = gethostbyname(arg);
92                if(!ent) { return false; }
93                ((struct sockaddr_in*)&v)->sin_family = AF_INET;
94                memcpy(&((struct sockaddr_in*)&v)->sin_addr, ent->h_addr_list[0], ent->h_length); // 最初の一つを使う
95#endif
96        }
97        addr = v;
98        return true;
99}
100
101inline bool ConvertHostName(const char* arg, struct sockaddr_in& addr, bool resolve = true)
102{
103        return ConvertHostNameIMPL(arg, addr, resolve, AF_INET, 0);
104}
105#ifndef DISABLE_IPV6
106inline bool ConvertHostName(const char* arg, struct sockaddr_in6& addr, bool resolve = true)
107{
108        return ConvertHostNameIMPL(arg, addr, resolve, AF_INET6, 0);
109}
110inline bool ConvertHostName(const char* arg, struct sockaddr_storage& addr, bool resolve = true)
111{
112        return ConvertHostNameIMPL(arg, addr, resolve, AF_UNSPEC, AI_ADDRCONFIG);
113}
114#endif
115
116
117inline bool ConvertAnyAddress(struct sockaddr_in& addr, unsigned short port) {
118        memset(&addr, 0, sizeof(addr));
119        addr.sin_family = AF_INET;
120        addr.sin_port = htons(port);
121        addr.sin_addr.s_addr = INADDR_ANY;
122        return true;
123}
124#ifndef DISABLE_IPV6
125inline bool ConvertAnyAddress(struct sockaddr_in6& addr, unsigned short port) {
126        memset(&addr, 0, sizeof(addr));
127        addr.sin6_family = AF_INET6;
128        addr.sin6_port = htons(port);
129        addr.sin6_addr = in6addr_any;
130        return true;
131}
132inline bool ConvertAnyAddress(struct sockaddr_storage& addr, unsigned short port) {
133        memset(&addr, 0, sizeof(addr));
134        addr.ss_family = AF_INET6;
135        ((struct sockaddr_in6*)&addr)->sin6_port = htons(port);
136        ((struct sockaddr_in6*)&addr)->sin6_addr = in6addr_any;
137        return true;
138}
139#endif
140
141
142#ifndef DISABLE_IFADDRS
143template <typename Address>
144bool ConvertNetworkInterfaceIMPL(const char* str, Address& addr,
145                int family, unsigned short port)
146{
147        struct ifaddrs* ifap;
148        if( getifaddrs(&ifap) ) {
149                return false;
150        }
151        for(struct ifaddrs* i(ifap); i != NULL; i = i->ifa_next) {
152                if( i->ifa_addr == NULL) { continue; }
153                if( strcmp(str, i->ifa_name) != 0 ) { continue; }
154                if( family == AF_UNSPEC || i->ifa_addr->sa_family == family ) {
155                        memcpy(&addr, i->ifa_addr, sizeof(addr));
156                        ((struct sockaddr_in*)&addr)->sin_port = htons(port);
157                        freeifaddrs(ifap);
158                        return true;
159                }
160        }
161        freeifaddrs(ifap);
162        return false;
163}
164inline bool ConvertNetworkInterface(const char* str, struct sockaddr_in& addr,
165                unsigned short port)
166{
167        return ConvertNetworkInterfaceIMPL(str, addr, AF_INET, port);
168}
169#ifndef DISABLE_IPV6
170inline bool ConvertNetworkInterface(const char* str, struct sockaddr_in6& addr,
171                unsigned short port)
172{
173        return ConvertNetworkInterfaceIMPL(str, addr, AF_INET6, port);
174}
175inline bool ConvertNetworkInterface(const char* str, struct sockaddr_storage& addr,
176                unsigned short port)
177{
178        return ConvertNetworkInterfaceIMPL(str, addr, AF_UNSPEC, port);
179}
180#endif
181#endif
182
183}  // namespace detail
184
185
186template <typename Address>
187unsigned int HostNameTMPL<Address>::operator() (int argc, const char* argv[])
188{
189        if( argc < 1 ) { throw LackOfArgumentsError("Host name is required"); }
190        if( !detail::ConvertHostName(argv[0], data, true) ) {
191                throw InvalidArgumentError("Invalid host name");
192        }
193        return 1;
194}
195
196
197template <typename Address>
198unsigned int IPAddressTMPL<Address>::operator() (int argc, const char* argv[])
199{
200        if( argc < 1 ) { throw LackOfArgumentsError("IP address is required"); }
201        if( !detail::ConvertHostName(argv[0], data, false) ) {
202                throw InvalidArgumentError("Invalid address");
203        }
204        return 1;
205}
206
207
208// 1. interface:port
209// 2. ip.add.re.ss:port
210// 3. [ip:add::re:ss]:port   (ipv6)
211// 4. :port
212// 5. port
213// 6. interface      (default port)
214// 7. ip.add.re.ss   (default port)
215// 8. ip::add::re:ss  (default port, ipv6)
216template <typename Address>
217unsigned int ListenAddressTMPL<Address>::operator() (int argc, const char* argv[])
218{
219        if( argc < 1 ) { throw LackOfArgumentsError("Network interface name or address:port is required"); }
220        if( !parse(argv[0]) ) {
221                throw InvalidArgumentError("Network interface name or address:port is required");
222        }
223        return 1;
224}
225
226template <typename Address>
227bool ListenAddressTMPL<Address>::parse(const std::string& str)
228{
229        std::string::size_type posc;
230        if( (posc = str.rfind(':')) != std::string::npos ) {
231                // 1 .. 4, 8
232                if( str.find(':') != posc ) {
233                        // 3, 8
234                        if( posc != 0 && str[posc-1] == ']' && str[0] == '[' ) {
235                                // 3
236                                std::string host( str.substr(1,posc-2) );
237                                std::string port( str.substr(posc+1) );
238                                return resolve_addr(host.c_str(), port.c_str());
239                        } else {
240                                // 8
241                                return resolve_addr(str.c_str(), NULL);
242                        }
243                } else {
244                        // 1, 2, 4
245                        std::string host( str.substr(0,posc) );
246                        std::string port( str.substr(posc+1) );
247                        if( host.empty() ) {
248                                // 4
249                                return resolve_any(port.c_str());
250                        } else if( resolve_addr(host.c_str(), port.c_str()) ) {
251                                // 2
252                                return true;
253                        } else {
254                                // 1
255#ifndef DISABLE_IFADDRS
256                                return resolve_netif(host.c_str(), port.c_str());
257#else
258                                return false;
259#endif
260                        }
261                }
262        } else {
263                // 5 .. 7
264                uint16_t p;
265                if( detail::ConvertNumeric(str.c_str(), p) ) {
266                        // 5
267                        return resolve_any(str.c_str());
268#ifndef DISABLE_IFADDRS
269                } else if( resolve_netif(str.c_str(), NULL) ) {
270                        // 6
271                        return true;
272#endif
273                } else {
274                        // 6
275                        return resolve_addr(str.c_str(), NULL);
276                }
277        }
278}
279
280template <typename Address>
281bool ListenAddressTMPL<Address>::resolve_addr(const char* addr, const char* port)
282{
283        unsigned short p = dport;
284        if( port && !detail::ConvertNumeric(port, p) ) {
285                return false;
286        }
287        if( !detail::ConvertHostName(addr, raddr, do_resolve) ) {
288                return false;
289        }
290        ((struct sockaddr_in*)&raddr)->sin_port = htons(p);
291        return true;
292}
293
294#ifndef DISABLE_IFADDRS
295template <typename Address>
296bool ListenAddressTMPL<Address>::resolve_netif(const char* netif, const char* port)
297{
298        unsigned short p = dport;
299        if( port && !detail::ConvertNumeric(port, p) ) {
300                return false;
301        }
302        if( !detail::ConvertNetworkInterface(netif, raddr, p) ) {
303                return false;
304        }
305        ((struct sockaddr_in*)&raddr)->sin_port = htons(p);
306        return true;
307}
308#endif
309
310template <typename Address>
311bool ListenAddressTMPL<Address>::resolve_any(const char* port)
312{
313        // FIXME
314        unsigned short p = dport;
315        if( port && !detail::ConvertNumeric(port, p) ) {
316                return false;
317        }
318        if( !detail::ConvertAnyAddress(raddr, p) ) {
319                return false;
320        }
321        ((struct sockaddr_in*)&raddr)->sin_port = htons(p);
322        return true;
323}
324
325
326// 1. host:port
327// 2. ip.add.re.ss:port
328// 3. [ip:add::re:ss]:port   (ipv6)
329// 4. host           (default port)
330// 5. ip.add.re.ss   (default port)
331// 6. ip:add::re:ss  (default port, ipv6)
332template <typename Address>
333unsigned int ConnectAddressTMPL<Address>::operator() (int argc, const char* argv[])
334{
335        if( argc < 1 ) { throw LackOfArgumentsError("Host name is required"); }
336        if( !parse(argv[0]) ) {
337                throw InvalidArgumentError("Host name is required");
338        }
339        return 1;
340}
341
342template <typename Address>
343bool ConnectAddressTMPL<Address>::parse(const std::string& str)
344{
345        std::string::size_type posc;
346        if( (posc = str.rfind(':')) != std::string::npos ) {
347                // 1 .. 3, 6
348                if( str.find(':') != posc ) {
349                        // 3, 6
350                        if( posc != 0 && str[posc-1] == ']' && str[0] == '[' ) {
351                                // 3
352                                std::string host( str.substr(1,posc-2) );
353                                std::string port( str.substr(posc+1) );
354                                return resolve_addr(host.c_str(), port.c_str());
355                        } else {
356                                // 6
357                                return resolve_addr(str.c_str(), NULL);
358                        }
359                } else {
360                        // 1, 2
361                        // 1と2は区別しない
362                        std::string host( str.substr(0,posc) );
363                        std::string port( str.substr(posc+1) );
364                        return resolve_addr(host.c_str(), port.c_str());
365                }
366        } else {
367                // 4, 5
368                // 4と5は区別しない
369                return resolve_addr(str.c_str(), NULL);
370        }
371}
372
373template <typename Address>
374bool ConnectAddressTMPL<Address>::resolve_addr(const char* addr, const char* port)
375{
376        unsigned short p = dport;
377        if( port && !detail::ConvertNumeric(port, p) ) {
378                return false;
379        }
380        if( !detail::ConvertHostName(addr, raddr, do_resolve) ) {
381                return false;
382        }
383        ((struct sockaddr_in*)&raddr)->sin_port = htons(p);
384        return true;
385}
386
387
388template <typename Address>
389unsigned int NetworkInterfaceTMPL<Address>::operator() (int argc, const char* argv[])
390{
391        if( argc < 1 ) { throw LackOfArgumentsError("Host name is required"); }
392        if( !detail::ConvertNetworkInterface(argv[0], raddr, dport) ) {
393                throw InvalidArgumentError("Invalid host name");
394        }
395        return 1;
396}
397
398
399}  // namespace Accept
400}  // namespace Kazuhiki
401
402#endif /* kazuhiki/network_impl.h */
403
Note: See TracBrowser for help on using the browser.