Skip to content

Instantly share code, notes, and snippets.

@Gelio
Created April 10, 2017 15:10
Show Gist options
  • Save Gelio/dc6a32ac40db4e9dadacb8d6e8017c31 to your computer and use it in GitHub Desktop.
Save Gelio/dc6a32ac40db4e9dadacb8d6e8017c31 to your computer and use it in GitHub Desktop.
UDP task scheduler with client-server architecture created in C for the Operating Systems class
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <signal.h>
#include <netdb.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#define ERR(source) (perror(source),\
fprintf(stderr,"%s:%d\n",__FILE__,__LINE__),\
exit(EXIT_FAILURE))
#define MAXBUF 576
#define PORT "2000"
#define DELAY_MIN 500
#define DELAY_MAX 2500
#define CLIENT_LIFESPAN 7
volatile sig_atomic_t lastSignal=0,
shouldQuit = 0;
void sigalrm_handler(int sig) {
lastSignal=sig;
}
void sigIntHandler(int signal)
{
shouldQuit = 1;
}
int sethandler( void (*f)(int), int sigNo) {
struct sigaction act;
memset(&act, 0, sizeof(struct sigaction));
act.sa_handler = f;
if (-1==sigaction(sigNo, &act, NULL))
return -1;
return 0;
}
int make_socket(void){
int sock;
sock = socket(PF_INET,SOCK_DGRAM,0);
if(sock < 0) ERR("socket");
return sock;
}
struct sockaddr_in make_address(char *address, char *port){
int ret;
struct sockaddr_in addr;
struct addrinfo *result;
struct addrinfo hints = {};
hints.ai_family = AF_INET;
if((ret=getaddrinfo(address,port, &hints, &result))){
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ret));
exit(EXIT_FAILURE);
}
addr = *(struct sockaddr_in *)(result->ai_addr);
freeaddrinfo(result);
return addr;
}
void usage(char * name){
fprintf(stderr,"USAGE: %s domain\n",name);
}
int checkForTimeout()
{
if (lastSignal == SIGALRM)
{
printf("Client timeout\n");
return 1;
}
return 0;
}
void doClient(int fd, struct sockaddr_in addr){
alarm(CLIENT_LIFESPAN);
socklen_t size = sizeof(struct sockaddr_in);
if (sendto(fd, NULL, 0, 0, &addr, size) < 0)
ERR("sendto");
char buf[MAXBUF];
if (recv(fd, buf, MAXBUF, 0) < 0)
{
if (errno == EINTR && (checkForTimeout() || shouldQuit))
return;
ERR("recv");
}
printf("Received from the server: %s\n", buf);
int digit1,
digit2;
int32_t result;
char operatorChar = buf[1];
digit1 = atoi(buf + 0);
digit2 = atoi(buf + 2);
switch (operatorChar)
{
case '+':
result = digit1 + digit2;
break;
case '-':
result = digit1 - digit2;
break;
case '*':
result = digit1 * digit2;
break;
default:
printf("Unknown operator %c\n", operatorChar);
return;
}
int timeToWait = DELAY_MIN + rand() % (DELAY_MAX - DELAY_MIN + 1);
printf("Waiting %d ms\n", timeToWait);
struct timespec sleepTime;
sleepTime.tv_sec = (int)(timeToWait / 1000);
sleepTime.tv_nsec = (timeToWait - sleepTime.tv_sec * 1000) * 1000;
if (nanosleep(&sleepTime, NULL) < 0 && errno != EINTR)
ERR("nanosleep");
if (shouldQuit || checkForTimeout())
return;
printf("Woke up, sending the result\n");
*(int32_t*)buf = htonl(result);
if (sendto(fd, buf, MAXBUF, 0, &addr, size) < 0)
{
if (errno == EINTR && (checkForTimeout() || shouldQuit))
return;
ERR("sendto");
}
printf("Sent the result (%d) to the server\n", result);
// Wait for retransmission
printf("Listening for retransmission request\n");
if (recv(fd, buf, MAXBUF, 0) < 0)
{
if (errno == EINTR && (checkForTimeout() || shouldQuit))
return;
ERR("recv");
}
printf("Retransmission request received\n");
*(int32_t*)buf = htonl(result);
if (sendto(fd, buf, MAXBUF, 0, &addr, size) < 0)
{
if (errno == EINTR && (checkForTimeout() || shouldQuit))
return;
ERR("sendto");
}
printf("Result retransmitted, exiting\n");
}
int main(int argc, char** argv) {
int fd;
struct sockaddr_in addr;
if(argc!=2) {
usage(argv[0]);
return EXIT_FAILURE;
}
srand(time(NULL));
if (sethandler(sigIntHandler, SIGINT) < 0)
ERR("setting sigint");
if(sethandler(sigalrm_handler,SIGALRM)) ERR("Seting SIGALRM:");
fd = make_socket();
addr=make_address(argv[1],PORT);
doClient(fd,addr);
if(TEMP_FAILURE_RETRY(close(fd))<0)ERR("close");
return EXIT_SUCCESS;
}
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <signal.h>
#include <netdb.h>
#include <fcntl.h>
#include <time.h>
#define ERR(source) (perror(source),\
fprintf(stderr,"%s:%d\n",__FILE__,__LINE__),\
exit(EXIT_FAILURE))
#define BACKLOG 3
#define MAXBUF 576
#define MAXADDR 5
#define PORT 2000
#define ALARM_TIME 2
struct connections{
int free;
int32_t chunkNo;
struct sockaddr_in addr;
};
int sethandler( void (*f)(int), int sigNo) {
struct sigaction act;
memset(&act, 0, sizeof(struct sigaction));
act.sa_handler = f;
if (-1==sigaction(sigNo, &act, NULL))
return -1;
return 0;
}
volatile sig_atomic_t shouldQuit = 0,
lastSignal = 0;
void sigIntHandler(int signal)
{
shouldQuit = 1;
}
void sigAlrmHandler(int signal)
{
lastSignal = signal;
}
int make_socket(int domain, int type){
int sock;
sock = socket(domain,type,0);
if(sock < 0) ERR("socket");
return sock;
}
int bind_inet_socket(uint16_t port,int type){
struct sockaddr_in addr;
int socketfd,t=1;
socketfd = make_socket(PF_INET,type);
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
if (setsockopt(socketfd, SOL_SOCKET, SO_REUSEADDR,&t, sizeof(t))) ERR("setsockopt");
if(bind(socketfd,(struct sockaddr*) &addr,sizeof(addr)) < 0) ERR("bind");
if(SOCK_STREAM==type)
if(listen(socketfd, BACKLOG) < 0) ERR("listen");
return socketfd;
}
void doServer(int fd){
struct sockaddr_in addr;
char buf[MAXBUF];
socklen_t size=sizeof(addr);;
int tasksSent = 0,
resultsReceived = 0;
for(;;){
printf("Waiting for clients\n");
ssize_t bytesReceived = recvfrom(fd,buf,MAXBUF,0,&addr,&size);
if(bytesReceived<0)
{
if (errno == EINTR && shouldQuit)
{
printf("C-c received\n");
break;
}
ERR("recvfrom");
}
if (bytesReceived > 0)
{
printf("Ignoring message\n");
continue;
}
struct sockaddr_in clientAddr = addr;
// New connection
int digit1 = rand() % 10,
digit2 = rand() % 10,
operatorInt = rand() % 3;
char operatorChar;
switch (operatorInt)
{
case 0:
operatorChar = '+';
break;
case 1:
operatorChar = '*';
break;
case 2:
operatorChar = '-';
break;
}
snprintf(buf, MAXBUF, "%d%c%d", digit1, operatorChar, digit2);
if (sendto(fd, buf, MAXBUF, 0, &addr, size) < 0)
ERR("sendto");
printf("Message %s sent to the client\n", buf);
tasksSent++;
addr.sin_addr.s_addr = 0;
alarm(ALARM_TIME);
int messageRetransmitted = 0;
while (1)
{
if (recvfrom(fd, buf, MAXBUF, 0, &addr, &size) < 0)
{
if (errno == EINTR)
{
if(shouldQuit)
break;
if (lastSignal == SIGALRM)
{
lastSignal = 0;
if (messageRetransmitted)
{
printf("No response from the client, moving on\n");
break;
}
// Retransmission
if (sendto(fd, buf, MAXBUF, 0, &addr, size) < 0)
ERR("sendto");
printf("Message %s retransmitted to the client\n", buf);
messageRetransmitted = 1;
alarm(ALARM_TIME);
continue;
}
}
ERR("recvfrom");
}
if (addr.sin_addr.s_addr != clientAddr.sin_addr.s_addr)
{
printf("Received data not from the client, ignoring\n");
continue;
}
alarm(0);
printf("Result received\n");
int32_t result = ntohl(*(int32_t*)buf);
printf("%d%c%d=%d\n", digit1, operatorChar, digit2, result);
resultsReceived++;
break;
}
if (shouldQuit)
break;
}
printf("Sent %d tasks and received %d results\n", tasksSent, resultsReceived);
}
void usage(char * name){
fprintf(stderr,"USAGE: %s\n",name);
}
int main(int argc, char** argv) {
int fd = bind_inet_socket(PORT,SOCK_DGRAM);
srand(time(NULL));
if (sethandler(sigIntHandler, SIGINT) < 0)
ERR("sethandler sigint");
if (sethandler(sigAlrmHandler, SIGALRM) < 0)
ERR("sethandler sigalrm");
doServer(fd);
if(TEMP_FAILURE_RETRY(close(fd))<0)ERR("close");
fprintf(stderr,"Server has terminated.\n");
return EXIT_SUCCESS;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment