Error Handling Functions
#include <keychain/keychain_headers.h>
Overview
Error handling functions provide comprehensive error code management, message retrieval, and diagnostic information for debugging and troubleshooting Keychain Core C API operations.
Error Code Functions
kc_common_get_error_message()
unsigned int kc_common_get_error_message(
char** out_error_message,
unsigned int* out_message_size,
unsigned int error_code
)
Gets a human-readable error message for a specific error code.
Parameters:
-
out_error_message
- Pointer to error message string pointer (output, caller must free) -
out_message_size
- Pointer to message string length (output) -
error_code
- Error code to get message for
Returns: Error code (0 = success)
Example:
unsigned int result = kc_gateway_create_persona(gateway, &persona, "test", 4, "test", 4, KC_SECURITY_LEVEL_HIGH, 1);
if (result != 0) {
char* error_msg = NULL;
unsigned int msg_size = 0;
unsigned int get_result = kc_common_get_error_message(&error_msg, &msg_size, result);
if (get_result == 0) {
printf("Operation failed: %s (error code: %u)\n", error_msg, result);
kc_common_delete_buffer(&error_msg);
} else {
printf("Operation failed with error code: %u\n", result);
}
}
kc_common_get_last_error()
unsigned int kc_common_get_last_error(unsigned int* out_error_code)
Gets the error code from the last failed operation in the current thread.
Parameters:
-
out_error_code
- Pointer to error code (output)
Returns: Error code (0 = success, non-zero if no error available)
Example:
// Perform some operation that might fail
unsigned int result = kc_gateway_hash(&hash_result, &hash_size, "data", 4);
// Check if operation failed
if (result != 0) {
unsigned int last_error = 0;
unsigned int get_result = kc_common_get_last_error(&last_error);
if (get_result == 0) {
printf("Last error code: %u\n", last_error);
assert(last_error == result); // Should match
}
}
kc_common_clear_last_error()
unsigned int kc_common_clear_last_error()
Clears the last error for the current thread.
Returns: Error code (0 = success)
Example:
// Clear any previous errors
kc_common_clear_last_error();
// Perform operation
unsigned int result = kc_gateway_some_operation(gateway);
// Check for new errors
unsigned int last_error = 0;
if (kc_common_get_last_error(&last_error) == 0) {
printf("New error occurred: %u\n", last_error);
}
kc_common_is_error_recoverable()
unsigned int kc_common_is_error_recoverable(
unsigned int error_code,
unsigned int* out_is_recoverable
)
Determines if an error condition is recoverable or requires restart.
Parameters:
-
error_code
- Error code to check -
out_is_recoverable
- Pointer to recoverable flag (output, 1 = recoverable, 0 = fatal)
Returns: Error code (0 = success)
Example:
unsigned int operation_result = kc_gateway_connect_to_server(gateway);
if (operation_result != 0) {
unsigned int is_recoverable = 0;
unsigned int check_result = kc_common_is_error_recoverable(operation_result, &is_recoverable);
if (check_result == 0) {
if (is_recoverable) {
printf("Recoverable error - retrying operation\n");
// Implement retry logic
} else {
printf("Fatal error - application restart required\n");
exit(1);
}
}
}
Error Category Functions
kc_common_get_error_category()
unsigned int kc_common_get_error_category(
unsigned int error_code,
char** out_category_name,
unsigned int* out_name_size
)
Gets the category name for an error code (e.g., "NETWORK", "CRYPTO", "VALIDATION").
Parameters:
-
error_code
- Error code to categorize -
out_category_name
- Pointer to category name string pointer (output, caller must free) -
out_name_size
- Pointer to name string length (output)
Returns: Error code (0 = success)
Example:
unsigned int crypto_error = KC_ERROR_INVALID_SIGNATURE;
char* category = NULL;
unsigned int category_size = 0;
unsigned int result = kc_common_get_error_category(crypto_error, &category, &category_size);
if (result == 0) {
printf("Error category: %s\n", category); // Outputs: "CRYPTO"
kc_common_delete_buffer(&category);
}
kc_common_get_error_severity()
unsigned int kc_common_get_error_severity(
unsigned int error_code,
unsigned int* out_severity_level
)
Gets the severity level for an error code (1=INFO, 2=WARNING, 3=ERROR, 4=CRITICAL).
Parameters:
-
error_code
- Error code to check -
out_severity_level
- Pointer to severity level (output)
Returns: Error code (0 = success)
Example:
unsigned int network_error = KC_ERROR_CONNECTION_TIMEOUT;
unsigned int severity = 0;
unsigned int result = kc_common_get_error_severity(network_error, &severity);
if (result == 0) {
switch (severity) {
case 1: printf("INFO level error\n"); break;
case 2: printf("WARNING level error\n"); break;
case 3: printf("ERROR level error\n"); break;
case 4: printf("CRITICAL level error\n"); break;
}
}
Diagnostic Functions
kc_common_get_diagnostic_info()
unsigned int kc_common_get_diagnostic_info(
char** out_diagnostic_json,
unsigned int* out_json_size
)
Gets comprehensive diagnostic information about the current library state in JSON format.
Parameters:
-
out_diagnostic_json
- Pointer to diagnostic JSON string pointer (output, caller must free) -
out_json_size
- Pointer to JSON string length (output)
Returns: Error code (0 = success)
Example:
char* diagnostics = NULL;
unsigned int diag_size = 0;
unsigned int result = kc_common_get_diagnostic_info(&diagnostics, &diag_size);
if (result == 0) {
printf("Library Diagnostics:\n%s\n", diagnostics);
kc_common_delete_buffer(&diagnostics);
}
kc_common_get_call_stack()
unsigned int kc_common_get_call_stack(
char** out_stack_trace,
unsigned int* out_trace_size
)
Gets the current call stack for debugging purposes (debug builds only).
Parameters:
-
out_stack_trace
- Pointer to stack trace string pointer (output, caller must free) -
out_trace_size
- Pointer to trace string length (output)
Returns: Error code (0 = success)
Example:
#ifdef DEBUG
char* stack_trace = NULL;
unsigned int trace_size = 0;
unsigned int result = kc_common_get_call_stack(&stack_trace, &trace_size);
if (result == 0) {
printf("Call Stack:\n%s\n", stack_trace);
kc_common_delete_buffer(&stack_trace);
}
#endif
kc_common_enable_debug_logging()
unsigned int kc_common_enable_debug_logging(
const char* log_file_path,
unsigned int path_size,
unsigned int log_level
)
Enables debug logging to a file with specified level (1=ERROR, 2=WARN, 3=INFO, 4=DEBUG, 5=TRACE).
Parameters:
-
log_file_path
- Path to log file -
path_size
- Length of file path -
log_level
- Logging level (1-5)
Returns: Error code (0 = success)
Example:
const char* log_path = "/var/log/keychain_debug.log";
unsigned int result = kc_common_enable_debug_logging(log_path, strlen(log_path), 4); // DEBUG level
if (result == 0) {
printf("Debug logging enabled at DEBUG level\n");
}
Common Error Codes
The following error codes are commonly returned by Keychain Core functions:
General Errors
-
KC_SUCCESS
(0) - Operation completed successfully -
KC_ERROR_INVALID_PARAMETER
(1) - Invalid parameter provided -
KC_ERROR_NULL_POINTER
(2) - Required pointer is NULL -
KC_ERROR_BUFFER_TOO_SMALL
(3) - Provided buffer is too small -
KC_ERROR_OUT_OF_MEMORY
(4) - Memory allocation failed -
KC_ERROR_NOT_INITIALIZED
(5) - Library not properly initialized
Network Errors (100-199)
-
KC_ERROR_CONNECTION_FAILED
(100) - Failed to connect to server -
KC_ERROR_CONNECTION_TIMEOUT
(101) - Connection timed out -
KC_ERROR_NETWORK_UNREACHABLE
(102) - Network is unreachable -
KC_ERROR_SERVER_UNAVAILABLE
(103) - Server is unavailable -
KC_ERROR_PROTOCOL_ERROR
(104) - Protocol communication error
Cryptographic Errors (200-299)
-
KC_ERROR_INVALID_SIGNATURE
(200) - Digital signature is invalid -
KC_ERROR_INVALID_CERTIFICATE
(201) - Certificate is invalid or expired -
KC_ERROR_KEY_NOT_FOUND
(202) - Cryptographic key not found -
KC_ERROR_ENCRYPTION_FAILED
(203) - Encryption operation failed -
KC_ERROR_DECRYPTION_FAILED
(204) - Decryption operation failed -
KC_ERROR_HASH_MISMATCH
(205) - Hash values do not match
Usage Patterns
Basic Error Handling Pattern
// Standard error handling pattern for Keychain operations
unsigned int safe_operation_with_error_handling() {
char* result_buffer = NULL;
unsigned int buffer_size = 0;
// Clear any previous errors
kc_common_clear_last_error();
// Perform operation
unsigned int result = kc_gateway_some_operation(gateway, &result_buffer, &buffer_size);
if (result != 0) {
// Get detailed error information
char* error_msg = NULL;
unsigned int msg_size = 0;
char* category = NULL;
unsigned int category_size = 0;
unsigned int severity = 0;
kc_common_get_error_message(&error_msg, &msg_size, result);
kc_common_get_error_category(result, &category, &category_size);
kc_common_get_error_severity(result, &severity);
printf("Operation failed:\n");
printf(" Error code: %u\n", result);
printf(" Message: %s\n", error_msg ? error_msg : "Unknown error");
printf(" Category: %s\n", category ? category : "Unknown");
printf(" Severity: %u\n", severity);
// Cleanup error strings
if (error_msg) kc_common_delete_buffer(&error_msg);
if (category) kc_common_delete_buffer(&category);
return result;
}
// Success - use result_buffer
if (result_buffer) {
printf("Operation succeeded: %s\n", result_buffer);
kc_common_delete_buffer(&result_buffer);
}
return KC_SUCCESS;
}
Retry Logic with Error Analysis
// Implement retry logic based on error recoverability
unsigned int operation_with_retry(kc_gateway_t* gateway, int max_retries) {
int retry_count = 0;
unsigned int result;
do {
result = kc_gateway_connect_to_server(gateway);
if (result == KC_SUCCESS) {
printf("Connection successful on attempt %d\n", retry_count + 1);
return KC_SUCCESS;
}
// Check if error is recoverable
unsigned int is_recoverable = 0;
unsigned int check_result = kc_common_is_error_recoverable(result, &is_recoverable);
if (check_result != 0 || !is_recoverable) {
char* error_msg = NULL;
unsigned int msg_size = 0;
kc_common_get_error_message(&error_msg, &msg_size, result);
printf("Non-recoverable error: %s\n", error_msg ? error_msg : "Unknown");
if (error_msg) kc_common_delete_buffer(&error_msg);
return result;
}
retry_count++;
if (retry_count < max_retries) {
printf("Recoverable error on attempt %d, retrying...\n", retry_count);
// Exponential backoff
unsigned int delay_ms = 1000 * (1 << (retry_count - 1)); // 1s, 2s, 4s, 8s...
#ifdef _WIN32
Sleep(delay_ms);
#else
usleep(delay_ms * 1000);
#endif
}
} while (retry_count < max_retries);
printf("Operation failed after %d attempts\n", max_retries);
return result;
}
Comprehensive Error Logging
// Log errors with full context for debugging
void log_error_with_context(unsigned int error_code, const char* operation_name) {
char* error_msg = NULL;
char* category = NULL;
char* diagnostics = NULL;
unsigned int msg_size = 0;
unsigned int category_size = 0;
unsigned int diag_size = 0;
unsigned int severity = 0;
// Get all available error information
kc_common_get_error_message(&error_msg, &msg_size, error_code);
kc_common_get_error_category(error_code, &category, &category_size);
kc_common_get_error_severity(error_code, &severity);
kc_common_get_diagnostic_info(&diagnostics, &diag_size);
// Log to file or console
FILE* log_file = fopen("/var/log/keychain_errors.log", "a");
if (log_file) {
time_t now = time(NULL);
char* timestamp = ctime(&now);
timestamp[strlen(timestamp) - 1] = '\0'; // Remove newline
fprintf(log_file, "\n=== ERROR LOG ENTRY ===\n");
fprintf(log_file, "Timestamp: %s\n", timestamp);
fprintf(log_file, "Operation: %s\n", operation_name);
fprintf(log_file, "Error Code: %u\n", error_code);
fprintf(log_file, "Message: %s\n", error_msg ? error_msg : "Unknown");
fprintf(log_file, "Category: %s\n", category ? category : "Unknown");
fprintf(log_file, "Severity: %u\n", severity);
if (diagnostics) {
fprintf(log_file, "Diagnostics:\n%s\n", diagnostics);
}
#ifdef DEBUG
char* stack_trace = NULL;
unsigned int trace_size = 0;
if (kc_common_get_call_stack(&stack_trace, &trace_size) == 0) {
fprintf(log_file, "Call Stack:\n%s\n", stack_trace);
kc_common_delete_buffer(&stack_trace);
}
#endif
fprintf(log_file, "========================\n");
fclose(log_file);
}
// Cleanup
if (error_msg) kc_common_delete_buffer(&error_msg);
if (category) kc_common_delete_buffer(&category);
if (diagnostics) kc_common_delete_buffer(&diagnostics);
}
// Usage example
void demonstrate_error_logging() {
unsigned int result = kc_gateway_create_persona(gateway, NULL, "test", 4, "test", 4, KC_SECURITY_LEVEL_HIGH, 1);
if (result != 0) {
log_error_with_context(result, "kc_gateway_create_persona");
}
}
Error Recovery Strategies
// Implement different recovery strategies based on error type
unsigned int handle_error_with_recovery(unsigned int error_code, kc_gateway_t* gateway) {
char* category = NULL;
unsigned int category_size = 0;
unsigned int severity = 0;
kc_common_get_error_category(error_code, &category, &category_size);
kc_common_get_error_severity(error_code, &severity);
if (category) {
if (strcmp(category, "NETWORK") == 0) {
// Network error - try reconnection
printf("Network error detected - attempting reconnection\n");
kc_gateway_on_stop(gateway);
// Wait before retry
#ifdef _WIN32
Sleep(5000); // 5 seconds
#else
sleep(5);
#endif
unsigned int restart_result = kc_gateway_on_start(gateway);
kc_common_delete_buffer(&category);
return restart_result;
} else if (strcmp(category, "CRYPTO") == 0) {
// Cryptographic error - may need key regeneration
printf("Cryptographic error detected - check key validity\n");
kc_common_delete_buffer(&category);
return KC_ERROR_KEY_NOT_FOUND; // Indicate key issue
} else if (strcmp(category, "STORAGE") == 0) {
// Storage error - try alternative storage
printf("Storage error detected - switching to backup storage\n");
// Implementation would switch to backup storage
kc_common_delete_buffer(&category);
return KC_SUCCESS;
} else if (strcmp(category, "VALIDATION") == 0) {
// Validation error - user input issue
printf("Validation error detected - check input parameters\n");
kc_common_delete_buffer(&category);
return error_code; // Return original error for user correction
}
kc_common_delete_buffer(&category);
}
// Unknown error category - log for investigation
printf("Unknown error category - logging for analysis\n");
log_error_with_context(error_code, "unknown_operation");
return error_code;
}
Debug Mode Error Handling
// Enhanced error handling for debug builds
#ifdef DEBUG
void debug_error_handler(unsigned int error_code) {
printf("\n*** DEBUG ERROR HANDLER ***\n");
// Enable comprehensive logging
kc_common_enable_debug_logging("/tmp/keychain_debug.log", 23, 5); // TRACE level
// Get all error details
char* error_msg = NULL;
char* category = NULL;
char* diagnostics = NULL;
char* stack_trace = NULL;
unsigned int msg_size, category_size, diag_size, trace_size;
unsigned int severity = 0;
kc_common_get_error_message(&error_msg, &msg_size, error_code);
kc_common_get_error_category(error_code, &category, &category_size);
kc_common_get_error_severity(error_code, &severity);
kc_common_get_diagnostic_info(&diagnostics, &diag_size);
kc_common_get_call_stack(&stack_trace, &trace_size);
printf("Error Code: %u\n", error_code);
printf("Message: %s\n", error_msg ? error_msg : "Unknown");
printf("Category: %s\n", category ? category : "Unknown");
printf("Severity: %u\n", severity);
if (diagnostics) {
printf("Diagnostics:\n%s\n", diagnostics);
}
if (stack_trace) {
printf("Call Stack:\n%s\n", stack_trace);
}
printf("*** END DEBUG ERROR HANDLER ***\n\n");
// Cleanup
if (error_msg) kc_common_delete_buffer(&error_msg);
if (category) kc_common_delete_buffer(&category);
if (diagnostics) kc_common_delete_buffer(&diagnostics);
if (stack_trace) kc_common_delete_buffer(&stack_trace);
}
#endif
Thread Safety
Error handling functions are thread-safe. Each thread maintains its own error context:
// Thread-safe error handling example
#include <pthread.h>
void* worker_thread(void* arg) {
int thread_id = *(int*)arg;
// Each thread has its own error context
kc_common_clear_last_error();
unsigned int result = kc_gateway_some_operation(gateway);
if (result != 0) {
unsigned int last_error = 0;
kc_common_get_last_error(&last_error);
printf("Thread %d error: %u\n", thread_id, last_error);
}
return NULL;
}
Related Functions
-
Initialization and Cleanup - Library setup and teardown
-
Memory Management - Buffer allocation and cleanup
-
Gateway Operations - Functions that return error codes
See Also
-
C++ Gateway Class - Exception-based error handling
-
{error-handling-best-practices}[Error Handling Best Practices]
-
{c-api-debugging}[C API Debugging Guide]