#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; }