platform/lib/src/bind_socket.cc
2018-07-08 18:59:51 -04:00

203 lines
No EOL
7 KiB
C++

#include <cstring>
#include <mutex>
#include <vector>
#include "wings.h"
std::vector<WingsServerInfo *> serverInfoVector;
std::mutex serverInfoVectorMutex;
void wings_BindSocket(Dart_NativeArguments arguments)
{
// Uint8List address, String addressString, int port, int backlog, bool shared
Dart_Handle addressHandle = Dart_GetNativeArgument(arguments, 0);
Dart_Handle addressStringHandle = Dart_GetNativeArgument(arguments, 1);
Dart_Handle portHandle = Dart_GetNativeArgument(arguments, 2);
Dart_Handle backlogHandle = Dart_GetNativeArgument(arguments, 3);
Dart_Handle sharedHandle = Dart_GetNativeArgument(arguments, 4);
Dart_TypedData_Type addressType;
void *addressData;
intptr_t addressLength;
const char *addressString;
uint64_t port, backlog;
bool shared;
// Read the arguments...
HandleError(Dart_TypedDataAcquireData(addressHandle, &addressType, &addressData, &addressLength));
HandleError(Dart_TypedDataReleaseData(addressHandle));
HandleError(Dart_StringToCString(addressStringHandle, &addressString));
HandleError(Dart_IntegerToUint64(portHandle, &port));
HandleError(Dart_IntegerToUint64(backlogHandle, &backlog));
HandleError(Dart_BooleanValue(sharedHandle, &shared));
// See if there is already a server bound to the port.
long existingIndex = -1;
std::string addressStringInstance(addressString);
std::lock_guard<std::mutex> lock(serverInfoVectorMutex);
#if __APPLE__
if (false)
#else
if (shared)
#endif
{
for (unsigned long i = 0; i < serverInfoVector.size(); i++)
{
WingsServerInfo *server_info = serverInfoVector.at(i);
if (server_info->addressString == addressStringInstance && server_info->port == port)
{
existingIndex = (long)i;
break;
}
}
}
if (existingIndex > -1)
{
// We found an existing socket, just return a reference to it.
Dart_SetReturnValue(arguments, Dart_NewIntegerFromUint64(existingIndex));
return;
}
else
{
// There's no existing server, so bind a new one, and add it to the serverInfoVector.
#ifndef WIN32
int sockfd;
#else
WSADATA wsaData;
SOCKET ConnectSocket = INVALID_SOCKET;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0)
{
Dart_Handle errorHandle = Dart_NewList(2);
Dart_ListSetAt(errorHandle, 0, Dart_NewStringFromCString("WSAStartup failed."));
Dart_ListSetAt(errorHandle, 1, Dart_NewInteger(iResult));
Dart_ThrowException(errorHandle);
return 1;
}
// TODO: Rest of Windows config:
// https://docs.microsoft.com/en-us/windows/desktop/winsock/complete-client-code
#endif
if (addressLength == 4)
{
// IPv4
sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
}
else
{
// IPv6
sockfd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
}
if (sockfd < 0)
{
Dart_Handle errorHandle = Dart_NewList(3);
Dart_ListSetAt(errorHandle, 0, Dart_NewStringFromCString("Failed to create socket."));
Dart_ListSetAt(errorHandle, 1, Dart_NewStringFromCString(strerror(errno)));
Dart_ListSetAt(errorHandle, 2, Dart_NewInteger(errno));
Dart_ThrowException(errorHandle);
return;
}
int i = 1;
int ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
if (ret < 0)
{
Dart_Handle errorHandle = Dart_NewList(3);
Dart_ListSetAt(errorHandle, 0, Dart_NewStringFromCString("Cannot reuse address for socket."));
Dart_ListSetAt(errorHandle, 1, Dart_NewStringFromCString(strerror(errno)));
Dart_ListSetAt(errorHandle, 2, Dart_NewInteger(errno));
Dart_ThrowException(errorHandle);
return;
}
#if __APPLE__
ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &i, sizeof(i));
if (ret < 0)
{
Dart_ThrowException(Dart_NewStringFromCString("Cannot reuse port for socket."));
return;
}
#endif
if (addressLength > 4)
{
struct sockaddr_in6 v6
{
};
memset(&v6, 0, sizeof(v6));
v6.sin6_family = AF_INET6;
v6.sin6_port = htons((uint16_t)port);
ret = inet_pton(v6.sin6_family, addressString, &v6.sin6_addr.s6_addr);
if (ret >= 0)
ret = bind(sockfd, (const sockaddr *)&v6, sizeof(v6));
}
else
{
struct sockaddr_in v4
{
};
memset(&v4, 0, sizeof(v4));
v4.sin_family = AF_INET;
v4.sin_port = htons((uint16_t)port);
v4.sin_addr.s_addr = inet_addr(addressString);
if (ret >= 0)
ret = bind(sockfd, (const sockaddr *)&v4, sizeof(v4));
//ret = inet_pton(family, host, &v4.sin_addr);
}
/*if (ret < 1) {
Dart_ThrowException(Dart_NewStringFromCString("Cannot parse IP address."));
return;
}*/
//if (bind(sock, (const sockaddr *) &serveraddr, sizeof(serveraddr)) < 0) {
if (ret < 0)
{
Dart_Handle errorHandle = Dart_NewList(3);
Dart_ListSetAt(errorHandle, 0, Dart_NewStringFromCString("Failed to bind socket."));
Dart_ListSetAt(errorHandle, 1, Dart_NewStringFromCString(strerror(errno)));
Dart_ListSetAt(errorHandle, 2, Dart_NewInteger(errno));
Dart_ThrowException(errorHandle);
return;
}
if (listen(sockfd, SOMAXCONN) < 0)
{
Dart_Handle errorHandle = Dart_NewList(3);
Dart_ListSetAt(errorHandle, 0, Dart_NewStringFromCString("Failed to listen to bound socket."));
Dart_ListSetAt(errorHandle, 1, Dart_NewStringFromCString(strerror(errno)));
Dart_ListSetAt(errorHandle, 2, Dart_NewInteger(errno));
Dart_ThrowException(errorHandle);
return;
}
if (listen(sockfd, (int)backlog) < 0)
{
Dart_Handle errorHandle = Dart_NewList(3);
Dart_ListSetAt(errorHandle, 0, Dart_NewStringFromCString("Failed to listen to bound socket."));
Dart_ListSetAt(errorHandle, 1, Dart_NewStringFromCString(strerror(errno)));
Dart_ListSetAt(errorHandle, 2, Dart_NewInteger(errno));
Dart_ThrowException(errorHandle);
return;
}
// Now that we've bound the socket, let's add it to the list.
auto *server_info = new WingsServerInfo;
server_info->sockfd = sockfd;
server_info->port = port;
server_info->ipv6 = addressLength > 4;
server_info->addressString += addressStringInstance;
Dart_SetReturnValue(arguments, Dart_NewIntegerFromUint64(serverInfoVector.size()));
serverInfoVector.push_back(server_info);
}
}