OLD | NEW |
---|---|
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 | 5 |
6 class _SocketBase { | 6 class _SocketBase { |
7 // Bit flags used when communicating between the eventhandler and | 7 // Bit flags used when communicating between the eventhandler and |
8 // dart code. The EVENT flags are used to indicate events of | 8 // dart code. The EVENT flags are used to indicate events of |
9 // interest when sending a message from dart code to the | 9 // interest when sending a message from dart code to the |
10 // eventhandler. When receiving a message from the eventhandler the | 10 // eventhandler. When receiving a message from the eventhandler the |
11 // EVENT flags indicate the events that actually happened. The | 11 // EVENT flags indicate the events that actually happened. The |
12 // COMMAND flags are used to send commands from dart to the | 12 // COMMAND flags are used to send commands from dart to the |
13 // eventhandler. COMMAND flags are never received from the | 13 // eventhandler. COMMAND flags are never received from the |
14 // eventhandler. Additional flags are used to communicate other | 14 // eventhandler. Additional flags are used to communicate other |
15 // information. | 15 // information. |
16 static final int _IN_EVENT = 0; | 16 static final int _IN_EVENT = 0; |
17 static final int _OUT_EVENT = 1; | 17 static final int _OUT_EVENT = 1; |
18 static final int _ERROR_EVENT = 2; | 18 static final int _ERROR_EVENT = 2; |
19 static final int _CLOSE_EVENT = 3; | 19 static final int _CLOSE_EVENT = 3; |
20 | 20 |
21 static final int _CLOSE_COMMAND = 8; | 21 static final int _CLOSE_COMMAND = 8; |
22 static final int _SHUTDOWN_READ_COMMAND = 9; | 22 static final int _SHUTDOWN_READ_COMMAND = 9; |
23 static final int _SHUTDOWN_WRITE_COMMAND = 10; | 23 static final int _SHUTDOWN_WRITE_COMMAND = 10; |
24 | 24 |
25 // Flag send to the eventhandler saying that the file descriptor in | 25 // Flag send to the eventhandler providing additional information on |
26 // question represents a listening socket. | 26 // the type of the file descriptor. |
27 static final int _LISTENING_SOCKET = 16; | 27 static final int _LISTENING_SOCKET = 16; |
28 static final int _PIPE = 17; | |
28 | 29 |
29 static final int _FIRST_EVENT = _IN_EVENT; | 30 static final int _FIRST_EVENT = _IN_EVENT; |
30 static final int _LAST_EVENT = _CLOSE_EVENT; | 31 static final int _LAST_EVENT = _CLOSE_EVENT; |
31 | 32 |
32 static final int _FIRST_COMMAND = _CLOSE_COMMAND; | 33 static final int _FIRST_COMMAND = _CLOSE_COMMAND; |
33 static final int _LAST_COMMAND = _SHUTDOWN_WRITE_COMMAND; | 34 static final int _LAST_COMMAND = _SHUTDOWN_WRITE_COMMAND; |
34 | 35 |
35 _SocketBase () { | 36 _SocketBase () { |
36 _handler = new ReceivePort(); | |
37 _handlerMap = new List(_LAST_EVENT + 1); | 37 _handlerMap = new List(_LAST_EVENT + 1); |
38 _handlerMask = 0; | 38 _handlerMask = 0; |
39 _canActivateHandlers = true; | 39 _canActivateHandlers = true; |
40 _id = -1; | 40 _id = -1; |
41 _handler.receive((var message, ignored) { | |
42 _multiplex(message); | |
43 }); | |
44 EventHandler._start(); | 41 EventHandler._start(); |
45 } | 42 } |
46 | 43 |
47 /* | 44 // Multiplexes socket events to the socket handlers. |
48 * Multiplexes socket events to the right socket handler. | |
49 */ | |
50 void _multiplex(List<int> message) { | 45 void _multiplex(List<int> message) { |
51 assert(message.length == 1); | 46 assert(message.length == 1); |
52 _canActivateHandlers = false; | 47 _canActivateHandlers = false; |
53 int event_mask = message[0]; | 48 int event_mask = message[0]; |
54 for (int i = _FIRST_EVENT; i <= _LAST_EVENT; i++) { | 49 for (int i = _FIRST_EVENT; i <= _LAST_EVENT; i++) { |
55 if (((event_mask & (1 << i)) != 0)) { | 50 if (((event_mask & (1 << i)) != 0)) { |
56 if ((i == _CLOSE_EVENT) && this is _Socket && _id >= 0) { | 51 if ((i == _CLOSE_EVENT) && this is _Socket && _id >= 0) { |
57 _closedRead = true; | 52 _closedRead = true; |
58 if (_closedWrite) _close(); | 53 if (_closedWrite) _close(); |
59 } | 54 } |
(...skipping 16 matching lines...) Expand all Loading... | |
76 _activateHandlers(); | 71 _activateHandlers(); |
77 } | 72 } |
78 | 73 |
79 void _setHandler(int event, void callback()) { | 74 void _setHandler(int event, void callback()) { |
80 if (callback == null) { | 75 if (callback == null) { |
81 _handlerMask &= ~(1 << event); | 76 _handlerMask &= ~(1 << event); |
82 } else { | 77 } else { |
83 _handlerMask |= (1 << event); | 78 _handlerMask |= (1 << event); |
84 } | 79 } |
85 _handlerMap[event] = callback; | 80 _handlerMap[event] = callback; |
86 _activateHandlers(); | 81 // If the socket is only for writing then close the receive port |
82 // when not waiting for any events. | |
83 if (this is _Socket && | |
84 _closedRead && | |
85 _handlerMask == 0 && | |
86 _handler != null) { | |
87 _handler.close(); | |
88 _handler = null; | |
89 } else { | |
90 _activateHandlers(); | |
91 } | |
87 } | 92 } |
88 | 93 |
89 void _getPort() native "Socket_GetPort"; | 94 void _getPort() native "Socket_GetPort"; |
90 | 95 |
91 void set errorHandler(void callback()) { | 96 void set errorHandler(void callback()) { |
92 _setHandler(_ERROR_EVENT, callback); | 97 _setHandler(_ERROR_EVENT, callback); |
93 } | 98 } |
94 | 99 |
95 void _activateHandlers() { | 100 void _activateHandlers() { |
96 if (_canActivateHandlers && (_id >= 0)) { | 101 if (_canActivateHandlers && (_id >= 0)) { |
97 int data = _handlerMask; | 102 int data = _handlerMask; |
98 if (_isListenSocket()) { | 103 if (_isListenSocket()) { |
99 data |= (1 << _LISTENING_SOCKET); | 104 data |= (1 << _LISTENING_SOCKET); |
100 } else { | 105 } else { |
101 if (_closedRead) { data &= ~(1 << _IN_EVENT); } | 106 if (_closedRead) { data &= ~(1 << _IN_EVENT); } |
102 if (_closedWrite) { data &= ~(1 << _OUT_EVENT); } | 107 if (_closedWrite) { data &= ~(1 << _OUT_EVENT); } |
103 if (_isListenSocket()) data |= (1 << _LISTENING_SOCKET); | 108 if (_isPipe()) data |= (1 << _PIPE); |
Mads Ager (google)
2011/11/14 14:14:23
Good catch. :)
| |
104 } | 109 } |
105 EventHandler._sendData(_id, _handler, data); | 110 _sendToEventHandler(data); |
106 } | 111 } |
107 } | 112 } |
108 | 113 |
109 void _scheduleEvent(int event) { | |
110 _handler.toSendPort().send([1 << event], null); | |
111 } | |
112 | |
113 int get port() { | 114 int get port() { |
114 if (_port === null) { | 115 if (_port === null) { |
115 _port = _getPort(); | 116 _port = _getPort(); |
116 } | 117 } |
117 return _port; | 118 return _port; |
118 } | 119 } |
119 | 120 |
120 void close([bool halfClose = false]) { | 121 void close([bool halfClose = false]) { |
121 if (_id >= 0) { | 122 if (_id >= 0) { |
122 if (halfClose) { | 123 if (halfClose) { |
123 _closeWrite(); | 124 _closeWrite(); |
124 } else { | 125 } else { |
125 _close(); | 126 _close(); |
126 } | 127 } |
127 } else if (_handler != null) { | 128 } else if (_handler != null) { |
128 // This is to support closing sockets created but never assigned | 129 // This is to support closing sockets created but never assigned |
129 // any actual socket. | 130 // any actual socket. |
130 _handler.close(); | 131 _handler.close(); |
131 _handler = null; | 132 _handler = null; |
132 } | 133 } |
133 } | 134 } |
134 | 135 |
135 void _closeWrite() { | 136 void _closeWrite() { |
136 if (_closedRead) { | 137 if (_closedRead) { |
137 _close(); | 138 _close(); |
138 } else { | 139 } else { |
139 EventHandler._sendData(_id, _handler, 1 << _SHUTDOWN_WRITE_COMMAND); | 140 _sendToEventHandler(1 << _SHUTDOWN_WRITE_COMMAND); |
140 } | 141 } |
141 _closedWrite = true; | 142 _closedWrite = true; |
142 } | 143 } |
143 | 144 |
144 void _closeRead() { | 145 void _closeRead() { |
145 if (_closedWrite) { | 146 if (_closedWrite) { |
146 _close(); | 147 _close(); |
147 } else { | 148 } else { |
148 EventHandler._sendData(_id, _handler, 1 << _SHUTDOWN_READ_COMMAND); | 149 _sendToEventHandler(1 << _SHUTDOWN_READ_COMMAND); |
149 } | 150 } |
150 _closedRead = true; | 151 _closedRead = true; |
151 } | 152 } |
152 | 153 |
153 void _close() { | 154 void _close() { |
154 EventHandler._sendData(_id, _handler, 1 << _CLOSE_COMMAND); | 155 _sendToEventHandler(1 << _CLOSE_COMMAND); |
155 _handler.close(); | 156 _handler.close(); |
156 _handler = null; | 157 _handler = null; |
157 _id = -1; | 158 _id = -1; |
158 } | 159 } |
159 | 160 |
161 void _sendToEventHandler(int data) { | |
162 if (_handler === null) { | |
163 _handler = new ReceivePort(); | |
164 _handler.receive((var message, ignored) { _multiplex(message); }); | |
165 } | |
166 EventHandler._sendData(_id, _handler, data); | |
167 } | |
168 | |
160 abstract bool _isListenSocket(); | 169 abstract bool _isListenSocket(); |
170 abstract bool _isPipe(); | |
161 | 171 |
162 /* | 172 /* |
163 * Socket id is set from native. -1 indicates that the socket was closed. | 173 * Socket id is set from native. -1 indicates that the socket was closed. |
164 */ | 174 */ |
165 int _id; | 175 int _id; |
166 | 176 |
167 /* | 177 /* |
168 * Dedicated ReceivePort for socket events. | 178 * Dedicated ReceivePort for socket events. |
169 */ | 179 */ |
170 ReceivePort _handler; | 180 ReceivePort _handler; |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
228 bool _accept(Socket socket) native "ServerSocket_Accept"; | 238 bool _accept(Socket socket) native "ServerSocket_Accept"; |
229 | 239 |
230 bool _createBindListen(String bindAddress, int port, int backlog) | 240 bool _createBindListen(String bindAddress, int port, int backlog) |
231 native "ServerSocket_CreateBindListen"; | 241 native "ServerSocket_CreateBindListen"; |
232 | 242 |
233 void set connectionHandler(void callback()) { | 243 void set connectionHandler(void callback()) { |
234 _setHandler(_IN_EVENT, callback); | 244 _setHandler(_IN_EVENT, callback); |
235 } | 245 } |
236 | 246 |
237 bool _isListenSocket() => true; | 247 bool _isListenSocket() => true; |
248 bool _isPipe() => false; | |
238 } | 249 } |
239 | 250 |
240 | 251 |
241 class _Socket extends _SocketBase implements Socket { | 252 class _Socket extends _SocketBase implements Socket { |
242 /* | 253 /* |
243 * Constructor for socket. First a socket object is allocated | 254 * Constructor for socket. First a socket object is allocated |
244 * in which the native socket is stored. After that _createConnect is | 255 * in which the native socket is stored. After that _createConnect is |
245 * called which creates a file discriptor and connects to the given | 256 * called which creates a file discriptor and connects to the given |
246 * host on the given port. Null is returned if file descriptor creation | 257 * host on the given port. Null is returned if file descriptor creation |
247 * or connect failed. | 258 * or connect failed. |
248 */ | 259 */ |
249 factory _Socket(String host, int port) { | 260 factory _Socket(String host, int port) { |
250 Socket socket = new _Socket._internal(); | 261 Socket socket = new _Socket._internal(); |
251 if (!socket._createConnect(host, port)) { | 262 if (!socket._createConnect(host, port)) { |
252 socket.close(); | 263 socket.close(); |
253 return null; | 264 return null; |
254 } | 265 } |
255 return socket; | 266 return socket; |
256 } | 267 } |
257 | 268 |
258 _Socket._internal(); | 269 _Socket._internal(); |
259 _Socket._internalReadOnly() : _closedWrite = true; | 270 _Socket._internalReadOnly() : _closedWrite = true, _pipe = true; |
260 _Socket._internalWriteOnly() : _closedRead = true; | 271 _Socket._internalWriteOnly() : _closedRead = true, _pipe = true; |
261 | 272 |
262 int available() { | 273 int available() { |
263 if (_id >= 0) { | 274 if (_id >= 0) { |
264 return _available(); | 275 return _available(); |
265 } | 276 } |
266 throw new | 277 throw new |
267 SocketIOException("Error: available failed - invalid socket handle"); | 278 SocketIOException("Error: available failed - invalid socket handle"); |
268 } | 279 } |
269 | 280 |
270 int _available() native "Socket_Available"; | 281 int _available() native "Socket_Available"; |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
329 | 340 |
330 void set dataHandler(void callback()) { | 341 void set dataHandler(void callback()) { |
331 _setHandler(_IN_EVENT, callback); | 342 _setHandler(_IN_EVENT, callback); |
332 } | 343 } |
333 | 344 |
334 void set closeHandler(void callback()) { | 345 void set closeHandler(void callback()) { |
335 _setHandler(_CLOSE_EVENT, callback); | 346 _setHandler(_CLOSE_EVENT, callback); |
336 } | 347 } |
337 | 348 |
338 bool _isListenSocket() => false; | 349 bool _isListenSocket() => false; |
350 bool _isPipe() => _pipe; | |
339 | 351 |
340 InputStream get inputStream() { | 352 InputStream get inputStream() { |
341 if (_inputStream === null) { | 353 if (_inputStream === null) { |
342 _inputStream = new SocketInputStream(this); | 354 _inputStream = new SocketInputStream(this); |
343 } | 355 } |
344 return _inputStream; | 356 return _inputStream; |
345 } | 357 } |
346 | 358 |
347 OutputStream get outputStream() { | 359 OutputStream get outputStream() { |
348 if (_outputStream === null) { | 360 if (_outputStream === null) { |
349 _outputStream = new SocketOutputStream(this); | 361 _outputStream = new SocketOutputStream(this); |
350 } | 362 } |
351 return _outputStream; | 363 return _outputStream; |
352 } | 364 } |
353 | 365 |
354 bool _closedRead = false; | 366 bool _closedRead = false; |
355 bool _closedWrite = false; | 367 bool _closedWrite = false; |
368 bool _pipe = false; | |
356 SocketInputStream _inputStream; | 369 SocketInputStream _inputStream; |
357 SocketOutputStream _outputStream; | 370 SocketOutputStream _outputStream; |
358 } | 371 } |
359 | 372 |
OLD | NEW |