Skip to content

Instantly share code, notes, and snippets.

@DmitryKhlus
Last active September 24, 2023 13:47
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save DmitryKhlus/b5b81363fdad02091f6f to your computer and use it in GitHub Desktop.
Save DmitryKhlus/b5b81363fdad02091f6f to your computer and use it in GitHub Desktop.
Unix domain sockets + select + pthread
#include <stdio.h>
#include <stdint.h>
#include <string.h> //strlen
#include <stdlib.h>
#include <errno.h>
#include <unistd.h> //close
#include <sys/un.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <sys/time.h> //FD_SET, FD_ISSET, FD_ZERO macros
#include<pthread.h> //for threading , link with lpthread
#include <fcntl.h>
#define SOCK_PATH "/tmp/echo_socket"
bool daemonize() {
int res = fork();
if (res < 0) {
perror("fork");
return false;
}
if (res != 0)
_exit(0);
// Now we're running as the daemon...
res = setsid();
if (res < 0) {
perror("setsid");
return false;
}
if (false) {
int fd = open("/dev/null", O_RDWR, 0);
if (fd >= 0) {
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
if (fd > 2)
close(fd);
}
}
return true;
}
/*
* This will handle connection for each client
* */
void *connection_handler(void *socket_desc)
{
//Get the socket descriptor
int& sock = *(int*)socket_desc;
int read_size;
char client_message[2000];
//Send some messages to the client
const char *message = "Greetings! I am your connection handler\n";
write(sock , message , strlen(message));
message = "Now type something and i shall repeat what you type \n";
write(sock , message , strlen(message));
//Receive a message from client
while( (read_size = recv(sock , client_message , 2000 , 0)) > 0 )
{
//end of string marker
client_message[read_size] = '\0';
//Send the message back to client
write(sock , client_message , strlen(client_message));
//clear the message buffer
memset(client_message, 0, 2000);
}
if(read_size == 0)
{
puts("Client disconnected");
fflush(stdout);
}
else if(read_size == -1)
{
perror("recv failed");
}
//
sock = 0;
return 0;
}
int main(int argc , char *argv[])
{
bool dflag = false;
if (dflag && !daemonize()) {
return -1;
}
int master_socket;
int client_socket[30];
int max_clients = 30;
struct sockaddr_un address;
//set of socket descriptors
fd_set readfds;
//initialize all client_socket[] to 0 so not checked
memset(client_socket, 0, sizeof(client_socket));
//create a master socket
if( (master_socket = socket(AF_UNIX , SOCK_STREAM , 0)) == 0)
{
perror("socket failed");
exit(EXIT_FAILURE);
}
unlink(SOCK_PATH);
//type of socket created
address.sun_family = AF_UNIX;
strcpy(address.sun_path, SOCK_PATH);
size_t len = strlen(address.sun_path) + sizeof(address.sun_family);
if (bind(master_socket, (struct sockaddr *)&address, len)<0)
{
perror("bind failed");
exit(EXIT_FAILURE);
}
printf("Listener on port %s \n", SOCK_PATH);
//try to specify maximum of 3 pending connections for the master socket
if (listen(master_socket, 3) < 0)
{
perror("listen");
exit(EXIT_FAILURE);
}
//accept the incoming connection
size_t addrlen = sizeof(address);
puts("Waiting for connections ...");
while(true)
{
//clear the socket set
FD_ZERO(&readfds);
//add master socket to set
FD_SET(master_socket, &readfds);
int max_sd = master_socket;
//add child sockets to set
for (int i = 0 ; i < max_clients ; i++)
{
//socket descriptor
int sd = client_socket[i];
//if valid socket descriptor then add to read list
if(sd > 0)
FD_SET( sd , &readfds);
//highest file descriptor number, need it for the select function
if(sd > max_sd)
max_sd = sd;
}
//wait for an activity on one of the sockets , timeout is NULL , so wait indefinitely
int activity = select( max_sd + 1 , &readfds , NULL , NULL , NULL);
if ((activity < 0) && (errno != EINTR))
{
printf("select error");
}
//If something happened on the master socket , then its an incoming connection
if (FD_ISSET(master_socket, &readfds))
{
int new_socket = 0;
if ((new_socket = accept(master_socket, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0)
{
perror("accept");
exit(EXIT_FAILURE);
}
puts("Welcome message sent successfully");
//add new socket to array of sockets
for (int i = 0; i < max_clients; i++)
{
//if position is empty
if( client_socket[i] == 0 )
{
client_socket[i] = new_socket;
printf("Adding to list of sockets as %d\n" , i);
pthread_t thread_id;
if( pthread_create( &thread_id , NULL , connection_handler , (void*) &client_socket[i]) < 0)
{
perror("could not create thread");
return 1;
}
pthread_detach(thread_id);
break;
}
}
}
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment