Last active
May 8, 2019 15:51
-
-
Save ariyike/ba991c12a0eab3b40a4e1fc784f4c8d5 to your computer and use it in GitHub Desktop.
A client coded in C to communicate with a server and send messages
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 <sys/socket.h> | |
#include <sys/types.h> | |
#include <netinet/in.h> | |
#include <netdb.h> | |
#include <stdio.h> | |
#include <string.h> | |
#include <stdlib.h> | |
#include <unistd.h> | |
#include <errno.h> | |
#include <arpa/inet.h> | |
#include <sys/utsname.h> | |
#include "rdwrn.h" | |
#define INPUTSIZ 10 | |
//*********************************************************** | |
// INITIALISING ALL THE FUNCTIONS TO BE CALLED | |
//*********************************************************** | |
void get_student_details(int); | |
void get_random_numbers(int); | |
void get_utname(int); | |
void get_filenames(int); | |
void send_options(int, char); | |
void send_file_name(int); | |
//*********************************************************** | |
// FUNCTION WHICH GETS THE SERVER UTSNAME DETAILS | |
//*********************************************************** | |
//this function is based on the starter code provided for sending the employee struct, it gets the machine's details from the utsname struct | |
void get_utname(int socket) | |
{ | |
struct utsname send_this; //initialise the struct which will contain the received struct | |
size_t payload_length;//initialise the size of the payload | |
size_t n;//do the same for the size of the struct received in bytes | |
readn(socket, (unsigned char *) &payload_length, sizeof(size_t));//reads the size of the information being sent by the server | |
n = readn(socket, (unsigned char *) &send_this, payload_length);//reads the information being sent by the server | |
//print out details of received & altered struct | |
//printf("%d", (int)sizeof(send_this)); | |
printf("OS name %s\n", send_this.sysname);//print the string to the client terminal | |
printf("version %s\n", send_this.release);//print the string to the client terminal | |
printf("release %s\n", send_this.version);//print the string to the client terminal | |
printf("machine %s\n", send_this.machine);//print the string to the client terminal | |
printf("nodename %s\n", send_this.nodename);//print the string to the client terminal | |
printf("(%zu bytes)\n", n);//print the size to the client terminal | |
} | |
//*********************************************************** | |
// FUNCTION WHICH SENDS THE INPUT OPTION | |
//*********************************************************** | |
//this function is based on the starter code provided for the hello_string, it sends the option selected by the user to the server | |
void send_options(int socket, char option)//it takes an additional argument, different from all the other functions in the form of a char | |
{ | |
size_t n = sizeof(option) + 1;//derives the size of the message to be sent | |
writen(socket, (unsigned char *) &n, sizeof(size_t));//write the size of the string being sent | |
writen(socket, (unsigned char *) &option, n);//write the char being sent | |
} | |
//*********************************************************** | |
// FUNCTION WHICH GETS STUDENT DETAILS FROM SERVER | |
//*********************************************************** | |
//this function is based on the starter code provided for the hello_string, it receives the student details from the server | |
void get_student_details(int socket) | |
{ | |
char std_details[200]; //empty string that will contain the output string | |
size_t k; //size variable that will be used to store the size of the string | |
readn(socket, (unsigned char *) &k, sizeof(size_t));//reads the size of the information being sent by the server | |
readn(socket, (unsigned char *) std_details, k);//reads the information being sent | |
printf("Code written by: %s\n", std_details);//print the string to the client terminal | |
printf("Received: %zu bytes\n\n", k);//print the size to the client terminal | |
} | |
//*********************************************************** | |
// FUNCTION WHICH GETS THE RANDOM NUMBERS FROM THE SERVER | |
//*********************************************************** | |
//this function is based on the starter code provided for the hello_string, it receives the student details from the server | |
void get_random_numbers(int socket) | |
{ | |
size_t g; //size variable that will be used to store the size of the string | |
readn(socket, (unsigned char *) &g, sizeof(size_t));//reads the size of the information being sent by the server | |
char random_num[40];//empty string that will contain the output string | |
readn(socket, (unsigned char *) random_num, g);//reads the information being sent | |
printf("Your random numbers are: %s\n", random_num);//print the string to the client terminal | |
printf("Received: %zu bytes\n\n", g);//print the size to the client terminal | |
} | |
//*********************************************************** | |
// FUNCTION WHICH GETS THE FILENAMES IN THE SERVER UPLOAD DIRECTORY | |
//*********************************************************** | |
//this function is based on the starter code provided for the hello_string, it receives the student details from the server | |
void get_filenames(int socket) | |
{ | |
char std_details[10000]; //empty string that will contain the output string | |
size_t k; //size variable that will be used to store the size of the string | |
readn(socket, (unsigned char *) &k, sizeof(size_t));//reads the size of the information being sent by the server | |
readn(socket, (unsigned char *) std_details, k);//reads the information being sent | |
const char s[2] = "*";//sets the delimeter for identification by strtok() | |
char *file;//sets the pointer to the first file name | |
file = strtok(std_details, s);//get the first file | |
printf("Files in upload\n");//prints the heading for the output | |
while( file != NULL ) { //this walks through the other files | |
printf("File: %s\n", file); | |
file = strtok(NULL, s); | |
} | |
printf("Received: %zu bytes\n\n", k);//prints the number of bytes received | |
} | |
//*********************************************************** | |
// FUNCTION WHICH GETS THE FILE THE USER WANTS TO CHANGE | |
//*********************************************************** | |
//this function is based on the starter code provided for the hello_string, it sends the filename that the user would like to copy from the server | |
//it then receives a copy of the file content and makes a duplicate file in the local directory | |
void send_file_name(int socket) | |
{ | |
size_t l; | |
FILE *file_write;//create a pointer | |
char file_name[50];//filename | |
printf("what file would you like to copy from server upload directory\n");//print instructions | |
scanf("%s", file_name);//specify the users outut and pass it to the file | |
//file_name[strcspn(file_name, "\n")]=0; //sets filename | |
size_t n = strlen(file_name) + 1;//gets the size | |
writen(socket, (unsigned char *) &n, sizeof(size_t));//print the string to the client terminal | |
writen(socket, (unsigned char *) file_name, n);//writes the information being sent | |
readn(socket, (unsigned char *) &l, sizeof(size_t));//reads the size of the information being sent by the client | |
char newfile[l];//create the variable to store the content being returned from the server, the file content | |
readn(socket, (unsigned char *) newfile, l);//reads the information being sent | |
file_write = fopen(file_name, "w");//use fopen to write to the file signified by file_name. If it doesn't exist it creates a new file | |
if (file_write == NULL)//error check, if the file contains nothing | |
{ | |
perror("This file does not exist in the server\n"); | |
} | |
else{ | |
fputs(newfile, file_write); | |
fclose(file_write); | |
} | |
} | |
//*********************************************************** | |
// MAIN METHOD | |
//*********************************************************** | |
int main(void) | |
{ | |
int sockfd = 0; | |
struct sockaddr_in serv_addr; | |
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { | |
perror("Error - could not create socket"); | |
exit(EXIT_FAILURE); | |
} | |
serv_addr.sin_family = AF_INET; | |
// IP address and port of server we want to connect to | |
serv_addr.sin_port = htons(50031); | |
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); | |
// try to connect... | |
if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) == -1) { | |
perror("Error - connect failed"); | |
exit(1); | |
} else | |
printf("Connected to server...\n"); | |
//*********************************************************** | |
// THE MENU WITHIN THE MAIN FUNCTION | |
//*********************************************************** | |
char input; //create a new var to use in the switch | |
char name[INPUTSIZ]; | |
printf("0. Get student details\n"); | |
printf("1. Get random numbers\n"); | |
printf("2. Get utname\n"); | |
printf("3. Get filenames\n"); | |
printf("4. Copy a file from the server\n"); | |
printf("5. Quit\n"); | |
do { | |
printf("option> "); | |
fgets(name, INPUTSIZ, stdin); // get the value from input | |
name[strcspn(name, "\n")] = 0; | |
input = name[0]; | |
if (strlen(name) > 1) | |
input = 'x'; // set invalid if input more 1 char | |
send_options(sockfd, input); | |
switch (input) { | |
case '0': | |
get_student_details(sockfd); | |
break; | |
case '1': | |
get_random_numbers(sockfd); | |
break; | |
case '2': | |
get_utname(sockfd); | |
break; | |
case '3': | |
get_filenames(sockfd); | |
break; | |
case '4': | |
send_file_name(sockfd); | |
break; | |
case '5': | |
printf("Goodbye!\n"); | |
break; | |
default: | |
printf("Invalid choice!\n"); | |
break; | |
} | |
} while (input != '5'); | |
//*********************************************************** | |
// THE END OF THE MAIN MENU | |
//*********************************************************** | |
// make sure sockets are cleaned up | |
close(sockfd); | |
exit(EXIT_SUCCESS); | |
} // end main() |
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 <sys/socket.h> | |
#include <netinet/in.h> | |
#include <arpa/inet.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <unistd.h> | |
#include <errno.h> | |
#include <string.h> | |
#include <sys/types.h> | |
#include <pthread.h> | |
#include <sys/utsname.h> | |
#include <dirent.h> | |
#include <sys/stat.h> | |
#include <time.h> | |
#include <signal.h> | |
#include "rdwrn.h" | |
//*********************************************************** | |
// INITIALISING ALL THE FUNCTIONS TO BE CALLED | |
//*********************************************************** | |
// thread function | |
void *client_handler(void *); | |
void send_utname(int); | |
void send_student_details(int); | |
void send_random_numbers(int); | |
void stat_file(char *); | |
void send_filenames(int); | |
char get_options(int); | |
void get_file_to_copy(int); | |
//these two global variables will be used to compute runtime | |
//written with help from https://www.mkyong.com/c/calculate-program-execute-time-time-elapsed-in-c/ | |
time_t start, stop; | |
//*********************************************************** | |
// SIGNAL HANDLER METHOD TO BE CALLED ON RECEIPT OF SIGINT | |
//*********************************************************** | |
// written with help from the code from lab 7 | |
static void handler(int sig, siginfo_t *siginfo, void *context) | |
{ | |
printf("exiting the server\n"); | |
//record the time at the end of the process | |
time(&stop); | |
printf("Finished in about %.0f seconds. \n", difftime(stop, start));//difftime calculates the amount of time that has passed between two supplied times | |
exit(130);//exit code to end the process | |
} | |
//*********************************************************** | |
// MAIN METHOD | |
//*********************************************************** | |
int main(void) | |
{ | |
//record the time at the start of the process | |
time(&start); | |
/* | |
the following block of code which works with the | |
handler to intercept ctrl+c events is from lab 7 | |
*/ | |
struct sigaction act; | |
memset(&act, '\0', sizeof(act)); | |
// this is a pointer to a function | |
act.sa_sigaction = &handler; | |
// the SA_SIGINFO flag tells sigaction() to use the sa_sigaction field, not sa_handler | |
act.sa_flags = SA_SIGINFO; | |
if (sigaction(SIGINT, &act, NULL) == -1) { | |
perror("sigaction"); | |
exit(EXIT_FAILURE); | |
}//end of code from lab 7 | |
//begin socket setup | |
int listenfd = 0, connfd = 0; | |
struct sockaddr_in serv_addr; | |
struct sockaddr_in client_addr; | |
socklen_t socksize = sizeof(struct sockaddr_in); | |
listenfd = socket(AF_INET, SOCK_STREAM, 0); | |
memset(&serv_addr, '0', sizeof(serv_addr)); | |
serv_addr.sin_family = AF_INET; | |
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); | |
serv_addr.sin_port = htons(50031); | |
bind(listenfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)); | |
if (listen(listenfd, 10) == -1) { | |
perror("Failed to listen"); | |
exit(EXIT_FAILURE); | |
} | |
// end socket setup | |
//Accept and incoming connection | |
puts("Waiting for incoming connections..."); | |
while (1) { | |
printf("Waiting for a client to connect...\n"); | |
connfd = | |
accept(listenfd, (struct sockaddr *) &client_addr, &socksize); | |
printf("Connection accepted...\n"); | |
pthread_t sniffer_thread; | |
// third parameter is a pointer to the thread function, fourth is its actual parameter | |
if (pthread_create | |
(&sniffer_thread, NULL, client_handler, | |
(void *) &connfd) < 0) { | |
perror("could not create thread"); | |
exit(EXIT_FAILURE); | |
} | |
//Now join the thread , so that we dont terminate before the thread | |
pthread_join( sniffer_thread , NULL); | |
printf("Handler assigned\n"); | |
} | |
// never reached... | |
exit(EXIT_SUCCESS); | |
} // end main() | |
//*********************************************************** | |
// CLIENT HANDLER FUNCTION | |
//*********************************************************** | |
// thread function - one instance of each for each connected client | |
void *client_handler(void *socket_desc) | |
{ | |
//Get the socket descriptor | |
int connfd = *(int *) socket_desc; | |
/*first initialise the variable that will be used to switch the cases, | |
it is used to store the output from the get_options function which receives the options from the client | |
*/ | |
char option; | |
do { | |
option = get_options(connfd);//run get_options and store the return value | |
switch (option) { | |
case '0': | |
send_student_details(connfd); | |
break; | |
case '1': | |
send_random_numbers(connfd); | |
break; | |
case '2': | |
send_utname(connfd); | |
break; | |
case '3': | |
send_filenames(connfd); | |
break; | |
case '4': | |
get_file_to_copy(connfd); | |
break; | |
case '5': | |
printf("Goodbye!\n"); | |
break; | |
default: | |
printf("Invalid choice!\n"); | |
break; | |
} | |
} while (option != '5');//*********might need to change back to 4 | |
shutdown(connfd, SHUT_RDWR); | |
close(connfd); | |
printf("Thread %lu exiting\n", (unsigned long) pthread_self()); | |
// always clean up sockets gracefully | |
shutdown(connfd, SHUT_RDWR); | |
close(connfd); | |
return 0; | |
} // end client_handler() | |
//*********************************************************** | |
// FUNCTION WHICH GETS THE USER OPTIONS | |
//*********************************************************** | |
//this function is based on the starter code provided for the hello_string, it receives the option selected by the user | |
char get_options(int socket){ | |
char optn;//initialise variable to store the option | |
size_t k;//initialise size of the variable | |
readn(socket, (unsigned char *) &k, sizeof(size_t));//reads the size of the information being sent by the client | |
readn(socket, (unsigned char *) &optn, k);//reads the information being sent | |
return optn;//return the now non-empty character | |
} | |
//*********************************************************** | |
// FUNCTION WHICH RECEIVES THE FILE TO BE COPIED FROM THE CLIENT | |
// THEN SENDS THE COPIED TEXT BACK TO THE CLIENT TO CREATE A NEW FILE | |
//*********************************************************** | |
void get_file_to_copy(int socket) | |
{ | |
char direct[] = "./upload/";//preparing the path of the file name to be used | |
size_t l;//the size of the file name | |
readn(socket, (unsigned char *) &l, sizeof(size_t));//reads the size of the information being sent by the client | |
char filename[l];//creates a string using the size of the file name to receive the file name | |
readn(socket, (unsigned char *) filename, l);//reads the information being sent | |
strcat(direct, filename);//concatenate the path to the file name to search the upload directory | |
FILE *file_open; //file pointer that will be used to read the file the contents | |
char content[200]; | |
//the following parts were completed with assistance from: https://www.geeksforgeeks.org/basics-file-handling-c/ | |
file_open = fopen(direct, "r"); // read mode, pass the file to fopen to be read | |
if (file_open == NULL)//error check, if the file contains nothing | |
{ | |
perror("Error while opening the file.\n"); | |
} | |
else{ | |
while( fgets ( content, sizeof(content), file_open ) != NULL ) | |
{ | |
printf( "%s" , content );//print the content of the file to the server terminal | |
} | |
fclose(file_open);//close the file pointer | |
} | |
size_t n = strlen(content) + 1;//get the size of the string being sent | |
writen(socket, (unsigned char *) &n, sizeof(size_t));//write the size of the string being sent | |
writen(socket, (unsigned char *) content, n);//write the string being sent | |
} | |
//*********************************************************** | |
// FUNCTION WHICH SENDS THE STUDENT DETAILS | |
//*********************************************************** | |
//this function is based on the starter code provided for the hello_string | |
void send_student_details(int socket) | |
{ | |
char fName[] = " Anjolaoluwa Ariyike "; | |
char lName[] = "Adetimehin "; | |
char sID[] = "S1719003"; | |
char terminator[] = "\0"; //the terminator that will indicate the end of the string | |
//will first create the string containing the IPadress of the server | |
//step 1: set up the buffer that will house the string | |
char buffer[INET_ADDRSTRLEN]; | |
//the next three lines are written with help from: | |
//https://stackoverflow.com/questions/5401942/how-to-get-the-ip-address-of-the-accepted-in-bound-socket | |
struct sockaddr_in addr;//create a new buffer address | |
socklen_t addr_size = sizeof(struct sockaddr_in);//get the size of the buffer address | |
getsockname(socket, (struct sockaddr*)&addr, &addr_size);//using sockname, get the current address that the socket has and returns it to the buffer | |
//then create a variable to store the ipaddress | |
const char* result=inet_ntop(AF_INET,(struct sockaddr_in *)&addr.sin_addr.s_addr,buffer,sizeof(buffer)); | |
if (result==0) { | |
printf("failed to convert address to string (errno=%d)",errno);//ensure that the action was successful | |
} | |
//end of IP string set up | |
char dest[200];//set the new string that will be used for the concatenation | |
strcat(dest, result); | |
strcat(dest, fName); | |
strcat(dest, lName); | |
strcat(dest, sID); | |
strcat(dest, terminator); | |
size_t n = strlen(dest) + 1;//get the size of the string being sent | |
writen(socket, (unsigned char *) &n, sizeof(size_t));//write the size of the string being sent | |
writen(socket, (unsigned char *) dest, n);//write the string being sent | |
} | |
//*********************************************************** | |
// FUNCTION WHICH SENDS THE RANDOM NUMBERS | |
//*********************************************************** | |
//this function is based on the starter code provided for the hello_string | |
void send_random_numbers(int socket){ | |
int random_array[5];//set an array for the random numbers | |
int i;//initialise my iterator | |
for(i = 0; i<5; i++){ | |
int num = (rand() % 1000) + 1;//the use of rand() will help the generation of random numbers to fill the array | |
random_array[i] = num;//add the numbers to the array | |
} | |
char output_string[40];//initialise output string | |
int a = random_array[0], b = random_array[1], c = random_array[2], d = random_array[3], e = random_array[4];//set the values to be passed in the string | |
snprintf(output_string, sizeof(random_array), "%d %d %d %d %d", a, b, c, d, e);//sprintf helps with redirecting variables on type int into a string | |
//see http://joequery.me/code/snprintf-c/ | |
size_t n = strlen(output_string) + 1;//get the size of the string being sent | |
writen(socket, (unsigned char *) &n, sizeof(size_t));//write the size of the string being sent | |
writen(socket, (unsigned char *) output_string, n);//write the string being sent | |
} | |
//*********************************************************** | |
// FUNCTION WHICH SENDS THE UTSNAME | |
//*********************************************************** | |
void send_utname(int socket) | |
{ | |
struct utsname xyz;//create a new struct to pass into uname | |
uname(&xyz);//pass the struct into uname to be populated with system information | |
size_t payload_length = sizeof(xyz);//set size of the payload | |
writen(socket, (unsigned char *) &payload_length, sizeof(size_t));//write the size of the string being sent | |
writen(socket, (unsigned char *) &xyz, payload_length);//write the string being sent | |
} | |
//*********************************************************** | |
// FUNCTION WHICH GETS THE FILENAMES FROM THE UPLOADS DIRECTORY | |
//*********************************************************** | |
/* | |
the following block of code which sends the filenames from the | |
upload directory is written with assistance from lab 9 activities | |
*/ | |
void send_filenames(int socket) | |
{ | |
struct dirent **namelist;//create a struct to be passed into scandir | |
int n; | |
char output_string[10000];//initialise the output string | |
if ((n = scandir("./upload", &namelist, NULL, alphasort)) == -1)//scans the directory specified and adds files it finds to the buffer struct, sorting them as it goes | |
perror("scandir");//error check | |
else { | |
while (n--) { | |
strcat(output_string, namelist[n]->d_name);//concatenates each filename to the output string | |
strcat(output_string, "*");//concatenates a delimeter after each filename | |
free(namelist[n]);//free up memory resources | |
} | |
free(namelist);//free up memory resources | |
} | |
size_t y = strlen(output_string) + 1;//get the size of the string being sent | |
writen(socket, (unsigned char *) &y, sizeof(size_t));//write the size of the string being sent | |
writen(socket, (unsigned char *) output_string, y);//write the string being sent | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment