/* * This file is part of the Owl Positioning System (OwlPS). * OwlPS is a project of the University of Franche-Comte * (Université de Franche-Comté), France. * * Copyright © Université de Franche-Comté 2007-2012. * * Corresponding author: Matteo Cypriani * *********************************************************************** * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, * modify and/or redistribute the software under the terms of the CeCILL * license as circulated by CEA, CNRS and INRIA at the following URL: * http://www.cecill.info * * As a counterpart to the access to the source code and rights to copy, * modify and redistribute granted by the license, users are provided * only with a limited warranty and the software's authors, the holder * of the economic rights, and the successive licensors have only * limited liability. * * In this respect, the user's attention is drawn to the risks * associated with loading, using, modifying and/or developing or * reproducing the software by the user in light of its specific status * of free software, that may mean that it is complicated to manipulate, * and that also therefore means that it is reserved for developers and * experienced professionals having in-depth computer knowledge. Users * are therefore encouraged to load and test the software's suitability * as regards their requirements in conditions enabling the security of * their systems and/or data to be ensured and, more generally, to use * and operate it in the same conditions as regards security. * * The fact that you are presently reading this means that you have had * knowledge of the CeCILL license and that you accept its terms. * *********************************************************************** * * This is the main source file of libowlps. */ #include "owlps.h" #include #include #include #include #include #include #include #include #include #include owl_bool owl_run = owl_true ; /* *** Miscellaneous functions *** */ /* * Converts a MAC address from bytes to string. * The string is allocated in a static buffer, and will be overwritten * each time this function is called. * This function is not thread-safe! */ const char* owl_mac_bytes_to_string(const uint8_t *const mac_binary) { static char mac_str[OWL_ETHER_ADDR_STRLEN] ; owl_mac_bytes_to_string_r(mac_binary, mac_str) ; return mac_str ; } /* * Converts a MAC address from bytes to string. * 'mac_str' must be allocated by the caller. * This function is thread-safe. */ void owl_mac_bytes_to_string_r(const uint8_t *const mac_binary, char mac_str[OWL_ETHER_ADDR_STRLEN]) { snprintf(mac_str, OWL_ETHER_ADDR_STRLEN, "%02x:%02x:%02x:%02x:%02x:%02x", mac_binary[0], mac_binary[1], mac_binary[2], mac_binary[3], mac_binary[4], mac_binary[5]) ; } /* * Compares two MAC addresses. * Returns owl_true if they are identical, owl_false otherwise. */ owl_bool owl_mac_equals(const uint8_t *const mac1, const uint8_t *const mac2) { int i ; for (i = ETHER_ADDR_LEN - 1 ; i >= 0 ; --i) if(mac1[i] != mac2[i]) return owl_false ; return owl_true ; } /* * Converts a IEEE 802.11 frequency into a channel number. * Returns 0 if the frequency does not correspond to an official channel. */ uint_fast8_t owl_frequency_to_channel(const uint_fast16_t channel) { uint_fast8_t c = 0 ; // Result switch (channel) { case OWL_80211_MHZ_CHANNEL_1 : c = 1 ; break ; case OWL_80211_MHZ_CHANNEL_2 : c = 2 ; break ; case OWL_80211_MHZ_CHANNEL_3 : c = 3 ; break ; case OWL_80211_MHZ_CHANNEL_4 : c = 4 ; break ; case OWL_80211_MHZ_CHANNEL_5 : c = 5 ; break ; case OWL_80211_MHZ_CHANNEL_6 : c = 6 ; break ; case OWL_80211_MHZ_CHANNEL_7 : c = 7 ; break ; case OWL_80211_MHZ_CHANNEL_8 : c = 8 ; break ; case OWL_80211_MHZ_CHANNEL_9 : c = 9 ; break ; case OWL_80211_MHZ_CHANNEL_10 : c = 10 ; break ; case OWL_80211_MHZ_CHANNEL_11 : c = 11 ; break ; case OWL_80211_MHZ_CHANNEL_12 : c = 12 ; break ; case OWL_80211_MHZ_CHANNEL_13 : c = 13 ; break ; case OWL_80211_MHZ_CHANNEL_14 : c = 14 ; break ; } return c ; } /* *** Time *** */ /* * Sleeps for a given amount of milliseconds. * 'time_ms' is an unsigned value, so please be careful: passing a * negative value may not do what you think. * In case of error, a message is displayed and a non-zero error code * is returned (if positive, it is the number of non-sleeped seconds). */ int owl_msleep(uint32_t time_ms) { int ret ; uint_fast32_t seconds, microseconds ; if (! time_ms) return 0 ; seconds = time_ms / 1000 ; microseconds = time_ms % 1000 * 1000 ; if ((ret = sleep(seconds))) { perror("Cannot sleep()") ; return ret ; } if ((ret = usleep(microseconds))) { perror("Cannot usleep()") ; return ret ; } return 0 ; } /* * Sets the owl_timestamp 'now' at the current time. * Returns 0 in case of success non-zero otherwise. */ int owl_timestamp_now(owl_timestamp *const now) { int ret ; #if _POSIX_TIMERS > 0 struct timespec now_ts ; ret = clock_gettime(CLOCK_REALTIME, &now_ts) ; #else // _POSIX_TIMERS struct timeval now_ts ; ret = gettimeofday(&now_ts, NULL) ; #endif // _POSIX_TIMERS if (ret) { perror("Cannot get the current time") ; return ret ; } #if _POSIX_TIMERS > 0 owl_timespec_to_timestamp(&now_ts, now) ; #else // _POSIX_TIMERS owl_timeval_to_timestamp(&now_ts, now) ; #endif // _POSIX_TIMERS return 0 ; } /* * Converts the struct timespec 'src' into the owl_timestamp 'dst'. */ void owl_timespec_to_timestamp(const struct timespec *const src, owl_timestamp *const dst) { assert(src) ; assert(dst) ; dst->tv_sec = src->tv_sec ; dst->tv_nsec = src->tv_nsec ; } /* * Converts the struct timeval 'src' into the owl_timestamp 'dst'. */ void owl_timeval_to_timestamp(const struct timeval *const src, owl_timestamp *const dst) { assert(src) ; assert(dst) ; dst->tv_sec = src->tv_sec ; dst->tv_nsec = src->tv_usec * 1000u ; } owl_bool owl_timestamp_equals(const owl_timestamp *const d1, const owl_timestamp *const d2) { assert(d1) ; assert(d2) ; return d1->tv_sec == d2->tv_sec && d1->tv_nsec == d2->tv_nsec ; } owl_bool owl_timestamp_is_null(const owl_timestamp *const d) { assert(d) ; return d->tv_sec == 0 && d->tv_nsec == 0 ; } /* * Converts a owl_timestamp date value into milliseconds. */ uint64_t owl_timestamp_to_ms(const owl_timestamp *const d) { assert(d) ; return (uint64_t) d->tv_sec * 1000u + (uint64_t) d->tv_nsec / 1000000lu ; } /* * Converts a owl_timestamp date value into a printable string. * 'dst' must be an allocated array of at least OWL_TIMESTAMP_STRLEN * characters. */ void owl_timestamp_to_string(const owl_timestamp *const src, char *const dst) { assert(src) ; assert(dst) ; snprintf(dst, OWL_TIMESTAMP_STRLEN, "%"PRIu32".%09"PRIu32, src->tv_sec, src->tv_nsec) ; } /* * Returns the time (in milliseconds) between two dates. */ uint_fast32_t owl_time_elapsed_ms(const owl_timestamp *const d1, const owl_timestamp *const d2) { owl_timestamp elapsed ; owl_time_elapsed(d1, d2, &elapsed) ; return owl_timestamp_to_ms(&elapsed) ; } /* * Computes the time difference between two owl_timestamp 'd1' and * 'd2'. * Note that it is a delay, not a simple substraction, therefore the * result is always positive. The result is stored in the 'elapsed' * argument. */ void owl_time_elapsed(const owl_timestamp *const d1, const owl_timestamp *const d2, owl_timestamp *const elapsed) { int_fast32_t sec, nsec ; assert(d1) ; assert(d2) ; assert(elapsed) ; sec = (int_fast64_t) d1->tv_sec - d2->tv_sec ; nsec = (int_fast64_t) d1->tv_nsec - d2->tv_nsec ; if (sec == 0) { elapsed->tv_sec = 0 ; elapsed->tv_nsec = abs(nsec) ; } else if (sec > 0) { if (nsec >= 0) { elapsed->tv_sec = sec ; elapsed->tv_nsec = nsec ; } else // nsec < 0 { elapsed->tv_sec = sec - 1 ; elapsed->tv_nsec = nsec + 1000000000ul ; } } else // sec < 0 { if (nsec > 0) { elapsed->tv_sec = abs(sec) - 1 ; elapsed->tv_nsec = 1000000000ul - nsec ; } else // nsec <= 0 { elapsed->tv_sec = abs(sec) ; elapsed->tv_nsec = abs(nsec) ; } } } /* *** Endianess *** */ /* * Converts a owl_timestamp from host endianess to network endianess. */ void owl_hton_timestamp(owl_timestamp *const d) { assert(d) ; d->tv_sec = htonl(d->tv_sec) ; d->tv_nsec = htonl(d->tv_nsec) ; } /* * Converts a owl_timestamp from network endianess to host endianess. */ void owl_ntoh_timestamp(owl_timestamp *const d) { assert(d) ; d->tv_sec = ntohl(d->tv_sec) ; d->tv_nsec = ntohl(d->tv_nsec) ; } /* * Swap bytes composing a float. * You probably want to use the macros owl_htonf() and owl_ntohf() * instead of this function. */ float owl_swap_float(const float f) { float ret ; char *f_bytes = (char*) &f, *ret_bytes = (char*) &ret ; assert(sizeof(float) == 4) ; ret_bytes[0] = f_bytes[3] ; ret_bytes[1] = f_bytes[2] ; ret_bytes[2] = f_bytes[1] ; ret_bytes[3] = f_bytes[0] ; return ret ; } /* *** Network *** */ /* * Creates a UDP transmission socket and returns its descriptor. * Parameters: * - server_address: the server IP address. * - server_port: the listening port on the server. * - server_description (in/out): the structure in which the server * description will be saved. * - client_description (in/out): the structure in which the client * description will be saved. * Returns a negative error code in case of error. */ int owl_create_udp_trx_socket(const char *const server_address, const uint_fast16_t server_port, struct sockaddr_in *const server_description, struct sockaddr_in *const client_description) { int sockfd ; // Socket descriptor /* Create the UDP socket */ sockfd = socket(AF_INET, SOCK_DGRAM, 0) ; if (sockfd < 0) { perror("UDP socket creation failed") ; return -OWL_ERR_SOCKET_CREATE ; } /* Initialise the client structure */ memset(client_description, 0, sizeof(*client_description)) ; client_description->sin_family = AF_INET ; // INET socket client_description->sin_addr.s_addr = htonl(INADDR_ANY) ; /* Initialise the server structure */ memset(server_description, 0, sizeof(*server_description)) ; server_description->sin_family = AF_INET ; // INET socket // Server IP address: server_description->sin_addr.s_addr = inet_addr(server_address) ; // Listening port on the server: server_description->sin_port = htons(server_port) ; return sockfd ; } /* * Creates a UDP reception socket and returns its descriptor. * Parameters: * - port: port on which the socket listens. * Returns a negative error code in case of error. */ int owl_create_udp_listening_socket(const uint_fast16_t port) { int sockfd ; // Socket descriptor struct sockaddr_in server_description ; // Server structure int ret = 0 ; // Return value /* Create the UDP socket */ sockfd = socket(AF_INET, SOCK_DGRAM, 0) ; if (sockfd < 0) { perror("UDP socket creation failed") ; return -OWL_ERR_SOCKET_CREATE ; } /* Initialise the server structure */ memset(&server_description, 0, sizeof(server_description)) ; server_description.sin_family = AF_INET ; // INET socket // All the connections are accepted: server_description.sin_addr.s_addr = htonl(INADDR_ANY) ; server_description.sin_port = htons(port) ; // Listening port /* Port reservation */ ret = bind(sockfd, (struct sockaddr*) &server_description, sizeof(server_description)) ; if (ret < 0) { perror("Cannot bind the UDP socket") ; close(sockfd) ; return -OWL_ERR_SOCKET_CREATE ; } return sockfd ; } /* *** Signals *** */ /* * Generic signal handler for SIGINT. */ void owl_sigint_handler(const int num) { if (num != SIGINT) { fprintf(stderr, "Error! The SIGINT handler was called but the" " signal is not SIGINT.\n") ; exit(OWL_ERR_BAD_SIGNAL) ; } owl_run = owl_false ; #ifndef NDEBUG fprintf(stderr, "\nSignal received: end.\n"); #endif // NDEBUG fflush(NULL) ; } /* * Generic signal handler for SIGTERM. */ void owl_sigterm_handler(const int num) { if (num != SIGTERM) { fprintf(stderr, "Error! The SIGTERM handler was called but the" " signal is not SIGTERM.\n") ; exit(OWL_ERR_BAD_SIGNAL) ; } owl_sigint_handler(SIGINT) ; } /* *** Thread-related functions *** */ /* * Closes the file descriptor 'fd'. * 'fd' must be passed as an int pointer (int*). */ void owl_close_fd(void *const fd) { if (fd == NULL) return ; const int *const file_desc = fd ; if (close(*file_desc) != 0) perror("Error closing file descriptor") ; #ifndef NDEBUG else fprintf(stderr, "File descriptor %d closed successfully.\n", *file_desc) ; #endif // NDEBUG } /* * Closes the stream 'file'. * 'file' must be passed as a pointer on a pointer of FILE (FILE**). * If *file either stdout, stderr or stdin, it will not be closed. */ void owl_close_file(void *const file) { if (file == NULL) return ; FILE **stream = file ; if (*stream == stdout || *stream == stderr || *stream == stdin) return ; if (fclose(*stream) != 0) perror("Error closing stream") ; #ifndef NDEBUG else fprintf(stderr, "Stream closed successfully.\n") ; #endif // NDEBUG }