152 lines
3.7 KiB
C
152 lines
3.7 KiB
C
#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;
|
|
}
|