Files
sdk/runtime/bin/socket.cc
T
asiva@google.com ebbb7c4134 - Represent strings internally in UTF-16 format, this makes it
compatible with webkit and will allow for easy externalization of
  strings. One byte strings are retained for pure ASCII strings.
  (The language specification was changed recently to reflect this as
   follows "A string is a sequence of UTF-16 code units").
- Remove four byte string class and all references to it.
- Rename some of the string functions in Dart API to make them
  consistent and better describe the underlying functionality
  Dart_NewString => Dart_NewStringFromCString
  Dart_NewString8 => Dart_NewStringFromUTF8
  Dart_NewString16 => Dart_NewStringFromUTF16
  Dart_NewString32 => Dart_NewStringFromUTF32
  Dart_NewExternalString8 => Dart_NewExternalUTF8String
  Dart_NewExternalString16 => Dart_NewExternalUTF16String
  Dart_NewExternalString32 => Dart_NewExternalUTF32String
  Dart_StringGet8 => Dart_StringToUTF8
  Dart_StringGet16 => Dart_StringToUTF16
  Dart_StringToCString => Dart_StringToCString
  Dart_IsString8 => Removed
  Dart_IsString16 -> Removed
  Dart_StringToBytes -> Removed
  Dart_StringGet32 -> Removed
Review URL: https://codereview.chromium.org//11318018

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@14357 260f80e4-7a28-3924-810f-c04153c831b5
2012-10-31 17:56:46 +00:00

413 lines
14 KiB
C++

// Copyright (c) 2012, 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.
#include "bin/io_buffer.h"
#include "bin/socket.h"
#include "bin/dartutils.h"
#include "bin/thread.h"
#include "bin/utils.h"
#include "platform/globals.h"
#include "platform/thread.h"
#include "platform/utils.h"
#include "include/dart_api.h"
static const int kSocketIdNativeField = 0;
dart::Mutex Socket::mutex_;
int Socket::service_ports_size_ = 0;
Dart_Port* Socket::service_ports_ = NULL;
int Socket::service_ports_index_ = 0;
void FUNCTION_NAME(Socket_CreateConnect)(Dart_NativeArguments args) {
Dart_EnterScope();
Dart_Handle socket_obj = Dart_GetNativeArgument(args, 0);
const char* host = DartUtils::GetStringValue(Dart_GetNativeArgument(args, 1));
int64_t port = 0;
if (DartUtils::GetInt64Value(Dart_GetNativeArgument(args, 2), &port)) {
intptr_t socket = Socket::CreateConnect(host, port);
if (socket >= 0) {
Socket::SetSocketIdNativeField(socket_obj, socket);
Dart_SetReturnValue(args, Dart_True());
} else {
Dart_SetReturnValue(args, DartUtils::NewDartOSError());
}
} else {
OSError os_error(-1, "Invalid argument", OSError::kUnknown);
Dart_Handle err = DartUtils::NewDartOSError(&os_error);
if (Dart_IsError(err)) Dart_PropagateError(err);
Dart_SetReturnValue(args, err);
}
Dart_ExitScope();
}
void FUNCTION_NAME(Socket_Available)(Dart_NativeArguments args) {
Dart_EnterScope();
Dart_Handle socket_obj = Dart_GetNativeArgument(args, 0);
intptr_t socket = 0;
Socket::GetSocketIdNativeField(socket_obj, &socket);
intptr_t available = Socket::Available(socket);
if (available >= 0) {
Dart_SetReturnValue(args, Dart_NewInteger(available));
} else {
Dart_SetReturnValue(args, DartUtils::NewDartOSError());
}
Dart_ExitScope();
}
void FUNCTION_NAME(Socket_Read)(Dart_NativeArguments args) {
Dart_EnterScope();
Dart_Handle socket_obj = Dart_GetNativeArgument(args, 0);
intptr_t socket = 0;
Socket::GetSocketIdNativeField(socket_obj, &socket);
intptr_t available = Socket::Available(socket);
if (available > 0) {
int64_t length = 0;
Dart_Handle length_obj = Dart_GetNativeArgument(args, 1);
if (DartUtils::GetInt64Value(length_obj, &length)) {
if (length == -1 || available < length) {
length = available;
}
uint8_t* buffer = NULL;
Dart_Handle result = IOBuffer::Allocate(length, &buffer);
if (Dart_IsError(result)) Dart_PropagateError(result);
ASSERT(buffer != NULL);
intptr_t bytes_read = Socket::Read(socket, buffer, length);
if (bytes_read == length) {
Dart_SetReturnValue(args, result);
} else if (bytes_read == 0) {
// On MacOS when reading from a tty Ctrl-D will result in one
// byte reported as available. Attempting to read it out will
// result in zero bytes read. When that happens there is no
// data which is indicated by a null return value.
Dart_SetReturnValue(args, Dart_Null());
} else {
ASSERT(bytes_read == -1);
Dart_SetReturnValue(args, DartUtils::NewDartOSError());
}
} else {
OSError os_error(-1, "Invalid argument", OSError::kUnknown);
Dart_Handle err = DartUtils::NewDartOSError(&os_error);
if (Dart_IsError(err)) Dart_PropagateError(err);
Dart_SetReturnValue(args, err);
}
} else if (available == 0) {
Dart_SetReturnValue(args, Dart_Null());
} else {
Dart_SetReturnValue(args, DartUtils::NewDartOSError());
}
Dart_ExitScope();
}
void FUNCTION_NAME(Socket_ReadList)(Dart_NativeArguments args) {
Dart_EnterScope();
Dart_Handle socket_obj = Dart_GetNativeArgument(args, 0);
intptr_t socket = 0;
Socket::GetSocketIdNativeField(socket_obj, &socket);
Dart_Handle buffer_obj = Dart_GetNativeArgument(args, 1);
int64_t offset = 0;
int64_t length = 0;
Dart_Handle offset_obj = Dart_GetNativeArgument(args, 2);
Dart_Handle length_obj = Dart_GetNativeArgument(args, 3);
if (Dart_IsList(buffer_obj) &&
DartUtils::GetInt64Value(offset_obj, &offset) &&
DartUtils::GetInt64Value(length_obj, &length)) {
intptr_t buffer_len = 0;
Dart_Handle result = Dart_ListLength(buffer_obj, &buffer_len);
if (Dart_IsError(result)) {
Dart_PropagateError(result);
}
ASSERT((offset + length) <= buffer_len);
if (Dart_IsVMFlagSet("short_socket_read")) {
length = (length + 1) / 2;
}
uint8_t* buffer = new uint8_t[length];
intptr_t bytes_read = Socket::Read(socket, buffer, length);
if (bytes_read > 0) {
Dart_Handle result =
Dart_ListSetAsBytes(buffer_obj, offset, buffer, bytes_read);
if (Dart_IsError(result)) {
delete[] buffer;
Dart_PropagateError(result);
}
}
delete[] buffer;
if (bytes_read >= 0) {
Dart_SetReturnValue(args, Dart_NewInteger(bytes_read));
} else {
Dart_SetReturnValue(args, DartUtils::NewDartOSError());
}
} else {
OSError os_error(-1, "Invalid argument", OSError::kUnknown);
Dart_Handle err = DartUtils::NewDartOSError(&os_error);
if (Dart_IsError(err)) Dart_PropagateError(err);
Dart_SetReturnValue(args, err);
}
Dart_ExitScope();
}
void FUNCTION_NAME(Socket_WriteList)(Dart_NativeArguments args) {
Dart_EnterScope();
Dart_Handle socket_obj = Dart_GetNativeArgument(args, 0);
intptr_t socket = 0;
Socket::GetSocketIdNativeField(socket_obj, &socket);
Dart_Handle buffer_obj = Dart_GetNativeArgument(args, 1);
ASSERT(Dart_IsList(buffer_obj));
intptr_t offset =
DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 2));
intptr_t length =
DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 3));
intptr_t buffer_len = 0;
Dart_Handle result = Dart_ListLength(buffer_obj, &buffer_len);
if (Dart_IsError(result)) {
Dart_PropagateError(result);
}
ASSERT((offset + length) <= buffer_len);
if (Dart_IsVMFlagSet("short_socket_write")) {
length = (length + 1) / 2;
}
// Send data in chunks of maximum 16KB.
const intptr_t max_chunk_length =
dart::Utils::Minimum(length, static_cast<intptr_t>(16 * KB));
uint8_t* buffer = new uint8_t[max_chunk_length];
intptr_t total_bytes_written = 0;
intptr_t bytes_written = 0;
do {
intptr_t chunk_length =
dart::Utils::Minimum(max_chunk_length, length - total_bytes_written);
result = Dart_ListGetAsBytes(buffer_obj,
offset + total_bytes_written,
buffer,
chunk_length);
if (Dart_IsError(result)) {
delete[] buffer;
Dart_PropagateError(result);
}
bytes_written =
Socket::Write(socket, reinterpret_cast<void*>(buffer), chunk_length);
total_bytes_written += bytes_written;
} while (bytes_written > 0 && total_bytes_written < length);
delete[] buffer;
if (bytes_written >= 0) {
Dart_SetReturnValue(args, Dart_NewInteger(total_bytes_written));
} else {
Dart_SetReturnValue(args, DartUtils::NewDartOSError());
}
Dart_ExitScope();
}
void FUNCTION_NAME(Socket_GetPort)(Dart_NativeArguments args) {
Dart_EnterScope();
Dart_Handle socket_obj = Dart_GetNativeArgument(args, 0);
intptr_t socket = 0;
Socket::GetSocketIdNativeField(socket_obj, &socket);
OSError os_error;
intptr_t port = Socket::GetPort(socket);
if (port > 0) {
Dart_SetReturnValue(args, Dart_NewInteger(port));
} else {
Dart_SetReturnValue(args, DartUtils::NewDartOSError());
}
Dart_ExitScope();
}
void FUNCTION_NAME(Socket_GetRemotePeer)(Dart_NativeArguments args) {
Dart_EnterScope();
Dart_Handle socket_obj = Dart_GetNativeArgument(args, 0);
intptr_t socket = 0;
Socket::GetSocketIdNativeField(socket_obj, &socket);
OSError os_error;
intptr_t port = 0;
char host[INET_ADDRSTRLEN];
if (Socket::GetRemotePeer(socket, host, &port)) {
Dart_Handle list = Dart_NewList(2);
Dart_ListSetAt(list, 0, Dart_NewStringFromCString(host));
Dart_ListSetAt(list, 1, Dart_NewInteger(port));
Dart_SetReturnValue(args, list);
} else {
Dart_SetReturnValue(args, DartUtils::NewDartOSError());
}
Dart_ExitScope();
}
void FUNCTION_NAME(Socket_GetError)(Dart_NativeArguments args) {
Dart_EnterScope();
Dart_Handle socket_obj = Dart_GetNativeArgument(args, 0);
intptr_t socket = 0;
Socket::GetSocketIdNativeField(socket_obj, &socket);
OSError os_error;
Socket::GetError(socket, &os_error);
Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
Dart_ExitScope();
}
void FUNCTION_NAME(Socket_GetStdioHandle)(Dart_NativeArguments args) {
Dart_EnterScope();
Dart_Handle socket_obj = Dart_GetNativeArgument(args, 0);
intptr_t num =
DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 1));
ASSERT(num == 0 || num == 1 || num == 2);
intptr_t socket = Socket::GetStdioHandle(num);
Socket::SetSocketIdNativeField(socket_obj, socket);
Dart_SetReturnValue(args, Dart_NewBoolean(socket >= 0));
Dart_ExitScope();
}
void FUNCTION_NAME(ServerSocket_CreateBindListen)(Dart_NativeArguments args) {
Dart_EnterScope();
Dart_Handle socket_obj = Dart_GetNativeArgument(args, 0);
Dart_Handle bind_address_obj = Dart_GetNativeArgument(args, 1);
Dart_Handle port_obj = Dart_GetNativeArgument(args, 2);
Dart_Handle backlog_obj = Dart_GetNativeArgument(args, 3);
int64_t port = 0;
int64_t backlog = 0;
if (Dart_IsString(bind_address_obj) &&
DartUtils::GetInt64Value(port_obj, &port) &&
DartUtils::GetInt64Value(backlog_obj, &backlog)) {
const char* bind_address = DartUtils::GetStringValue(bind_address_obj);
intptr_t socket =
ServerSocket::CreateBindListen(bind_address, port, backlog);
if (socket >= 0) {
Socket::SetSocketIdNativeField(socket_obj, socket);
Dart_SetReturnValue(args, Dart_True());
} else {
if (socket == -5) {
OSError os_error(-1, "Invalid host", OSError::kUnknown);
Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
} else {
Dart_SetReturnValue(args, DartUtils::NewDartOSError());
}
}
} else {
OSError os_error(-1, "Invalid argument", OSError::kUnknown);
Dart_Handle err = DartUtils::NewDartOSError(&os_error);
if (Dart_IsError(err)) Dart_PropagateError(err);
Dart_SetReturnValue(args, err);
}
Dart_ExitScope();
}
void FUNCTION_NAME(ServerSocket_Accept)(Dart_NativeArguments args) {
Dart_EnterScope();
Dart_Handle socket_obj = Dart_GetNativeArgument(args, 0);
intptr_t socket = 0;
Socket::GetSocketIdNativeField(socket_obj, &socket);
Dart_Handle result_socket_obj = Dart_GetNativeArgument(args, 1);
intptr_t new_socket = ServerSocket::Accept(socket);
if (new_socket >= 0) {
Socket::SetSocketIdNativeField(result_socket_obj, new_socket);
Dart_SetReturnValue(args, Dart_True());
} else if (new_socket == ServerSocket::kTemporaryFailure) {
Dart_SetReturnValue(args, Dart_False());
} else {
Dart_SetReturnValue(args, DartUtils::NewDartOSError());
}
Dart_ExitScope();
}
static CObject* LookupRequest(const CObjectArray& request) {
if (request.Length() == 2 && request[1]->IsString()) {
CObjectString host(request[1]);
CObject* result = NULL;
OSError* os_error = NULL;
const char* ip_address =
Socket::LookupIPv4Address(host.CString(), &os_error);
if (ip_address != NULL) {
result = new CObjectString(CObject::NewString(ip_address));
free(const_cast<char*>(ip_address));
} else {
result = CObject::NewOSError(os_error);
delete os_error;
}
return result;
}
return CObject::IllegalArgumentError();
}
void SocketService(Dart_Port dest_port_id,
Dart_Port reply_port_id,
Dart_CObject* message) {
CObject* response = CObject::False();
CObjectArray request(message);
if (message->type == Dart_CObject::kArray) {
if (request.Length() > 1 && request[0]->IsInt32()) {
CObjectInt32 request_type(request[0]);
switch (request_type.Value()) {
case Socket::kLookupRequest:
response = LookupRequest(request);
break;
default:
UNREACHABLE();
}
}
}
Dart_PostCObject(reply_port_id, response->AsApiCObject());
}
Dart_Port Socket::GetServicePort() {
MutexLocker lock(&mutex_);
if (service_ports_size_ == 0) {
ASSERT(service_ports_ == NULL);
service_ports_size_ = 16;
service_ports_ = new Dart_Port[service_ports_size_];
service_ports_index_ = 0;
for (int i = 0; i < service_ports_size_; i++) {
service_ports_[i] = ILLEGAL_PORT;
}
}
Dart_Port result = service_ports_[service_ports_index_];
if (result == ILLEGAL_PORT) {
result = Dart_NewNativePort("SocketService",
SocketService,
true);
ASSERT(result != ILLEGAL_PORT);
service_ports_[service_ports_index_] = result;
}
service_ports_index_ = (service_ports_index_ + 1) % service_ports_size_;
return result;
}
void FUNCTION_NAME(Socket_NewServicePort)(Dart_NativeArguments args) {
Dart_EnterScope();
Dart_SetReturnValue(args, Dart_Null());
Dart_Port service_port = Socket::GetServicePort();
if (service_port != ILLEGAL_PORT) {
// Return a send port for the service port.
Dart_Handle send_port = Dart_NewSendPort(service_port);
Dart_SetReturnValue(args, send_port);
}
Dart_ExitScope();
}
Dart_Handle Socket::SetSocketIdNativeField(Dart_Handle socket, intptr_t id) {
return Dart_SetNativeInstanceField(socket, kSocketIdNativeField, id);
}
Dart_Handle Socket::GetSocketIdNativeField(Dart_Handle socket, intptr_t* id) {
return Dart_GetNativeInstanceField(socket, kSocketIdNativeField, id);
}