OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 import "dart:async"; |
| 6 import "dart:io"; |
| 7 import "dart:typed_data"; |
| 8 |
| 9 import "package:async_helper/async_helper.dart"; |
| 10 import "package:expect/expect.dart"; |
| 11 |
| 12 class FutureExpect { |
| 13 static Future check(Future result, check) => |
| 14 result.then((value) => check(value)); |
| 15 static Future throws(Future result) => |
| 16 result.then((value) { |
| 17 throw new ExpectException( |
| 18 "FutureExpect.throws received $value instead of an exception"); |
| 19 }, onError: (_) => null); |
| 20 } |
| 21 |
| 22 testDatagramBroadcastOptions() { |
| 23 test(address) { |
| 24 asyncStart(); |
| 25 RawDatagramSocket.bind(address, 0).then((socket) { |
| 26 Expect.isFalse(socket.broadcastEnabled); |
| 27 socket.broadcastEnabled = true; |
| 28 Expect.isTrue(socket.broadcastEnabled); |
| 29 socket.broadcastEnabled = false; |
| 30 Expect.isFalse(socket.broadcastEnabled); |
| 31 asyncEnd(); |
| 32 }); |
| 33 } |
| 34 |
| 35 test(InternetAddress.LOOPBACK_IP_V4); |
| 36 test(InternetAddress.ANY_IP_V4); |
| 37 } |
| 38 |
| 39 testDatagramMulticastOptions() { |
| 40 test(address) { |
| 41 asyncStart(); |
| 42 RawDatagramSocket.bind(address, 0).then((socket) { |
| 43 Expect.isTrue(socket.multicastLoopback); |
| 44 Expect.equals(1, socket.multicastHops); |
| 45 Expect.throws(() => socket.multicastInterface); |
| 46 |
| 47 socket.multicastLoopback = false; |
| 48 socket.multicastHops = 4; |
| 49 Expect.isFalse(socket.multicastLoopback); |
| 50 Expect.equals(4, socket.multicastHops); |
| 51 Expect.throws(() => socket.multicastInterface = null); |
| 52 |
| 53 socket.multicastLoopback = true; |
| 54 socket.multicastHops = 1; |
| 55 Expect.isTrue(socket.multicastLoopback); |
| 56 Expect.equals(1, socket.multicastHops); |
| 57 Expect.throws(() => socket.multicastInterface); |
| 58 |
| 59 asyncEnd(); |
| 60 }); |
| 61 } |
| 62 |
| 63 test(InternetAddress.LOOPBACK_IP_V4); |
| 64 test(InternetAddress.ANY_IP_V4); |
| 65 test(InternetAddress.LOOPBACK_IP_V6); |
| 66 test(InternetAddress.ANY_IP_V6); |
| 67 } |
| 68 |
| 69 testDatagramSocketReuseAddress() { |
| 70 test(address, reuseAddress) { |
| 71 asyncStart(); |
| 72 RawDatagramSocket.bind( |
| 73 address, 0, reuseAddress: reuseAddress).then((socket) { |
| 74 if (reuseAddress) { |
| 75 RawDatagramSocket.bind(address, socket.port) |
| 76 .then((s) => Expect.isTrue(s is RawDatagramSocket)) |
| 77 .then(asyncSuccess); |
| 78 } else { |
| 79 FutureExpect.throws(RawDatagramSocket.bind(address, socket.port)) |
| 80 .then(asyncSuccess); |
| 81 } |
| 82 }); |
| 83 } |
| 84 |
| 85 test(InternetAddress.LOOPBACK_IP_V4, true); |
| 86 test(InternetAddress.LOOPBACK_IP_V4, false); |
| 87 test(InternetAddress.LOOPBACK_IP_V6, true); |
| 88 test(InternetAddress.LOOPBACK_IP_V6, false); |
| 89 } |
| 90 |
| 91 testBroadcast() { |
| 92 test(bindAddress, broadcastAddress, enabled) { |
| 93 asyncStart(); |
| 94 Future.wait([RawDatagramSocket.bind(bindAddress, 0), |
| 95 RawDatagramSocket.bind(bindAddress, 0)]).then((values) { |
| 96 var broadcastTimer; |
| 97 var sender = values[0]; |
| 98 var receiver = values[1]; |
| 99 // On Windows at least the receiver needs to have broadcast |
| 100 // enabled whereas on Linux at least the sender needs to. |
| 101 receiver.broadcastEnabled = enabled; |
| 102 sender.broadcastEnabled = enabled; |
| 103 receiver.listen((event) { |
| 104 if (event == RawSocketEvent.READ) { |
| 105 Expect.isTrue(enabled); |
| 106 sender.close(); |
| 107 receiver.close(); |
| 108 broadcastTimer.cancel(); |
| 109 asyncEnd(); |
| 110 } |
| 111 }); |
| 112 |
| 113 int sendCount = 0; |
| 114 send(_) { |
| 115 int bytes = |
| 116 sender.send(new Uint8List(1), broadcastAddress, receiver.port); |
| 117 Expect.isTrue(bytes == 0 || bytes == 1); |
| 118 sendCount++; |
| 119 if (!enabled && sendCount == 50) { |
| 120 sender.close(); |
| 121 receiver.close(); |
| 122 broadcastTimer.cancel(); |
| 123 asyncEnd(); |
| 124 } |
| 125 } |
| 126 broadcastTimer = new Timer.periodic(new Duration(milliseconds: 10), send); |
| 127 }); |
| 128 } |
| 129 |
| 130 var broadcast = new InternetAddress("255.255.255.255"); |
| 131 test(InternetAddress.ANY_IP_V4, broadcast, false); |
| 132 test(InternetAddress.ANY_IP_V4, broadcast, true); |
| 133 } |
| 134 |
| 135 testLoopbackMulticast() { |
| 136 test(bindAddress, multicastAddress, enabled) { |
| 137 asyncStart(); |
| 138 Future.wait([RawDatagramSocket.bind(bindAddress, 0), |
| 139 RawDatagramSocket.bind(bindAddress, 0)]).then((values) { |
| 140 var senderTimer; |
| 141 var sender = values[0]; |
| 142 var receiver = values[1]; |
| 143 |
| 144 sender.joinMulticast(multicastAddress); |
| 145 receiver.joinMulticast(multicastAddress); |
| 146 // On Windows at least the receiver needs to have multicast |
| 147 // loop enabled whereas on Linux at least the sender needs to. |
| 148 receiver.multicastLoopback = enabled; |
| 149 sender.multicastLoopback = enabled; |
| 150 |
| 151 receiver.listen((event) { |
| 152 if (event == RawSocketEvent.READ) { |
| 153 Expect.isTrue(enabled); |
| 154 sender.close(); |
| 155 receiver.close(); |
| 156 senderTimer.cancel(); |
| 157 asyncEnd(); |
| 158 } |
| 159 }); |
| 160 |
| 161 int sendCount = 0; |
| 162 send(_) { |
| 163 int bytes = |
| 164 sender.send(new Uint8List(1), multicastAddress, receiver.port); |
| 165 Expect.isTrue(bytes == 0 || bytes == 1); |
| 166 sendCount++; |
| 167 if (!enabled && sendCount == 50) { |
| 168 sender.close(); |
| 169 receiver.close(); |
| 170 senderTimer.cancel(); |
| 171 asyncEnd(); |
| 172 } |
| 173 } |
| 174 senderTimer = new Timer.periodic(new Duration(milliseconds: 10), send); |
| 175 }); |
| 176 } |
| 177 |
| 178 test(InternetAddress.ANY_IP_V4, new InternetAddress("228.0.0.4"), true); |
| 179 test(InternetAddress.ANY_IP_V4, new InternetAddress("224.0.0.0"), false); |
| 180 test(InternetAddress.ANY_IP_V6, new InternetAddress("ff11::0"), true); |
| 181 test(InternetAddress.ANY_IP_V6, new InternetAddress("ff11::0"), false); |
| 182 } |
| 183 |
| 184 testSendReceive(InternetAddress bindAddress) { |
| 185 asyncStart(); |
| 186 |
| 187 var total = 1000; |
| 188 |
| 189 int receivedSeq = 0; |
| 190 |
| 191 var ackSeq = 0; |
| 192 Timer ackTimer; |
| 193 |
| 194 Future.wait([RawDatagramSocket.bind(bindAddress, 0), |
| 195 RawDatagramSocket.bind(bindAddress, 0)]).then((values) { |
| 196 var sender = values[0]; |
| 197 var receiver = values[1]; |
| 198 if (bindAddress.isMulticast) { |
| 199 sender.multicastLoopback = true; |
| 200 receiver.multicastLoopback = true; |
| 201 sender.joinMulticast(bindAddress); |
| 202 receiver.joinMulticast(bindAddress); |
| 203 } |
| 204 |
| 205 UInt8List createDataPackage(int seq) { |
| 206 var data = new Uint8List(1000); |
| 207 (new ByteData.view(data.buffer, 0, 4)).setUint32(0, seq); |
| 208 return data; |
| 209 } |
| 210 |
| 211 UInt8List createAckPackage(int seq) { |
| 212 var data = new Uint8List(4); |
| 213 new ByteData.view(data.buffer, 0, 4).setUint32(0, seq); |
| 214 return data; |
| 215 } |
| 216 |
| 217 int packageSeq(Datagram datagram) => |
| 218 new ByteData.view(datagram.data.buffer).getUint32(0); |
| 219 |
| 220 void sendData(int seq) { |
| 221 // Send a datagram acknowledging the received sequence. |
| 222 int bytes = sender.send(createDataPackage(seq), bindAddress, receiver.port); |
| 223 Expect.isTrue(bytes == 0 || bytes == 1000); |
| 224 } |
| 225 |
| 226 void sendAck(address, port) { |
| 227 // Send a datagram acknowledging the received sequence. |
| 228 int bytes = receiver.send(createAckPackage(receivedSeq), address, port); |
| 229 Expect.isTrue(bytes == 0 || bytes == 4); |
| 230 // Start a "long" timer for more data. |
| 231 if (ackTimer != null) ackTimer.cancel(); |
| 232 ackTimer = new Timer.periodic( |
| 233 new Duration(milliseconds: 100), (_) => sendAck(address, port)); |
| 234 } |
| 235 |
| 236 sender.listen((event) { |
| 237 switch (event) { |
| 238 case RawSocketEvent.READ: |
| 239 var datagram = sender.receive(); |
| 240 if (datagram != null) { |
| 241 Expect.equals(datagram.port, receiver.port); |
| 242 if (!bindAddress.isMulticast) { |
| 243 Expect.equals(receiver.address, datagram.address); |
| 244 } |
| 245 ackSeq = packageSeq(datagram); |
| 246 if (ackSeq < total) { |
| 247 sender.writeEventsEnabled = true; |
| 248 } else { |
| 249 sender.close(); |
| 250 receiver.close(); |
| 251 ackTimer.cancel(); |
| 252 asyncEnd(); |
| 253 } |
| 254 } |
| 255 break; |
| 256 case RawSocketEvent.WRITE: |
| 257 // Send the next package. |
| 258 sendData(ackSeq + 1); |
| 259 break; |
| 260 case RawSocketEvent.CLOSED: |
| 261 break; |
| 262 default: |
| 263 throw "Unexpected event $event"; |
| 264 } |
| 265 }); |
| 266 |
| 267 receiver.writeEventsEnabled = false; |
| 268 receiver.listen((event) { |
| 269 switch (event) { |
| 270 case RawSocketEvent.READ: |
| 271 var datagram = receiver.receive(); |
| 272 if (datagram != null) { |
| 273 Expect.equals(datagram.port, sender.port); |
| 274 if (!bindAddress.isMulticast) { |
| 275 Expect.equals(receiver.address, datagram.address); |
| 276 } |
| 277 var seq = packageSeq(datagram); |
| 278 if (seq == receivedSeq + 1) { |
| 279 receivedSeq = seq; |
| 280 sendAck(bindAddress, sender.port); |
| 281 } |
| 282 } |
| 283 break; |
| 284 case RawSocketEvent.WRITE: |
| 285 throw "Unexpected WRITE"; |
| 286 break; |
| 287 case RawSocketEvent.CLOSED: |
| 288 break; |
| 289 default: |
| 290 throw "Unexpected event $event"; |
| 291 } |
| 292 }); |
| 293 }); |
| 294 } |
| 295 |
| 296 |
| 297 main() { |
| 298 testDatagramBroadcastOptions(); |
| 299 testDatagramMulticastOptions(); |
| 300 testDatagramSocketReuseAddress(); |
| 301 testBroadcast(); |
| 302 testLoopbackMulticast(); |
| 303 testSendReceive(InternetAddress.LOOPBACK_IP_V4); |
| 304 testSendReceive(InternetAddress.LOOPBACK_IP_V6); |
| 305 } |
OLD | NEW |