|
|
|
|
@@ -19,18 +19,37 @@ ResultType(int64_t, objectPtr) impl_Socket_INIT(int64_t* args, CometVM* vm) {
|
|
|
|
|
|
|
|
|
|
self->fields[0] = fd;
|
|
|
|
|
self->fields[1] = family;
|
|
|
|
|
self->fields[2] = type;
|
|
|
|
|
|
|
|
|
|
return Success(int64_t, objectPtr, (int64_t)self);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct sockaddr_in createIPV4Address(int family, char* ip, int port) {
|
|
|
|
|
struct sockaddr_in address;
|
|
|
|
|
typedef struct sockaddr_in SocketAddress;
|
|
|
|
|
|
|
|
|
|
inet_pton(family, ip, &address.sin_addr.s_addr);
|
|
|
|
|
address.sin_family = family;
|
|
|
|
|
address.sin_port = htons(port);
|
|
|
|
|
Result(SocketAddress, objectPtr);
|
|
|
|
|
ResultType(SocketAddress, objectPtr) createIPV4Address(CometVM* vm, int family, int type, char* host, int port) {
|
|
|
|
|
struct sockaddr_in address = {};
|
|
|
|
|
|
|
|
|
|
return address;
|
|
|
|
|
struct addrinfo hints = {};
|
|
|
|
|
struct addrinfo* result;
|
|
|
|
|
|
|
|
|
|
hints.ai_family = family;
|
|
|
|
|
hints.ai_socktype = type;
|
|
|
|
|
|
|
|
|
|
char portString[16];
|
|
|
|
|
snprintf(portString, sizeof(portString), "%d", port);
|
|
|
|
|
|
|
|
|
|
int status = getaddrinfo(host, portString, &hints, &result);
|
|
|
|
|
if (status < 0) {
|
|
|
|
|
char* errMsg = strerror(errno);
|
|
|
|
|
ResultType(int64_t, objectPtr) error = cometError(vm, "SocketError", errMsg);
|
|
|
|
|
return Error(SocketAddress, objectPtr, error.as.error);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memcpy(&address, result->ai_addr, sizeof(address));
|
|
|
|
|
freeaddrinfo(result);
|
|
|
|
|
|
|
|
|
|
return Success(SocketAddress, objectPtr, address);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ResultType(int64_t, objectPtr) impl_connect(int64_t* args, CometVM* vm) {
|
|
|
|
|
@@ -40,11 +59,14 @@ ResultType(int64_t, objectPtr) impl_connect(int64_t* args, CometVM* vm) {
|
|
|
|
|
|
|
|
|
|
int fd = self->fields[0];
|
|
|
|
|
int family = self->fields[1];
|
|
|
|
|
int type = self->fields[2];
|
|
|
|
|
|
|
|
|
|
struct sockaddr_in address = createIPV4Address(family, ip, port);
|
|
|
|
|
ResultType(SocketAddress, objectPtr) address = createIPV4Address(vm, family, type, ip, port);
|
|
|
|
|
if (address.error)
|
|
|
|
|
return Error(int64_t, objectPtr, address.as.error);
|
|
|
|
|
|
|
|
|
|
// then connect
|
|
|
|
|
int result = connect(fd, (struct sockaddr*)&address, sizeof(address));
|
|
|
|
|
int result = connect(fd, (struct sockaddr*)&address.as.success, sizeof(address));
|
|
|
|
|
|
|
|
|
|
if (result != 0) {
|
|
|
|
|
char* errMsg = strerror(errno);
|
|
|
|
|
@@ -61,11 +83,13 @@ ResultType(int64_t, objectPtr) impl_bind(int64_t* args, CometVM* vm) {
|
|
|
|
|
|
|
|
|
|
int fd = self->fields[0];
|
|
|
|
|
int family = self->fields[1];
|
|
|
|
|
int type = self->fields[2];
|
|
|
|
|
|
|
|
|
|
struct sockaddr_in address = createIPV4Address(family, ip, port);
|
|
|
|
|
ResultType(SocketAddress, objectPtr) address = createIPV4Address(vm, family, type, ip, port);
|
|
|
|
|
if (address.error)
|
|
|
|
|
return Error(int64_t, objectPtr, address.as.error);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int result = bind(fd, (struct sockaddr*)&address, sizeof(address));
|
|
|
|
|
int result = bind(fd, (struct sockaddr*)&address.as.success, sizeof(address));
|
|
|
|
|
if (result != 0) {
|
|
|
|
|
char* errMsg = strerror(errno);
|
|
|
|
|
return cometError(vm, "SocketError", errMsg);
|
|
|
|
|
@@ -107,7 +131,9 @@ ResultType(int64_t, objectPtr) impl_accept(int64_t* args, CometVM* vm) {
|
|
|
|
|
CometObject* clientCometSocket = cometCreateObject(socketStruct);
|
|
|
|
|
|
|
|
|
|
clientCometSocket->fields[0] = clientSocket;
|
|
|
|
|
clientCometSocket->fields[1] = clientAddr.sin_port;
|
|
|
|
|
clientCometSocket->fields[1] = self->fields[1];
|
|
|
|
|
clientCometSocket->fields[2] = self->fields[2];
|
|
|
|
|
clientCometSocket->fields[3] = clientAddr.sin_port;
|
|
|
|
|
|
|
|
|
|
return Success(int64_t, objectPtr, (int64_t)clientCometSocket);
|
|
|
|
|
}
|
|
|
|
|
@@ -148,17 +174,22 @@ ResultType(int64_t, objectPtr) impl_readExact(int64_t* args, CometVM* vm) {
|
|
|
|
|
return cometError(vm, "MemoryAllocFail", "Failed to allocate memory for buffer (readExact)");
|
|
|
|
|
|
|
|
|
|
ssize_t amountReceived = recv(fd, buffer, amount, 0);
|
|
|
|
|
if (amountReceived != amount) {
|
|
|
|
|
char* buffer = malloc(128);
|
|
|
|
|
snprintf(buffer, 128, "Expected to read %d bytes but only got %zu", amount, amountReceived);
|
|
|
|
|
return cometError(vm, "UnexpectedEOF", buffer);
|
|
|
|
|
} else if (amountReceived == -1) { // connection closed by peer
|
|
|
|
|
|
|
|
|
|
if (amountReceived < 0) { // connection closed by peer
|
|
|
|
|
char* errMsg = strerror(errno);
|
|
|
|
|
close(fd);
|
|
|
|
|
free(buffer);
|
|
|
|
|
return cometError(vm, "SocketError", errMsg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (amountReceived != amount) {
|
|
|
|
|
char* buffer = malloc(128);
|
|
|
|
|
snprintf(buffer, 128, "Expected to read %d bytes but only got %zu", amount, amountReceived);
|
|
|
|
|
return cometError(vm, "UnexpectedEOF", buffer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
buffer[amountReceived] = 0;
|
|
|
|
|
|
|
|
|
|
int64_t serializedString = cometSerializeString(buffer);
|
|
|
|
|
@@ -238,7 +269,28 @@ ResultType(int64_t, objectPtr) impl_send(int64_t* args, CometVM* vm) {
|
|
|
|
|
return cometError(vm, "SocketError", errMsg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Success(int64_t, objectPtr, 0);
|
|
|
|
|
return Success(int64_t, objectPtr, bytesSent);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ResultType(int64_t, objectPtr) impl_sendAll(int64_t* args, CometVM* vm) {
|
|
|
|
|
char* buffer = cometArgString(args[0]);
|
|
|
|
|
CometObject* self = (CometObject*)args[1];
|
|
|
|
|
|
|
|
|
|
int fd = self->fields[0];
|
|
|
|
|
|
|
|
|
|
size_t length = strlen(buffer);
|
|
|
|
|
|
|
|
|
|
ssize_t bytesSent = 0;
|
|
|
|
|
while (bytesSent < length) {
|
|
|
|
|
bytesSent += send(fd, buffer + bytesSent, length - bytesSent, MSG_NOSIGNAL);
|
|
|
|
|
|
|
|
|
|
if (bytesSent < 0) {
|
|
|
|
|
char* errMsg = strerror(errno);
|
|
|
|
|
return cometError(vm, "SocketError", errMsg);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Success(int64_t, objectPtr, bytesSent);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ResultType(int64_t, objectPtr) impl_sendByte(int64_t* args, CometVM* vm) {
|
|
|
|
|
@@ -262,13 +314,28 @@ ResultType(int64_t, objectPtr) impl_close(int64_t* args, CometVM* vm) {
|
|
|
|
|
CometObject* self = (CometObject*)args[0];
|
|
|
|
|
|
|
|
|
|
int fd = self->fields[0];
|
|
|
|
|
|
|
|
|
|
int result = close(fd);
|
|
|
|
|
if (result != 0) {
|
|
|
|
|
char* errMsg = strerror(errno);
|
|
|
|
|
return cometError(vm, "IOError", errMsg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self->fields[0] = -1;
|
|
|
|
|
|
|
|
|
|
return Success(int64_t, objectPtr, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ResultType(int64_t, objectPtr) impl_shutdown(int64_t* args, CometVM* vm) {
|
|
|
|
|
int method = mapLanguageShutdownToOS(cometArgSmall(args[0]));
|
|
|
|
|
CometObject* self = (CometObject*)args[1];
|
|
|
|
|
|
|
|
|
|
int fd = self->fields[0];
|
|
|
|
|
int result = shutdown(fd, method);
|
|
|
|
|
if (result != 0) {
|
|
|
|
|
char* errMsg = strerror(errno);
|
|
|
|
|
return cometError(vm, "SocketError", errMsg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Success(int64_t, objectPtr, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -427,6 +494,7 @@ ResultType(int64_t, objectPtr) impl_waitWriteable(int64_t* args, CometVM* vm) {
|
|
|
|
|
void defineSocketStruct(CometEnvironment* env, CometTypeMap* typeMap) {
|
|
|
|
|
CometType familyEnum = defineFamilyEnum(env, typeMap);
|
|
|
|
|
CometType typeEnum = defineTypeEnum(env, typeMap);
|
|
|
|
|
CometType shutdownEnum = defineShutdownEnum(env, typeMap);
|
|
|
|
|
|
|
|
|
|
CometStruct* socketStruct = cometDefineStruct(env, "Socket", NULL);
|
|
|
|
|
|
|
|
|
|
@@ -438,6 +506,8 @@ void defineSocketStruct(CometEnvironment* env, CometTypeMap* typeMap) {
|
|
|
|
|
List(StructField) fields = newList(StructField);
|
|
|
|
|
append(fields, cometCreateField("fd", cometTypeInt, FIELD_PRIVATE));
|
|
|
|
|
append(fields, cometCreateField("family", cometTypeSmall, FIELD_READ_ONLY));
|
|
|
|
|
append(fields, cometCreateField("type", cometTypeSmall, FIELD_READ_ONLY));
|
|
|
|
|
append(fields, cometCreateField("port", cometTypeInt, FIELD_READ_ONLY));
|
|
|
|
|
|
|
|
|
|
/// METHODS ///
|
|
|
|
|
List(externalMethodPtr) methods = newList(externalMethodPtr);
|
|
|
|
|
@@ -454,8 +524,10 @@ void defineSocketStruct(CometEnvironment* env, CometTypeMap* typeMap) {
|
|
|
|
|
append(methods, cometDefineMethod(env, "readAll", socketStruct, FIELD_PUBLIC, cometTypeString, 0, false));
|
|
|
|
|
append(methods, cometDefineMethod(env, "readExact", socketStruct, FIELD_PUBLIC, cometTypeString, 1, false, cometTypeInt));
|
|
|
|
|
append(methods, cometDefineMethod(env, "readByte", socketStruct, FIELD_PUBLIC, cometTypeSmall, 0, false));
|
|
|
|
|
append(methods, cometDefineMethod(env, "send", socketStruct, FIELD_PUBLIC, cometTypeVoid, 1, false, cometTypeString));
|
|
|
|
|
append(methods, cometDefineMethod(env, "send", socketStruct, FIELD_PUBLIC, cometTypeInt, 1, false, cometTypeString));
|
|
|
|
|
append(methods, cometDefineMethod(env, "sendAll", socketStruct, FIELD_PUBLIC, cometTypeVoid, 1, false, cometTypeString));
|
|
|
|
|
append(methods, cometDefineMethod(env, "sendByte", socketStruct, FIELD_PUBLIC, cometTypeVoid, 1, false, cometTypeSmall));
|
|
|
|
|
append(methods, cometDefineMethod(env, "shutdown", socketStruct, FIELD_PUBLIC, cometTypeVoid, 1, false, shutdownEnum));
|
|
|
|
|
append(methods, cometDefineMethod(env, "close", socketStruct, FIELD_PUBLIC, cometTypeVoid, 0, false));
|
|
|
|
|
|
|
|
|
|
// options
|
|
|
|
|
|