Skip to content

Instantly share code, notes, and snippets.

@imamhidayat92
Last active June 11, 2017 11:09
Show Gist options
  • Save imamhidayat92/cded58b4b6b0f32a2cc12787b247cf4a to your computer and use it in GitHub Desktop.
Save imamhidayat92/cded58b4b6b0f32a2cc12787b247cf4a to your computer and use it in GitHub Desktop.
A simple server implementation that will send "Hello world!" message to every client that connects to it.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#define PORT "54321"
#define BACKLOG 10
/**
* Handle SIGCHLD signal.
*/
void child_process_terminated_handler(int s) {
int saved_errno = errno;
while(waitpid(-1, NULL, WNOHANG) > 0) {
// No operations.
}
errno = saved_errno;
}
/**
* Classify incoming address, whether it's IPv4 or IPv6.
*/
void *get_incoming_address(struct sockaddr *address) {
if (address->sa_family == AF_INET) {
return &(((struct sockaddr_in*)address)->sin_addr);
}
return &(((struct sockaddr_in6*)address)->sin6_addr);
}
int main(int argc, char** argv) {
printf("Starting server...\n");
struct addrinfo hint;
memset(&hint, 0, sizeof hint);
hint.ai_family = AF_UNSPEC;
hint.ai_socktype = SOCK_STREAM;
hint.ai_flags = AI_PASSIVE;
int status;
struct addrinfo *server_info;
status = getaddrinfo(NULL, PORT, &hint, &server_info);
if (status != 0) {
fprintf(stderr, "error, getaddrinfo: %s\n", gai_strerror(status));
return 1;
}
int sockfd;
struct addrinfo *p;
for (p = server_info; p != NULL; p = p->ai_next) {
sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (sockfd == -1) {
perror("socket");
continue;
}
int yes = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
perror("bind");
continue;
}
break;
}
freeaddrinfo(server_info);
if (p == NULL) {
fprintf(stderr, "Server failed to bind.\n");
exit(1);
}
if (listen(sockfd, BACKLOG) == -1) {
perror("listen");
exit(1);
}
struct sigaction action;
action.sa_handler = child_process_terminated_handler;
sigemptyset(&action.sa_mask);
action.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &action, NULL) == -1) {
perror("sigaction");
exit(1);
}
printf("Server started, waiting for connections...\n");
while(1) {
struct sockaddr_storage incoming_address;
socklen_t sin_size = sizeof incoming_address;
int incoming_sockfd = accept(sockfd,
(struct sockaddr *)&incoming_address,
&sin_size);
if (incoming_sockfd == -1) {
perror("accept");
continue;
}
char ip_address[INET6_ADDRSTRLEN];
inet_ntop(incoming_address.ss_family,
get_incoming_address((struct sockaddr *)&incoming_address),
ip_address,
sizeof ip_address);
printf("Incoming connection from %s.\n", ip_address);
pid_t pid = fork();
if (pid == 0) {
close(sockfd);
printf("Sending message.. ");
char *message = "Hello world!\n";
int length = strlen(message);
int send_status = send(incoming_sockfd, message, length, 0);
if (send_status == -1) {
perror("send");
}
close(incoming_sockfd);
printf("Message sent, connection closed.\n");
exit(0);
}
close(incoming_sockfd);
}
return (EXIT_SUCCESS);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment