Software /
code /
prosody
Annotate
util-src/net.c @ 5750:fbff8ecb6662
util.net: Include missing header needed for successful compiltion on FreeBSD
author | Matthew Wild <mwild1@gmail.com> |
---|---|
date | Mon, 15 Jul 2013 23:34:59 +0100 |
parent | 5699:e9f5384f5ff1 |
child | 5752:729c78581308 |
rev | line source |
---|---|
5699
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
1 /* Prosody IM |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
2 -- |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
3 -- This project is MIT/X11 licensed. Please see the |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
4 -- COPYING file in the source package for more information. |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
5 -- |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
6 -- Copyright (C) 2012 Paul Aurich |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
7 -- Copyright (C) 2013 Matthew Wild |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
8 -- Copyright (C) 2013 Florian Zeitz |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
9 -- |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
10 */ |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
11 |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
12 #include <stddef.h> |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
13 #include <string.h> |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
14 #include <errno.h> |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
15 |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
16 #ifndef _WIN32 |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
17 #include <sys/ioctl.h> |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
18 #include <sys/types.h> |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
19 #include <sys/socket.h> |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
20 #include <net/if.h> |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
21 #include <ifaddrs.h> |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
22 #include <arpa/inet.h> |
5750
fbff8ecb6662
util.net: Include missing header needed for successful compiltion on FreeBSD
Matthew Wild <mwild1@gmail.com>
parents:
5699
diff
changeset
|
23 #include <netinet/in.h> |
5699
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
24 #endif |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
25 |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
26 #include <lua.h> |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
27 #include <lauxlib.h> |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
28 |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
29 /* Enumerate all locally configured IP addresses */ |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
30 |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
31 const char * const type_strings[] = { |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
32 "both", |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
33 "ipv4", |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
34 "ipv6", |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
35 NULL |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
36 }; |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
37 |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
38 static int lc_local_addresses(lua_State *L) |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
39 { |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
40 /* Link-local IPv4 addresses; see RFC 3927 and RFC 5735 */ |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
41 const long ip4_linklocal = htonl(0xa9fe0000); /* 169.254.0.0 */ |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
42 const long ip4_mask = htonl(0xffff0000); |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
43 #ifndef _WIN32 |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
44 struct ifaddrs *addr = NULL, *a; |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
45 int n = 1; |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
46 #endif |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
47 int type = luaL_checkoption(L, 1, "both", type_strings); |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
48 const char link_local = lua_toboolean(L, 2); /* defaults to 0 (false) */ |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
49 const char ipv4 = (type == 0 || type == 1); |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
50 const char ipv6 = (type == 0 || type == 2); |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
51 |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
52 #ifndef _WIN32 |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
53 if (getifaddrs(&addr) < 0) { |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
54 lua_pushnil(L); |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
55 lua_pushfstring(L, "getifaddrs failed (%d): %s", errno, |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
56 strerror(errno)); |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
57 return 2; |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
58 } |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
59 |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
60 lua_newtable(L); |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
61 |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
62 for (a = addr; a; a = a->ifa_next) { |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
63 int family; |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
64 char ipaddr[INET6_ADDRSTRLEN]; |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
65 const char *tmp = NULL; |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
66 |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
67 if (a->ifa_addr == NULL || a->ifa_flags & IFF_LOOPBACK) |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
68 continue; |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
69 |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
70 family = a->ifa_addr->sa_family; |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
71 |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
72 if (ipv4 && family == AF_INET) { |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
73 struct sockaddr_in *sa = (struct sockaddr_in *)a->ifa_addr; |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
74 if (!link_local &&((sa->sin_addr.s_addr & ip4_mask) == ip4_linklocal)) |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
75 continue; |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
76 tmp = inet_ntop(family, &sa->sin_addr, ipaddr, sizeof(ipaddr)); |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
77 } else if (ipv6 && family == AF_INET6) { |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
78 struct sockaddr_in6 *sa = (struct sockaddr_in6 *)a->ifa_addr; |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
79 if (!link_local && IN6_IS_ADDR_LINKLOCAL(&sa->sin6_addr)) |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
80 continue; |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
81 if (IN6_IS_ADDR_V4MAPPED(&sa->sin6_addr) || IN6_IS_ADDR_V4COMPAT(&sa->sin6_addr)) |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
82 continue; |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
83 tmp = inet_ntop(family, &sa->sin6_addr, ipaddr, sizeof(ipaddr)); |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
84 } |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
85 |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
86 if (tmp != NULL) { |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
87 lua_pushstring(L, tmp); |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
88 lua_rawseti(L, -2, n++); |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
89 } |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
90 /* TODO: Error reporting? */ |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
91 } |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
92 |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
93 freeifaddrs(addr); |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
94 |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
95 return 1; |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
96 #endif |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
97 } |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
98 |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
99 int luaopen_util_net(lua_State* L) |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
100 { |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
101 luaL_Reg exports[] = { |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
102 { "local_addresses", lc_local_addresses }, |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
103 { NULL, NULL } |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
104 }; |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
105 |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
106 luaL_register(L, "net", exports); |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
107 return 1; |
e9f5384f5ff1
util.net: Add util.net, containing local_addresses() (removed from LuaSocket 3.0)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
108 } |