Extend dart:io error handling to all socket functions

There are currently no tests of the error handling, as it is hard to
create consistent tests. I have done some manual tests locally:

* Lowering the number of file descriptors available (ulimit -n) and hitting that limit
* Running two dart programs communicating and terminating one (using Ctrl-C)
* Running two dart programs communicating on two machines and pulling out the network cable.

If there is an error we always call the onError callback and never the onClosed callback.

On Windows there is the issue that both closing the connection correctly and terminating one end gives the same error (ERROR_NETNAME_DELETED) so both are reported as connection close. Pulling out the network cable gives a different (real) error on Windows though.

On Mac OS it turned out the for kqueue EV_EOF is also used to indicate errors with the error code set in the fflags field. EV_ERROR is only reported if there is an internal error in  kevent processing (see http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man2/kqueue.2.html).

R=ager@google.com

BUG=
TEST=

Review URL: https://chromiumcodereview.appspot.com//9720045

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@5709 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
sgjesse@google.com 2012-03-21 09:39:47 +00:00
parent d3d668d94b
commit 0b3f4a1190
17 changed files with 262 additions and 110 deletions

View file

@ -57,6 +57,7 @@
V(Socket_ReadList, 4) \
V(Socket_WriteList, 4) \
V(Socket_GetPort, 1) \
V(Socket_GetError, 1) \
V(Socket_GetStdioHandle, 2) \
V(Socket_NewServicePort, 0)

View file

@ -261,8 +261,14 @@ intptr_t EventHandlerImplementation::GetPollEvents(intptr_t events,
if ((events & EPOLLIN) != 0) {
if (FDUtils::AvailableBytes(sd->fd()) != 0) {
event_mask = (1 << kInEvent);
} else if (((events & EPOLLHUP) != 0)) {
event_mask = (1 << kCloseEvent);
} else if ((events & EPOLLHUP) != 0) {
// If both EPOLLHUP and EPOLLERR are reported treat it as an
// error.
if ((events & EPOLLERR) != 0) {
event_mask = (1 << kErrorEvent);
} else {
event_mask = (1 << kCloseEvent);
}
sd->MarkClosedRead();
} else if ((events & EPOLLERR) != 0) {
event_mask = (1 << kErrorEvent);

View file

@ -232,16 +232,16 @@ void EventHandlerImplementation::HandleInterruptFd() {
}
}
#ifdef DEBUG_KQUEUE
static void PrintEventMask(intptr_t fd, struct kevent* event) {
printf("%d ", fd);
printf("%d ", static_cast<int>(fd));
if (event->filter == EVFILT_READ) printf("EVFILT_READ ");
if (event->filter == EVFILT_WRITE) printf("EVFILT_WRITE ");
printf("flags: %x: ", event->flags);
if ((event->flags & EV_EOF) != 0) printf("EV_EOF ");
if ((event->flags & EV_ERROR) != 0) printf("EV_ERROR ");
printf("(available %d) ", FDUtils::AvailableBytes(fd));
printf("- fflags: %d ", event->fflags);
printf("(available %d) ", static_cast<int>(FDUtils::AvailableBytes(fd)));
printf("\n");
}
#endif
@ -257,8 +257,13 @@ intptr_t EventHandlerImplementation::GetEvents(struct kevent* event,
// On a listening socket the READ event means that there are
// connections ready to be accepted.
if (event->filter == EVFILT_READ) {
if ((event->flags & EV_EOF) != 0) event_mask |= (1 << kCloseEvent);
if ((event->flags & EV_ERROR) != 0) event_mask |= (1 << kErrorEvent);
if ((event->flags & EV_EOF) != 0) {
if (event->fflags != 0) {
event_mask |= (1 << kErrorEvent);
} else {
event_mask |= (1 << kCloseEvent);
}
}
if (event_mask == 0) event_mask |= (1 << kInEvent);
}
} else {
@ -267,18 +272,22 @@ intptr_t EventHandlerImplementation::GetEvents(struct kevent* event,
if (FDUtils::AvailableBytes(sd->fd()) != 0) {
event_mask = (1 << kInEvent);
} else if ((event->flags & EV_EOF) != 0) {
event_mask = (1 << kCloseEvent);
if (event->fflags != 0) {
event_mask |= (1 << kErrorEvent);
} else {
event_mask |= (1 << kCloseEvent);
}
sd->MarkClosedRead();
} else if ((event->flags & EV_ERROR) != 0) {
event_mask = (1 << kErrorEvent);
}
}
if (event->filter == EVFILT_WRITE) {
if ((event->flags & EV_ERROR) != 0) {
event_mask = (1 << kErrorEvent);
sd->MarkClosedWrite();
} else if ((event->flags & EV_EOF) != 0) {
if ((event->flags & EV_EOF) != 0) {
if (event->fflags != 0) {
event_mask |= (1 << kErrorEvent);
} else {
event_mask |= (1 << kCloseEvent);
}
// If the receiver closed for reading, close for writing,
// update the registration with kqueue, and do not report a
// write event.
@ -297,6 +306,10 @@ intptr_t EventHandlerImplementation::GetEvents(struct kevent* event,
void EventHandlerImplementation::HandleEvents(struct kevent* events,
int size) {
for (int i = 0; i < size; i++) {
// If flag EV_ERROR is set it indicates an error in kevent processing.
if ((events[i].flags & EV_ERROR) != 0) {
FATAL1("kevent failed %s\n", strerror(events[i].data));
}
if (events[i].udata != NULL) {
SocketData* sd = reinterpret_cast<SocketData*>(events[i].udata);
intptr_t event_mask = GetEvents(events + i, sd);
@ -360,8 +373,7 @@ void EventHandlerImplementation::EventHandlerEntry(uword args) {
kMaxEvents,
timeout));
if (result == -1) {
perror("kevent failed");
FATAL("kevent failed\n");
FATAL1("kevent failed %s\n", strerror(errno));
} else {
handler->HandleTimeout();
handler->HandleEvents(events, result);

View file

@ -99,7 +99,8 @@ Handle::Handle(HANDLE handle)
event_handler_(NULL),
data_ready_(NULL),
pending_read_(NULL),
pending_write_(NULL) {
pending_write_(NULL),
last_error_(NOERROR) {
InitializeCriticalSection(&cs_);
}
@ -112,7 +113,8 @@ Handle::Handle(HANDLE handle, Dart_Port port)
event_handler_(NULL),
data_ready_(NULL),
pending_read_(NULL),
pending_write_(NULL) {
pending_write_(NULL),
last_error_(NOERROR) {
InitializeCriticalSection(&cs_);
}
@ -721,6 +723,15 @@ void EventHandlerImplementation::HandleClosed(Handle* handle) {
}
void EventHandlerImplementation::HandleError(Handle* handle) {
handle->set_last_error(WSAGetLastError());
if (!handle->IsClosing()) {
int event_mask = 1 << kErrorEvent;
DartUtils::PostInt32(handle->port(), event_mask);
}
}
void EventHandlerImplementation::HandleRead(Handle* handle,
int bytes,
IOBuffer* buffer) {
@ -734,9 +745,12 @@ void EventHandlerImplementation::HandleRead(Handle* handle,
}
}
} else {
ASSERT(bytes == 0);
handle->MarkClosedRead();
HandleClosed(handle);
if (bytes == 0) {
HandleClosed(handle);
} else {
HandleError(handle);
}
}
if (handle->IsClosed()) {
@ -757,9 +771,10 @@ void EventHandlerImplementation::HandleWrite(Handle* handle,
DartUtils::PostInt32(handle->port(), event_mask);
}
}
} else {
ASSERT(bytes == 0);
} else if (bytes == 0) {
HandleClosed(handle);
} else {
HandleError(handle);
}
if (handle->IsClosed()) {
@ -862,9 +877,6 @@ static void EventHandlerThread(uword args) {
handler->HandleTimeout();
}
} else if (!ok) {
// If GetQueuedCompletionStatus return false and overlapped is
// not NULL then it did dequeue a request which failed.
// Treat ERROR_CONNECTION_ABORTED as connection closed.
// The error ERROR_OPERATION_ABORTED is set for pending
// accept requests for a listen socket which is closed.
@ -878,8 +890,9 @@ static void EventHandlerThread(uword args) {
ASSERT(bytes == 0);
handler->HandleIOCompletion(bytes, key, overlapped);
} else {
UNREACHABLE();
}
ASSERT(bytes == 0);
handler->HandleIOCompletion(-1, key, overlapped);
}
} else if (key == NULL) {
// A key of NULL signals an interrupt message.
InterruptMessage* msg = reinterpret_cast<InterruptMessage*>(overlapped);

View file

@ -198,6 +198,9 @@ class Handle {
void ReadSyncCompleteAsync();
DWORD last_error() { return last_error_; }
void set_last_error(DWORD last_error) { last_error_ = last_error; }
protected:
enum Flags {
kClosing = 0,
@ -222,6 +225,8 @@ class Handle {
IOBuffer* pending_read_; // IO buffer for pending read.
IOBuffer* pending_write_; // IO buffer for pending write
DWORD last_error_;
private:
int flags_;
CRITICAL_SECTION cs_; // Critical section protecting this object.
@ -349,6 +354,7 @@ class EventHandlerImplementation {
void HandleTimeout();
void HandleAccept(ListenSocket* listen_socket, IOBuffer* buffer);
void HandleClosed(Handle* handle);
void HandleError(Handle* handle);
void HandleRead(Handle* handle, int bytes, IOBuffer* buffer);
void HandleWrite(Handle* handle, int bytes, IOBuffer* buffer);
void HandleClose(ClientSocket* client_socket);

View file

@ -22,8 +22,12 @@ void FUNCTION_NAME(Socket_CreateConnect)(Dart_NativeArguments args) {
const char* host = DartUtils::GetStringValue(Dart_GetNativeArgument(args, 1));
int64_t port = DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 2));
intptr_t socket = Socket::CreateConnect(host, port);
DartUtils::SetIntegerField(socketobj, DartUtils::kIdFieldName, socket);
Dart_SetReturnValue(args, Dart_NewBoolean(socket >= 0));
if (socket >= 0) {
DartUtils::SetIntegerField(socketobj, DartUtils::kIdFieldName, socket);
Dart_SetReturnValue(args, Dart_True());
} else {
Dart_SetReturnValue(args, DartUtils::NewDartOSError());
}
Dart_ExitScope();
}
@ -71,7 +75,11 @@ void FUNCTION_NAME(Socket_ReadList)(Dart_NativeArguments args) {
}
}
delete[] buffer;
Dart_SetReturnValue(args, Dart_NewInteger(bytes_read));
if (bytes_read >= 0) {
Dart_SetReturnValue(args, Dart_NewInteger(bytes_read));
} else {
Dart_SetReturnValue(args, DartUtils::NewDartOSError());
}
Dart_ExitScope();
}
@ -120,7 +128,11 @@ void FUNCTION_NAME(Socket_WriteList)(Dart_NativeArguments args) {
total_bytes_written += bytes_written;
} while (bytes_written > 0 && total_bytes_written < length);
delete[] buffer;
Dart_SetReturnValue(args, Dart_NewInteger(total_bytes_written));
if (bytes_written >= 0) {
Dart_SetReturnValue(args, Dart_NewInteger(total_bytes_written));
} else {
Dart_SetReturnValue(args, DartUtils::NewDartOSError());
}
Dart_ExitScope();
}
@ -130,8 +142,25 @@ void FUNCTION_NAME(Socket_GetPort)(Dart_NativeArguments args) {
intptr_t socket =
DartUtils::GetIntegerField(Dart_GetNativeArgument(args, 0),
DartUtils::kIdFieldName);
OSError os_error;
intptr_t port = Socket::GetPort(socket);
Dart_SetReturnValue(args, Dart_NewInteger(port));
if (port > 0) {
Dart_SetReturnValue(args, Dart_NewInteger(port));
} else {
Dart_SetReturnValue(args, DartUtils::NewDartOSError());
}
Dart_ExitScope();
}
void FUNCTION_NAME(Socket_GetError)(Dart_NativeArguments args) {
Dart_EnterScope();
intptr_t socket =
DartUtils::GetIntegerField(Dart_GetNativeArgument(args, 0),
DartUtils::kIdFieldName);
OSError os_error;
Socket::GetError(socket, &os_error);
Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
Dart_ExitScope();
}
@ -160,9 +189,13 @@ void FUNCTION_NAME(ServerSocket_CreateBindListen)(Dart_NativeArguments args) {
DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 3));
intptr_t socket =
ServerSocket::CreateBindListen(bindAddress, port, backlog);
DartUtils::SetIntegerField(
socketobj, DartUtils::kIdFieldName, socket);
Dart_SetReturnValue(args, Dart_NewBoolean(socket >= 0));
if (socket >= 0) {
DartUtils::SetIntegerField(
socketobj, DartUtils::kIdFieldName, socket);
Dart_SetReturnValue(args, Dart_True());
} else {
Dart_SetReturnValue(args, DartUtils::NewDartOSError());
}
Dart_ExitScope();
}
@ -177,8 +210,10 @@ void FUNCTION_NAME(ServerSocket_Accept)(Dart_NativeArguments args) {
if (newSocket >= 0) {
DartUtils::SetIntegerField(
socketobj, DartUtils::kIdFieldName, newSocket);
Dart_SetReturnValue(args, Dart_True());
} else {
Dart_SetReturnValue(args, DartUtils::NewDartOSError());
}
Dart_SetReturnValue(args, Dart_NewBoolean(newSocket >= 0));
Dart_ExitScope();
}

View file

@ -134,7 +134,7 @@ class SocketIOException implements Exception {
sb.add(" ($osError)");
}
} else if (osError != null) {
sb.add(": osError");
sb.add(": $osError");
}
return sb.toString();
}

View file

@ -23,6 +23,7 @@ class Socket {
static int Write(intptr_t fd, const void* buffer, intptr_t num_bytes);
static intptr_t CreateConnect(const char* host, const intptr_t port);
static intptr_t GetPort(intptr_t fd);
static void GetError(intptr_t fd, OSError* os_error);
static intptr_t GetStdioHandle(int num);
// Perform a IPv4 hostname lookup. Returns the hostname string in

View file

@ -64,7 +64,7 @@ class _SocketBase {
continue;
}
if (i == _ERROR_EVENT) {
eventHandler(new SocketIOException(""));
eventHandler(new SocketIOException("", _getError()));
close();
} else {
eventHandler();
@ -96,6 +96,7 @@ class _SocketBase {
}
}
OSError _getError() native "Socket_GetError";
int _getPort() native "Socket_GetPort";
void set onError(void callback(Exception e)) {
@ -185,6 +186,34 @@ class _SocketBase {
_EventHandler._sendData(_id, _handler, data);
}
bool _reportError(error, String message) {
// For all errors we close the socket, call the error handler and
// disable further calls of the error handler.
close();
var onError = _handlerMap[_ERROR_EVENT];
if (onError != null) {
if (error is OSError) {
onError(new SocketIOException(message, error));
} else if (error is List) {
assert(_isErrorResponse(error));
switch (error[0]) {
case _FileUtils.kIllegalArgumentResponse:
onError(new IllegalArgumentException());
break;
case _FileUtils.kOSErrorResponse:
onError(new SocketIOException(
message, new OSError(error[2], error[1])));
break;
default:
onError(new Exception("Unknown error"));
break;
}
} else {
onError(new SocketIOException(message));
}
}
}
int hashCode() => _hashCode;
abstract bool _isListenSocket();
@ -224,10 +253,12 @@ class _ServerSocket extends _SocketBase implements ServerSocket {
// bind failed.
factory _ServerSocket(String bindAddress, int port, int backlog) {
_ServerSocket socket = new _ServerSocket._internal();
if (!socket._createBindListen(bindAddress, port, backlog)) {
var result = socket._createBindListen(bindAddress, port, backlog);
if (result is OSError) {
socket.close();
return null;
throw new SocketIOException("Failed to create server socket", result);
}
assert(result);
if (port != 0) {
socket._port = port;
}
@ -250,7 +281,12 @@ class _ServerSocket extends _SocketBase implements ServerSocket {
void _connectionHandler() {
if (_id >= 0) {
_Socket socket = new _Socket._internal();
if (_accept(socket)) _clientConnectionHandler(socket);
var result = _accept(socket);
if (result is OSError) {
_reportError(result, "Accept failed");
} else {
_clientConnectionHandler(socket);
}
}
}
@ -280,10 +316,11 @@ class _Socket extends _SocketBase implements Socket {
_socketService.call(request).then((response) {
if (socket._isErrorResponse(response)) {
socket._reportError(response, "Failed host name lookup");
} else {
if (!socket._createConnect(response, port)) {
} else{
var result = socket._createConnect(response, port);
if (result is OSError) {
socket.close();
socket._reportError(null, "Connection failed");
socket._reportError(result, "Connection failed");
} else {
socket._activateHandlers();
}
@ -321,8 +358,9 @@ class _Socket extends _SocketBase implements Socket {
throw new IndexOutOfRangeException(offset + bytes);
}
int result = _readList(buffer, offset, bytes);
if (result < 0) {
_reportError(null, "Read failed");
if (result is OSError) {
_reportError(result, "Read failed");
return -1;
}
return result;
}
@ -368,17 +406,16 @@ class _Socket extends _SocketBase implements Socket {
j++;
}
}
var bytes_written = _writeList(outBuffer, outOffset, bytes);
if (bytes_written < 0) {
var result = _writeList(outBuffer, outOffset, bytes);
if (result is OSError) {
// If writing fails we return 0 as the number of bytes and
// report the error on the error handler.
bytes_written = 0;
_reportError(null, "Write failed");
result = 0;
_reportError(result, "Write failed");
}
return bytes_written;
return result;
}
throw new
SocketIOException("Error: writeList failed - invalid socket handle");
throw new SocketIOException("writeList failed - invalid socket handle");
}
int _writeList(List<int> buffer, int offset, int bytes)
@ -388,34 +425,6 @@ class _Socket extends _SocketBase implements Socket {
return response is List && response[0] != _FileUtils.kSuccessResponse;
}
bool _reportError(response, String message) {
if (response != null) {
assert(_isErrorResponse(response));
}
// For all errors we close the socket, call the error handler and
// disable further calls of the error handler.
close();
var onError = _handlerMap[_ERROR_EVENT];
if (onError != null) {
if (response != null) {
switch (response[0]) {
case _FileUtils.kIllegalArgumentResponse:
onError(new IllegalArgumentException());
break;
case _FileUtils.kOSErrorResponse:
onError(new SocketIOException(
message, new OSError(response[2], response[1])));
break;
default:
onError(new Exception("Unknown error"));
break;
}
} else {
onError(new SocketIOException(message));
}
}
}
bool _createConnect(String host, int port) native "Socket_CreateConnect";
void set onWrite(void callback()) {

View file

@ -95,13 +95,23 @@ intptr_t Socket::GetPort(intptr_t fd) {
getsockname(fd,
reinterpret_cast<struct sockaddr *>(&socket_address),
&size))) {
fprintf(stderr, "Error getsockname: %s\n", strerror(errno));
return 0;
}
return ntohs(socket_address.sin_port);
}
void Socket::GetError(intptr_t fd, OSError* os_error) {
int len = sizeof(errno);
getsockopt(fd,
SOL_SOCKET,
SO_ERROR,
&errno,
reinterpret_cast<socklen_t*>(&len));
os_error->SetCodeAndMessage(OSError::kSystem, errno);
}
intptr_t Socket::GetStdioHandle(int num) {
return static_cast<intptr_t>(num);
}
@ -121,8 +131,6 @@ const char* Socket::LookupIPv4Address(char* host, OSError** os_error) {
*os_error = new OSError(status,
gai_strerror(status),
OSError::kGetAddressInfo);
(*os_error)->set_code(status);
(*os_error)->SetMessage(gai_strerror(status));
return NULL;
}
// Convert the address into IPv4 dotted decimal notation.

View file

@ -102,6 +102,17 @@ intptr_t Socket::GetPort(intptr_t fd) {
}
void Socket::GetError(intptr_t fd, OSError* os_error) {
int len = sizeof(errno);
getsockopt(fd,
SOL_SOCKET,
SO_ERROR,
&errno,
reinterpret_cast<socklen_t*>(&len));
os_error->SetCodeAndMessage(OSError::kSystem, errno);
}
intptr_t Socket::GetStdioHandle(int num) {
return static_cast<intptr_t>(num);
}
@ -121,8 +132,6 @@ const char* Socket::LookupIPv4Address(char* host, OSError** os_error) {
*os_error = new OSError(status,
gai_strerror(status),
OSError::kGetAddressInfo);
(*os_error)->set_code(status);
(*os_error)->SetMessage(gai_strerror(status));
return NULL;
}
// Convert the address into IPv4 dotted decimal notation.

View file

@ -57,7 +57,6 @@ intptr_t Socket::GetPort(intptr_t fd) {
intptr_t Socket::CreateConnect(const char* host, const intptr_t port) {
SOCKET s = socket(AF_INET, SOCK_STREAM, 0);
if (s == INVALID_SOCKET) {
fprintf(stderr, "Error CreateConnect: %d\n", WSAGetLastError());
return -1;
}
@ -82,7 +81,6 @@ intptr_t Socket::CreateConnect(const char* host, const intptr_t port) {
struct addrinfo* result = NULL;
status = getaddrinfo(host, 0, &hints, &result);
if (status != NO_ERROR) {
fprintf(stderr, "getaddrinfo failed with error: %d\n", status);
return -1;
}
@ -98,8 +96,9 @@ intptr_t Socket::CreateConnect(const char* host, const intptr_t port) {
reinterpret_cast<struct sockaddr*>(&server_address),
sizeof(server_address));
if (status == SOCKET_ERROR) {
fprintf(stderr, "Error CreateConnect: %d\n", WSAGetLastError());
DWORD rc = WSAGetLastError();
closesocket(s);
SetLastError(rc);
return -1;
}
@ -108,6 +107,12 @@ intptr_t Socket::CreateConnect(const char* host, const intptr_t port) {
}
void Socket::GetError(intptr_t fd, OSError* os_error) {
Handle* handle = reinterpret_cast<Handle*>(fd);
os_error->SetCodeAndMessage(OSError::kSystem, handle->last_error());
}
intptr_t Socket::GetStdioHandle(int num) {
HANDLE handle;
switch (num) {
@ -123,7 +128,6 @@ intptr_t Socket::GetStdioHandle(int num) {
default: UNREACHABLE();
}
if (handle == INVALID_HANDLE_VALUE) {
fprintf(stderr, "Error GetStdHandle: %d\n", GetLastError());
return -1;
}
FileHandle* file_handle = new FileHandle(handle);
@ -158,8 +162,6 @@ const char* Socket::LookupIPv4Address(char* host, OSError** os_error) {
*os_error = new OSError(status,
gai_strerror(status),
OSError::kGetAddressInfo);
(*os_error)->set_code(status);
(*os_error)->SetMessage(gai_strerror(status));
return NULL;
}
// Convert the address into IPv4 dotted decimal notation.
@ -183,7 +185,6 @@ intptr_t ServerSocket::CreateBindListen(const char* host,
intptr_t backlog) {
SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s == INVALID_SOCKET) {
fprintf(stderr, "Error CreateBindListen: %d\n", WSAGetLastError());
return -1;
}
@ -194,8 +195,9 @@ intptr_t ServerSocket::CreateBindListen(const char* host,
reinterpret_cast<const char*>(&optval),
sizeof(optval));
if (status == SOCKET_ERROR) {
fprintf(stderr, "Error CreateBindListen: %d\n", WSAGetLastError());
DWORD rc = WSAGetLastError();
closesocket(s);
SetLastError(rc);
return -1;
}
@ -208,15 +210,17 @@ intptr_t ServerSocket::CreateBindListen(const char* host,
reinterpret_cast<struct sockaddr *>(&addr),
sizeof(addr));
if (status == SOCKET_ERROR) {
fprintf(stderr, "Error CreateBindListen: %d\n", WSAGetLastError());
DWORD rc = WSAGetLastError();
closesocket(s);
SetLastError(rc);
return -1;
}
status = listen(s, backlog);
if (status == SOCKET_ERROR) {
fprintf(stderr, "Error socket listen: %d\n", WSAGetLastError());
DWORD rc = WSAGetLastError();
closesocket(s);
SetLastError(rc);
return -1;
}

View file

@ -29,10 +29,13 @@ class OSError {
virtual ~OSError() { free(message_); }
SubSystem sub_system() { return sub_system_; }
void set_sub_system(SubSystem sub_system) { sub_system_ = sub_system; }
int code() { return code_; }
void set_code(int code) { code_ = code; }
char* message() { return message_; }
void SetCodeAndMessage(SubSystem sub_system, int code);
private:
void set_sub_system(SubSystem sub_system) { sub_system_ = sub_system; }
void set_code(int code) { code_ = code; }
void SetMessage(const char* message) {
free(message_);
if (message == NULL) {
@ -42,7 +45,6 @@ class OSError {
}
}
private:
SubSystem sub_system_;
int code_;
char* message_;

View file

@ -3,11 +3,26 @@
// BSD-style license that can be found in the LICENSE file.
#include <errno.h>
#include <netdb.h>
#include "bin/utils.h"
#include "platform/assert.h"
OSError::OSError() : sub_system_(kSystem), code_(0), message_(NULL) {
set_sub_system(kSystem);
set_code(errno);
SetMessage(strerror(errno));
}
void OSError::SetCodeAndMessage(SubSystem sub_system, int code) {
set_sub_system(sub_system);
set_code(code);
if (sub_system == kSystem) {
SetMessage(strerror(code));
} else if (sub_system == kGetAddressInfo) {
SetMessage(gai_strerror(code));
} else {
UNREACHABLE();
}
}

View file

@ -3,11 +3,26 @@
// BSD-style license that can be found in the LICENSE file.
#include <errno.h>
#include <netdb.h>
#include "bin/utils.h"
#include "platform/assert.h"
OSError::OSError() : sub_system_(kSystem), code_(0), message_(NULL) {
set_sub_system(kSystem);
set_code(errno);
SetMessage(strerror(errno));
}
void OSError::SetCodeAndMessage(SubSystem sub_system, int code) {
set_sub_system(sub_system);
set_code(code);
if (sub_system == kSystem) {
SetMessage(strerror(code));
} else if (sub_system == kGetAddressInfo) {
SetMessage(gai_strerror(code));
} else {
UNREACHABLE();
}
}

View file

@ -6,26 +6,42 @@
#include "bin/utils.h"
OSError::OSError() : sub_system_(kSystem), code_(0), message_(NULL) {
set_code(GetLastError());
static const int kMaxMessageLength = 256;
char message[kMaxMessageLength];
static void FormatMessageIntoBuffer(DWORD code,
char* buffer,
int buffer_length) {
DWORD message_size =
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
code_,
code,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
message,
kMaxMessageLength,
buffer,
buffer_length,
NULL);
if (message_size == 0) {
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
fprintf(stderr, "FormatMessage failed %d\n", GetLastError());
}
snprintf(message, kMaxMessageLength, "OS Error %d", code_);
snprintf(buffer, buffer_length, "OS Error %d", code);
}
message[kMaxMessageLength - 1] = '\0';
buffer[buffer_length - 1] = '\0';
}
OSError::OSError() : sub_system_(kSystem), code_(0), message_(NULL) {
set_code(GetLastError());
static const int kMaxMessageLength = 256;
char message[kMaxMessageLength];
FormatMessageIntoBuffer(code_, message, kMaxMessageLength);
SetMessage(message);
}
void OSError::SetCodeAndMessage(SubSystem sub_system, int code) {
set_sub_system(sub_system);
set_code(code);
static const int kMaxMessageLength = 256;
char message[kMaxMessageLength];
FormatMessageIntoBuffer(code_, message, kMaxMessageLength);
SetMessage(message);
}

View file

@ -300,7 +300,7 @@ class SocketCloseServer extends Isolate {
}
void errorHandler(Exception e) {
Expect.fail("Socket error");
Expect.fail("Socket error $e");
}
_iterations++;