Authentication and parsing problem web server - c

I am currently working on a piece of code that redirects me to a website that asks for authentification first (username and password). If the correct username and password is inputted, it should be parsed so that it can be compared to the string token.
To show it visually:
Token: MjAxOC0xMzc0OTpwYXNzd29yZA==, tokensize : 28
Authorization: Basic MjAxOC0xMzc0OToyMDE4LTEzNzQ5
What I need to do is parse MjAxOC0xMzc0OToyMDE4LTEzNzQ5 from Authorization: Basic and then compare it to the token value. If they match, the loop ends and the user can enter the website. If they don't, the user needs to keep inputting the username and password. However, my code does not seem to be working.
while(1){
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
//accept connection
//send 401 message(more information about 401 message and authentificate user
if(newsockfd == -1){
perror("accept error");
exit(1);
}
char buffer[9000];
int tracker = 1;
int bytes;
bytes = 0;
//receive the socket
bytes = recv(newsockfd, buffer, 1500, 0);
//send the 401 unauthorized message
char message[] = "HTTP/1.1 401 Unauthorized\r\nWWW-authenticate: Basic realm='localhost'\r\nContent-Type: text/html;\r\n\r\n";
//get the length of the message
int length = strlen(message);
//while the message exists, send it to the client
while(length > 0){
printf("send bytes : %d\n", bytes);
bytes = send(newsockfd, message, length, 0);
if(bytes==-1){
continue;
}
length -= bytes;
}
//get the size of the token
int tokensize = strlen(token);
printf("Token: %s, tokensize : %d\n", token, tokensize);
// this is where the parsing happens
char* parse;
bytes = 0;
bytes = recv(newsockfd, buffer, 1500, 0);
if(bytes == -1){
printf("error receiving message");
exit(1);
}
parse = strtok(buffer, "\r\n");
while(parse != 0){
parse = strtok(NULL, "\r\n");
if(parse != NULL && strncmp(parse, "Authorization", strlen("Authorization")) == 0){
printf("%s\n", parse);
char* str;
str = strtok(parse, " ");
printf("%s", str);
//this is where it's compared to the string token
while(str){
str = strtok(NULL, " ");
printf("%s", str);
if(str == NULL)
break;
else if (strcmp(str, "Basic") == 0){
continue;
}
if(strcmp(str, token) == 0){
break;
}
}
}
}

Related

Segmentation Fault caused by a read into the client

I wrote this code for a simple client/server application:
This is a portion of the code of the server:
while(TRUE){
struct sockaddr_in clientName = {0};
int simpleChildSocket = 0;
unsigned int clientNameLength = sizeof(clientName);
simpleChildSocket = accept(simpleSocket,(struct sockaddr *)&clientName, &clientNameLength);
if (simpleChildSocket == -1) {
fprintf(stderr, "Cannot accept connections!\n");
close(simpleSocket);
exit(EXIT_FAILURE);
}
/* write out our message to the client */
snprintf(buffer, sizeof(buffer), "OK %s", MESSAGE);
write(simpleChildSocket, buffer, strlen(buffer));
/* Start server operations */
array = NULL, j = 0, k = 0, numberSample = 0;
tmpValue = NULL;
do{
do{
memset(buffer, '\0', sizeof(buffer));
returnStatus = read(simpleChildSocket, buffer, sizeof(buffer));
if(returnStatus <= 0)
fprintf(stderr, "Status: %d\n", returnStatus);
for(i = 0; i < (int)strlen(buffer); i++){
if(isdigit(buffer[i]))
flag = 1;
else if(isspace(buffer[i]))
continue;
else{
flag = 0;
break;
}
}
if(flag == 0){
memset(buffer, '\0', sizeof(buffer));
snprintf(buffer, sizeof(buffer), BOLD RED "ER" RESET " Devi inserire solo numeri\n");
write(simpleChildSocket, buffer, strlen(buffer));
}
}while(flag != 1);
token = strtok(buffer, " ");
digit = atoi(token);
if(digit != 0){
printf("Token #%d: %d\n", k, digit);
k++;
}
else
printf("Ricevuto %d\n", digit);
numberSample += digit;
array = realloc(array, numberSample * sizeof(int));
for(i = 0; (tmpValue = strtok(NULL, " "))!= NULL; i++, j++){
array[j] = atoi(tmpValue);
}
}while(digit != 0);
for(i = 0; i < numberSample; i++)
printf("%d: %d\n", i, array[i]);
printf("\n\n<%d>\n\n", numberSample);
free(array);
close(simpleChildSocket);
}
Instead this is a portion of the code of the client:
/* get the message from the server */
memset(buffer, '\0', sizeof(buffer));
returnStatus = read(simpleSocket, buffer, sizeof(buffer));
if(returnStatus > 0)
printf("%s", buffer);
else
fprintf(stderr, "Return Status: %d\n", returnStatus);
/* start client operations */
do{
memset(buffer, '\0', sizeof(buffer));
fgets(buffer, sizeof(buffer), stdin);
/*fflush(stdout);*/
write(simpleSocket, buffer, strlen(buffer));
memset(string, '\0', sizeof(string));
returnStatus = read(simpleSocket, string, sizeof(string));
if(returnStatus > 0)
printf("%s\n", string);
else
fprintf(stderr, "Return Status: %d\n", returnStatus);
}while(atoi(&buffer[0]) != 0);
The problem is that when I send data for the first time to the server, the latter goes into segmentation fault. The problem is caused by the client's read, which must take the error if the user attempts to send letters or symbols instead of the numbers. How can I fix the problem?

Why is my client not receiving any bytes?

I am writing a simple client-server program. My server works fine with telnet, but my client can only send bytes, not receive them. Is there something obvious I'm missing? I think it may be because of my usage of the recv function in some way but it's not evident to me. The recv function consistently gets 0 bytes. I should add that the recv function doesn't block, yet the received number of bytes is always zero.
A snippet of the code in the client's main function is below. The function changeIPOrPort sets the servers ip address and port and works fine since the server receives the clients message. I can post the server code as well if necessary.
int main() {
int client_fd, numbytes = 0;
//int quit = 0;
struct sockaddr_in their_addr;
char response[MAXDATASIZE] = "";
char buf[MAXDATASIZE] = "";
size_t len = 0;
/* Server config*/
their_addr.sin_family = AF_INET;
memset(their_addr.sin_zero, '\0', sizeof their_addr.sin_zero);
printf("Configuring the server\n");
changeIPOrPort(&their_addr);
printf("Hello! please input letters to know things about me.\n");
printf("Each character will give you a piece of information about me\n");
printf("%s\n", serviceInfo); //info string "UI"...
/*create client socket*/
client_fd = socket(AF_INET, SOCK_STREAM, 0);
if(connect(client_fd, (struct sockaddr *)&their_addr, sizeof(their_addr)) < 0) {
printf("\n Error : Connect Failed \n");
return 1;
}
if(!fgets(response, sizeof (response), stdin)) {
printf("Error reading line.\n");
}
else {
len = strlen(response);
if(response[len - 1] == '\n') {
response[len - 1] = '\0';
}
printf("You entered the characters:%s\n", response);
printf("sending...\n");
send(client_fd, response, len, 0);
numbytes = recv(client_fd, buf, strlen(buf), 0) ;
if(numbytes < 0) {
printf("Error receiving from server, quitting\n");
exit(1);
}
else {
printf("Number of bytes received: %d\n", numbytes);
buf[numbytes] = '\0';
printf("%s\n", buf);
printf("This is errno\n", errno);
}
}
close(client_fd);
return 0;
}
Replace 'strlen(buf)' with 'sizeof(buf)-1'

password authentication in Client server model in C

I am trying to authenticate client using a password and if the client enters different password he should be again asked to re-enter the password
Following is my server code:
while (1) {
printf("Expecting the pass\n");
ret = recv(sock, pass, sizeof(pass), 0);
if (ret == -1) {
perror("Error receiving message");
exit(1);
} else {
pass[strlen(pass) - 1] = '\0';
printf("Password received %s of length %d\n", pass, strlen(pass));
}
printf("Received\n");
if (strcmp("Abhishek", pass) == 0) {
printf("Password entered is correct\n");
snprintf(buffer, sizeof(buffer), "CORRECT");
break;
} else {
printf("Incorrect Password %s\n", pass);
snprintf(buffer, sizeof(buffer), "I");
}
printf("SENDING : %s\n",buffer);
ret = send(sock, buffer, strlen(buffer), 0);
if (ret == -1) {
perror("Error sending message");
exit(1);
}
}
And client side code is :
while (1) {
printf("Enter the password :");
fgets(buf, sizeof(buf), stdin);
buf[ret] = '\0';
ret = send(sockid, buf, strlen(buf), 0);
if (ret == -1) {
perror("Error sending message");
exit(1);
} else {
printf("Password sent\n");
}
memset(&buf[0], 0, sizeof(buf));
ret = recv(sockid, buf, sizeof(buf), 0);
printf("RECEIVED %s\n", buf);
if (ret == -1) {
perror("Error receiving message");
exit(1);
}
if (buf[0] != 'I') {
break;
}
}
When I execute them in different windows, I can see at server side:
Asking for password authentication
Expecting the pass
At client side:
Start the Admin Dialogue
Enter the password :
Now when I enter password in client window, it says:
Password sent
but Server is still at
Expecting the pass
Can somebody help me with that I am new to this concept
You did not provide a complete function: definitions for the arrays and various variables are missing. Are pass and buf indeed defined an arrays?
You are not sending the '\0' terminators. The message recv'd on the client side is not null terminated. strlen(pass) invokes undefined behavior. Unlikely to be the cause of your problem, but a significant bug nonetheless.
You need some kind of protocol to determine in the server and in the client when a complete message has been received. You should either use '\n' as an end of message indicator or possibly a '\0'.
Here is how you would force null termination on the server side:
printf("Expecting the pass\n");
ret = recv(sock, pass, sizeof(pass) - 1, 0);
if (ret == -1) {
perror("Error receiving message");
exit(1);
} else {
pass[ret] = '\0';
if (ret > 0 && pass[ret - 1] == '\n')
pass[--ret] = '\0';
printf("Password received %s of length %d\n", pass, ret);
}
But this is not sufficient to ensure that the full message has been received by the server, you really should recv until you get a linefeed, or some sort of protocol indicating a complete message.
On the client side, buf[ret] = '\0'; seems useless and potentially risky.

My c socket program spitting out garbage on the command following a successful one, no clue why

I've tried everything. No idea what's happening with my program. I've written a tcp server and a client. I can issue some commands from the client to the server, they are: ls-local, ls-remote, get filename, put filename (i have not yet implemented put, because I am stuck on get).
Everything works perfectly until I issue the get command. The server.c and client.c files are in different folders. When you issue 'get filename' where filename is the name of the file you want to get, the server checks if the file exists in its current directory, if it does, it sends it to the client.
On the first iteration, this works perfectly. The file is sent to the client and the client creates a copy of said file. However, ANY command besides 'ls-local' results in pure garbage being printed out to the client terminal and I have no idea why. I think it might have to do with me needing to clear a buffer but I tried that and it still didn't work so I'm obviously doing something very wrong.
Here is what happens when I issue a command after get file:
when I issue get filename again, I get a line of garbage and nothing is sent even though the file exists in the server.
If I issue the command ls-remote, this is where it goes crazy printing gibberish non stop to my client terminal.
I've included both files in case you want to test them to see what I mean. Usage is: 'get filename', no single quotes. Remember, it breaks after the first time, works fine the first. Sorry for the long files, the sending file code is in the method named sendfile, I've tried to organize it so its easy to read.
Need some major help on this, thanks in advance!!
server.c
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <dirent.h>
/**
* Structure used to contain the type of command: 'get' or 'put'
* as well as the name of the file
*/
struct command{
char* type;
char* filename;
};
void syserr(char *msg) { perror(msg); exit(-1); }
/* function prototypes */
void handleConnection(int);
void sendDirectories(int);
struct command getCommand(char*);
int fileExists(char*);
void sendFile(char*, int);
int main(int argc, char *argv[]){
int sockfd, newsockfd, portno, processId;
struct sockaddr_in serv_addr, clt_addr;
socklen_t addrlen;
switch(argc) {
case 1:
portno = 5555;
break;
case 2 :
portno = atoi(argv[1]);
break;
default :
fprintf(stderr,"Usage: %s <port>\n", argv[0]);
return 1;
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0) syserr("can't open socket");
printf("create socket...\n");
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if(bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
syserr("can't bind");
}
printf("bind socket to port %d...\n", portno);
listen(sockfd, 5);
for(;;) {
printf("wait on port %d...\n", portno);
addrlen = sizeof(clt_addr);
newsockfd = accept(sockfd, (struct sockaddr*)&clt_addr, &addrlen);
if(newsockfd < 0) syserr("can't accept");
printf("connected to client....\n");
signal(SIGCHLD,SIG_IGN);//prevent zombie process
processId = fork();
if(processId < 0){
// printf("process id < 0, nothing closed\n");
syserr("ERROR while attempting to fork");
}
if(processId == 0){//child process
// printf("process id == 0, close(sockfd)\n");
close(sockfd);
handleConnection(newsockfd);
exit(0);
}
else{//parent process
// printf("else statement, close(newsockfd)\n");
close(newsockfd);
}
}
// printf("outside of loop, close(sockfd)\n");
// close(sockfd);
return 0;
}
/**
* Method that handles the commands received and routes them to the proper methods
* #param newsockfd the file descriptor created when the connection was accepted
*/
void handleConnection(int newsockfd){
int n;
char buffer[256];
while(1){
bzero(buffer,256);
printf("waiting for client's command.....\n");
n = recv(newsockfd, buffer, 255, 0);
if(n < 0) syserr("can't receive from client");
else buffer[n] = '\0';
printf("SERVER GOT MESSAGE: %s\n", buffer);
/**
* exit command
*/
if (strcmp(buffer, "exit") == 0){
printf("Ending session with client....\n");
break;
}
/*
* ls-remote command
*/
if (strcmp(buffer, "ls-remote") == 0){
sendDirectories(newsockfd);
}else{
struct command userCommand = getCommand(buffer);
//USER SENDS VALID COMMAND
if(strcmp(userCommand.type, "invalid") != 0){
printf("Command %s %s is valid\n", userCommand.type, userCommand.filename);
/**
* 'get' command
*/
if(strcmp(userCommand.type, "get") == 0){
//File exists
if(fileExists(userCommand.filename) == 1){
sendFile(userCommand.filename, newsockfd);
}
//File does not exist
else{
n = send(newsockfd, "ERROR: FILE DOES NOT EXIST IN REMOTE DIRECTORY", 255, 0);
if(n < 0) syserr("Unable to send FILE DOES NOT EXIST ERROR to client");
printf("Sending FILE DOES NOT EXIST ERROR..\n");
}
}
/**
* 'put' command
* no check needed for 'put' because only possible options at this point are 'get' and 'put'
* since invalid commands are filtered out in getCommand method
*/
else{
}
}
//USER SENDS INVALID COMMAND
else{
n = send(newsockfd, "INVALID COMMAND: you may only send 'ls-remote' OR ' get ' or ' put ' followed by a filename", 255, 0);
if(n < 0) syserr("Unable to send INVALID COMMAND ERROR' to client");
printf("Sending INVALID COMMAND ERROR...\n");
}
}
}
// printf("in handleConnection, close(sockfd)\n");
// close(newsockfd);
}
/**
* Method that executes when the command 'ls-remote' is received, sends entire file listing in working directory
* #param newsockfd the file descriptor created when the connection was accepted, will be used to send file listing
*/
void sendDirectories(int newsockfd){
DIR* directory;
struct dirent *dir;
directory = opendir(".");
int n;
if (directory){
int count = 0;
while ((dir = readdir(directory)) != NULL){
//ignore current dir and parent dir names
if(strcmp(dir->d_name, ".") != 0 && strcmp(dir->d_name, "..") != 0){
// // printf("%s\n", dir->d_name);
// strcat(dir->d_name, "\n");//concatenates new line char to end of dir name, consider sending without new line and handle new line in client
// n = send(newsockfd, dir->d_name,255, 0);
// if(n < 0) syserr("can't send file list to client");
// printf("sending file name: '%s' to client...\n", dir->d_name);
count++;
}
}
int32_t convCount = htonl(count);
n = send(newsockfd, &convCount, sizeof(convCount), 0);
if(n < 0) syserr("can't send file list count");
printf("sending file list count: '%d' to client...\n", count);
rewinddir(directory);
while ((dir = readdir(directory)) != NULL){
//ignore current dir and parent dir names
if(strcmp(dir->d_name, ".") != 0 && strcmp(dir->d_name, "..") != 0){
// printf("%s\n", dir->d_name);
// strcat(dir->d_name, "\n");//concatenates new line char to end of dir name, consider sending without new line and handle new line in client
n = send(newsockfd, dir->d_name,255, 0);
if(n < 0) syserr("can't send file list to client");
printf("sending file name: '%s' to client...\n", dir->d_name);
}
}
closedir(directory);
}
}
/**
* Method that extracts a valid command from a given string
* #param string the string containing the commands
* #return the valid command if found, a command with type 'invalid' if not found
*/
struct command getCommand(char* string){
char* temp;
int count;
struct command userCommand;
count = 0;
//Split the string on spaces, if more than one space then # of arguments is > 2, thus invalid command
temp = strtok(string, " ");
while(temp != NULL){
if(count == 0){
userCommand.type = temp;
}else if(count == 1){
userCommand.filename = temp;
}else{
userCommand.type = "invalid";
break;
}
temp = strtok(NULL, " ");
count++;
}
//We test count ==1 because this means only one space in string but also only one word because count did not increment again
//which is still an invalid command
if(strcmp(userCommand.type, "get") != 0 && strcmp(userCommand.type, "put") != 0 || count == 1){
userCommand.type = "invalid";
}
return userCommand;
}
/**
* Method that searches server directory for a given file name
* #param filename the name of the file to search for
* #return 1 if the file is found, 0 if not found
*/
int fileExists(char* filename){
DIR* directory;
struct dirent *dir;
directory = opendir(".");
int n;
if (directory){
while ((dir = readdir(directory)) != NULL){
//ignore current dir and parent dir names
if(strcmp(dir->d_name, ".") != 0 && strcmp(dir->d_name, "..") != 0){
if(strcmp(dir->d_name, filename) == 0) {
printf("File: '%s' was FOUND!\n", filename);
return 1;
}
}
}
closedir(directory);
}
printf("Sorry file: '%s' was NOT found!\n", filename);
return 0;
}
/**
* Method that sends the specified file using the file descriptor passed
* #param filename the name of the file to be sent
* #param newsockfd the file descriptor to use to send the file
*/
void sendFile(char* filename, int newsockfd){
int n, fd;
struct stat file_stat;
char buffer[256];
char* file_buffer;
char file_chunk[BUFSIZ];
fd = open(filename, O_RDONLY);
if(fd < 0){
n = send(newsockfd, "ERROR: File could not be opened by server....",255, 0);
if(n < 0) syserr("Error opening file client has requested");
}
if (fstat(fd, &file_stat) < 0){
n = send(newsockfd, "ERROR:File stats could not be obtained by server....",255, 0);
if(n < 0) syserr("Error getting stats of file client has requested");
}
n = send(newsockfd, "Server found file and successfully opened...",255, 0);
if(n < 0) syserr("can't send file open confirmation to client");
printf("File found and successfully opened....\n");
// int data_remaining = file_stat.st_size;
// int32_t convSize = htonl(data_remaining);
// n = send(newsockfd, &convSize, sizeof(convSize), 0);
// if(n < 0) syserr("can't send file size ");
// printf("N IS: %d\n", n);
// printf("Sending file size to client, size is : %d bytes....\n", file_stat.st_size);
int data_remaining = file_stat.st_size;
int sent_bytes = 0;
char str[255];//store file size in string to send, for some reason the above code was sending fine but client could not receive, even though it works perfectly for ls-remote
sprintf(str, "%d", data_remaining);
file_buffer = (char*) malloc (sizeof(char)*data_remaining);
n = send(newsockfd,str,255, 0);
if(n < 0) syserr("can't send file size to client...");
printf("Sending file size to client, size is : %d bytes....\n", file_stat.st_size);
int read_bytes;
read_bytes = read(fd, file_buffer, data_remaining);
while((sent_bytes = send(newsockfd, file_buffer, file_stat.st_size, 0)) > 0 && data_remaining > 0){
data_remaining -= sent_bytes;
printf("Sent %d bytes of file, %d bytes remain\n", sent_bytes, data_remaining);
}
printf("File %s has finished sending....\n", filename);
close(fd);
}
client.c
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <dirent.h>
/**
* Structure used to contain the type of command: 'get' or 'put'
* as well as the name of the file
*/
struct command{
char* type;
char* filename;
};
void syserr(char* msg) { perror(msg); exit(-1); }
/*function prototypes*/
void listDirectories();
struct command getCommand(char*);
int main(int argc, char *argv[]){
int sockfd, portno, n;
int32_t *convCount, *convSize;
struct hostent* server;
struct sockaddr_in serv_addr;
FILE *received_file;
char buffer[256];
if(argc != 3){
fprintf(stderr, "Usage: %s <hostname> <port>\n", argv[0]);
return 1;
}
server = gethostbyname(argv[1]);
if(!server){
fprintf(stderr, "ERROR: no such host: %s\n", argv[1]);
return 2;
}
portno = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(sockfd < 0) syserr("Error opening socket.");
printf("create socket...\n");
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr = *((struct in_addr*)server->h_addr);
serv_addr.sin_port = htons(portno);
if(connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0){
syserr("can't connect to server");
}
printf("connection to %s:%s established. Now awaiting commands...\n", argv[1], argv[2]);
while(1){
// printf("PLEASE ENTER MESSAGE: ");
printf("%s:%s> ", argv[1], argv[2]);
fgets(buffer, 255, stdin);
n = strlen(buffer);
if(n>0 && buffer[n-1] == '\n'){
buffer[n-1] = '\0';
}
if(strcmp(buffer, "exit") == 0){
n = send(sockfd, buffer, strlen(buffer), 0);
if(n < 0) syserr("can't send 'exit' command to server");
printf("send...\n");
break;
}else if(strcmp(buffer, "ls-local") == 0){
listDirectories();
}else if(strcmp(buffer, "ls-remote") == 0){
n = send(sockfd, buffer, strlen(buffer), 0);
if(n < 0) syserr("can't send to server");
printf("send...\n");
n = recv(sockfd, convCount, sizeof(int32_t), 0);
if(n < 0) syserr("can't receive from server");
int fileCount = ntohl(*convCount);
// printf("CLIENT RECEIVED FILE COUNT: %d\n", fileCount);
printf("Files at server (%s:%s):\n", argv[1], argv[2]);
int i = 0;
while(i < fileCount){
n = recv(sockfd, buffer, 255, 0);
if(n < 0) syserr("can't receive from server");
printf("%s\n", buffer);
i++;
}
}else{
char cmdCopy[256];
strcpy(cmdCopy, buffer);
struct command userCommand = getCommand(cmdCopy);
if(strcmp(userCommand.type, "invalid") != 0){
printf("Command %s %s is valid\n", userCommand.type, userCommand.filename);
/**
* 'get' command
*/
if(strcmp(userCommand.type, "get") == 0){
//Re-append the entire command since
n = send(sockfd, buffer, strlen(buffer), 0);
if(n < 0) syserr("can't send to server");
printf("send GET request for file: %s\n", userCommand.filename);
n = recv(sockfd, buffer, 255, 0);
if(n < 0) syserr("can't receive from server");
else buffer[n] = '\0';
if(strcmp(buffer, "ERROR: FILE DOES NOT EXIST IN REMOTE DIRECTORY") != 0
&& strcmp(buffer, "ERROR: File could not be opened by server....") != 0
&& strcmp(buffer, "ERROR:File stats could not be obtained by server....") != 0){
printf("%s\n", buffer);
//// Not working for some reason, must receive as char*
// n = recv(sockfd, convSize, sizeof(int32_t), 0);
// printf("N IS: %d\n", n);
// if(n < 0) syserr("can't receive file size from server");
// int fileSize = ntohl(*convSize);
// printf("Size of file: %s to be received is %d\n bytes",buffer, fileSize);
// printf("Receiving file: %s \n....", userCommand.filename);
n = recv(sockfd, buffer, 255, 0);
if(n < 0) syserr("can't receive size from server");
else buffer[n] = '\0';
int data_remaining = atoi(buffer);
printf("file size is %d\n", data_remaining);
received_file = fopen(userCommand.filename, "w");
if (received_file == NULL){
syserr("Failed to open file.");
}else{
char file_buffer[BUFSIZ];
int bytes_received;
while((bytes_received = recv(sockfd, file_buffer, BUFSIZ, 0)) >0 && data_remaining > 0){
fwrite(file_buffer, 1, bytes_received, received_file);
data_remaining -= bytes_received;
printf("Received %d bytes of file, %d bytes remain\n", bytes_received, data_remaining);
}
printf("File receive complete\n");
fclose(received_file);
}
}else{
printf("%s\n", buffer);
}
}
/**
* 'put' command
* no check needed for 'put' because only possible options at this point are 'get' and 'put'
* since invalid commands are filtered out in getCommand method
*/
else{
// //File exists
// if(fileExists(userCommand.filename) == 1){
// sendFile(userCommand.filename, newsockfd);
// }
// //File does not exist
// else{
// printf( "ERROR: FILE DOES NOT EXIST IN LOCAL DIRECTORY\n");
// }
}
}
//USER TYPES INVALID COMMAND
else{
printf("INVALID COMMAND: you may only send 'ls-remote' OR ' get ' or ' put ' followed by a filename");
}
}
// n = send(sockfd, buffer, strlen(buffer), 0);
// if(n < 0) syserr("can't send to server");
// printf("send...\n");
// while( (n = recv(sockfd , buffer , 255 , 0)) > 0 ){
// printf("in while and n is: %d\n", n);
// printf("%s", buffer);
// }
// if(n < 0){
// printf("in if and n is: %d\n", n);
// syserr("can't receive from server");
// }else{
// printf("in else and n is: %d\n", n);
// buffer[n] = '\0';
// }
// printf("in no loop and n is: %d\n", n);
}
close(sockfd);
return 0;
}
// printf("connection to %s:%s established. Now awaiting commands...\n", argv[1], argv[2]);
// do{
// printf("%s:%s> ", argv[1], argv[2]);
// fgets(buffer, 255, stdin);
// n = strlen(buffer);
// if(n>0 && buffer[n-1] == '\n'){
// buffer[n-1] = '\0';
// }
// n = send(sockfd, buffer, strlen(buffer), 0);
// if(n < 0) syserr("can't send to server");
// printf("send...\n");
// n = recv(sockfd, buffer, 255, 0);
// if(n < 0) syserr("can't receive from server");
// else buffer[n] = '\0';
// printf("CLIENT RECEIVED MESSAGE: %s\n", buffer);
// }while(strcmp(buffer, "exit") != 0);
// close(sockfd);
// return 0;
/**
* Method that extracts a valid command from a given string
* #param string the string containing the commands
* #return the valid command if found, a command with type 'invalid' if not found
*/
struct command getCommand(char* string){
char* temp;
int count;
struct command userCommand;
count = 0;
//Split the string on spaces, if more than one space then # of arguments is > 2, thus invalid command
temp = strtok(string, " ");
while(temp != NULL){
if(count == 0){
userCommand.type = temp;
}else if(count == 1){
userCommand.filename = temp;
}else{
userCommand.type = "invalid";
break;
}
temp = strtok(NULL, " ");
count++;
}
//We test count ==1 because this means only one space in string but also only one word because count did not increment again
//which is still an invalid command
if(strcmp(userCommand.type, "get") != 0 && strcmp(userCommand.type, "put") != 0 || count == 1){
userCommand.type = "invalid";
}
return userCommand;
}
/**
* Method that executes when the command 'ls-local' is received, sends entire file listing in working directory
*/
void listDirectories(){
DIR* directory;
struct dirent *dir;
directory = opendir(".");
if (directory){
printf("Files at the client:\n");
while ((dir = readdir(directory)) != NULL){
//ignore current dir and parent dir names
if(strcmp(dir->d_name, ".") != 0 && strcmp(dir->d_name, "..") != 0){
printf("%s\n", dir->d_name);
}
}
closedir(directory);
}
}
printf("SERVER GOT MESSAGE: %s\n", buffer);
No, you didn't get a message. You got some bytes. TCP is not a message protocol. If you want to send and receive messages, you have to write code to send and receive messages, which you have not done.
"TCP is a reliable, byte-stream protocol that does not preserve application message boundaries." Memorize this. Do not write any code that uses TCP until you understand everything in it or your code will be doomed to fail.
Another important point: Do not write any code that uses TCP until you have a specification for the protocol that you are using on top of TCP. Who sends when? Are there timeouts? Which side implements them? How is the connection shut down? Who initiates it? Are there application message boundaries? How are they marked?
And so on. It really is worth the time to document this in detail. You can look at the specifications for existing protocols that use TCP (such as HTTP, SMTP, IRC, and so on) for examples of what s protocol specification should look like.
Addressing your immediate problem, there are two issues:
First in server.c:
while((sent_bytes = send(newsockfd, file_buffer, file_stat.st_size, 0)) > 0 && data_remaining > 0){
On each send, you're sending file_stat.st_size bytes, instead of data_remaining bytes.
Also, you should be checking data_remaining > 0 first. Since the && operator is a short circuit operator, it won't evaluate the second part unless the first part evaluates to true. So if you have 0 bytes left to send, it will try to send them anyway.
So the above line should be:
while((data_remaining > 0) && ((sent_bytes = send(newsockfd, file_buffer, file_stat.st_size, 0)) > 0)) {
Similarly in client.c, you have this:
while((bytes_received = recv(sockfd, file_buffer, BUFSIZ, 0)) >0 && data_remaining > 0){
If you've received the whole file, it will try one more recv before it realizes that data_remaining > 0 is false. Since the server is done sending, it gets stuck waiting forever.
As before, switch the order of the && operands:
while((data_remaining > 0) && ((bytes_received = recv(sockfd, file_buffer, BUFSIZ, 0)) > 0)){
This should at least get you running.
There are further issues in addition to this. As David Schwartz mentioned, the streaming nature of TCP does not preserve message boundaries.
That means that just because you try to read 255 bytes doesn't mean you'll actually get that many. Anyplace you expect a message of a particular size, make sure you actually got that many bytes. If you didn't get enough, keep reading until you do.
In addition to the fundamental fallacy in your code noted by David Schwartz, you are committing all the usual mistakes.
bzero(buffer,256);
Redundant. Remove.
n = recv(newsockfd, buffer, 255, 0);
if(n < 0) syserr("can't receive from client");
else
Missing test for n == 0 and break here.
buffer[n] = '\0';
Ths is only valid if the data is entirely text. What you should be doing throughout, including the following printf(), is using n as the exclusive upper bound for what you retrieve out of the buffer.
And as noted, you have no reason to believe this constitutes a complete message, or only one.

C client/server program: server sends answer multiple times when it shouldn't

I have the following scenario in C: a simple client program sends HTTP-like requests to a server, which is then supposed to return the input of the specified file. So far, there are only three methods the server should support: GET, HEAD and a default answer for bad requests.
Here's part of the server program:
for(;;){
struct sockaddr_in clientAddr;
int clientAddrLen = sizeof(clientAddr);
int clientSocket;
clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddr, &clientAddrLen);
char buf[BUFSIZE];
int bytesRecv;
bytesRecv = recv(clientSocket, (char*)&buf, BUFSIZE, 0);
while(bytesRecv > 0){
char *method;
method = strtok(buf, " ");
printf("method %s\n", method);
if(strncmp(method, head, 4) == 0){
/*HEAD*/
char answer[] = "method: HEAD\0";
send(clientSocket, answer, sizeof(answer) + 1, 0);
}else{
if (strncmp(method, get, 3) == 0){
/*GET*/
char answer[] = "method: GET\0";
send(clientSocket, answer, sizeof(answer) + 1, 0);
}else{
/*bad request*/
char answer[] = "HTTP/1.1 400 Bad Request\0";
send(clientSocket, answer, sizeof(answer) + 1, 0);
}
}
/*Read*/
bytesRecv = recv(clientSocket, (char*)&buf, BUFSIZE, 0);
}
And this is the part of the client program, that asks to enter a request on the command line and then sends the respective input:
char* server_reply[1024];
char* msg[100];
/*send requests*/
for(;;){
printf("Request:\n");
scanf("%s", &msg);
if(strcmp(msg, "quit") == 0){
break;
}
send(clientSocket, msg, sizeof(msg), 0);
if(recv(clientSocket, server_reply, sizeof(server_reply), 0) < 0){
printf("Failure in recv.");
}else{
printf("Server: %s\n", server_reply);
}
}
Now, the problem is the following: When I enter for example "GET HEAD asd" on the client side, I get three answers from the server, namely
method: GET
method: HEAD
HTTP/1.1 400 Bad Request
when it actually should only be "method: GET". I really don't understand this beaviour ... Thanks for your help!
scanf("%s", &msg);
Reads strings Not a whole line. Which means when you enter GET HEAD asd your loop runs three times.
First it reads GET sends it
and then HEAD sends it
and then asd

Resources