6abaad8aa1
Most of the socket tests where written with closing both the server and client ends of the socket. However on Windows this can lead to errors once in a while (WSAECONNRESET). The tests now closes the socket in the client and and waits for a close event on the server side. The readUntil on InputStream did not take data in the internal buffer into account. This has been fixed and the related test have been rewritten to check for two patterns which together will match all the input. R=ager@google.com BUG= TEST= Review URL: https://chromereviews.googleplex.com/3536016 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@126 260f80e4-7a28-3924-810f-c04153c831b5
289 lines
7.1 KiB
Dart
289 lines
7.1 KiB
Dart
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
/*
|
|
* SocketNativeWrapper is defined in native and holds a field to store the
|
|
* native socket object.
|
|
*/
|
|
class _SocketBase {
|
|
|
|
/*
|
|
* Keep these constants in sync with the native poll event identifiers.
|
|
*/
|
|
static final int _IN_EVENT = 0;
|
|
static final int _OUT_EVENT = 1;
|
|
static final int _ERROR_EVENT = 2;
|
|
static final int _CLOSE_EVENT = 3;
|
|
static final int _FIRST_EVENT = _IN_EVENT;
|
|
static final int _LAST_EVENT = _CLOSE_EVENT;
|
|
|
|
static final int _CLOSE_COMMAND = 4;
|
|
|
|
_SocketBase () {
|
|
_handler = new ReceivePort();
|
|
_handlerMap = new List(_CLOSE_EVENT + 1);
|
|
_handlerMask = 0;
|
|
_canActivateHandlers = true;
|
|
_id = 0;
|
|
_handler.receive((var message, ignored) {
|
|
_multiplex(message);
|
|
});
|
|
EventHandler._start();
|
|
}
|
|
|
|
/*
|
|
* Multiplexes socket events to the right socket handler.
|
|
*/
|
|
void _multiplex(List<int> message) {
|
|
assert(message.length == 1);
|
|
_canActivateHandlers = false;
|
|
int event_mask = message[0];
|
|
for (int i = _FIRST_EVENT; i <= _LAST_EVENT; i++) {
|
|
if (((event_mask & (1 << i)) != 0) && _handlerMap[i] !== null) {
|
|
var handleEvent = _handlerMap[i];
|
|
/*
|
|
* Unregister the out handler before executing it.
|
|
*/
|
|
if (i == _OUT_EVENT) {
|
|
_setHandler(i, null);
|
|
}
|
|
handleEvent();
|
|
}
|
|
}
|
|
_canActivateHandlers = true;
|
|
_doActivateHandlers();
|
|
}
|
|
|
|
void _setHandler(int event, void callback()) {
|
|
if (callback === null) {
|
|
_handlerMask &= ~(1 << event);
|
|
} else {
|
|
_handlerMask |= (1 << event);
|
|
}
|
|
_handlerMap[event] = callback;
|
|
_doActivateHandlers();
|
|
}
|
|
|
|
void _getPort() native "Socket_GetPort";
|
|
|
|
void setErrorHandler(void callback()) {
|
|
_setHandler(_ERROR_EVENT, callback);
|
|
}
|
|
|
|
void _doActivateHandlers() {
|
|
if (_canActivateHandlers && (_id >= 0)) {
|
|
EventHandler._sendData(_id, _handler, _handlerMask);
|
|
}
|
|
}
|
|
|
|
void _scheduleEvent(int event) {
|
|
_handler.toSendPort().send([1 << event], null);
|
|
}
|
|
|
|
int get port() {
|
|
if (_port == null) {
|
|
_port = _getPort();
|
|
}
|
|
return _port;
|
|
}
|
|
|
|
void close() {
|
|
if (_id >= 0) {
|
|
EventHandler._sendData(_id, _handler, 1 << _CLOSE_COMMAND);
|
|
_handler.close();
|
|
_id = -1;
|
|
} else {
|
|
throw new
|
|
SocketIOException("Error: close failed - invalid socket handle");
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Socket id is set from native. -1 indicates that the socket was closed.
|
|
*/
|
|
int _id;
|
|
|
|
/*
|
|
* Dedicated ReceivePort for socket events.
|
|
*/
|
|
ReceivePort _handler;
|
|
|
|
/*
|
|
* Poll event to handler map.
|
|
*/
|
|
List _handlerMap;
|
|
|
|
/*
|
|
* Indicates for which poll events the socket registered handlers.
|
|
*/
|
|
int _handlerMask;
|
|
|
|
/*
|
|
* Indicates if native interrupts can be activated.
|
|
*/
|
|
bool _canActivateHandlers;
|
|
|
|
/*
|
|
* Holds the port of the socket, null if not known.
|
|
*/
|
|
int _port;
|
|
}
|
|
|
|
|
|
class _ServerSocket extends _SocketBase implements ServerSocket {
|
|
/*
|
|
* Constructor for server socket. First a socket object is allocated
|
|
* in which the native socket is stored. After that _createBind
|
|
* is called which creates a file descriptor and binds the given address
|
|
* and port to the socket. Null is returned if file descriptor creation or
|
|
* bind failed.
|
|
*/
|
|
factory _ServerSocket(String bindAddress, int port, int backlog) {
|
|
ServerSocket socket = new _ServerSocket._internal();
|
|
if (!socket._createBindListen(bindAddress, port, backlog)) {
|
|
return null;
|
|
}
|
|
if (port != 0) {
|
|
socket._port = port;
|
|
}
|
|
return socket;
|
|
}
|
|
|
|
_ServerSocket._internal() : super() {}
|
|
|
|
Socket accept() {
|
|
if (_id >= 0) {
|
|
_Socket socket = new _Socket._internal();
|
|
if (_accept(socket)) {
|
|
return socket;
|
|
}
|
|
return null;
|
|
}
|
|
throw new
|
|
SocketIOException("Error: accept failed - invalid socket handle");
|
|
}
|
|
|
|
bool _accept(Socket socket) native "ServerSocket_Accept";
|
|
|
|
bool _createBindListen(String bindAddress, int port, int backlog)
|
|
native "ServerSocket_CreateBindListen";
|
|
|
|
void setConnectionHandler(void callback()) {
|
|
_setHandler(_IN_EVENT, callback);
|
|
}
|
|
}
|
|
|
|
|
|
class _Socket extends _SocketBase implements Socket {
|
|
/*
|
|
* Constructor for socket. First a socket object is allocated
|
|
* in which the native socket is stored. After that _createConnect is
|
|
* called which creates a file discriptor and connects to the given
|
|
* host on the given port. Null is returned if file descriptor creation
|
|
* or connect failsed
|
|
*/
|
|
factory _Socket(String host, int port) {
|
|
Socket socket = new _Socket._internal();
|
|
if (!socket._createConnect(host, port)) {
|
|
return null;
|
|
}
|
|
return socket;
|
|
}
|
|
|
|
_Socket._internal() : super() {}
|
|
|
|
int available() {
|
|
if (_id >= 0) {
|
|
return _available();
|
|
}
|
|
throw new
|
|
SocketIOException("Error: available failed - invalid socket handle");
|
|
}
|
|
|
|
int _available() native "Socket_Available";
|
|
|
|
int readList(List<int> buffer, int offset, int bytes) {
|
|
if (_id >= 0) {
|
|
if (bytes == 0) {
|
|
return 0;
|
|
}
|
|
if (offset < 0) {
|
|
throw new IndexOutOfRangeException(offset);
|
|
}
|
|
if (bytes < 0) {
|
|
throw new IndexOutOfRangeException(bytes);
|
|
}
|
|
if ((offset + bytes) > buffer.length) {
|
|
throw new IndexOutOfRangeException(offset + bytes);
|
|
}
|
|
return _readList(buffer, offset, bytes);
|
|
}
|
|
throw new
|
|
SocketIOException("Error: readList failed - invalid socket handle");
|
|
}
|
|
|
|
int _readList(List<int> buffer, int offset, int bytes)
|
|
native "Socket_ReadList";
|
|
|
|
int writeList(List<int> buffer, int offset, int bytes) {
|
|
if (_id >= 0) {
|
|
if (bytes == 0) {
|
|
return 0;
|
|
}
|
|
if (offset < 0) {
|
|
throw new IndexOutOfRangeException(offset);
|
|
}
|
|
if (bytes < 0) {
|
|
throw new IndexOutOfRangeException(bytes);
|
|
}
|
|
if ((offset + bytes) > buffer.length) {
|
|
throw new IndexOutOfRangeException(offset + bytes);
|
|
}
|
|
return _writeList(buffer, offset, bytes);
|
|
}
|
|
throw new
|
|
SocketIOException("Error: writeList failed - invalid socket handle");
|
|
}
|
|
|
|
int _writeList(List<int> buffer, int offset, int bytes)
|
|
native "Socket_WriteList";
|
|
|
|
bool _createConnect(String host, int port) native "Socket_CreateConnect";
|
|
|
|
void setWriteHandler(void callback()) {
|
|
_setHandler(_OUT_EVENT, callback);
|
|
}
|
|
|
|
void setConnectHandler(void callback()) {
|
|
_setHandler(_OUT_EVENT, callback);
|
|
}
|
|
|
|
void setDataHandler(void callback()) {
|
|
_setHandler(_IN_EVENT, callback);
|
|
}
|
|
|
|
void setCloseHandler(void callback()) {
|
|
_setHandler(_CLOSE_EVENT, callback);
|
|
}
|
|
|
|
InputStream get inputStream() {
|
|
if (_inputStream === null) {
|
|
_inputStream = new SocketInputStream(this);
|
|
}
|
|
return _inputStream;
|
|
}
|
|
|
|
OutputStream get outputStream() {
|
|
if (_outputStream === null) {
|
|
_outputStream = new SocketOutputStream(this);
|
|
}
|
|
return _outputStream;
|
|
}
|
|
|
|
SocketInputStream _inputStream;
|
|
SocketOutputStream _outputStream;
|
|
}
|
|
|