Skip to content
Snippets Groups Projects
Commit 63309939 authored by Guillaume Chanel's avatar Guillaume Chanel
Browse files

Uncompleted version

parents
Branches main
No related tags found
No related merge requests found
Makefile 0 → 100644
CC=gcc
CFLAGS=-g
LDFLAGS=
.PHONY: all clean
all: server client
server: server.o common.o
$(CC) server.o common.o -o server
client: client.o common.o
$(CC) client.o common.o -o client $(LDFLAGS)
server.o: server.c common.o
$(CC) $(CFLAGS) -c server.c -o server.o
client.o: client.c common.o
$(CC) $(CFLAGS) -c client.c -o client.o
common.o: common.c common.h
$(CC) $(CFLAGS) -c common.c -o common.o
clean:
rm *.o server client
common.c 0 → 100644
#include "common.h"
// This fonction takes a string as input and convert it to a
// uint16_t. It stops the program with an error message if the
// string does not correspond to an integer fitting an uint16_t
uint16_t string_to_port(const char *str) {
// Convert input in port number
errno = 0;
long int port = strtol(str, NULL, 10);
if (errno != 0)
die("port value");
// Check long int fit in uint16 (as it is the returned value)
if (port > UINT16_MAX) {
errno = ERANGE;
die("port value");
}
// If port == 0 either no valid numerical value was found or 0 was found
// none is a valid port
if (port == 0) {
fprintf(stderr, "%s is not a valid port\n", str);
exit(1);
}
return port;
}
// This function attempts to read on the file descriptor
// count bytes of data. It outputs an error and exit if:
// - a read call returns 0 (no more data on fd)
// - a read call returns an error
void read_full(int fd, void* buff, size_t count) {
ssize_t nb_read;
do {
nb_read = read(fd, buff, count);
if ( nb_read == -1)
die("read_full");
if (nb_read == 0) {
fprintf(stderr, "read_full: file descriptor end is reached before count bytes were read\n");
exit(EXIT_FAILURE);
}
count -= nb_read;
buff += nb_read;
} while(count > 0);
}
// This function attempts to write on the file descriptor
// count bytes of data. It outputs an error and exit if:
// - a write call returns 0 (no more space on fd)
// - a write call returns an error
void write_full(int fd, const void* buff, size_t count) {
ssize_t nb_write;
do {
nb_write = write(fd, buff, count);
if ( nb_write == -1)
die("write socket");
if (nb_write == 0) {
fprintf(stderr, "write_full: file descriptor end is reached before count bytes were written\n");
exit(EXIT_FAILURE);
}
count -= nb_write;
buff += nb_write;
} while(count > 0);
}
\ No newline at end of file
common.h 0 → 100644
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#define die(msg) do { perror(msg); exit(errno); } while(0);
typedef /* TBD */ value_t; //The type of the value to send
// The type of the init message sent by the server
// specifies min and max values
typedef struct {
/* TBD */
} initmsg_t;
// The type of the message exchanged between client and server
typedef struct {
/* TBD */
} msg_t;
// the cmd member can take the following values
#define TOO_LOW -1
#define WIN 0
#define TOO_HIGH 1
#define LOSE 2
// This fonction takes a string as input and convert it to a
// uint16_t. It stops the program with an error message if the
// string does not correspond to an integer fitting an uint16_t
uint16_t string_to_port(const char*);
// This function attempts to read on the file descriptor
// count bytes of data. It outputs an error and exit if:
// - a read call returns 0 (no more data on fd)
// - a read call returns an error
void read_full(int, void*, size_t);
// This function attempts to write on the file descriptor
// count bytes of data. It outputs an error and exit if:
// - a write call returns 0 (no more space on fd)
// - a write call returns an error
void write_full(int, const void*, size_t);
\ No newline at end of file
server.c 0 → 100644
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <errno.h>
#include <string.h>
#include <sys/wait.h>
#include "common.h"
#define MIN_VALUE 0
#define MAX_VALUE 255
#define NB_TRIES 200
// get a random value between min and max
// urandom is read up to moment where valid
// value is obtained. Theoretically this function
// could loop for ever
value_t get_random_value(value_t min, value_t max) {
// Open random generator
int fd = open("/dev/urandom", O_RDONLY);
if( fd == -1 )
die("/dev/urandom");
// Read from random generator as long as value is not in range
value_t value;
do {
read_full(fd, &value, sizeof(value));
} while( value < min || value > max );
close(fd);
return value;
}
// Manages each client on a different socket
// returns 0 if the client lost and different value otherwise
int process_client(int socket, struct sockaddr_in client) {
// Get random number in range
value_t value = get_random_value(MIN_VALUE, MAX_VALUE);
printf("Selected value for client %d: %d\n", socket, value);
// Send init message to client
initmsg_t initmsg = { MIN_VALUE, MAX_VALUE };
write_full(socket, &initmsg, sizeof(initmsg));
// As long as the client does not exeed the maximum number tries
// or found the correct answer, read proposition and send answer
long int proposition = 0;
msg_t msg = {TOO_LOW, value};
while ( msg.cmd != LOSE && msg.cmd != WIN ) {
// Read client proposition
read_full(socket, &msg, sizeof(msg));
proposition++;
printf("Client %d proposes %d\n", socket, msg.value);
// Check proposition against true value
if(msg.value == value) {
msg.cmd = WIN;
} else {
if(proposition < NB_TRIES) {
if(msg.value < value)
msg.cmd = TOO_LOW;
else
msg.cmd = TOO_HIGH;
} else
msg.cmd = LOSE;
}
// Send answer
msg.value = value;
write_full(socket, &msg, sizeof(msg));
} ;
printf("Client %d ", socket);
if(msg.cmd == WIN)
printf("wins !!!\n");
else
printf("miserably lost...");
printf("\n");
return msg.cmd == WIN;
}
// The server takes one parameter: the port on which it will listen
// it then attaches to any interface available
int main(int argc, char *argv[]) {
//Check number of input args
if(argc != 2) {
fprintf(stderr, "Usage:\n\t%s port\n", argv[0]);
return 1;
}
// Convert input to port number
uint16_t port = string_to_port(argv[1]);
// Create a TCP/IP socket on which the server will listen for connexions
int socket_wait = socket(AF_INET, SOCK_STREAM, 0);
if (socket_wait == -1)
die("socket");
// Associate address and port number with socket
struct sockaddr_in server_addr;
memset( &server_addr, 0, sizeof(server_addr) );
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(port);
if( bind(socket_wait, (struct sockaddr*) &server_addr, sizeof(server_addr)) == -1 )
die("bind");
// Mark socket as a listenning socket
if( listen(socket_wait, 5) == -1)
die("listen");
// Wait and accept connections as they come
int socket_proc; // processing socket which will be used for communication with the client
struct sockaddr_in client_addr;
while(1) {
// Wait for client
socklen_t client_addr_length = sizeof(client_addr);
socket_proc = accept(socket_wait, (struct sockaddr*) &client_addr, &client_addr_length);
if (socket_proc > 0) {
// Client connected print information about client ip
char ip[INET_ADDRSTRLEN];
if( inet_ntop(AF_INET, &client_addr.sin_addr, ip, sizeof(ip)) != NULL )
printf("Client %d connected with ip %s:%d\n", socket_proc, ip, ntohs(client_addr.sin_port));
else
printf("Client connected but could not retreive address !!!\n");
// Play with the client
process_client(socket_proc, client_addr);
close(socket_proc);
}
else
perror("accept");
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment