Last active
June 11, 2017 11:09
-
-
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.
This file contains 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
#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