diff options
author | zugz <mbays+tox@sdf.org> | 2017-01-19 18:51:14 +0100 |
---|---|---|
committer | zugz <mbays+tox@sdf.org> | 2017-01-21 22:08:52 +0100 |
commit | b630121f2f659027e1c9f00cd97087ef34e95677 (patch) | |
tree | 7972d498fa05b0955c684c83b79bf12000cb7cf2 /toxcore/LAN_discovery.c | |
parent | f185834e9afe83a2bb06e015a3e41b4ac97b48c3 (diff) |
reduce thread-unsafe use of static variables
- rework ip_ntoa() to avoid use of static variables
- rework sort_client_list() to avoid use of static variables
- move static 'lastdump' into Messenger struct
- rework ID2String() to avoid use of static variables; rename to id_to_string()
- fetch_broadcast_info(): attempt to mitigate risks from concurrent execution
- current_time_monotonic(): attempt to mitigate risks from concurrent execution
- comment on non-thread-safety of unix_time_update
Diffstat (limited to 'toxcore/LAN_discovery.c')
-rw-r--r-- | toxcore/LAN_discovery.c | 56 |
1 files changed, 40 insertions, 16 deletions
diff --git a/toxcore/LAN_discovery.c b/toxcore/LAN_discovery.c index 75dca605..40c64cda 100644 --- a/toxcore/LAN_discovery.c +++ b/toxcore/LAN_discovery.c | |||
@@ -39,8 +39,10 @@ | |||
39 | #define MAX_INTERFACES 16 | 39 | #define MAX_INTERFACES 16 |
40 | 40 | ||
41 | 41 | ||
42 | /* TODO: multiple threads might concurrently try to set these, and it isn't clear that this couldn't lead to undesirable | ||
43 | * behaviour. Consider storing the data in per-instance variables instead. */ | ||
42 | static int broadcast_count = -1; | 44 | static int broadcast_count = -1; |
43 | static IP_Port broadcast_ip_port[MAX_INTERFACES]; | 45 | static IP_Port broadcast_ip_ports[MAX_INTERFACES]; |
44 | 46 | ||
45 | #if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) | 47 | #if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) |
46 | 48 | ||
@@ -48,8 +50,6 @@ static IP_Port broadcast_ip_port[MAX_INTERFACES]; | |||
48 | 50 | ||
49 | static void fetch_broadcast_info(uint16_t port) | 51 | static void fetch_broadcast_info(uint16_t port) |
50 | { | 52 | { |
51 | broadcast_count = 0; | ||
52 | |||
53 | IP_ADAPTER_INFO *pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof(IP_ADAPTER_INFO)); | 53 | IP_ADAPTER_INFO *pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof(IP_ADAPTER_INFO)); |
54 | unsigned long ulOutBufLen = sizeof(IP_ADAPTER_INFO); | 54 | unsigned long ulOutBufLen = sizeof(IP_ADAPTER_INFO); |
55 | 55 | ||
@@ -66,6 +66,13 @@ static void fetch_broadcast_info(uint16_t port) | |||
66 | } | 66 | } |
67 | } | 67 | } |
68 | 68 | ||
69 | /* We copy these to the static variables broadcast_* only at the end of fetch_broadcast_info(). | ||
70 | * The intention is to ensure that even if multiple threads enter fetch_broadcast_info() concurrently, only valid | ||
71 | * interfaces will be set to be broadcast to. | ||
72 | * */ | ||
73 | int count = 0; | ||
74 | IP_Port ip_ports[MAX_INTERFACES]; | ||
75 | |||
69 | int ret; | 76 | int ret; |
70 | 77 | ||
71 | if ((ret = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) == NO_ERROR) { | 78 | if ((ret = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) == NO_ERROR) { |
@@ -77,16 +84,16 @@ static void fetch_broadcast_info(uint16_t port) | |||
77 | if (addr_parse_ip(pAdapter->IpAddressList.IpMask.String, &subnet_mask) | 84 | if (addr_parse_ip(pAdapter->IpAddressList.IpMask.String, &subnet_mask) |
78 | && addr_parse_ip(pAdapter->GatewayList.IpAddress.String, &gateway)) { | 85 | && addr_parse_ip(pAdapter->GatewayList.IpAddress.String, &gateway)) { |
79 | if (gateway.family == AF_INET && subnet_mask.family == AF_INET) { | 86 | if (gateway.family == AF_INET && subnet_mask.family == AF_INET) { |
80 | IP_Port *ip_port = &broadcast_ip_port[broadcast_count]; | 87 | IP_Port *ip_port = &ip_ports[count]; |
81 | ip_port->ip.family = AF_INET; | 88 | ip_port->ip.family = AF_INET; |
82 | uint32_t gateway_ip = ntohl(gateway.ip4.uint32), subnet_ip = ntohl(subnet_mask.ip4.uint32); | 89 | uint32_t gateway_ip = ntohl(gateway.ip4.uint32), subnet_ip = ntohl(subnet_mask.ip4.uint32); |
83 | uint32_t broadcast_ip = gateway_ip + ~subnet_ip - 1; | 90 | uint32_t broadcast_ip = gateway_ip + ~subnet_ip - 1; |
84 | ip_port->ip.ip4.uint32 = htonl(broadcast_ip); | 91 | ip_port->ip.ip4.uint32 = htonl(broadcast_ip); |
85 | ip_port->port = port; | 92 | ip_port->port = port; |
86 | broadcast_count++; | 93 | count++; |
87 | 94 | ||
88 | if (broadcast_count >= MAX_INTERFACES) { | 95 | if (count >= MAX_INTERFACES) { |
89 | return; | 96 | break; |
90 | } | 97 | } |
91 | } | 98 | } |
92 | } | 99 | } |
@@ -98,6 +105,12 @@ static void fetch_broadcast_info(uint16_t port) | |||
98 | if (pAdapterInfo) { | 105 | if (pAdapterInfo) { |
99 | free(pAdapterInfo); | 106 | free(pAdapterInfo); |
100 | } | 107 | } |
108 | |||
109 | broadcast_count = count; | ||
110 | |||
111 | for (uint32_t i = 0; i < count; i++) { | ||
112 | broadcast_ip_ports[i] = ip_ports[i]; | ||
113 | } | ||
101 | } | 114 | } |
102 | 115 | ||
103 | #elif defined(__linux__) | 116 | #elif defined(__linux__) |
@@ -108,7 +121,6 @@ static void fetch_broadcast_info(uint16_t port) | |||
108 | * so it's wrapped in __linux for now. | 121 | * so it's wrapped in __linux for now. |
109 | * Definitely won't work like this on Windows... | 122 | * Definitely won't work like this on Windows... |
110 | */ | 123 | */ |
111 | broadcast_count = 0; | ||
112 | sock_t sock = 0; | 124 | sock_t sock = 0; |
113 | 125 | ||
114 | if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { | 126 | if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { |
@@ -128,14 +140,21 @@ static void fetch_broadcast_info(uint16_t port) | |||
128 | return; | 140 | return; |
129 | } | 141 | } |
130 | 142 | ||
143 | /* We copy these to the static variables broadcast_* only at the end of fetch_broadcast_info(). | ||
144 | * The intention is to ensure that even if multiple threads enter fetch_broadcast_info() concurrently, only valid | ||
145 | * interfaces will be set to be broadcast to. | ||
146 | * */ | ||
147 | int count = 0; | ||
148 | IP_Port ip_ports[MAX_INTERFACES]; | ||
149 | |||
131 | /* ifconf.ifc_len is set by the ioctl() to the actual length used; | 150 | /* ifconf.ifc_len is set by the ioctl() to the actual length used; |
132 | * on usage of the complete array the call should be repeated with | 151 | * on usage of the complete array the call should be repeated with |
133 | * a larger array, not done (640kB and 16 interfaces shall be | 152 | * a larger array, not done (640kB and 16 interfaces shall be |
134 | * enough, for everybody!) | 153 | * enough, for everybody!) |
135 | */ | 154 | */ |
136 | int i, count = ifconf.ifc_len / sizeof(struct ifreq); | 155 | int i, n = ifconf.ifc_len / sizeof(struct ifreq); |
137 | 156 | ||
138 | for (i = 0; i < count; i++) { | 157 | for (i = 0; i < n; i++) { |
139 | /* there are interfaces with are incapable of broadcast */ | 158 | /* there are interfaces with are incapable of broadcast */ |
140 | if (ioctl(sock, SIOCGIFBRDADDR, &i_faces[i]) < 0) { | 159 | if (ioctl(sock, SIOCGIFBRDADDR, &i_faces[i]) < 0) { |
141 | continue; | 160 | continue; |
@@ -148,12 +167,11 @@ static void fetch_broadcast_info(uint16_t port) | |||
148 | 167 | ||
149 | struct sockaddr_in *sock4 = (struct sockaddr_in *)&i_faces[i].ifr_broadaddr; | 168 | struct sockaddr_in *sock4 = (struct sockaddr_in *)&i_faces[i].ifr_broadaddr; |
150 | 169 | ||
151 | if (broadcast_count >= MAX_INTERFACES) { | 170 | if (count >= MAX_INTERFACES) { |
152 | close(sock); | 171 | break; |
153 | return; | ||
154 | } | 172 | } |
155 | 173 | ||
156 | IP_Port *ip_port = &broadcast_ip_port[broadcast_count]; | 174 | IP_Port *ip_port = &ip_ports[count]; |
157 | ip_port->ip.family = AF_INET; | 175 | ip_port->ip.family = AF_INET; |
158 | ip_port->ip.ip4.in_addr = sock4->sin_addr; | 176 | ip_port->ip.ip4.in_addr = sock4->sin_addr; |
159 | 177 | ||
@@ -162,10 +180,16 @@ static void fetch_broadcast_info(uint16_t port) | |||
162 | } | 180 | } |
163 | 181 | ||
164 | ip_port->port = port; | 182 | ip_port->port = port; |
165 | broadcast_count++; | 183 | count++; |
166 | } | 184 | } |
167 | 185 | ||
168 | close(sock); | 186 | close(sock); |
187 | |||
188 | broadcast_count = count; | ||
189 | |||
190 | for (uint32_t i = 0; i < count; i++) { | ||
191 | broadcast_ip_ports[i] = ip_ports[i]; | ||
192 | } | ||
169 | } | 193 | } |
170 | 194 | ||
171 | #else // TODO(irungentoo): Other platforms? | 195 | #else // TODO(irungentoo): Other platforms? |
@@ -196,7 +220,7 @@ static uint32_t send_broadcasts(Networking_Core *net, uint16_t port, const uint8 | |||
196 | int i; | 220 | int i; |
197 | 221 | ||
198 | for (i = 0; i < broadcast_count; i++) { | 222 | for (i = 0; i < broadcast_count; i++) { |
199 | sendpacket(net, broadcast_ip_port[i], data, length); | 223 | sendpacket(net, broadcast_ip_ports[i], data, length); |
200 | } | 224 | } |
201 | 225 | ||
202 | return 1; | 226 | return 1; |