This commit is contained in:
2025-03-21 10:59:34 +10:00
commit 32e2a09b8d
7 changed files with 1062 additions and 0 deletions

151
dbclient.c Normal file
View File

@@ -0,0 +1,151 @@
#include "dbclient.h"
char *construct_header(char *key, char *value) {
char *header = NULL;
// If there is no value, make a get request, otherwise make a put request
// with that value
if (!value) {
size_t needed_size = snprintf(NULL, 0, GET_REQUEST, key);
header = (char *)malloc(needed_size + sizeof(char));
sprintf(header, GET_REQUEST, key);
} else {
size_t body_size = strlen(value) * sizeof(char);
size_t needed_size =
snprintf(NULL, 0, PUT_REQUEST, key, body_size, value);
header = (char *)malloc(needed_size + sizeof(char));
sprintf(header, PUT_REQUEST, key, body_size, value);
}
return header;
}
int handle_connect(char *port, int *fd) {
struct addrinfo *ai = NULL;
struct addrinfo hints;
memset(&hints, 0, sizeof(struct addrinfo));
// Set hints
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
// Get address information
int err;
if ((err = getaddrinfo("localhost", port, &hints, &ai))) {
freeaddrinfo(ai);
fprintf(stderr, "%s\n", gai_strerror(err));
return EXIT_ERR;
}
// Connect to port
*fd = socket(AF_INET, SOCK_STREAM, 0);
// clang-format off
if (connect(*fd, (struct sockaddr *)ai->ai_addr,
sizeof(struct sockaddr))) {
// clang-format on
freeaddrinfo(ai);
close(*fd);
fprintf(stderr, "dbclient: unable to connect to port %s\n", port);
return EXIT_PORT_ERR;
}
freeaddrinfo(ai);
return EXIT_OK;
}
int handle_response(FILE *recv, int valueSet) {
HttpHeader **responseHeaders = NULL;
memset(&responseHeaders, 0, sizeof(HttpHeader *));
int status;
char *statusExplain = NULL;
char *body = NULL;
get_HTTP_response(recv, &status, &statusExplain, &responseHeaders, &body);
// Print the value only if GET and got status 200
if (!valueSet && status == 200) {
printf("%s\n", body);
}
free_array_of_headers(responseHeaders);
free(statusExplain);
free(body);
if (status != 200 && valueSet) {
return EXIT_PUT_ERR;
} else if (status != 200) {
return EXIT_GET_ERR;
}
return EXIT_OK;
}
int handle_connection(char *port, char *key, char *value) {
int connectStatus = 0;
int sendFd;
if ((connectStatus = handle_connect(port, &sendFd))) {
close(sendFd);
return connectStatus;
}
// Setup fd's for sending and receiving requests
int recvFd = dup(sendFd);
FILE *send = fdopen(sendFd, "w");
FILE *recv = fdopen(recvFd, "r");
// Send Request
char *header = construct_header(key, value);
fprintf(send, "%s", header);
fflush(send);
fclose(send);
free(header);
close(sendFd);
// Get Response
int valueSet = (value != NULL);
int exitCode = handle_response(recv, valueSet);
fclose(recv);
close(recvFd);
return exitCode;
}
int is_valid_key(char *key) {
for (int i = 0; i < strlen(key); i++) {
if (isspace(key[i])) {
return 0;
}
}
return 1;
}
int main(int argc, char *argv[]) {
if (argc < 3) {
fprintf(stderr, "Usage: dbclient portnum key [value]\n");
return EXIT_ERR;
}
char *portnumArgument = strdup(argv[1]);
char *keyArgument = strdup(argv[2]);
char *valueArgument = NULL;
if (argc > 3) {
valueArgument = strdup(argv[3]);
}
if (!is_valid_key(keyArgument)) {
fprintf(stderr, "dbclient: key must not contain spaces or newlines\n");
return EXIT_ERR;
}
int exitStatus =
handle_connection(portnumArgument, keyArgument, valueArgument);
free(portnumArgument);
free(keyArgument);
free(valueArgument);
return exitStatus;
}