summaryrefslogtreecommitdiff
path: root/toxcore/LAN_discovery.c
diff options
context:
space:
mode:
authorzugz <mbays+tox@sdf.org>2017-01-19 18:51:14 +0100
committerzugz <mbays+tox@sdf.org>2017-01-21 22:08:52 +0100
commitb630121f2f659027e1c9f00cd97087ef34e95677 (patch)
tree7972d498fa05b0955c684c83b79bf12000cb7cf2 /toxcore/LAN_discovery.c
parentf185834e9afe83a2bb06e015a3e41b4ac97b48c3 (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.c56
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. */
42static int broadcast_count = -1; 44static int broadcast_count = -1;
43static IP_Port broadcast_ip_port[MAX_INTERFACES]; 45static 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
49static void fetch_broadcast_info(uint16_t port) 51static 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;