OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2017, 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 @patch | |
6 class RawSynchronousSocket { | |
7 @patch | |
8 static RawSynchronousSocket connectSync(host, int port) { | |
9 return _RawSynchronousSocket.connectSync(host, port); | |
10 } | |
11 } | |
12 | |
13 class _RawSynchronousSocket implements RawSynchronousSocket { | |
14 final _NativeSynchronousSocket _socket; | |
15 | |
16 _RawSynchronousSocket(this._socket) {} | |
17 | |
18 static RawSynchronousSocket connectSync(host, int port) { | |
19 _throwOnBadPort(port); | |
20 return new _RawSynchronousSocket( | |
21 _NativeSynchronousSocket.connectSync(host, port)); | |
22 } | |
23 | |
24 InternetAddress get address => _socket.address; | |
25 int get port => _socket.port; | |
26 InternetAddress get remoteAddress => _socket.remoteAddress; | |
27 int get remotePort => _socket.remotePort; | |
28 | |
29 int available() => _socket.available; | |
30 | |
31 void closeSync() => _socket.closeSync(); | |
32 | |
33 int readIntoSync(List<int> buffer, [int start = 0, int end]) => | |
34 _socket.readIntoSync(buffer, start, end); | |
35 | |
36 List<int> readSync(int bytes) => _socket.readSync(bytes); | |
37 | |
38 void shutdown(SocketDirection direction) => _socket.shutdown(direction); | |
39 | |
40 void writeFromSync(List<int> buffer, [int start = 0, int end]) => | |
41 _socket.writeFromSync(buffer, start, end); | |
42 } | |
43 | |
44 // The NativeFieldWrapperClass1 can not be used with a mixin, due to missing | |
45 // implicit constructor. | |
46 class _NativeSynchronousSocketNativeWrapper extends NativeFieldWrapperClass1 {} | |
47 | |
48 // The _NativeSynchronousSocket class encapsulates a synchronous OS socket. | |
49 class _NativeSynchronousSocket extends _NativeSynchronousSocketNativeWrapper { | |
50 // Socket close state. | |
51 bool isClosed = false; | |
52 bool isClosedRead = false; | |
53 bool isClosedWrite = false; | |
54 | |
55 // Holds the address used to connect the socket. | |
56 InternetAddress localAddress; | |
57 | |
58 // Holds the port of the socket, 0 if not known. | |
59 int localPort = 0; | |
60 | |
61 _ReadWriteResourceInfo resourceInfo; | |
zra
2017/04/07 16:29:41
It looks like you need to call _SocketResourceInfo
bkonyi
2017/04/10 19:20:06
Added SocketClosed() call in CloseSync()
| |
62 | |
63 InternetAddress get address => localAddress; | |
64 int get available => nativeAvailable(); | |
65 | |
66 int get port { | |
67 if (localPort != 0) return localPort; | |
zra
2017/04/07 16:29:41
Please put single line ifs in {}
bkonyi
2017/04/10 19:20:06
Done.
| |
68 if (isClosed) throw const SocketException.closed(); | |
69 var result = nativeGetPort(); | |
70 if (result is OSError) throw result; | |
71 return localPort = result; | |
72 } | |
73 | |
74 InternetAddress get remoteAddress { | |
75 if (isClosed) throw const SocketException.closed(); | |
76 var result = nativeGetRemotePeer(); | |
77 if (result is OSError) throw result; | |
78 var addr = result[0]; | |
79 var type = new InternetAddressType._from(addr[0]); | |
80 return new _InternetAddress(addr[1], null, addr[2]); | |
81 } | |
82 | |
83 int get remotePort { | |
84 if (isClosed) throw const SocketException.closed(); | |
85 var result = nativeGetRemotePeer(); | |
86 if (result is OSError) throw result; | |
87 return result[1]; | |
88 } | |
89 | |
90 static _NativeSynchronousSocket connectSync(host, int port) { | |
zra
2017/04/07 16:29:41
statics like this that generate an instance I thin
bkonyi
2017/04/10 19:20:06
Ah, I wasn't sure where static methods like this s
| |
91 List<_InternetAddress> addresses = null; | |
92 var error = null; | |
93 if (host is _InternetAddress) { | |
94 addresses = [host]; | |
95 } else { | |
96 try { | |
97 addresses = lookup(host); | |
98 } catch (e) { | |
99 error = e; | |
100 } | |
101 if (error != null || addresses == null || addresses.isEmpty) { | |
102 throw createError(error, "Failed host lookup: '$host'"); | |
103 } | |
104 } | |
105 assert(addresses is List); | |
106 var it = addresses.iterator; | |
107 _NativeSynchronousSocket connectNext() { | |
108 if (!it.moveNext()) { | |
109 // Could not connect. Throw the first connection error we encountered. | |
110 assert(error != null); | |
111 throw error; | |
112 } | |
113 var address = it.current; | |
114 var socket = new _NativeSynchronousSocket(); | |
115 socket.localAddress = address; | |
116 var result = socket.nativeCreateConnectSync(address._in_addr, port); | |
117 if (result is OSError) { | |
118 // Keep first error, if present. | |
119 if (error == null) { | |
120 int errorCode = result.errorCode; | |
zra
2017/04/07 16:29:40
errorCode doesn't appear to be used.
bkonyi
2017/04/10 19:20:06
Removed.
| |
121 error = createError(result, "Connection failed", address, port); | |
122 } | |
123 return connectNext(); | |
124 } else { | |
125 // Query the local port, for error messages. | |
126 try { | |
127 socket.port; | |
128 } catch (e) { | |
129 error = createError(e, "Connection failed", address, port); | |
zra
2017/04/07 16:29:41
if (error == null)
bkonyi
2017/04/10 19:20:05
Done.
| |
130 return connectNext(); | |
131 } | |
132 setupResourceInfo(socket); | |
133 } | |
134 return socket; | |
135 } | |
136 | |
137 return connectNext(); | |
138 } | |
139 | |
140 void closeSync() { | |
141 if (!isClosed) { | |
142 nativeCloseSync(); | |
143 isClosed = true; | |
144 } | |
145 } | |
146 | |
147 // Create the appropriate error/exception from different returned | |
148 // error objects. | |
149 static createError(error, String message, | |
150 [InternetAddress address, int port]) { | |
151 if (error is OSError) { | |
152 return new SocketException(message, | |
153 osError: error, address: address, port: port); | |
154 } else { | |
155 return new SocketException(message, address: address, port: port); | |
156 } | |
157 } | |
158 | |
159 static List<InternetAddress> lookup(String host, | |
160 {InternetAddressType type: InternetAddressType.ANY}) { | |
161 var response = nativeLookupRequest(host, type._value); | |
162 if (response is OSError) { | |
163 throw response; | |
164 } | |
165 // TODO(bkonyi) do we need this first empty element? Or is this something sp ecific | |
zra
2017/04/07 16:29:41
I don't see what this is used for either. Let's ge
bkonyi
2017/04/10 19:20:06
Done.
| |
166 // for io_service? | |
167 return response.skip(1).map((result) { | |
168 var type = new InternetAddressType._from(result[0]); | |
169 return new _InternetAddress(result[1], host, result[2]); | |
170 }).toList(); | |
171 } | |
172 | |
173 int readIntoSync(List<int> buffer, int start, int end) { | |
zra
2017/04/07 16:29:40
This shouldn't be implemented on top of readSync.
bkonyi
2017/04/10 19:20:06
Done.
| |
174 if (buffer == null) { | |
175 throw new ArgumentError("Illegal buffer: buffer cannot be null"); | |
176 } | |
177 if (start != null && ((start >= buffer.length) || (start < 0))) { | |
178 throw new ArgumentError("Illegal start $start"); | |
179 } | |
180 if ((start != null && end != null) && | |
181 ((start > end) || (end > buffer.length))) { | |
182 throw new ArgumentError("Illegal range [$start, $end)"); | |
183 } | |
184 int len = 0; | |
185 if (start == null) { | |
186 start = 0; | |
187 len = buffer.length; | |
188 } else if (end == null) { | |
189 len = buffer.length - start; | |
190 } else { | |
191 len = end - start; | |
192 } | |
193 List<int> result = readSync(len); | |
194 len = min(result.length, len); | |
195 | |
196 for (int i = start; i < start + len; i++) { | |
197 buffer[i] = result[i - start]; | |
198 } | |
199 return result.length; | |
200 } | |
201 | |
202 List<int> readSync(int len) { | |
203 if (len != null && len <= 0) { | |
204 throw new ArgumentError("Illegal length $len"); | |
205 } | |
206 if (isClosed) return null; | |
207 if (len == 0) return null; | |
208 var result = nativeRead(len); | |
209 if (result is OSError) { | |
210 throw result; | |
211 return null; | |
212 } | |
213 if (result != null) { | |
214 assert(resourceInfo != null); | |
215 if (resourceInfo != null) { | |
216 resourceInfo.totalRead += result.length; | |
217 } | |
218 } | |
219 assert(resourceInfo != null); | |
zra
2017/04/07 16:29:41
If you move this assert above if (result != null)
bkonyi
2017/04/10 19:20:06
Done.
| |
220 if (resourceInfo != null) { | |
221 resourceInfo.didRead(); | |
222 } | |
223 return result; | |
224 } | |
225 | |
226 static void setupResourceInfo(_NativeSynchronousSocket socket) { | |
227 socket.resourceInfo = new _SocketResourceInfo(socket); | |
228 } | |
229 | |
230 void shutdown(SocketDirection direction) { | |
231 if (!isClosed) { | |
zra
2017/04/07 16:29:41
if (isClosed) return
then un-indent, here and bel
bkonyi
2017/04/10 19:20:06
Done.
| |
232 switch (direction) { | |
233 case SocketDirection.RECEIVE: | |
234 shutdownRead(); | |
235 break; | |
236 case SocketDirection.SEND: | |
237 shutdownWrite(); | |
238 break; | |
239 case SocketDirection.BOTH: | |
240 closeSync(); | |
241 break; | |
242 default: | |
243 throw new ArgumentError(direction); | |
244 } | |
245 } | |
246 } | |
247 | |
248 void shutdownRead() { | |
249 if (!isClosed) { | |
250 if (isClosedWrite) { | |
251 closeSync(); | |
252 } else { | |
253 nativeShutdownRead(); | |
zra
2017/04/07 16:29:41
What if isClosedRead is already true?
bkonyi
2017/04/10 19:20:05
Then the native shutdown read method would be call
| |
254 } | |
255 isClosedRead = true; | |
256 } | |
257 } | |
258 | |
259 void shutdownWrite() { | |
260 if (!isClosed) { | |
261 if (isClosedRead) { | |
262 closeSync(); | |
263 } else { | |
264 nativeShutdownWrite(); | |
265 } | |
266 isClosedWrite = true; | |
267 } | |
268 } | |
269 | |
270 void writeFromSync(List<int> buffer, int start, int end) { | |
zra
2017/04/07 16:29:41
Have a look at _RandomAccessFile.writeFromSync for
bkonyi
2017/04/10 19:20:05
Done.
| |
271 if (isClosed) return; | |
272 int offset = start; | |
273 int bytes = null; | |
274 if (buffer is! List) throw new ArgumentError(); | |
zra
2017/04/07 16:29:41
Please give an error message.
bkonyi
2017/04/10 19:20:06
Acknowledged.
| |
275 if (offset == null) offset = 0; | |
276 if (end == null) { | |
zra
2017/04/07 16:29:41
Can you use RangeError.checkValidRange()?
bkonyi
2017/04/10 19:20:06
I didn't know that existed... super useful! Done.
| |
277 if (offset > (buffer.length)) { | |
278 throw new RangeError.value(offset); | |
279 } | |
280 bytes = buffer.length - offset; | |
281 } else { | |
282 bytes = end - offset; | |
283 } | |
284 if (offset is! int || bytes is! int) { | |
zra
2017/04/07 16:29:40
This should probably be up at the top of the funct
bkonyi
2017/04/10 19:20:06
Acknowledged.
| |
285 throw new ArgumentError("Invalid arguments to write on Socket"); | |
286 } | |
287 if (bytes == 0) return; | |
288 if (offset < 0) throw new RangeError.value(offset); | |
289 if (bytes < 0) throw new RangeError.value(bytes); | |
290 if ((offset + bytes) > buffer.length) { | |
291 throw new RangeError.value(offset + bytes); | |
292 } | |
293 _BufferAndStart bufferAndStart = | |
294 _ensureFastAndSerializableByteData(buffer, offset, offset + bytes); | |
295 var result = | |
296 nativeWrite(bufferAndStart.buffer, bufferAndStart.start, bytes); | |
297 if (result is OSError) { | |
298 throw result; | |
299 } | |
300 // TODO(bkonyi) we don't currently handle short writes or reads. | |
301 // The result may be negative, if we forced a short write for testing | |
302 // purposes. Negate the result to get the actual number of bytes written. | |
303 if (result < 0) result = -result; | |
zra
2017/04/07 16:29:41
Let's remove this logic if it isn't supported.
bkonyi
2017/04/10 19:20:05
Done.
| |
304 assert(resourceInfo != null); | |
305 if (resourceInfo != null) { | |
306 resourceInfo.addWrite(result); | |
307 } | |
308 } | |
309 | |
310 // Native method declarations. | |
311 static nativeLookupRequest(host, int type) | |
312 native "SynchronousSocket_LookupRequest"; | |
313 nativeCreateConnectSync(host, int port) | |
314 native "SynchronousSocket_CreateConnectSync"; | |
315 nativeAvailable() native "SynchronousSocket_Available"; | |
316 nativeCloseSync() native "SynchronousSocket_CloseSync"; | |
317 int nativeGetPort() native "SynchronousSocket_GetPort"; | |
318 List nativeGetRemotePeer() native "SynchronousSocket_GetRemotePeer"; | |
319 nativeRead(int len) native "SynchronousSocket_Read"; | |
320 nativeShutdownRead() native "SynchronousSocket_ShutdownRead"; | |
321 nativeShutdownWrite() native "SynchronousSocket_ShutdownWrite"; | |
322 nativeWrite(List<int> buffer, int offset, int bytes) | |
323 native "SynchronousSocket_WriteList"; | |
324 } | |
OLD | NEW |