From c2aaa3af15b18f3a66e285960935fcbefe872983 Mon Sep 17 00:00:00 2001 From: Matteo Cypriani Date: Mon, 22 Aug 2011 15:07:56 +0200 Subject: [PATCH] [UDP-HTTP] Big refactoring Create owlps-udp-to-http.h, rename variables, refactor functions, etc. --- owlps-udp-to-http/owlps-udp-to-http.c | 297 ++++++++++++++------------ owlps-udp-to-http/owlps-udp-to-http.h | 48 +++++ 2 files changed, 204 insertions(+), 141 deletions(-) create mode 100644 owlps-udp-to-http/owlps-udp-to-http.h diff --git a/owlps-udp-to-http/owlps-udp-to-http.c b/owlps-udp-to-http/owlps-udp-to-http.c index 0048abc..521417a 100644 --- a/owlps-udp-to-http/owlps-udp-to-http.c +++ b/owlps-udp-to-http/owlps-udp-to-http.c @@ -29,7 +29,7 @@ * UnknownRequest;NOK */ -#include +#include "owlps-udp-to-http.h" #include #include @@ -42,58 +42,25 @@ #include -#define TCP_PORT 8080 -#define NB_CONNECTIONS 1 -#define CLIENT_MESSAGE_STRLEN 2500 - -#define SIMPLE_RESULTS_ID 1 -#define SIMPLE_RESULTS_REQUEST "ReadSimpleResults" -#define SIMPLE_RESULTS_ANSWER "SimpleResults" -#define CLIENT_REQUEST_STRLEN 21 - -#ifndef OWLPS_VERSION -# define OWLPS_VERSION "unknown version" -#endif // OWLPS_VERSION - -#define ANSWER_HEADER \ - "HTTP/1.1 200 OK\n" \ - "Date: Sat, 01 Jan 0001 00:00:01 GMT\n" \ - "Server: OwlPS UDP-to-HTTP ["OWLPS_VERSION"]\n" \ - "Access-Control-Allow-Origin: *\n" \ - "Connection: close\n" \ - "Content-Type: text/html\n" \ - "\n" - - -typedef struct _results_list -{ - owl_result *result ; - struct _results_list *next ; -} results_list ; - - -void store_result(owl_result *result) ; -void* tcp_server(void *NULL_value) ; -int -extract_request_from_message(char client_request[CLIENT_REQUEST_STRLEN], - char *client_message) ; -void free_results_list(void) ; - - char *program_name = NULL ; results_list *results = NULL ; unsigned int nb_results = 0 ; sem_t lock_results ; +int udp_sockfd = -1 ; +int tcp_sockfd = -1 ; + +char *answer = NULL ; // Answer to send to the client +size_t answer_strlen = 0 ; // Total size of the answer string +size_t answer_buflen = 0 ; // Size of the answer allocated buffer + int main(int argc, char *argv[]) { struct sigaction action ; // Signal handler structure int ret = 0 ; // Program return value pthread_t tcp_server_thread ; - owl_result *result ; - int udp_sockfd ; program_name = argv[0] ; owl_run = owl_true ; @@ -109,14 +76,6 @@ int main(int argc, char *argv[]) /* Set up the semaphore */ sem_init(&lock_results, 0, 1) ; - /* Open the UDP socket */ - udp_sockfd = owl_create_udp_listening_socket(OWL_DEFAULT_RESULT_PORT) ; - if (udp_sockfd < 0) - { - ret = 1 ; - goto exit ; - } - /* Launch the TCP thread */ ret = pthread_create(&tcp_server_thread, NULL, &tcp_server, NULL) ; @@ -127,19 +86,8 @@ int main(int argc, char *argv[]) goto exit ; } - /* UDP read loop */ - while (owl_run) - { - result = owl_receive_position(udp_sockfd) ; - if (result == NULL) - { - ret = 1 ; - goto exit ; - } - owl_print_result(result) ; - store_result(result) ; - printf("--------------\n") ; - } + /* Main loop */ + ret = receive_udp() ; /* Stop the TCP thread */ if (pthread_join(tcp_server_thread, NULL)) @@ -147,15 +95,54 @@ int main(int argc, char *argv[]) /* Cleaning */ exit: + if (tcp_sockfd >= 0) + if (close(tcp_sockfd)) + perror("Error closing the TCP socket") ; + if (udp_sockfd >= 0) + if (close(udp_sockfd)) + perror("Error closing the UDP socket") ; + + free(answer) ; free_results_list() ; sem_destroy(&lock_results) ; - close(udp_sockfd) ; printf("%s: end.\n", program_name) ; return ret ; } +/* + * Opens the UDP socket and reads from it the results sent by OwlPS + * Positioning. + * Returns a non-zero value in case of error. + */ +int receive_udp() +{ + owl_result *result ; + + /* Open the UDP socket */ + udp_sockfd = owl_create_udp_listening_socket(OWL_DEFAULT_RESULT_PORT) ; + if (udp_sockfd < 0) + return 1 ; + + /* UDP read loop */ + while (owl_run) + { + result = owl_receive_position(udp_sockfd) ; + if (result == NULL) + return 1 ; + owl_print_result(result) ; + store_result(result) ; + printf("--------------\n") ; + } + + return 0 ; +} + + +/* + * Adds a new owl_result to the results' list. + */ void store_result(owl_result *new_result) { sem_wait(&lock_results) ; @@ -200,18 +187,18 @@ void store_result(owl_result *new_result) } +/* + * Opens the TCP socket and wait for requests from HTTP clients. + */ void* tcp_server(void *NULL_value) { - int tcp_sockfd, newsockfd ; + int newsockfd ; socklen_t client_len ; struct sockaddr_in server_addr, client_addr ; ssize_t nbytes ; // recv/send return value char client_message[CLIENT_MESSAGE_STRLEN] ; char client_request[CLIENT_REQUEST_STRLEN] ; int request_id ; - char *answer ; // Answer to send to the client - size_t answer_hdr_len = strlen(ANSWER_HEADER) ; - size_t answer_len ; // Total size of the answer tcp_sockfd = socket(AF_INET, SOCK_STREAM, 0) ; if (tcp_sockfd < 0) @@ -219,7 +206,6 @@ void* tcp_server(void *NULL_value) perror("Error opening the TCP socket") ; exit(1) ; } - pthread_cleanup_push(&owl_close_fd, &tcp_sockfd) ; bzero((char *) &server_addr, sizeof(server_addr)) ; server_addr.sin_family = AF_INET ; @@ -236,10 +222,11 @@ void* tcp_server(void *NULL_value) listen(tcp_sockfd, NB_CONNECTIONS) ; client_len = sizeof(client_addr) ; - // Prepare the answer, assuming there is only 1 result (an error + // Prepare the answer, assuming there is only 1 full result (an error // message will also fit) - answer = malloc(answer_hdr_len + OWL_CSV_RESULT_STRLEN) ; - strncpy(answer, ANSWER_HEADER, answer_hdr_len) ; + answer_buflen = ANSWER_HDR_STRLEN + OWL_CSV_RESULT_STRLEN ; + answer = malloc(answer_buflen) ; + strncpy(answer, ANSWER_HDR, ANSWER_HDR_STRLEN) ; while (owl_run) { @@ -259,7 +246,6 @@ void* tcp_server(void *NULL_value) close(newsockfd) ; continue ; } - client_message[nbytes] = '\0' ; #ifdef DEBUG @@ -267,86 +253,22 @@ void* tcp_server(void *NULL_value) "\"%s\"\n", client_message) ; #endif // DEBUG - answer_len = answer_hdr_len ; request_id = extract_request_from_message(client_request, client_message) ; - switch (request_id) - { - case SIMPLE_RESULTS_ID: - strncpy(answer + answer_len, SIMPLE_RESULTS_ANSWER, - strlen(SIMPLE_RESULTS_ANSWER)) ; - answer_len += strlen(SIMPLE_RESULTS_ANSWER) ; + prepare_answer(request_id) ; - sem_wait(&lock_results) ; - - if (! results) - { - char answer_end[] = ";NOK;NoResult" ; - strncpy(answer + answer_len, answer_end, - strlen(answer_end)) ; - answer_len += strlen(answer_end) ; - } - - else - { - results_list *result ; - char answer_begin[10] ; - size_t answer_begin_len, answer_buf_len ; - - snprintf(answer_begin, 10, ";OK;%u", nb_results) ; - answer_begin_len = strlen(answer_begin) ; - strncpy(answer + answer_len, answer_begin, - answer_begin_len) ; - answer_len += answer_begin_len ; - - answer_buf_len = - answer_len + - nb_results * OWL_CSV_RESULT_STRLEN ; - answer = realloc(answer, answer_buf_len) ; - - result = results ; - while (result != NULL) - { - char result_str[OWL_CSV_RESULT_STRLEN] ; - size_t result_len ; - owl_result_to_csv_simple(result_str, result->result) ; - result_len = strlen(result_str) ; - answer[answer_len++] = ';' ; - strncpy(answer + answer_len, result_str, - result_len) ; - answer_len += result_len ; - result = result->next ; - } - } - - sem_post(&lock_results) ; - - break ; - - default: - { - char answer_end[] = "UnknownRequest;NOK" ; - strncpy(answer + answer_hdr_len, answer_end, - strlen(answer_end)) ; - answer_len += strlen(answer_end) ; - } - } - - answer[answer_len] = '\0' ; +#ifdef DEBUG printf("Answer to send:\n\"%s\"\n", answer) ; +#endif // DEBUG - nbytes = send(newsockfd, answer, answer_len, 0) ; + /* Send the answer */ + nbytes = send(newsockfd, answer, answer_strlen, 0) ; if (nbytes < 0) perror("Error sending answer to the TCP socket") ; close(newsockfd) ; } - /* Cleaning */ - // Close tcp_sockfd - pthread_cleanup_pop(1) ; - free(answer) ; - pthread_exit(NULL_value) ; } @@ -375,6 +297,99 @@ extract_request_from_message(char client_request[CLIENT_REQUEST_STRLEN], } +/* + * Prepare the answer string to send to the TCP client. + */ +void prepare_answer(int request_id) +{ + // Reset the answer's length: + answer_strlen = ANSWER_HDR_STRLEN ; + + switch (request_id) + { + case SIMPLE_RESULTS_ID: + strncpy(answer + answer_strlen, SIMPLE_RESULTS_ANSWER, + strlen(SIMPLE_RESULTS_ANSWER)) ; + answer_strlen += strlen(SIMPLE_RESULTS_ANSWER) ; + + sem_wait(&lock_results) ; + + if (! results) + { + char answer_end[] = ";NOK;NoResult" ; + strncpy(answer + answer_strlen, answer_end, + strlen(answer_end)) ; + answer_strlen += strlen(answer_end) ; + } + + else + { + results_list *result ; + char answer_begin[10] ; + size_t answer_begin_len ; + + snprintf(answer_begin, 10, ";OK;%u", nb_results) ; + answer_begin_len = strlen(answer_begin) ; + strncpy(answer + answer_strlen, answer_begin, + answer_begin_len) ; + answer_strlen += answer_begin_len ; + + realloc_answer(answer_strlen + + nb_results * OWL_CSV_RESULT_SIMPLE_STRLEN) ; + + result = results ; + while (result != NULL) + { + char result_str[OWL_CSV_RESULT_SIMPLE_STRLEN] ; + size_t result_len ; + owl_result_to_csv_simple(result_str, result->result) ; + result_len = strlen(result_str) ; + answer[answer_strlen++] = ';' ; + strncpy(answer + answer_strlen, result_str, + result_len) ; + answer_strlen += result_len ; + result = result->next ; + } + } + + sem_post(&lock_results) ; + + break ; + + default: + { + char answer_end[] = "UnknownRequest;NOK" ; + strncpy(answer + ANSWER_HDR_STRLEN, answer_end, + strlen(answer_end)) ; + answer_strlen += strlen(answer_end) ; + } + } + + answer[answer_strlen] = '\0' ; +} + + +/* + * Realloc the answer buffer to the if needed: grows it if new_size is + * greater than the current size, shrink it if the current size is + * greater than the double of new_size. + */ +void realloc_answer(size_t new_size) +{ + if (new_size > answer_buflen) + answer_buflen = new_size ; + else if (answer_buflen / 2 >= new_size) + answer_buflen /= 2 ; + else + return ; + + answer = realloc(answer, answer_buflen) ; +} + + +/* + * Frees the memory allocated for the results' list. + */ void free_results_list() { results_list *ptr = results ; diff --git a/owlps-udp-to-http/owlps-udp-to-http.h b/owlps-udp-to-http/owlps-udp-to-http.h new file mode 100644 index 0000000..aebfb3e --- /dev/null +++ b/owlps-udp-to-http/owlps-udp-to-http.h @@ -0,0 +1,48 @@ +#ifndef _OWLPS_UDP_TO_HTTP_H_ +#define _OWLPS_UDP_TO_HTTP_H_ + +#include + +#define TCP_PORT 8080 +#define NB_CONNECTIONS 1 +#define CLIENT_MESSAGE_STRLEN 2500 + +#define SIMPLE_RESULTS_ID 1 +#define SIMPLE_RESULTS_REQUEST "ReadSimpleResults" +#define SIMPLE_RESULTS_ANSWER "SimpleResults" +#define CLIENT_REQUEST_STRLEN 21 + +#ifndef OWLPS_VERSION +# define OWLPS_VERSION "unknown version" +#endif // OWLPS_VERSION + +#define ANSWER_HDR \ + "HTTP/1.1 200 OK\n" \ + "Date: Sat, 01 Jan 0001 00:00:01 GMT\n" \ + "Server: OwlPS UDP-to-HTTP ["OWLPS_VERSION"]\n" \ + "Access-Control-Allow-Origin: *\n" \ + "Connection: close\n" \ + "Content-Type: text/html\n" \ + "\n" +#define ANSWER_HDR_STRLEN strlen(ANSWER_HDR) + + +typedef struct _results_list +{ + owl_result *result ; + struct _results_list *next ; +} results_list ; + + +int receive_udp(void) ; +void store_result(owl_result *result) ; +void* tcp_server(void *NULL_value) ; +int +extract_request_from_message(char client_request[CLIENT_REQUEST_STRLEN], + char *client_message) ; +void prepare_answer(int request_id) ; +void realloc_answer(size_t new_size) ; +void free_results_list(void) ; + + +#endif // _OWLPS_UDP_TO_HTTP_H_