Created
February 25, 2025 15:51
-
-
Save dmaynor/7578bc52c6150f0b18e6a216e2c5bf9e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* LINUX KERNEL STYLE */ /* SEI CERT STYLE */ | |
/** /** | |
* Simple socket server example * Simple socket server example following | |
* following Linux Kernel style * SEI CERT secure coding practices | |
*/ */ | |
#include <stdio.h> #include <stdio.h> | |
#include <stdlib.h> #include <stdlib.h> | |
#include <string.h> #include <string.h> | |
#include <unistd.h> #include <unistd.h> | |
#include <arpa/inet.h> #include <arpa/inet.h> | |
#include <sys/socket.h> #include <sys/socket.h> | |
#include <errno.h> | |
#include <stdbool.h> | |
#define PORT 8080 #define PORT 8080 | |
#define BUFFER_SIZE 1024 #define BUFFER_SIZE 1024 | |
#define MAX_CLIENTS 5 #define MAX_CLIENTS 5 | |
/** | |
* Handles client communication securely | |
* @param client_fd Client socket file descriptor | |
* @return true on success, false on error | |
*/ | |
static void handle_client(int client_fd) bool HandleClient(const int client_fd) { | |
{ | |
char buffer[BUFFER_SIZE] = {0}; char buffer[BUFFER_SIZE]; | |
memset(buffer, 0, sizeof(buffer)); | |
int bytes_read; /* Bounds checking and error handling */ | |
ssize_t bytes_read = read(client_fd, buffer, | |
BUFFER_SIZE - 1); | |
bytes_read = read(client_fd, buffer, if (bytes_read < 0) { | |
BUFFER_SIZE); fprintf(stderr, "Error reading from socket: %s\n", | |
if (bytes_read < 0) { strerror(errno)); | |
perror("read failed"); return false; | |
return; } | |
} | |
/* Ensure null termination regardless of client input */ | |
buffer[bytes_read] = '\0'; | |
printf("Message received: %s\n", buffer); printf("Message received: %s\n", buffer); | |
char *response = "Message received"; const char* response = "Message received"; | |
send(client_fd, response, strlen(response), | |
0); /* Check return value of send() */ | |
ssize_t bytes_sent = send(client_fd, response, | |
strlen(response), 0); | |
if (bytes_sent < 0) { | |
fprintf(stderr, "Error sending response: %s\n", | |
strerror(errno)); | |
return false; | |
} | |
} return true; | |
} | |
int main(void) int main(void) { | |
{ | |
int server_fd, client_fd; int server_fd = -1; | |
int client_fd = -1; | |
struct sockaddr_in address; struct sockaddr_in address; | |
int opt = 1; int opt = 1; | |
int addrlen = sizeof(address); socklen_t addrlen = sizeof(address); | |
bool keep_running = true; | |
/* Create socket file descriptor */ /* Create socket with explicit error checking */ | |
if ((server_fd = socket(AF_INET, server_fd = socket(AF_INET, SOCK_STREAM, 0); | |
SOCK_STREAM, 0)) < 0) { if (server_fd < 0) { | |
perror("socket failed"); fprintf(stderr, "Socket creation failed: %s\n", | |
exit(EXIT_FAILURE); strerror(errno)); | |
} return EXIT_FAILURE; | |
} | |
/* Set socket options */ /* Set socket options with explicit error checking */ | |
if (setsockopt(server_fd, SOL_SOCKET, if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, | |
SO_REUSEADDR, &opt, &opt, sizeof(opt)) != 0) { | |
sizeof(opt))) { fprintf(stderr, "Setsockopt failed: %s\n", | |
perror("setsockopt failed"); strerror(errno)); | |
exit(EXIT_FAILURE); close(server_fd); | |
} return EXIT_FAILURE; | |
} | |
/* Initialize address structure */ | |
memset(&address, 0, sizeof(address)); | |
address.sin_family = AF_INET; address.sin_family = AF_INET; | |
address.sin_addr.s_addr = INADDR_ANY; address.sin_addr.s_addr = INADDR_ANY; | |
address.sin_port = htons(PORT); address.sin_port = htons(PORT); | |
/* Bind socket to the port */ /* Bind with explicit error checking */ | |
if (bind(server_fd, (struct sockaddr *) if (bind(server_fd, (struct sockaddr *)&address, | |
&address, sizeof(address)) < 0) { sizeof(address)) != 0) { | |
perror("bind failed"); fprintf(stderr, "Bind failed: %s\n", | |
exit(EXIT_FAILURE); strerror(errno)); | |
} close(server_fd); | |
return EXIT_FAILURE; | |
} | |
/* Listen for connections */ /* Listen with explicit error checking */ | |
if (listen(server_fd, MAX_CLIENTS) < 0) { if (listen(server_fd, MAX_CLIENTS) != 0) { | |
perror("listen failed"); fprintf(stderr, "Listen failed: %s\n", | |
exit(EXIT_FAILURE); strerror(errno)); | |
} close(server_fd); | |
return EXIT_FAILURE; | |
} | |
printf("Server listening on port %d\n", printf("Server listening on port %d\n", PORT); | |
PORT); | |
/* Main server loop */ /* Main server loop with defensive programming */ | |
while (1) { while (keep_running) { | |
printf("Waiting for connection...\n"); printf("Waiting for connection...\n"); | |
if ((client_fd = accept(server_fd, client_fd = accept(server_fd, (struct sockaddr *) | |
(struct sockaddr *)&address, &address, &addrlen); | |
(socklen_t*)&addrlen)) < 0) { if (client_fd < 0) { | |
perror("accept failed"); fprintf(stderr, "Accept failed: %s\n", | |
continue; strerror(errno)); | |
} continue; | |
} | |
/* Handle client connection */ /* Handle client with error checking */ | |
handle_client(client_fd); if (!HandleClient(client_fd)) { | |
close(client_fd); fprintf(stderr, "Client handling failed\n"); | |
} } | |
/* Always close client socket even if errors occurred */ | |
close(client_fd); | |
client_fd = -1; | |
} | |
/* Clean up resources */ | |
if (server_fd >= 0) { | |
close(server_fd); | |
} | |
return 0; return EXIT_SUCCESS; | |
} } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment