// ======================================================================================================== // ======================================================================================================== // *********************************************** common.c *********************************************** // ======================================================================================================== // ======================================================================================================== #include "utility.h" #include "common.h" #include #include #include #define TRUE 1 #define FALSE 0 // ======================================================================================================== // ======================================================================================================== // Open up a socket and listen for connections from clients int OpenSocketServer(int max_string_len, int *server_socket_desc_ptr, char *server_IP, int port_number, int *client_socket_desc_ptr, struct sockaddr_in *client_addr_ptr, int accept_only, int check_and_return) { struct sockaddr_in server_addr; int sizeof_sock; int queue_size = 1; int opt = TRUE; // Create a socket and prepare the socket_in structure. if ( accept_only == 0 ) { // printf("OpenSocketServer(): Creating a socket\n"); fflush(stdout); *server_socket_desc_ptr = socket(AF_INET, SOCK_STREAM, 0); if ( *server_socket_desc_ptr == -1 ) { printf("ERROR: OpenSocketServer(): Could not create socket"); fflush(stdout); } // Set master socket to allow multiple connections, this is just a good habit, it will work without this. if( setsockopt(*server_socket_desc_ptr, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) < 0 ) { perror("OpenSocketServer(): setsockopt"); exit(EXIT_FAILURE); } // Do non-block fctrl call if ( check_and_return == 1 ) { int flags = fcntl(*server_socket_desc_ptr, F_GETFL, 0); if (flags < 0) return 0; flags = flags | O_NONBLOCK; if ( fcntl(*server_socket_desc_ptr, F_SETFL, flags) != 0 ) { printf("ERROR: OpenSocketServer(): Failed to set 'fcntl' flags to non-blocking!\n"); fflush(stdout); exit(EXIT_FAILURE); } } // Prepare the sockaddr_in structure for the server. For the XWIN version when the devices are on different subnets, e.g. // 192.168.1.10 and 192.168.2.10, etc, use INADDR_ANY to allow them to connect to the server. Can't do this if running // multiple command line versions of the protocol. server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = inet_addr(server_IP); // server_addr.sin_addr.s_addr = htonl(INADDR_ANY); server_addr.sin_port = htons(port_number); memset(server_addr.sin_zero, 0, 8); // Bind the server with the socket. if ( bind(*server_socket_desc_ptr, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0 ) { printf("ERROR: OpenSocketServer(): Failed to bind!\n"); fflush(stdout); exit(EXIT_FAILURE); } // printf("OpenSocketServer(): Bind done!\n"); fflush(stdout); // Listen to the socket. 'queue_size' indicates how many requests can be pending before an error is // returned to the remote computer requesting a connection. listen(*server_socket_desc_ptr, queue_size); } // printf("OpenSocketServer(): Waiting for incoming connections from clients ....\n"); fflush(stdout); // Waiting and accept incoming connection from the client. Token address information is returned // Note: you can also use 'select' here to determine if a connection request exists. sizeof_sock = sizeof(struct sockaddr_in); if ( check_and_return == 0 ) { while ( (*client_socket_desc_ptr = accept(*server_socket_desc_ptr, (struct sockaddr *)client_addr_ptr, (socklen_t*)&sizeof_sock)) < 0 ) ; // if (*client_socket_desc_ptr < 0) // { printf("ERROR: OpenSocketServer(): Failed accept\n"); fflush(stdout); exit(EXIT_FAILURE); } // printf("OpenSocketServer(): Connection accepted!\n"); fflush(stdout); return 1; } else { if ( (*client_socket_desc_ptr = accept(*server_socket_desc_ptr, (struct sockaddr *)client_addr_ptr, (socklen_t*)&sizeof_sock)) < 0 ) return 0; else return 1; } return 1; } // ======================================================================================================== // ======================================================================================================== // Open up a client socket connection. Returns 0 on success and -1 if fails. int OpenSocketClient(int max_string_len, char *server_IP, int port_number, int *server_socket_desc_ptr) { struct sockaddr_in server_addr; int result; // printf("OpenSocketClient(): Creating a socket\n"); fflush(stdout); if ( (*server_socket_desc_ptr = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) { printf("ERROR: OpenSocketClient(): Could not create socket"); fflush(stdout); exit(EXIT_FAILURE); } server_addr.sin_addr.s_addr = inet_addr(server_IP); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(port_number); memset(server_addr.sin_zero, 0, 8); // Connect to it. 9/14/2018: Changing this from 'exit' to return error. if ( (result = connect(*server_socket_desc_ptr, (struct sockaddr *)&server_addr, sizeof(server_addr))) < 0 ) { printf("INFO: OpenSocketClient: Connect failed -- no listener\n"); fflush(stdout); } // printf("OpenSocketClient(): Connected\n"); fflush(stdout); // Close the socket if the connect fails. if ( result < 0 ) close(*server_socket_desc_ptr); return result; } // ======================================================================================================== // ======================================================================================================== // This function is designed to buffer data but in kernel space. It allows binary data to be transmitted. // To accomplish this, the first two bytes are interpreted as the length of the binary byte stream that follows. // NOTE: I updated this to send all THREE BYTES for the size at some point but the labview code is set up // to handle ONLY 2 (the original version in /picard_data/FPGAs/ZED/WDDL/PROTOCOL/KG_ALL/common.c) int SockGetB(unsigned char *buffer, int buffer_size, int socket_desc) { int tot_bytes_received, target_num_bytes; unsigned char buffer_num_bytes[3]; // Call until two bytes are returned. The 2-byte buffer represents a number that is to be interpreted as the exact // number of binary bytes that will follow in the socket. target_num_bytes = 2; tot_bytes_received = 0; while ( tot_bytes_received < target_num_bytes ) if ( (tot_bytes_received += recv(socket_desc, &buffer_num_bytes[tot_bytes_received], target_num_bytes - tot_bytes_received, 0)) < 0 ) { printf("ERROR: SockGetB(): Error in receiving two byte cnt!\n"); fflush(stdout); return -1; } // Translate the two binary bytes into an integer. target_num_bytes = (int)(buffer_num_bytes[1] << 8) + (int)buffer_num_bytes[0]; // DEBUG //printf("SockGetB(): fetching %d bytes from socket\n", target_num_bytes); fflush(stdout); // Sanity check. if ( target_num_bytes > buffer_size ) { printf("ERROR: SockGetB(): 'target_num_bytes' %d is larger than buffer input size %d\n", target_num_bytes, buffer_size); fflush(stdout); return -1; } // Now start reading binary bytes from the socket tot_bytes_received = 0; while ( tot_bytes_received < target_num_bytes ) if ( (tot_bytes_received += recv(socket_desc, &buffer[tot_bytes_received], target_num_bytes - tot_bytes_received, 0)) < 0 ) { printf("ERROR: SockGetB(): Error in receiving transmitted data!\n"); fflush(stdout); return -1; } // Sanity check if ( tot_bytes_received != target_num_bytes ) { printf("ERROR: SockGetB(): Read more bytes then requested -- 'tot_bytes_received' %d is larger than target %d\n", tot_bytes_received, target_num_bytes); fflush(stdout); return -1; } // DEBUG //printf("SockGetB(): received %d bytes\n", tot_bytes_received); fflush(stdout); return tot_bytes_received; } // ======================================================================================================== // ======================================================================================================== // This function sends binary or ASCII data of 'buffer_size' unsigned characters through the socket. It first // sends two binary bytes that represent the length of the binary or ASCII byte stream that follows. int SockSendB(unsigned char *buffer, int buffer_size, int socket_desc) { unsigned char num_bytes[2]; // Sanity check. Don't yet support transfers larger than 65,536 bytes. if ( buffer_size > 65535 ) { printf("ERROR: SockSendB(): Size of buffer %d larger than max (65536)!\n", buffer_size); fflush(stdout); return -1; } num_bytes[1] = (unsigned char)((buffer_size & 0x0000FF00) >> 8); num_bytes[0] = (unsigned char)(buffer_size & 0x000000FF); if ( send(socket_desc, num_bytes, 2, 0) < 0 ) { printf("ERROR: SockSendB(): Send 'num_bytes' %d failed\n", buffer_size); fflush(stdout); return -1; } if ( send(socket_desc, buffer, buffer_size, 0) < 0 ) { printf("ERROR: SockSendB(): Send failed\n"); fflush(stdout); return -1; } return 0; } // ======================================================================================================== // ======================================================================================================== // This function is designed to buffer data but in kernel space. It allows binary data to be transmitted. // To accomplish this, the first two bytes are interpreted as the length of the binary byte stream that follows. int SockGetB_3Bytes(unsigned char *buffer, int buffer_size, int socket_desc) { int tot_bytes_received, target_num_bytes; unsigned char buffer_num_bytes[4]; // Call until two bytes are returned. The 2-byte buffer represents a number that is to be interpreted as the exact // number of binary bytes that will follow in the socket. target_num_bytes = 3; tot_bytes_received = 0; while ( tot_bytes_received < target_num_bytes ) if ( (tot_bytes_received += recv(socket_desc, &buffer_num_bytes[tot_bytes_received], target_num_bytes - tot_bytes_received, 0)) < 0 ) { printf("ERROR: SockGetB(): Error in receiving three byte cnt!\n"); fflush(stdout); return -1; } // Translate the binary bytes into an integer. target_num_bytes = (int)(buffer_num_bytes[2] << 16) + (int)(buffer_num_bytes[1] << 8) + (int)buffer_num_bytes[0]; // DEBUG //printf("SockGetB(): fetching %d bytes from socket\n", target_num_bytes); fflush(stdout); // Sanity check. if ( target_num_bytes > buffer_size ) { printf("ERROR: SockGetB(): 'target_num_bytes' %d is larger than buffer input size %d\n", target_num_bytes, buffer_size); fflush(stdout); return -1; } // Now start reading binary bytes from the socket tot_bytes_received = 0; while ( tot_bytes_received < target_num_bytes ) if ( (tot_bytes_received += recv(socket_desc, &buffer[tot_bytes_received], target_num_bytes - tot_bytes_received, 0)) < 0 ) { printf("ERROR: SockGetB(): Error in receiving transmitted data!\n"); fflush(stdout); return -1; } // Sanity check if ( tot_bytes_received != target_num_bytes ) { printf("ERROR: SockGetB(): Read more bytes then requested -- 'tot_bytes_received' %d is larger than target %d\n", tot_bytes_received, target_num_bytes); fflush(stdout); return -1; } // DEBUG //printf("SockGetB(): received %d bytes\n", tot_bytes_received); fflush(stdout); return tot_bytes_received; } // ======================================================================================================== // ======================================================================================================== // This function sends binary or ASCII data of 'buffer_size' unsigned characters through the socket. It first // sends two binary bytes that represent the length of the binary or ASCII byte stream that follows. int SockSendB_3Bytes(unsigned char *buffer, int buffer_size, int socket_desc) { unsigned char num_bytes[3]; // Sanity check. Don't yet support transfers larger than 16,777,215 bytes. if ( buffer_size > 16777215 ) { printf("ERROR: SockSendB(): Size of buffer %d larger than max (16777215)!\n", buffer_size); fflush(stdout); return -1; } num_bytes[2] = (unsigned char)((buffer_size & 0x00FF0000) >> 16); num_bytes[1] = (unsigned char)((buffer_size & 0x0000FF00) >> 8); num_bytes[0] = (unsigned char)(buffer_size & 0x000000FF); if ( send(socket_desc, num_bytes, 3, 0) < 0 ) { printf("ERROR: SockSendB(): Send 'num_bytes' %d failed\n", buffer_size); fflush(stdout); return -1; } if ( send(socket_desc, buffer, buffer_size, 0) < 0 ) { printf("ERROR: SockSendB(): Send failed\n"); fflush(stdout); return -1; } return 0; } // ======================================================================================================== // ======================================================================================================== // This function prints a header followed by a block of hex digits. Used in DEBUG mode. void PrintHeaderAndHexVals(char *header_str, int num_vals, unsigned char *vals, int max_vals_per_row) { int i; printf("%s", header_str); printf("\t\t"); fflush(stdout); for ( i = 0; i < num_vals; i++ ) { printf("%02X ", vals[i]); if ( (i+1) % max_vals_per_row == 0 ) printf("\n\t\t"); } // printf("\n\t\tThis last byte may have additional bits if non-zero (given left-to-right) %02X\n", vals[num_vals]); printf("\n\n"); fflush(stdout); return; } // ======================================================================================================== // ======================================================================================================== // Send num_chlngs and vector pairs to the device for ID phase enrollment. void SendChlngsAndMasks(int max_string_len, int num_chlngs, int device_socket_desc, int num_rise_chlngs, int num_chlng_bits, unsigned char **challenges_b, int has_masks, int num_POs, unsigned char **masks) { char num_chlngs_str[max_string_len]; int i; // Send num_chlnges first. sprintf(num_chlngs_str, "%d %d %d", num_chlngs, num_rise_chlngs, has_masks); #ifdef DEBUG printf("Sending '%s'\n to device\n", num_chlngs_str); fflush(stdout); #endif // Send num_bytes of string as two-binary bytes. When sending ASCII character strings, be sure to add one to include // the NULL termination character (+ 1) so the receiver can treat this as a string. if ( SockSendB((unsigned char *)num_chlngs_str, strlen(num_chlngs_str) + 1, device_socket_desc) < 0 ) { printf("ERROR: SendChlngsAndMasks(): Send '%s' failed\n", num_chlngs_str); fflush(stdout); exit(EXIT_FAILURE); } // Send first_vecs and second_vecs to remote server for ( i = 0; i < num_chlngs; i++ ) { if ( SockSendB(challenges_b[i], num_chlng_bits/8, device_socket_desc) < 0 ) { printf("ERROR: SendChlngsAndMasks(): Send 'challenges_b[%d]' failed\n", i); fflush(stdout); exit(EXIT_FAILURE); } if ( has_masks == 1 && SockSendB(masks[i], num_POs/8, device_socket_desc) < 0 ) { printf("ERROR: SendChlngsAndMasks(): Send 'masks[%d]' failed\n", i); fflush(stdout); exit(EXIT_FAILURE); } } // DEBUG // printf("SendChlngsAndMasks(): Sent %d vector pairs!\n", num_chlngs); fflush(stdout); return; } // ======================================================================================================== // ======================================================================================================== // Reads in the challenges file. int ReadChlngAndMaskFilesBinary(int max_string_len, char *chlng_path, int num_chlng_bits, int *num_rise_chlngs_ptr, unsigned char ***challenges_b_ptr, int has_masks, char *mask_file_path, int num_POs, unsigned char ***masks_b_ptr, int num_direction_chlng_bits) { char line[max_string_len], *char_ptr; char challenge[num_chlng_bits+1]; unsigned char *vec_ptr; int rise_or_fall; int chlng_cnt; FILE *INFILE; if ( (INFILE = fopen(chlng_path, "r")) == NULL ) { printf("ERROR: ReadChlngAndMaskFilesBinary(): Could not open VectorPair file %s\n", chlng_path); exit(EXIT_FAILURE); } // Sanity check. Make sure 'num_chlng_bits' is evenly divisible by 8 otherwise the binary conversion routine below will NOT work. if ( (num_chlng_bits % 8) != 0 ) { printf("ERROR: ReadChlngAndMaskFilesBinary(): 'num_chlng_bits' %d MUST be divisible by 8!\n", num_chlng_bits); exit(EXIT_FAILURE); } if ( has_masks == 1 && (num_POs % 8) != 0 ) { printf("ERROR: ReadChlngAndMaskFilesBinary(): 'num_POs' %d MUST be divisible by 8!\n", num_POs); exit(EXIT_FAILURE); } // Force realloc to behave like malloc. DO NOT DO 'masks_asc_ptr' here because we set it to NULL sometimes in the caller. Done below. *challenges_b_ptr = NULL; *masks_b_ptr = NULL; chlng_cnt = 0; *num_rise_chlngs_ptr = 0; while ( fgets(line, max_string_len, INFILE) != NULL ) { // Find the newline and eliminate it. if ((char_ptr = strrchr(line, '\n')) != NULL) *char_ptr = '\0'; // Sanity checks if ( strlen(line) != (unsigned int)num_chlng_bits ) { printf("ERROR: ReadChlngAndMaskFilesBinary(): Unexpected vector size %u -- expected %d!\n", (unsigned int)strlen(line), num_chlng_bits); exit(EXIT_FAILURE); } // Copy the ASCII version of the vector into the stack allocated space + 1 (for NULL termination). strcpy(challenge, line); // Assume the challenges are constructed to be rising only or falling only. For the SRP, a rising vector includes a '1' in the LSB of the high order 16 // bits (dummy bits). Each bit refers to a row in the SRP with the LSB bit referring to the LAST row. Use that bit as the rise/fall indicator. // Note the file ASCII version of the challenge has the high order bits of the challenge in the low order ASCII bit positions. // LSB bit of high order 16 bit word that is referred to as the direction word. A value of '1' indicates a rising transition (THIS MAY CHANGE IN THE FUTURE). if ( challenge[num_direction_chlng_bits - 1] == '1' ) rise_or_fall = 0; else rise_or_fall = 1; // Count up the rising chlngs if ( rise_or_fall == 0 ) (*num_rise_chlngs_ptr)++; // ============================================= // Convert from ASCII to binary. Allocate space for binary unsigned char version of vectors. if ( (*challenges_b_ptr = (unsigned char **)realloc(*challenges_b_ptr, sizeof(unsigned char *)*(chlng_cnt + 1))) == NULL ) { printf("ERROR: ReadChlngAndMaskFilesBinary(): Failed to reallocate storage for challenges_b_ptr array!\n"); exit(EXIT_FAILURE); } if ( ((*challenges_b_ptr)[chlng_cnt] = (unsigned char *)malloc(sizeof(unsigned char)*num_chlng_bits/8)) == NULL ) { printf("ERROR: ReadChlngAndMaskFilesBinary(): Failed to allocate storage for challenges_b_ptr string!\n"); exit(EXIT_FAILURE); } vec_ptr = (*challenges_b_ptr)[chlng_cnt]; // DEBUG // printf("ReadChlngAndMaskFilesBinary(): Binary vec for chlng_cnt %d\n\t", chlng_cnt); fflush(stdout); // Convert ASCII version of vector to binary, reversing the order as appropriate for the hardware that uses these vectors. ASCII version of vector // processed from 0 to 'num_chlng_bits' is high order to low order. Preserve this characteristics in the unsigned char binary byte array by starting the // load at the highest byte. NOTE: 'num_chlng_bits' MUST BE DIVISIBLE BY 8 otherwise this code does not work properly, which is checked above. // Added this call 7/29/2019. ConvertASCIIVecMaskToBinary(num_chlng_bits, line, vec_ptr); chlng_cnt++; } fclose(INFILE); // Read in the mask file if specified if ( has_masks == 1 ) { int mask_vec_num; if ( (INFILE = fopen(mask_file_path, "r")) == NULL ) { printf("ERROR: ReadChlngAndMaskFilesBinary(): Could not open Mask file %s\n", mask_file_path); exit(EXIT_FAILURE); } // We MUST find a mask for every vector read above. for ( mask_vec_num = 0; mask_vec_num < chlng_cnt; mask_vec_num++ ) { // Sanity check if ( fgets(line, max_string_len, INFILE) == NULL ) { printf("ERROR: ReadChlngAndMaskFilesBinary(): A mask file is requested but number of masks_b does NOT equal number of vectors!\n"); exit(EXIT_FAILURE); } // Find the newline and eliminate it. if ((char_ptr = strrchr(line, '\n')) != NULL) *char_ptr = '\0'; // Allocate space for the mask (num_POs/8) if ( (*masks_b_ptr = (unsigned char **)realloc(*masks_b_ptr, sizeof(unsigned char *)*(mask_vec_num + 1))) == NULL ) { printf("ERROR: ReadChlngAndMaskFilesBinary(): Failed to reallocate storage for masks_b_ptr array!\n"); exit(EXIT_FAILURE); } if ( ((*masks_b_ptr)[mask_vec_num] = (unsigned char *)malloc(sizeof(unsigned char)*num_POs/8)) == NULL ) { printf("ERROR: ReadChlngAndMaskFilesBinary(): Failed to allocate storage for masks_b_ptr string!\n"); exit(EXIT_FAILURE); } // ASCII version of mask processed from 0 to 'num_POs' is high order to low order. Preserve this characteristics in the unsigned char binary // byte array by starting the load at the highest byte. NOTE: 'num_POs' MUST BE DIVISIBLE BY 8 otherwise this code does not work properly, // which is checked above. Added this call 7/29/2019. ConvertASCIIVecMaskToBinary(num_POs, line, (*masks_b_ptr)[mask_vec_num]); } fclose(INFILE); } return chlng_cnt; }