diff --git a/src/socket.c b/src/socket.c index 93f8f0d..62d1b05 100644 --- a/src/socket.c +++ b/src/socket.c @@ -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,7 +494,8 @@ 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); CometType socketStructType = { @@ -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 diff --git a/src/socket.h b/src/socket.h index 90c6139..477cde8 100644 --- a/src/socket.h +++ b/src/socket.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include diff --git a/src/socket_enums.c b/src/socket_enums.c index 08149a7..9d319c5 100644 --- a/src/socket_enums.c +++ b/src/socket_enums.c @@ -74,6 +74,18 @@ CometType defineTypeEnum(CometEnvironment* env, CometTypeMap* typeMap) { return domainEnum; } +CometType defineShutdownEnum(CometEnvironment* env, CometTypeMap* typeMap) { + char* items[] = { + "Read", + "Write", + "ReadWrite" + }; + + CometType shutdownEnum = cometDefineEnum(env, typeMap, "Shutdown", items, sizeof(items)/sizeof(items[0])); + + return shutdownEnum; +} + int mapLanguageTypeToOS(int cometType) { /* ughhhh... @@ -148,4 +160,13 @@ int mapLanguageFamilyToOS(int cometFamily) { case 46: return AF_MAX; default: return -1; } +} + +int mapLanguageShutdownToOS(int cometShutdown) { + switch (cometShutdown) { + case 0: return SHUT_RD; + case 1: return SHUT_WR; + case 2: return SHUT_RDWR; + default: return -1; + } } \ No newline at end of file diff --git a/src/socket_enums.h b/src/socket_enums.h index 3001d59..7fa9217 100644 --- a/src/socket_enums.h +++ b/src/socket_enums.h @@ -6,7 +6,9 @@ CometType defineFamilyEnum(CometEnvironment* env, CometTypeMap* typeMap); CometType defineTypeEnum(CometEnvironment* env, CometTypeMap* typeMap); +CometType defineShutdownEnum(CometEnvironment* env, CometTypeMap* typeMap); int mapLanguageFamilyToOS(int cometFamily); int mapLanguageTypeToOS(int cometFamily); +int mapLanguageShutdownToOS(int cometShutdown); #endif \ No newline at end of file