/*
 * ==================================================================================
 * Common Header - Shared definitions and utilities for ISA ICMP Covert Channel
 *
 * ISA Project
 * Author: Roman Necas (xnecasr00)
 * Date: 13. October 2025
 *
 * PURPOSE:
 * This header file serves as the central repository for all common definitions,
 * constants, macros, and data structures used throughout the application. It is
 * included by virtually every module in the project.
 *
 * CONTENTS:
 * - System and POSIX includes
 * - Network-related includes (BSD sockets, ICMP)
 * - Application-wide constants and limits
 * - Common data structures (config_t)
 * - Utility macros (SAFE_FREE, SAFE_CLOSE, etc.)
 * - Global variable declarations
 * - Function prototypes for utility functions
 * ==================================================================================
 */

#ifndef COMMON_H
#define COMMON_H

/*
 * ==================================================================================
 * SYSTEM INCLUDES
 * ==================================================================================
 */

/* Enable GNU extensions and POSIX features */
#define _GNU_SOURCE

/* Standard C library headers */
#include <stdio.h>        /* Standard I/O (printf, fprintf, FILE) */
#include <stdlib.h>       /* Memory allocation (malloc, free), exit codes */
#include <string.h>       /* String operations (memcpy, strlen, strcmp) */
#include <unistd.h>       /* POSIX API (getuid, access, close) */
#include <getopt.h>       /* Command-line argument parsing (getopt) */
#include <errno.h>        /* Error number definitions (errno) */
#include <signal.h>       /* Signal handling (not currently used but available) */
#include <time.h>         /* Time functions (time, localtime, strftime) */
#include <ctype.h>        /* Character type checking (isalnum, isdigit) */

/* POSIX socket and system headers */
#include <sys/socket.h>   /* Socket API (socket, bind, sendto, recvfrom) */
#include <sys/types.h>    /* Data types (size_t, ssize_t, pid_t) */
#include <sys/time.h>     /* Time structures (timeval for socket timeouts) */
#include <sys/stat.h>     /* File status (stat, access) */
#include <fcntl.h>        /* File control (open flags, fcntl for non-blocking) */

/* Network protocol headers - BSD sockets */
#include <netinet/in.h>      /* Internet address structures (sockaddr_in, sockaddr_in6) */
#include <netinet/ip.h>      /* IPv4 header structure (struct iphdr) */
#include <netinet/ip_icmp.h> /* ICMPv4 structures (struct icmphdr, ICMP_ECHO, ICMP_ECHOREPLY) */
#include <netinet/ip6.h>     /* IPv6 header structure (struct ip6_hdr) */
#include <netinet/icmp6.h>   /* ICMPv6 structures (struct icmp6_hdr, ICMP6_ECHO_REQUEST, ICMP6_ECHO_REPLY) */
#include <arpa/inet.h>       /* Internet operations (inet_pton, inet_ntop, htons, ntohs) */
#include <netdb.h>           /* Network database (getaddrinfo for hostname resolution) */

/*
 * ==================================================================================
 * APPLICATION CONSTANTS
 * ==================================================================================
 */

/* Application identification */
#define APP_NAME "secret"          /* Application binary name */

/*
 * BUFFER AND SIZE LIMITS
 * ----------------------
 * These constants define the maximum sizes for various buffers and data structures.
 * They are carefully chosen to balance functionality with security and memory usage.
 */

/* Maximum ICMP payload size (1400 bytes)
 * This is chosen to stay well within the typical MTU (1500 bytes) while leaving
 * room for IP header (20 bytes IPv4/40 bytes IPv6) and ICMP header (8 bytes).
 * Formula: 1500 (MTU) - 20 (IP) - 8 (ICMP) - 48 (IFTP header) = 1424 bytes safe
 * We use 1400 for additional safety margin. */
#define MAX_PAYLOAD_SIZE 1400

/* Maximum filename length (255 bytes)
 * Matches the typical filesystem limit for filename components. This does not
 * include the directory path, only the filename itself. */
#define MAX_FILENAME_LEN 255

/* General-purpose buffer size (2048 bytes)
 * Used for temporary operations like packet reception, string formatting, etc.
 * Large enough to hold any ICMP packet including IP header and payload. */
#define MAX_BUFFER_SIZE 2048

/* Maximum path length (4096 bytes)
 * Matches Linux PATH_MAX constant. Used for validating file paths provided
 * by the user on the command line. */
#define MAX_PATH_LEN 4096

/*
 * NETWORK CONFIGURATION
 * ---------------------
 * Timeout and retry parameters for reliable communication over ICMP.
 */

/* Maximum number of retry attempts for failed transmissions
 * After this many retries, the operation is considered failed. */
#define MAX_RETRIES 5

/* Initial timeout value in seconds
 * Time to wait for ACK response before retrying. This value increases
 * exponentially with each retry (exponential backoff). */
#define INITIAL_TIMEOUT 2

/* Maximum timeout value in seconds
 * Upper limit for exponential backoff. Prevents waiting too long. */
#define MAX_TIMEOUT 30

/*
 * ==================================================================================
 * APPLICATION MODE ENUMERATION
 * ==================================================================================
 */

/*
 * app_mode_t - Operating mode of the application
 *
 * The application can run in one of two modes:
 * - CLIENT: Sends a file to a remote server via ICMP
 * - SERVER: Listens for incoming ICMP packets and receives files
 *
 * The mode is determined by command-line arguments:
 * - Client requires: -r <file> -s <destination>
 * - Server requires: -l
 */
typedef enum {
    MODE_CLIENT = 0,    /* Client mode: transmit file via ICMP Echo Request */
    MODE_SERVER = 1     /* Server mode: listen for ICMP Echo Request and save file */
} app_mode_t;

/*
 * ==================================================================================
 * UTILITY MACROS
 * ==================================================================================
 */

/* Get the number of elements in an array
 * Usage: ARRAY_SIZE(my_array) returns the element count
 * Note: Only works with arrays, not pointers */
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))

/* Return the maximum of two values */
#define MAX(a, b) ((a) > (b) ? (a) : (b))

/* Return the minimum of two values */
#define MIN(a, b) ((a) < (b) ? (a) : (b))

/*
 * SAFE MEMORY AND RESOURCE MANAGEMENT MACROS
 * -------------------------------------------
 * These macros provide safe wrappers around common operations that prevent
 * common bugs like double-free and resource leaks.
 */

/*
 * SAFE_FREE - Safely free memory and set pointer to NULL
 *
 * This macro prevents double-free bugs by:
 * 1. Checking if the pointer is non-NULL
 * 2. Calling free()
 * 3. Setting the pointer to NULL
 *
 * After SAFE_FREE(ptr), the pointer is guaranteed to be NULL, making
 * subsequent SAFE_FREE calls safe (they become no-ops).
 *
 * Usage:
 *   char *buffer = malloc(100);
 *   SAFE_FREE(buffer);  // buffer is now NULL
 *   SAFE_FREE(buffer);  // safe - does nothing
 */
#define SAFE_FREE(ptr) do { \
    if (ptr) { \
        free(ptr); \
        ptr = NULL; \
    } \
} while(0)

/*
 * SAFE_CLOSE - Safely close file descriptor and set to -1
 *
 * This macro prevents double-close bugs and resource leaks by:
 * 1. Checking if the file descriptor is valid (>= 0)
 * 2. Calling close()
 * 3. Setting the descriptor to -1
 *
 * After SAFE_CLOSE(fd), the descriptor is -1, making subsequent
 * SAFE_CLOSE calls safe (they become no-ops).
 *
 * Usage:
 *   int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
 *   SAFE_CLOSE(sockfd);  // sockfd is now -1
 *   SAFE_CLOSE(sockfd);  // safe - does nothing
 */
#define SAFE_CLOSE(fd) do { \
    if (fd >= 0) { \
        close(fd); \
        fd = -1; \
    } \
} while(0)

/*
 * ==================================================================================
 * APPLICATION CONFIGURATION STRUCTURE
 * ==================================================================================
 */

/*
 * config_t - Application runtime configuration
 *
 * This structure holds all configuration parameters parsed from command-line
 * arguments. It is populated by parse_arguments() and passed to client_run()
 * or server_run() to control application behavior.
 *
 * LIFECYCLE:
 * 1. Initialized (zeroed) in main()
 * 2. Populated by parse_arguments()
 * 3. Used by client_run() or server_run()
 * 4. Cleaned up by cleanup_config()
 *
 * MEMORY MANAGEMENT:
 * Fields marked with (*) are dynamically allocated and must be freed.
 * Use cleanup_config() to properly release all resources.
 */
typedef struct {
    /* Source file path for transfer (CLIENT MODE ONLY)
     * (*) Dynamically allocated - freed by cleanup_config()
     * Example: "/home/user/document.pdf" */
    char *source_file;

    /* Destination IP address or hostname (CLIENT MODE ONLY)
     * (*) Dynamically allocated - freed by cleanup_config()
     * Examples: "192.168.1.100", "::1", "hostname.example.com" */
    char *dest_address;

    /* Operating mode - CLIENT or SERVER */
    app_mode_t mode;

    /* Listen mode flag (1 = server mode, 0 = client mode)
     * This is redundant with 'mode' field but kept for backward compatibility */
    int listen_mode;

    /* Timeout in seconds for network operations
     * Default: INITIAL_TIMEOUT (2 seconds)
     * Range: 1-300 seconds (validated by argument parser) */
    int timeout_seconds;

    /* Maximum retry attempts for failed operations
     * Default: MAX_RETRIES (5 attempts) */
    int max_retries;
} config_t;

/*
 * ==================================================================================
 * GLOBAL VARIABLES
 * ==================================================================================
 */

/*
 * login - User's login name used as encryption password
 *
 * SECURITY NOTE:
 * This global variable holds the login name which is used as the password
 * for PBKDF2 key derivation. In this implementation, it is hardcoded to
 * "xnecasr00" as required by the assignment specification.
 *
 * USAGE:
 * - Set in argument_parser.c during initialization
 * - Used by crypto_engine.c for AES-256 key derivation via PBKDF2
 * - Both client and server must use the same login for successful decryption
 *
 * REQUIREMENT:
 * According to the assignment specification, the login name must be used
 * as the encryption key. This creates a shared secret between client and
 * server running under the same username.
 */
extern char *login;

/*
 * ==================================================================================
 * FUNCTION DECLARATIONS
 * ==================================================================================
 */

/*
 * Command-line argument parsing
 * ------------------------------
 */

/*
 * parse_arguments - Parse and validate command-line arguments
 *
 * Processes command-line arguments and populates the config structure.
 * Performs comprehensive validation of all inputs including:
 * - File existence and readability (client mode)
 * - IP address/hostname format validation
 * - Timeout range validation
 * - Root privilege verification
 *
 * @param argc: Argument count from main()
 * @param argv: Argument vector from main()
 * @param config: Configuration structure to populate (output parameter)
 *
 * @return:
 *   >0 : Help was displayed (normal exit)
 *    0 : Arguments parsed successfully
 *   -1 : Error occurred (details in error context)
 */
int parse_arguments(int argc, char *argv[], config_t *config);

/*
 * print_usage - Display usage information to stderr
 *
 * Prints comprehensive help text including:
 * - Syntax and options
 * - Usage examples for client and server modes
 * - Security notes and requirements
 *
 * @param progname: Name of the program (typically argv[0])
 */
void print_usage(const char *progname);

/*
 * print_error - Print error message to stderr
 *
 * Convenience function that outputs an error message to stderr
 * and logs it to the error handling system.
 *
 * @param message: Error message to display
 */
void print_error(const char *message);

/*
 * cleanup_config - Free resources allocated in config structure
 *
 * Releases all dynamically allocated memory in the config_t structure.
 * Safe to call multiple times (uses SAFE_FREE internally).
 *
 * @param config: Configuration structure to clean up
 */
void cleanup_config(config_t *config);

/*
 * Filename validation and security
 * ---------------------------------
 */

/*
 * validate_filename - Validate filename for security
 *
 * Performs security checks on a filename to prevent:
 * - Path traversal attacks (.. sequences)
 * - Absolute path abuse
 * - Invalid characters
 * - Control characters
 *
 * This is critical for server-side security when receiving filenames
 * from untrusted clients.
 *
 * @param filename: Filename to validate
 * @return: 0 on success, -1 if filename is invalid
 */
int validate_filename(const char *filename);

/*
 * get_safe_filename - Extract safe filename from path
 *
 * Extracts the basename from a path and ensures the resulting filename
 * is safe to use. If a file with that name already exists, appends a
 * numeric suffix (_1, _2, etc.) to avoid overwriting.
 *
 * SECURITY:
 * This function strips all directory components from the input path,
 * preventing directory traversal attacks.
 *
 * @param original_filename: Input filename (may include path)
 * @param safe_filename: Output buffer for safe filename
 * @param max_len: Maximum length of output buffer
 * @return: 0 on success, -1 on error
 */
int get_safe_filename(const char *original_filename, char *safe_filename, size_t max_len);

/*
 * Session management
 * ------------------
 */

/*
 * generate_secure_session_id - Generate cryptographically secure session ID
 *
 * Creates a random 16-bit session identifier using OpenSSL's RAND_bytes()
 * for cryptographic quality randomness. This ensures session IDs are
 * unpredictable and unique.
 *
 * SECURITY:
 * Uses RAND_bytes() from OpenSSL for cryptographic randomness. Falls back
 * to less secure rand() only if RAND_bytes() fails (extremely rare).
 *
 * @return: 16-bit session ID (never returns 0)
 */
uint16_t generate_secure_session_id(void);

#endif /* COMMON_H */
