c program not writing same result as it is displaying - c

My C program is not writing to a file the same data that it is displaying. how do i save what is outputted to the screen in a file. I am trying to save a webpage, the file name is defined by the third option, [site] [page] [path]
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <netdb.h>
#include <string.h>
int create_tcp_socket();
char *get_ip(char *host);
char *build_get_query(char *host, char *page);
void usage();
#define HOST "coding.debuntu.org"
#define PAGE "/"
#define PORT 80
#define USERAGENT "HTMLGET 1.0"
#define OS "mac osx"
int main(int argc, char **argv)
{
struct sockaddr_in *remote;
int sock;
int tmpres;
char *ip;
char *get;
char buf[BUFSIZ+1];
char *host;
char *page;
char *HTMLfile;
if(argc == 1){
usage();
exit(2);
}
host = argv[1];
if(argc > 2){
page = argv[2];
}else{
page = PAGE;
}
HTMLfile = argv[3];
sock = create_tcp_socket();
ip = get_ip(host);
fprintf(stderr, "<!--\nIP is %s\n", ip);
remote = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in *));
remote->sin_family = AF_INET;
tmpres = inet_pton(AF_INET, ip, (void *)(&(remote->sin_addr.s_addr)));
if( tmpres < 0)
{
perror("Can't set remote->sin_addr.s_addr");
exit(1);
}else if(tmpres == 0)
{
fprintf(stderr, "%s is not a valid IP address\n", ip);
exit(1);
}
remote->sin_port = htons(PORT);
if(connect(sock, (struct sockaddr *)remote, sizeof(struct sockaddr)) < 0){
perror("Could not connect");
exit(1);
}
get = build_get_query(host, page);
fprintf(stderr, "nQuery is:\n<<START>>\n%s<<END>>\n-->\n", get);
//Send the query to the server
int sent = 0;
while(sent < strlen(get))
{
tmpres = send(sock, get+sent, strlen(get)-sent, 0);
if(tmpres == -1){
perror("Can't send query");
exit(1);
}
sent += tmpres;
}
//now it is time to receive the page
memset(buf, 0, sizeof(buf));
int htmlstart = 0;
char * htmlcontent;
while((tmpres = recv(sock, buf, BUFSIZ, 0)) > 0){
if(htmlstart == 0)
{
/* Under certain conditions this will not work.
* If the \r\n\r\n part is splitted into two messages
* it will fail to detect the beginning of HTML content
*/
htmlcontent = strstr(buf, "\r\n\r\n");
if(htmlcontent != NULL){
htmlstart = 1;
htmlcontent += 4;
}
}else{
htmlcontent = buf;
}
if(htmlstart){
fprintf(stdout, "%s", htmlcontent);
}
FILE *f;
f = fopen(HTMLfile, "w");
fprintf(f, "%s", htmlcontent); //stderr, "%s"
fclose(f);
memset(buf, 0, tmpres);
}
if(tmpres < 0)
{
perror("Error receiving data");
}
free(get);
free(remote);
free(ip);
close(sock);
return 0;
}
void usage()
{
fprintf(stderr, "USAGE: htmlget host [page]\n\
\thost: the website hostname. ex: coding.debuntu.org\n\
\tpage: the page to retrieve. ex: index.html, default: /\n");
}
int create_tcp_socket()
{
int sock;
if((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0){
perror("Can't create TCP socket");
exit(1);
}
return sock;
}
char *get_ip(char *host)
{
struct hostent *hent;
int iplen = 15; //XXX.XXX.XXX.XXX
char *ip = (char *)malloc(iplen+1);
memset(ip, 0, iplen+1);
if((hent = gethostbyname(host)) == NULL)
{
herror("Can't get IP");
exit(1);
}
if(inet_ntop(AF_INET, (void *)hent->h_addr_list[0], ip, iplen) == NULL)
{
perror("Can't resolve host");
exit(1);
}
return ip;
}
char *build_get_query(char *host, char *page)
{
char *query;
char *getpage = page;
char *tpl = "GET /%s HTTP/1.0\r\nHost: %s\r\nUser-Agent: %s\r\n\r\n";
if(getpage[0] == '/'){
getpage = getpage + 1;
fprintf(stderr,"Removing leading \"/\", converting %s to %s\n", page, getpage);
}
// -5 is to consider the %s %s %s in tpl and the ending \0
query = (char *)malloc(strlen(host)+strlen(getpage)+strlen(USERAGENT)+strlen(OS)+strlen(tpl)-5);
sprintf(query, tpl, getpage, host, USERAGENT);
return query;
// FILE *f;
// f = fopen(HTMLfile, "w");
// fprintf(f, htmlcontent);
// fclose(f);
}
Here is where i am saving the file:
FILE *f;
f = fopen(HTMLfile, "w");
fprintf(f, "%s", htmlcontent); //stderr, "%s"
fclose(f);
Here is the result that it saves for my question (This Page)
(['_setCustomVar', 1, 'tags', '|c|file|networking|']);
_gaq.push(['_trackPageview']);
var _qevents = _qevents || [];
(function () {
var ssl='https:'==document.location.protocol,
s=document.getElementsByTagName('script')[0],
ga=document.createElement('script');
ga.type='text/javascript';
ga.async=true;
ga.src=(ssl?'https://ssl':'http://www')+'.google-analytics.com/ga.js';
s.parentNode.insertBefore(ga,s);
var sc=document.createElement('script');
sc.type='text/javascript';
sc.async=true;
sc.src=(ssl?'https://secure':'http://edge')+'.quantserve.com/quant.js';
s.parentNode.insertBefore(sc,s);
})();
_qevents.push({ qacct: "p-c1rF4kxgLUzNc" });
</script>
</body>
</html>

FILE *f;
f = fopen(HTMLfile, "w");
fprintf(f, "%s", htmlcontent); //stderr, "%s"
fclose(f);
Rather than opening and closing the file each time through the loop, you should open
it once before the loop, keep it open while you're writing into it, then close it after
the loop.

Instead of opening the file with "w" use "a". Better yet, only open the file once.
f = fopen(HTMLfile, "a");
w" write: Create an empty file for output operations. If a file with the same name already exists, its contents are discarded and the file is treated as a new empty file.
"a" append: Open file for output at the end of a file. Output operations always write data at the end of the file, expanding it. Repositioning operations (fseek, fsetpos, rewind) are ignored. The file is created if it does not exist.

Related

Sending mutiple file using socket and c under ubuntu 22

So I'm trying to send more than a file from my server side to the client .I have already completed the task of sending one file with its size. To explain more the name of the file is passed as argument to the client then send to the server to check if there is a file with this name in the shared folder by the server, if yes then the server sends the file to the client.
My idea was send the number of files to be sent to the client then do the same stuff I do for one single file in for loop but the cold crush I don't now why.
And I also try to connect using wifi in 2 different PC but the code does it work correctly, I test it before using ethernet cable and all go ok
Can any one help me please?
this link to the project folder :
https://github.com/amaraoussama94/Server_Client-C-app
i try some video youtube and some other solution but it crush
i expect to have some idea , or code to boost me
Snap of project :
server :
#include <arpa/inet.h> // inet_addr()/
#include <stdio.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdlib.h>//system
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h> // read(), write(), close()
#include <errno.h>
#include "Const.h"
#include "arg_test.h"
#include <time.h>//get time and date for log file
#include <string.h>//
//void* SendFileToClient(int *arg)
void SendFileToClient(int *ptr_connfd,char * fname ,struct sockaddr_in cli )
{
//int connfd=(int)*arg;
printf("[i]Connection accepted and id: %d\n",*ptr_connfd);
printf("[i]Connected to Clent: %s:%d\n",inet_ntoa(cli.sin_addr),ntohs(cli.sin_port));
write(*ptr_connfd, fname,256);
FILE *fp = fopen(fname,"rb");
if(fp==NULL)
{
printf("\033[0;31m");
printf("[-]File for transfer open error\n");
printf("\033[0m");
exit(1);
}
/*******************************************/
fseek(fp, 0L, SEEK_END);
// calculating the size of the file
long int res = ftell(fp);
//conver to char to send it
char size[10];
sprintf(size, "%f", (res/1024.0) );
//send file size to the client
write(*ptr_connfd, size, sizeof(size));
printf("[i]size of the file to transfer is %f Kb\n",(res/1024.0));
fseek(fp, 0, SEEK_SET);
/******************************************/
/* Read data from file and send it */
while(1)
{
/* First read file in chunks of 256 bytes */
unsigned char buff[1024]={0};
int nread = fread(buff,1,1024,fp);
//printf("Bytes read %d \n", nread);
/* If read was success, send data. */
if(nread > 0)
{
//printf("Sending \n");
write(*ptr_connfd, buff, nread);
}
if (nread < 1024)
{
if (feof(fp))
{
// printf("End of file\n");
printf("\033[0;32m");
printf("[+]File transfer completed for id: %d\n",*ptr_connfd);
printf("\033[0m");
}
if (ferror(fp))
{
printf("\033[0;31m");
printf("[-]Error reading file for transfer \n");
printf("\033[0m");
}
break;
}
}
printf("\033[0;32m");
printf("[+]Closing Connection for id: %d\n",*ptr_connfd);
printf("\033[0;31m");
close(*ptr_connfd);
//shutdown(*ptr_connfd,SHUT_WR);
sleep(2);
}
// Function designed for chat between client and server.
int share_msg(int* ptr_connfd,char **argv ,struct sockaddr_in cli,int *ptr_change )
{
FILE *filePointer,*filePointerTransfer ;
char cmd [100]="./script.sh ";
char buff[MAX];
char string[MAX];
int Exist =0 ;
int j =0;
int err ;
pthread_t tid;
// bzero :Set N bytes of pointer to 0.
bzero(buff, MAX);//or you can use memset (&buff,'\0',sizeof(buff))
// read the message from client and copy it in buffer
read(*ptr_connfd, buff, sizeof(buff));
// print buffer which contains the client contents
if (strncmp("bash_list", buff, 9) == 0)
{ printf("[i]The client wants information about shared folder\n ");
//| awk '{print $1 " " $11 }' " " : field are sparate with space , $1 et $ 11 print colom1 and 11
//chdir(argv[4]);// change the path
strcat(cmd,argv[4]);
//int status = system("ls -al|awk '{print $1 " " $11}' > cmdoutput" );
int status = system(cmd);
//open file
filePointer = fopen("stdout.txt", "r");
//ste the psotion of the pointer at the bening of the file
if (filePointer == NULL)
{
printf("\033[0;31m");
printf("[-]Error can t find list of file to share \n");
printf("\033[0m");
bzero(buff,sizeof(buff));
strcat(buff,"ERRORFILE1");
write(*ptr_connfd, buff, sizeof(buff));
exit(1);
}
fseek(filePointer, 0, SEEK_SET);
while(fgets(buff, MAX, filePointer))
{
// send that buffer to clients
if (strncmp(buff ,".",1)==0 || strncmp(buff ,"..",2)==0 || strncmp(buff ,"/",1)==0)
{
continue;
}
write(*ptr_connfd, buff, sizeof(buff));
}
bzero(buff, MAX);
for(int j =0 ;j<sizeof(buff);j++)
{
buff[j] = '#';
}
//send to client
write(*ptr_connfd, buff, sizeof(buff));
//file
fclose(filePointer);
return 1;
}
else if (strcmp("bash_Transf", buff) == 0)
{
int num_file ;
//get numlber of file to send
bzero(buff, MAX);
read(*ptr_connfd, buff, sizeof(buff));
sscanf(buff,"%d",&num_file);
printf("[i] the number of file to send to the client is %d\n",num_file);
//get file name
bzero(buff, MAX);
read(*ptr_connfd, buff, sizeof(buff));
printf("the file name is %s \n",buff);
/*********************************************///must change dir if it run 2nd it crush
char path[100] ;
//get the current dir path
if (*ptr_change)
{
getcwd(path, sizeof(path)) ;
}
*ptr_change =0 ;
int dir_test = chdir(path);
//printf(" hello dir_test =%d and path=%s\n",dir_test,path);
//system("pwd");//test to check dir path
/********************************************/
filePointer = fopen("stdout.txt", "r");
if (filePointer == NULL)
{
printf("\033[0;31m");
printf("[-]Error can t find list of file to share \n");
printf("\033[0m");
exit(1);
}
//get iof the file name existt or no in the shared folder
while ( fgets( string ,MAX, filePointer) )// fscanf(filePointer,"%s", string) == 1
{
//lets take out the \n introduce by fgets
string[strcspn(string,"\n")]= 0;
if (strcmp(string,buff)==0)
{
Exist = 1;
break;
}
}
if (Exist)
{
fclose(filePointer);
//transfer file here
chdir(argv[4]);// change the path
printf( "[i]the file for transfer name is = %s \n",buff);
SendFileToClient(ptr_connfd,buff ,cli );
//create thread for sending the file to the client
/*err = pthread_create(&tid, NULL, &SendFileToClient, ptr_connfd);
if (err != 0)
printf("\ncan't create thread :[%s]", strerror(err));*/
}
else
{
bzero(buff, sizeof(buff));
strcat(buff,"file_error");
write(*ptr_connfd, buff, sizeof(buff));
bzero(buff, sizeof(buff));
printf("\033[0;31m");
printf("[-] Client try to get file that doesn't exist in the shared folder \n");
printf("\033[0m");
}
// si il n y a aucun paramatere passe au clien ni t ni
// list le server se ferme par return 1 and close the while loop
return 1;
}
else
return 0;
}
void create_scoket(int * sockfd)
{
*sockfd = socket(AF_INET, SOCK_STREAM, 0);// AF_INET :IPV4 , SOCK_STREAM:TCP
if (sockfd < 0)
{
printf("\033[0;31m");
perror("[-]socket creation failed...\n");
printf("\033[0m");
exit(1);
}
else
{
printf("\033[0;32m");
printf("[+]Socket successfully created..\n");
printf("\033[0m");
}
}
void socket_bind(struct sockaddr_in *servaddr ,int * sockfd)
{
// Binding newly created socket to given IP and verification
if ((bind(*sockfd, (SA*)servaddr, sizeof(*servaddr))) < 0)
{
printf("\033[0;31m");
perror("[-]socket bind failed...\n");
printf("\033[0m");
exit(1);
}
else
{
printf("\033[0;32m");
printf("[+]Socket successfully binded..\n");
printf("\033[0m");
}
}
void socket_listening (int *sockfd)
{
if ((listen(*sockfd, LISTENQ)) != 0) //5 connection requests will be queued before further requests are refused.
{
printf("\033[0;31m");
printf("[-]Listen failed...\n");
printf("\033[0m");
exit(1);
}
else
{
printf("\033[0;32m");
printf("[+]Server listening..\n");
printf("\033[0m");
}
}
void socket_accept (int *connfd , int* sockfd ,struct sockaddr_in*cli , int *len)
{
*connfd = accept(*sockfd, (SA*)cli, len);
if (connfd < 0)
{
printf("\033[0;31m");
perror("[-]server accept failed...\n");
printf("\033[0m");
exit(1);
}
else
{
printf("\033[0;32m");
printf("[+]server accept the client...\n");
printf("\033[0m");
}
}
// Driver function
int main(int argc, char **argv)
{
//for socket
int sockfd, connfd, len;
int *ptr_sockfd ,*ptr_connfd , *ptr_len;
struct sockaddr_in servaddr, cli;
struct sockaddr_in *ptr_servaddr , *ptr_cli;
int change =1 ; //for transfer
int *ptr_change =&change;
check_arg_server(argc,argv);
// socket create and verification
ptr_sockfd = &sockfd;
create_scoket(ptr_sockfd);
//initialize to zeo
// bzero :Set N bytes of pointer to 0.
bzero(&servaddr, sizeof(servaddr));//or you can use memset (&servaddr,'\0', sizeof(servaddr))
// assign IP, PORT
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr =htonl(INADDR_ANY);// Address to accept any incoming messages.
servaddr.sin_port = htons(atoi(argv[2]));//htons :Functions to convert between host and network byte order
//binding
ptr_servaddr = &servaddr;
socket_bind(ptr_servaddr ,ptr_sockfd);
// Now server is ready to listen and verification
socket_listening (ptr_sockfd);
//chek for ctr+z as input to stope server
while (1)
{
len = sizeof(cli);
//printf("hello ok \n");
// Accept the data packet from client and verification
ptr_connfd = &connfd;
ptr_len = &len;
ptr_cli= &cli ;
socket_accept (ptr_connfd , ptr_sockfd , ptr_cli , ptr_len);
//temp sol to stop server
int b = share_msg(ptr_connfd,argv,cli,ptr_change);
if (!b)
{
close(connfd);
break;
}
close(connfd);
sleep(1);
}
// After chatting close the socket
close(sockfd);
printf("[i] Server will Shutdown \n");
return 0;
}
client :
#include <arpa/inet.h> // inet_addr()/
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h> // bzero()
#include <sys/socket.h>
#include <unistd.h> // read(), write(), close()
#include "Const.h"
#include "arg_test.h"
// for mkdir function
#include <sys/stat.h>
#include <sys/types.h>
const int PROG_BAR_LENGTH =30 ;//30 caractere
void update_bar(float percent_done )
{
int num_car =(int) percent_done * PROG_BAR_LENGTH / 100 ;//number of caractere to print
printf(" \r[");
for(int i =0;i<num_car;i++)
{
printf("\033[0;32m"); //Set the text to the color Green
printf("■");
}
for(int i =0;i<(PROG_BAR_LENGTH -num_car);i++) //unfinish part of progress bar
{
printf(" ");
}
if((int)percent_done > 100)
{
percent_done =100 ;
}
printf("\033[0m"); //Resets the text to default color
printf("] %d%% Done.",(int)percent_done );
// fflush(stdout);//print all to the screen
}
void share_msg(int *sockfd,char ** argv, int argc)
{
char buff[MAX]="bash";
char msg[MAX];
FILE *filetransferPointer;
int n , bytesReceived = 0 ;
if (strcmp("--list", argv[5]) == 0)
{
strcat(buff,"_list");
}
if (strcmp("-T", argv[5]) == 0)
{
strcat(buff,"_Transf");
}
//send to server
write(*sockfd, buff, sizeof(buff));
bzero(buff, sizeof(buff));
if (strcmp("--list", argv[5]) == 0)
{
//read receive msg from server
read(*sockfd, msg, sizeof(msg));
read(*sockfd, msg, sizeof(msg));
if(!strcmp(msg,"ERRORFILE1"))
{
printf("[-] Error server can t list file \n ");
exit(1);
}
printf("[i]This is the list of file and folder shared by the server : \n These are the directories : \n" );
while(1)
{
read(*sockfd, msg, sizeof(msg));
if(!strncmp(msg, "#", 1) )
{
break;
}
printf("%s \n ",msg);
}
}
else if (strcmp("-T", argv[5]) == 0)
{
//get number of file to receive from server
int num_file = argc-6;
bzero(msg, sizeof(msg));
sprintf(msg,"%d",num_file);
write(*sockfd, msg, sizeof(msg));
//printf ("num = %s\n",msg);
//send file name to server
bzero(msg, sizeof(msg));
strcat(msg,argv[6]);
printf(" the buff is = %s",msg);
write(*sockfd, msg, sizeof(msg));
//check if the file name exist or no
bzero(msg, sizeof(msg));
read(*sockfd, msg, sizeof(msg));
if (strcmp(msg,"file_error")==0)
{ printf("\033[0;31m");
printf("[-]Please try again ,maybe try --list first then try again ,or maybe no file has this name \n" );
printf("\033[0m");
exit(1);
}
//get the file
char* dirname = "transfer";
mkdir(dirname,0755);
//system("mkdir transfer");
chdir("transfer");
//system("cd test/");
//system("pwd");
filetransferPointer = fopen(argv[6] , "ab");
if (filetransferPointer == NULL)
{
printf("\033[0;31m");
printf("[-]Error can t create file for transfer \n");
printf("\033[0m");
exit(-1);
}
/**********************************************/
char size[10];
long double size_file =0;
read(*sockfd, size, sizeof(size));
//convert data to long double
sscanf(size, "%Lf", &size_file);
printf("[i]Size of the file %Lf Kb \n",size_file);
/*************************************************/
/* Receive data in chunks of 256 bytes */
long double sz=0;
long double * ptr_sz =&sz;
while((bytesReceived = read(*sockfd, msg, 1024)) > 0)
{
//sz++;
//gotoxy(0,4);
//printf(" \r Received: %LF Mb \t \t \t",(sz/1024)); //LF for long double
//fflush(stdout);
// recvBuff[n] = 0;
/******************************************************/
double percent_done;
//long double batch_size =1/1024 ;//Mb
percent_done += 100/ size_file ; //;(batch_size/size_file)*100
//printf(" the file size is %Lf the percent_done = %lf and in in = %d \n",size_file,percent_done,(int)percent_done);
update_bar(percent_done);
fflush(stdout);
fwrite(msg, 1,bytesReceived,filetransferPointer);
usleep(20000);//sleep for 20ms
//printf("%s \n", recvBuff);
}
printf("\n");
if(bytesReceived < 0)
{
printf("[-]Error can t create file %s to recive it \n",argv[6]);
}
fclose(filetransferPointer);
printf("[i] file transmission %s is done you can check transfer folder \n",argv[6]);
}
}
void create_scoket(int * sockfd)
{
*sockfd = socket(AF_INET, SOCK_STREAM, 0);// AF_INET :IPV4 , SOCK_STREAM:TCP
if (sockfd < 0)
{
printf("\033[0;31m");
perror("[-]socket creation failed...\n");
printf("\033[0;31m");
exit(1);
}
else
{ printf("\033[0;32m");
printf("[+]Socket successfully created..\n");
printf("\033[0m");
}
}
void socket_connect(struct sockaddr_in *servaddr ,int * sockfd)
{
if (connect(*sockfd, (SA*)servaddr, sizeof(*servaddr)) <0)
{
printf("\033[0;31m");
perror("[-]connection with the server failed...\n");
printf("\033[0m");
exit(1);
}
else
{
printf("\033[0;32m");
printf("[+]connected to the server..\n");
printf("\033[0m");
}
}
int main(int argc, char **argv)
{
int sockfd, connfd;
int *ptr_sockfd;
struct sockaddr_in servaddr, client_addr;
struct sockaddr_in *ptr_servaddr;
//check argument
check_arg_client(argc,argv);
// socket create and verification
ptr_sockfd= &sockfd;
create_scoket(ptr_sockfd);
//initialize to zeo
// bzero :Set N bytes of pointer to 0.
bzero(&servaddr, sizeof(servaddr));//or you can use memset (&servaddr,'\0', sizeof(servaddr))
// assign IP, PORT
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr(argv[2]);// the adress of the serveur
servaddr.sin_port = htons(atoi(argv[4])); //htons :Functions to convert between host and network byte order
// connect the client socket to server socket
ptr_servaddr = &servaddr ;
socket_connect(ptr_servaddr ,ptr_sockfd);
// run the lisst or transfer option
if( argc > 5)
{
share_msg(ptr_sockfd,argv, argc);
}
// close the socket
close(sockfd);
}
enter code here

Recieve a message from server asynchronously

I have a client program and a server program. There could be multiple servers and multiple
clients that can connect to multiple servers of there choice
The client program lists a menu
connect 4000 // connects to server on port 4000
bid 1000 4000 // send a bid value of 1000 to the server at port 4000
Now a server may recieve bids from several clients connected to it and keeps track of the highest
bid till now. Whenever a new bid is placed the server sends a broadcast to each client connected
to it one by one like - write(users[i].sock_fd, msg, size).
How do I listen to this message on the client side ?
There are two things here
The client needs to listen to the message sent by server.
The client is also reading the text or menu items (connect and bid) from command line from the user.
I have coded the part 2) But confused how to code 1) into client and simultaneously make the 2) also working
Client code :
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#define BUF_SIZE 128
#define MAX_AUCTIONS 5
#ifndef VERBOSE
#define VERBOSE 0
#endif
#define ADD 0
#define SHOW 1
#define BID 2
#define QUIT 3
/* Auction struct - this is different than the struct in the server program
*/
typedef struct auction_data
{
int sock_fd;
char item[BUF_SIZE];
int current_bid;
} auction_data;
auction_data *auction_data_ptr;
/* Displays the command options available for the user.
* The user will type these commands on stdin.
*/
void print_menu()
{
printf("The following operations are available:\n");
printf(" show\n");
printf(" add <server address> <port number>\n");
printf(" bid <item index> <bid value>\n");
printf(" quit\n");
}
/* Prompt the user for the next command
*/
void print_prompt()
{
printf("Enter new command: ");
fflush(stdout);
}
/* Unpack buf which contains the input entered by the user.
* Return the command that is found as the first word in the line, or -1
* for an invalid command.
* If the command has arguments (add and bid), then copy these values to
* arg1 and arg2.
*/
int parse_command(char *buf, int size, char *arg1, char *arg2)
{
int result = -1;
char *ptr = NULL;
if (strncmp(buf, "show", strlen("show")) == 0)
{
return SHOW;
}
else if (strncmp(buf, "quit", strlen("quit")) == 0)
{
return QUIT;
}
else if (strncmp(buf, "add", strlen("add")) == 0)
{
result = ADD;
}
else if (strncmp(buf, "bid", strlen("bid")) == 0)
{
result = BID;
}
ptr = strtok(buf, " "); // first word in buf
ptr = strtok(NULL, " "); // second word in buf
if (ptr != NULL)
{
strncpy(arg1, ptr, BUF_SIZE);
}
else
{
return -1;
}
ptr = strtok(NULL, " "); // third word in buf
if (ptr != NULL)
{
strncpy(arg2, ptr, BUF_SIZE);
return result;
}
else
{
return -1;
}
return -1;
}
/* Connect to a server given a hostname and port number.
* Return the socket for this server
*/
int add_server(char *hostname, int port)
{
// Create the socket FD.
int sock_fd = socket(AF_INET, SOCK_STREAM, 0);
if (sock_fd < 0)
{
perror("client: socket");
exit(1);
}
// Set the IP and port of the server to connect to.
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(port);
struct addrinfo *ai;
/* this call declares memory and populates ailist */
if (getaddrinfo(hostname, NULL, NULL, &ai) != 0)
{
close(sock_fd);
return -1;
}
/* we only make use of the first element in the list */
server.sin_addr = ((struct sockaddr_in *)ai->ai_addr)->sin_addr;
// free the memory that was allocated by getaddrinfo for this list
freeaddrinfo(ai);
// Connect to the server.
if (connect(sock_fd, (struct sockaddr *)&server, sizeof(server)) == -1)
{
perror("client: connect");
close(sock_fd);
return -1;
}
if (VERBOSE)
{
fprintf(stderr, "\nDebug: New server connected on socket %d. Awaiting item\n", sock_fd);
}
return sock_fd;
}
/* ========================= Add helper functions below ========================
* Please add helper functions below to make it easier for the TAs to find the
* work that you have done. Helper functions that you need to complete are also
* given below.
*/
/* Print to standard output information about the auction
*/
void print_auctions(struct auction_data *a, int size)
{
printf("Current Auctions:\n");
for (int i = 0; i < size; i++)
{
struct auction_data auction_data = a[i];
printf("(%d) %s bid = %d\n", i, auction_data.item, auction_data.current_bid);
}
/* TODO Print the auction data for each currently connected
* server. Use the follosing format string:
* "(%d) %s bid = %d\n", index, item, current bid
* The array may have some elements where the auction has closed and
* should not be printed.
*/
}
/* Process the input that was sent from the auction server at a[index].
* If it is the first message from the server, then copy the item name
* to the item field. (Note that an item cannot have a space character in it.)
*/
void update_auction(char *buf, int size, struct auction_data *a, int index)
{
// TODO: Complete this function
// fprintf(stderr, "ERROR malformed bid: %s", buf);
// printf("\nNew bid for %s [%d] is %d (%d seconds left)\n", );
}
int main(void)
{
char name[BUF_SIZE];
int size = 0;
// Declare and initialize necessary variables
// TODO
// Get the user to provide a name.
printf("Please enter a username: ");
fflush(stdout);
int num_read = read(STDIN_FILENO, name, BUF_SIZE);
printf("%s-name\n", name);
if (num_read <= 0)
{
fprintf(stderr, "ERROR: read from stdin failed\n");
exit(1);
}
print_menu();
// TODO
char server_reply[2000];
while (1)
{
print_prompt();
char *command;
scanf("%m[^\n]s", &command);
getchar();
char arg1[100];
char arg2[100];
int commandNumber = parse_command(command, 1000, arg1, arg2);
char dest[100] = "";
strcpy(dest, name);
dest[strlen(dest) - 1] = '\0';
if (commandNumber == ADD)
{
printf("%s-name4\n", dest);
int port = atoi(arg2);
int sock_fd = add_server(arg1, port);
printf("%s-server\n", server_reply);
write(sock_fd, dest, strlen(dest));
auction_data_ptr = (auction_data *)realloc(auction_data_ptr, (size + 1) * sizeof(auction_data_ptr));
auction_data_ptr[size].sock_fd = sock_fd;
size++;
}
else if (commandNumber == SHOW)
{
print_auctions(auction_data_ptr, size);
}
else if (commandNumber == BID)
{
int itemIndex = atoi(arg1);
int bidValue = atoi(arg2);
printf("%d-test\n", auction_data_ptr[itemIndex].sock_fd);
send(auction_data_ptr[itemIndex].sock_fd, arg2, strlen(arg2), 0);
}
else if (commandNumber == QUIT)
{
}
// TODO
}
return 0; // Shoud never get here
}
Server Code :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#ifndef PORT
#define PORT 30000
#endif
#define MAX_BACKLOG 5
#define MAX_CONNECTIONS 20
#define BUF_SIZE 128
#define MAX_NAME 56
int verbose = 0;
struct user
{
int sock_fd;
char name[MAX_NAME];
int bid;
};
typedef struct
{
char *item;
int highest_bid; // value of the highest bid so far
int client; // index into the users array of the top bidder
} Auction;
/*
* Accept a connection. Note that a new file descriptor is created for
* communication with the client. The initial socket descriptor is used
* to accept connections, but the new socket is used to communicate.
* Return the new client's file descriptor or -1 on error.
*/
int accept_connection(int fd, struct user *users)
{
int user_index = 0;
while (user_index < MAX_CONNECTIONS && users[user_index].sock_fd != -1)
{
user_index++;
}
if (user_index == MAX_CONNECTIONS)
{
fprintf(stderr, "server: max concurrent connections\n");
return -1;
}
int client_fd = accept(fd, NULL, NULL);
if (client_fd < 0)
{
perror("server: accept");
close(fd);
exit(1);
}
users[user_index].sock_fd = client_fd;
users[user_index].name[0] = '\0';
return client_fd;
}
/* Remove \r\n from str if the characters are at the end of the string.
* Defensively assuming that \r could be the last or second last character.
*/
void strip_newline(char *str)
{
if (str[strlen(str) - 1] == '\n' || str[strlen(str) - 1] == '\r')
{
if (str[strlen(str) - 2] == '\r')
{
str[strlen(str) - 2] = '\0';
}
else
{
str[strlen(str) - 1] = '\0';
}
}
}
/*
* Read a name from a client and store in users.
* Return the fd if it has been closed or 0 otherwise.
*/
int read_name(int client_index, struct user *users)
{
int fd = users[client_index].sock_fd;
/* Note: This is not the best way to do this. We are counting
* on the client not to send more than BUF_SIZE bytes for the
* name.
*/
int num_read = read(fd, users[client_index].name, MAX_NAME);
if (num_read == 0)
{
users[client_index].sock_fd = -1;
return fd;
}
users[client_index].name[num_read] = '\0';
strip_newline(users[client_index].name);
if (verbose)
{
fprintf(stderr, "[%d] Name: %s\n", fd, users[client_index].name);
}
/*
if (num_read == 0 || write(fd, buf, strlen(buf)) != strlen(buf)) {
users[client_index].sock_fd = -1;
return fd;
}
*/
return 0;
}
/* Read a bid from a client and store it in bid.
* If the client does not send a number, bid will be set to -1
* Return fd if the socket is closed, or 0 otherwise.
*/
int read_bid(int client_index, struct user *users, int *bid)
{
printf("inside bid\n");
int fd = users[client_index].sock_fd;
char buf[BUF_SIZE];
char *endptr;
int num_read = read(fd, buf, BUF_SIZE);
if (num_read == 0)
{
return fd;
}
buf[num_read] = '\0';
if (verbose)
{
fprintf(stderr, "[%d] bid: %s", fd, buf);
}
// Check if the client sent a valid number
// (We are not checking for a good bid here.)
errno = 0;
*bid = strtol(buf, &endptr, 10);
if (errno != 0 || endptr == buf)
{
*bid = -1;
}
return 0;
}
void broadcast(struct user *users, char *msg, int size)
{
for (int i = 0; i < MAX_CONNECTIONS; i++)
{
if (users[i].sock_fd != -1)
{
if (write(users[i].sock_fd, msg, size) == -1)
{
// Design flaw: can't remove this socket from select set
close(users[i].sock_fd);
users[i].sock_fd = -1;
}
}
}
}
int prep_bid(char *buf, Auction *a, struct timeval *t)
{
// send item, current bid, time left in seconds
printf("robin2-%s-%d\n", a->item, a->highest_bid);
printf("robin-%ld\n", t->tv_sec);
sprintf(buf, "%s %d %ld", a->item, a->highest_bid, t->tv_sec);
printf("robin-bid2\n");
return 0;
}
/* Update auction if new_bid is higher than current bid.
* Write to the client who made the bid if it is lower
* Broadcast to all clients if the bid is higher
*/
int update_bids(int client_index, struct user *users,
int new_bid, Auction *auction, struct timeval *t)
{
char buf[BUF_SIZE];
if (new_bid > auction->highest_bid)
{
auction->highest_bid = new_bid;
auction->client = client_index;
prep_bid(buf, auction, t);
if (verbose)
{
fprintf(stderr, "[%d] Sending to %d:\n %s\n",
getpid(), users[client_index].sock_fd, buf);
}
broadcast(users, buf, strlen(buf) + 1);
}
else
{
fprintf(stderr, "Client %d sent bid that was too low. Ignored\n",
client_index);
}
return 0;
}
int main(int argc, char **argv)
{
argc = 7;
argv[1] = "-v";
argv[2] = "-t";
argv[3] = "5";
argv[4] = "-p";
argv[5] = "4000";
argv[6] = "robin";
Auction auction;
int opt;
int port = PORT;
struct timeval timeout;
struct timeval *time_ptr = NULL;
int minutes = 0;
while ((opt = getopt(argc, argv, "vt:p:")) != -1)
{
switch (opt)
{
case 'v':
verbose = 1;
break;
case 't':
minutes = atoi(optarg);
timeout.tv_sec = minutes * 60;
timeout.tv_usec = 0;
time_ptr = &timeout;
break;
case 'p':
port = atoi(optarg);
break;
default:
fprintf(stderr, "Usage: auction_server [-v] [-t timeout] [-p port] item\n");
exit(1);
}
}
if (optind >= argc)
{
fprintf(stderr, "Expected argument after options\n");
exit(1);
}
auction.item = argv[optind];
auction.client = -1;
auction.highest_bid = -1;
struct user users[MAX_CONNECTIONS];
for (int index = 0; index < MAX_CONNECTIONS; index++)
{
users[index].sock_fd = -1;
users[index].name[0] = '\0';
}
// Create the socket FD.
int sock_fd = socket(AF_INET, SOCK_STREAM, 0);
if (sock_fd < 0)
{
perror("server: socket");
exit(1);
}
// Set information about the port (and IP) we want to be connected to.
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = INADDR_ANY;
// This sets an option on the socket so that its port can be reused right
// away. Since you are likely to run, stop, edit, compile and rerun your
// server fairly quickly, this will mean you can reuse the same port.
int on = 1;
int status = setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR,
(const char *)&on, sizeof(on));
if (status == -1)
{
perror("setsockopt -- REUSEADDR");
}
// This should always be zero. On some systems, it won't error if you
// forget, but on others, you'll get mysterious errors. So zero it.
memset(&server.sin_zero, 0, 8);
// Bind the selected port to the socket.
if (bind(sock_fd, (struct sockaddr *)&server, sizeof(server)) < 0)
{
perror("server: bind");
close(sock_fd);
exit(1);
}
// Announce willingness to accept connections on this socket.
if (listen(sock_fd, MAX_BACKLOG) < 0)
{
perror("server: listen");
close(sock_fd);
exit(1);
}
if (verbose)
{
fprintf(stderr, "[%d] Ready to accept connections on %d\n",
getpid(), port);
}
// The client accept - message accept loop. First, we prepare to listen
// to multiple file descriptors by initializing a set of file descriptors.
int max_fd = sock_fd;
fd_set all_fds;
FD_ZERO(&all_fds);
FD_SET(sock_fd, &all_fds);
while (1)
{
// select updates the fd_set it receives, so we always use a copy
// and retain the original.
fd_set listen_fds = all_fds;
int nready;
if ((nready = select(max_fd + 1, &listen_fds, NULL, NULL, time_ptr)) == -1)
{
perror("server: select");
exit(1);
}
if (nready == 0)
{
char buf[BUF_SIZE];
sprintf(buf, "Auction closed: %s wins with a bid of %d\r\n",
users[auction.client].name, auction.highest_bid);
printf("%s", buf);
broadcast(users, buf, BUF_SIZE);
exit(0);
}
// Is it the original socket? Create a new connection ...
if (FD_ISSET(sock_fd, &listen_fds))
{
int client_fd = accept_connection(sock_fd, users);
if (client_fd != -1)
{
if (client_fd > max_fd)
{
max_fd = client_fd;
}
FD_SET(client_fd, &all_fds);
if (verbose)
{
fprintf(stderr, "[%d] Accepted connection on %d\n",
getpid(), client_fd);
}
}
}
// Next, check the clients.
for (int index = 0; index < MAX_CONNECTIONS; index++)
{
if (users[index].sock_fd > -1 && FD_ISSET(users[index].sock_fd, &listen_fds))
{
int client_closed = 0;
int new_bid = 0;
if (users[index].name[0] == '\0')
{
client_closed = read_name(index, users);
if (client_closed == 0)
{
char buf[BUF_SIZE];
prep_bid(buf, &auction, time_ptr);
if (verbose)
{
fprintf(stderr, "[%d] Sending to %d:\n %s\n",
getpid(), users[index].sock_fd, buf);
}
if (write(users[index].sock_fd, buf, strlen(buf) + 1) == -1)
{
fprintf(stderr, "Write to %d failed\n", sock_fd);
close(sock_fd);
}
}
}
else
{ // read a bid
client_closed = read_bid(index, users, &new_bid);
if (client_closed == 0)
{
update_bids(index, users, new_bid, &auction, time_ptr);
}
}
if (client_closed > 0)
{
FD_CLR(client_closed, &all_fds);
printf("Client %d disconnected\n", client_closed);
}
}
}
}
// Should never get here.
return 1;
}
Caveat: Because you've only posted partial code for server and client, this will be some suggestions.
Your client can attach/connect to multiple bid servers simultaneously. As such, it must be able to keep track of the multiple connections in a manner similar to a server.
Your main [stated] issue is that you're blocking the client on a user prompt (e.g. from stdin via scanf et. al.). Presently, this means that the client is "stuck" at user input prompt and can not field messages from the servers it is connected to. More on how to fix this below.
So, you'll have a bunch of code from the server that needs to be in the client with some minor differences. You may wish to generalize some of the server code a bit, so it can work both in server and client (e.g. you may want to move it to common.c).
You already have code in the server to handle multiple connections. The server needs a select mask that is the OR of the listen fd and all active client fds.
Likewise, your client needs a select mask that is the OR of the fd for user input (e.g. 0) and all active server connections.
Doing select on fd 0 and using stdio.h streams won't work too well. So, replace access to stdin with (e.g.) read(0,line_buffer,sizeof(line_buffer)). You do this if fd 0 is set in the select mask. The role is very similar to what your server does for the accept on sock_fd.
You'll need to allow for partial reads and append to the buffer until you see a newline. So, you'll have to do the work that fgets would normally do in assembling a whole line. Then, you can call parse_command.
Because read doesn't understand newline demarcations, the user could enter more than one line before you can do a read.
So, for user input of:
connect 4000\n
bid 100 4000\n
connect 5000\n
You may get partial reads of:
conn
ect
4000\nbid 100 4000
\nconnect
5000\n
You may also need to use the FIONREAD ioctl on the fd 0 to prevent blocking. And, you may need to set the kernel TTY layer into raw mode via termios calls.
The client now becomes very similar to your server code. It will handle [asynchronously] actions by any connected servers and user input.
A tip: Under the DRY principle ["don't repeat yourself"] ...
You already have a struct user in the server. The client will need something similar/identical, such as struct server. When generalizing the code, rather than having two distinct structs that do essentially the same thing, consider renaming the existing struct to (e.g.) struct connection

Server - Browser showes site only after server is terminated

I am trying to programm a small HTTP-Server with fork(). When I connect to it via firefox, it doesn't show the the page, until I terminate the Server.
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdbool.h>
#include <sys/socket.h>
#include <signal.h>
#define LISTEN_MAX 5
#define CONT_MAX 10000
#define PORT 8081
#define MAX_FILE 2
#define S_SHORT 50
#define MAX_CONTENT 1000
#define MAX_HEADER 200
const size_t BUF_LEN = 1024; //was 128
const size_t REQUEST_LEN=1024;
char file_names[MAX_FILE][S_SHORT];
FILE *file_deskriptors[MAX_FILE];
int file_sizes[MAX_FILE];
char file_contents[MAX_FILE][MAX_CONTENT];
// Something unexpected happened. Report error and terminate.
void sysErr( char *msg, int exitCode ) {
fprintf( stderr, "%s\n\t%s\n", msg, strerror( errno ) );
exit( exitCode );
}
// get_line was borrowed from Tiny HTTPd under GPLv2
// https://sourceforge.net/projects/tinyhttpd/?source=typ_redirect
int get_line(int sock, char *buf, int size) {
int i = 0;
char c = '\0';
int n;
while ((i < size - 1) && (c != '\n'))
{
n = recv(sock, &c, 1, 0);
/* DEBUG printf("%02X\n", c); */
if (n > 0)
{
if (c == '\r')
{
n = recv(sock, &c, 1, MSG_PEEK);
/* DEBUG printf("%02X\n", c); */
if ((n > 0) && (c == '\n'))
recv(sock, &c, 1, 0);
else
c = '\n';
}
buf[i] = c;
i++;
}
else
c = '\n';
}
buf[i] = '\0';
return(i);
}
void copyHeaderToBuffer(char *tx_buff, int *status) {
switch(*status) {
case 200: strcpy(tx_buff,"HTTP/1.0 200 OK\r\nContent­type: text/html\r\n\r\n"); break;
}
return;
}
void answer(int *accfd, char *request ) {
int file_size, file_index, status, sent_bytes;
file_size, file_index, status = 0;
char method[S_SHORT], ressource[S_SHORT], proto[S_SHORT];
char tx_buff[MAX_CONTENT+MAX_HEADER];
//rehash query
splitRequest(request, method, ressource, proto);
//check for <GET>
checkMethod(method);
//search the file and get index
getFileIndexByName(ressource, &file_index);
file_size = file_sizes[file_index];
status = getFileStatus(&file_index);
createAnswerMessage(tx_buff, &status, &file_index);
//send the answer
if ( (sent_bytes= write( accfd, tx_buff, strlen(tx_buff))) == -1 ) {
sysErr( "[-] Client Fault: SEND", -4 );
}
return;
}
void createAnswerMessage(char *tx_buff, int *status, int *file_index) {
copyHeaderToBuffer(tx_buff, status);
strcat(tx_buff,file_contents[*file_index]);
strcat(tx_buff,"\r\n");
return;
}
int getFileStatus(int *file_index) {
return 200;
}
void splitRequest(char *request, char *method, char *ressource, char *proto) {
char *temp;
if ((temp = strtok(request, " ")) != NULL) {
strcpy(method, temp);
}
if ((temp = strtok(NULL, " ")) != NULL) {
strcpy(ressource, temp);
}
if ((temp = strtok(NULL, " ")) != NULL) {
strcpy(proto, temp);
}
//remove leading "/" from ressource
cleanRessource(ressource);
return;
}
void cleanRessource(char *ressource) {
if (*ressource == '/') {
printf("\nstr_len_ressource: %i",strlen(ressource));
for ( int i=0; i < strlen(ressource); i++ ) {
ressource[i]=ressource[i+1];
}
}
return;
}
void checkMethod(char *method){
if (strcmp(method, "GET") ) {
printf("\n[-] Error: Method \"%s\" not known .",method);
exit(0);
}
printf("\nincheckMethod method = %s",method);
return;
}
void getFileIndexByName (char *ressource, int *file_index) {
for (int i=0; i<MAX_FILE; i++) {
if ( !strcmp(ressource, file_names[i]) ) {
*file_index = i;
return;
}
}
printf("\[-] Error: File \"%s\" not known.",ressource);
exit(0);
}
void filesInit () {
memset(file_names, '\0', sizeof(file_names));
memset(file_contents, '\0', sizeof(file_contents));
//define your files here:
strcpy(file_names[0],"index.htm");
for (int i=0; i<MAX_FILE; i++) {
//choose only existing files
if (file_names[i][0]!='\0') {
//open file
file_deskriptors[i] = fopen(file_names[i],"r");
//get file size
fseek(file_deskriptors[i], 0, SEEK_END);
file_sizes[i] = ftell(file_deskriptors[i]);
//read the file content to file_contents
fseek(file_deskriptors[i], 0, SEEK_SET);
fread(file_contents[i], 1, CONT_MAX, file_deskriptors[i]);
}
}
return;
}
void filesClose() {
return;
}
int main(int argc, char **argv)
{
//kill childs if recieving SIGCHLD
signal(SIGCHLD,SIG_IGN);
int connfd, accfd;
struct sockaddr_in server_addr, client_addr;
socklen_t sockaddr_len = sizeof(struct sockaddr_in);
//initial the available files on server
filesInit();
// create socket
if ( ( connfd = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0) {
sysErr( "Server Fault : SOCKET", -1 );
}
// Set params so that we receive IPv4 packets from anyone on the specified port
memset( &server_addr, 0, sockaddr_len );
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons( PORT );
//bind socket to port
if ( bind( connfd, (struct sockaddr *) &server_addr, sockaddr_len ) < 0 ) {
sysErr( "\n[-] Server Fault : BIND", -2 );
}else{printf("[+] SERVER ONLINE");}
//let server listen for incoming connections
if ( listen( connfd, LISTEN_MAX) < 0 ) {
sysErr( "[-] Server Fault : LISTEN", -3 );
}
//main loop for accepting clients
while ( true ) {
pid_t pid;
//connecting specific client
if ( (accfd=accept( connfd, (struct sockaddr *) &client_addr, &sockaddr_len )) < 0 ) {
sysErr( "[-] Server Fault : ACCEPT", -4 );
}
//fork & answer
else {
printf("\n[+] CLIENT CONNECTED\n");
switch ( pid = fork() ) {
case -1: {
printf("\n[-] Error while fork()");
return EXIT_FAILURE;
}
case 0: {
int req_line_len=1; //length of request line
int first_line_on = 1; //set first line parameter
char req_line[S_SHORT]; //current read line
char first_line[S_SHORT]; //save first line
memset(req_line, 0, S_SHORT);
memset(first_line, 0, S_SHORT);
printf("\n[+] HTTP REQUEST on accfd: %i",accfd);
//reading line by line from socket
while((req_line_len > 0) && strcmp("\n", req_line)){
req_line_len = get_line( accfd, req_line, S_SHORT-1);
//get first line and save it
if (first_line_on) { first_line_on = 0; strcpy(first_line,req_line); }
if((req_line_len > 0) && strcmp("\n", req_line)) printf("%s",req_line);
}
//answering to client
answer(accfd, first_line);
//close connection
if (!close(accfd)) {printf("\n[+] CONNECTION CLOSED");}
exit(0);
break;
}
default: {
//main process
break;
}
}
}
}
//close listening socket
close( connfd );
//close server files
filesClose();
return 0;
}
The child is terminated, and I get the answer CONNECTION CLOSED
Is there a logical mistake in my Code?
EDIT:
I added a full minimum code.
The "\r\n" I add at to the transmitting msg.
It works fine if I add
close(accfd);
to the main(), but I think it is not actually the problem(only a side effect solution)
the index.htm could be:
<html><body><b>index</b><br>C is a interesting language!</body></html>
When you call fork() the file descriptors of the parent in copied to the child, this is why you can still access the socket in the child process. The network stack will keep the socket alive as long as you have at least one file descriptor open to the socket. You close the socket in the child process but still have it open in the parent.
In other words adding a call to close(accfd) in the parent should fix your problem.

Socket Programming -- recv() is not receiving data correctly

I have looked at the similar threads but can't seem to find anything that could solve my problem.
I am programming a server that could send an image(jpg) file from the path sent to it from the client. I am using send/recv functions in C for that.
I read files one chunk of data at a time and send it to the client that receives the contents and writes them at some location to build the file.
Problem is 'recv' doesn't receive the number of bytes sent by the 'send'.
As part of debugging, I have tried different buffer sizes and '128' buffer size doesn't give me any problem, and the file is successfully transferred and built.
However, for '32' and '64' bit buffers, 'recv' receives '32' bit or '64' bit data at the last chunk, even though the data sent by the server is less than either '32' bit or '64' bit. And, for '256', '512', '1024' so on, 'recv' returns ONLY '128' bits at EXACTLY one of the responses, even though the server sends complete chunk, i.e. '256' or'512', depending on the buffer size.
I'll appreciate any advise for debugging. Following code is for the relevant parts only, but I can provide more, should someone requires it.
//Client Code
#define BUFFER_SIZE 4096
#define HEADER_LEN 512
const char * const scheme = "GETFILE";
const char* const method = "GET";
const char * const end_marker = "\\r\\n\\r\\n";
struct gfcrequest_t
{
int filelen;
char cport[12];
char servIP[50];
gfstatus_t ret_status;
char spath[1024];
int tot_bytes;
char filecontent[BUFFER_SIZE];
void (*fl_handler)(void *, size_t, void *);
void * fDesc;
void (*head_handler)(void *, size_t, void *);
void * headarg;
};
static pthread_mutex_t counter_mutex;
gfcrequest_t *gfc;
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET)
{
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
static char *stringFromError(gfstatus_t stat)
{
static const char *strings[] = {"GF_OK", "GF_FILE_NOT_FOUND", "GF_ERROR", "GF_INVALID"};
return strings[stat];
}
int getFileRequestHeader(char * req_header)
{
return snprintf(req_header,HEADER_LEN, "%s%s%s%s", scheme, method,gfc->spath, end_marker);
// return snprintf(req_header,HEADER_LEN, "%s%s%s%s", scheme, method,"/courses/ud923/filecorpus/yellowstone.jpg", end_marker);
}
gfcrequest_t *gfc_create()
{
gfc = (gfcrequest_t*)malloc(1* sizeof(gfcrequest_t));
return gfc;
}
void gfc_set_server(gfcrequest_t *gfr, char* server)
{
strcpy(gfr->servIP, server);
}
void gfc_set_path(gfcrequest_t *gfr, char* path)
{
strcpy(gfr->spath, path);
}
void gfc_set_port(gfcrequest_t *gfr, unsigned short port)
{
snprintf(gfr->cport,12, "%u",port);
}
void gfc_set_headerfunc(gfcrequest_t *gfr, void (*headerfunc)(void*, size_t, void *))
{
gfr->head_handler = headerfunc;
}
void gfc_set_headerarg(gfcrequest_t *gfr, void *headerarg)
{
/*have to change this...*/
gfr->headarg = headerarg;
}
int isEndMarker(char *iheader, int start)
{
char *marker = "\\r\\n\\r\\n";
int i = 0; int ind=0;
while (ind <= 7)
{
if (iheader[start++] == marker[ind++])
{
continue;
}
return 0;
}
return 1;
}
int getFileLen(char *resp_header, gfcrequest_t *gfr)
{
char scheme[8];
char status[4];
int istatus;
char filelen[12];
int contentlen = 0;
int fileindex = 0;
char end_marker[12];
int fexit=0;
int end=0;
sscanf(resp_header, "%7s%3s", scheme, status);
istatus = atoi(status);
if (istatus == 200)
{
gfr->ret_status = GF_OK;
}
else if (istatus == 400)
{
gfr->ret_status = GF_FILE_NOT_FOUND;
}
else if (istatus == 500)
{
gfr->ret_status = GF_ERROR;
}
if (!strcmp(scheme, "GETFILE") && (istatus == 200 || istatus == 400 || istatus == 500))
{
int index = 10;
while(1)
{
if (resp_header[index] == '\\')
{
end = isEndMarker(resp_header, index);
}
if (end)
break;
filelen[fileindex++] = resp_header[index++];
}
filelen[fileindex] = '\0';
}
int head_len = strlen(scheme) + strlen(status) + strlen(filelen) + 8;
return atoi(filelen);
}
void gfc_set_writefunc(gfcrequest_t *gfr, void (*writefunc)(void*, size_t, void *))
{
gfr->fl_handler = writefunc;
}
void gfc_set_writearg(gfcrequest_t *gfr, void *writearg)
{
gfr->fDesc = writearg;
}
int gfc_perform(gfcrequest_t *gfr){
struct addrinfo hints, *servinfo, *p;
int sockfd, rv, totalBytesRcvd;
char req_header[HEADER_LEN];
int bytesRcvd;
int header_len;
char s[INET6_ADDRSTRLEN];
memset(&hints, 0, sizeof(hints));
memset(req_header,0,sizeof(req_header));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; //use my IP
if ((rv = getaddrinfo(NULL, gfr->cport, &hints, &servinfo)) != 0)
{
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop through all the results and connect to the first we can
for(p = servinfo; p != NULL; p = p->ai_next)
{
if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1)
{
perror("client: socket");
continue;
}
if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1)
{
close(sockfd);
perror("client: connect");
continue;
}
break;
}
if (p == NULL)
{
fprintf(stderr, "client: failed to connect\n");
return 2;
}
//printf("connected...\n");
inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr), s, sizeof(s));
//Ahsan
// printf("Before getFileRequestHeader...\n");
header_len = getFileRequestHeader(req_header);
//printf("Header Description:%s, Header Len: %u\n", req_header, header_len);
if (send(sockfd, req_header, header_len, 0) != header_len)
perror("send() sent a different number of bytes than expected");
if ((bytesRcvd = recv(sockfd, gfr->filecontent, BUFFER_SIZE, 0)) <= 0)
perror("recv() failed or connection closed prematurely");
//printf("Header Received: %s\n", gfr->filecontent);
gfr->filelen = getFileLen(gfr->filecontent, gfr);
//printf("File Length: %d\n", gfr->filelen);
/* Receive the same string back from the server */
int req_no=1;
gfr->tot_bytes = 0;
while ( 1 )
{
printf("Request: %d ", req_no++);
ssize_t nb = recv( sockfd, gfr->filecontent, BUFFER_SIZE, 0 );
if ( nb == -1 ) err( "recv failed" );
if ( nb == 0 ) {printf("zero bytes received...breaking");break;} /* got end-of-stream */
gfr->fl_handler(gfr->filecontent, nb, gfr->fDesc);
gfr->tot_bytes += nb;
printf("Received Bytes: %zd Total Received Bytes: %d\n", nb, gfr->tot_bytes);
}
return 0;
}
/*
* Returns the string associated with the input status
*/
char* gfc_strstatus(gfstatus_t status)
{
return stringFromError(status);
}
gfstatus_t gfc_get_status(gfcrequest_t *gfr){
return gfr->ret_status;
}
size_t gfc_get_filelen(gfcrequest_t *gfr)
{
return gfr->filelen;
}
size_t gfc_get_bytesreceived(gfcrequest_t *gfr)
{
return gfr->tot_bytes;
}
void gfc_cleanup(gfcrequest_t *gfr)
{
free(gfr);
gfr=NULL;
}
void gfc_global_init()
{
;
// pthread_mutex_lock(&counter_mutex);
//
// gfc = (gfcrequest_t*)malloc(1* sizeof(gfcrequest_t));
//
// pthread_mutex_unlock(&counter_mutex);
}
void gfc_global_cleanup()
{
;
// pthread_mutex_lock(&counter_mutex);
//
// free(gfc);
//
// pthread_mutex_unlock(&counter_mutex);
}
//Server Code
struct gfcontext_t
{
int sockfd;
int clntSock;
};
struct gfserver_t
{
char port[12];
unsigned short max_npending;
char fpath[256];
ssize_t (*fp_handler)(gfcontext_t *ctx, char *, void*);
int *handler_arg;
};
/*Variable decalation*/
static gfserver_t *gfserv;
static gfcontext_t *gfcontext;
int isEndMarker(char *iheader, int start)
{
char *marker = "\\r\\n\\r\\n";
int i = 0; int ind=0;
while (ind <= 7)
{
if (iheader[start++] == marker[ind++])
{
//printf("Header Char:%c Marker:%c\n", iheader[start], marker[ind]);
//start++;
continue;
}
return 0;
}
//printf("Its a marker!!!\n");
return 1;
}
int parseHeader(char *iheader, gfserver_t *gfs, int hlen)
{
//"GETFILEGET/courses/ud923/filecorpus/road.jpg\r\n\r\n"
char scheme[8];
char method[4];
// char path[256];
int pathindex = 0;
char end_marker[12];
int end = 0;
int fexit=0;
sscanf(iheader, "%7s%3s", scheme, method);
int i=10;
if (iheader[i] == '/')
{
// printf("Path has started...\n");
if (!strcmp(scheme, "GETFILE") && !strcmp(method, "GET"))
{
while(1)
{
if (iheader[i] == '\\')
{
end = isEndMarker(iheader, i);
}
if (end)
break;
gfs->fpath[pathindex++] = iheader[i++];
}
gfs->fpath[pathindex] = '\0';
}
}
printf("Scheme: %s Method:%s Path:%s\n", scheme, method, gfs->fpath);
return 0;
}
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET)
{
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
ssize_t gfs_sendheader(gfcontext_t *ctx, gfstatus_t stat, size_t file_len)
{
char resp_header[MAX_REQUEST_LEN];
char end_marker[12] = "\\r\\n\\r\\n";
sprintf(resp_header, "GETFILE%d%zd%s",stat, file_len, end_marker);
printf("Response: %s\n", resp_header);
if (send(ctx->clntSock, resp_header, MAX_REQUEST_LEN, 0) != MAX_REQUEST_LEN)
perror("send() failed");
return 0;
}
ssize_t gfs_send(gfcontext_t *ctx, void *data, size_t len)
{
size_t total = 0;
size_t bytesLeft = len;
size_t n;
int debug_req=1;
while (total < len)
{
n = send(ctx->clntSock, data+total, bytesLeft, 0);
if (n == -1) { printf("Nothing to send...\n"); break; }
fprintf(stderr, "Tries: %d Bytes Sent: %zu\n", debug_req++, n);
total += n;
bytesLeft -= n;
}
// if ( shutdown( ctx->clntSock, SHUT_WR ) == -1 ) err( "socket shutdown failed" );
return total;
}
void gfs_abort(gfcontext_t *ctx){
close(ctx->clntSock);
close(ctx->sockfd);
free(ctx);
free(gfserv);
perror("aborting...");
exit(1);
}
gfserver_t* gfserver_create()
{
gfserv = (gfserver_t*) malloc(1 * sizeof(gfserver_t));
gfcontext = (gfcontext_t*) malloc(1*sizeof(gfcontext_t));
return gfserv;
}
void gfserver_set_port(gfserver_t *gfs, unsigned short port)
{
//set port number in gfs structure
snprintf(gfs->port,12, "%u",port);
}
void gfserver_set_maxpending(gfserver_t *gfs, int max_npending)
{
//set maxpending connections
gfs->max_npending = max_npending;
}
void gfserver_set_handler(gfserver_t *gfs, ssize_t (*handler)(gfcontext_t *, char *, void*))
{
gfs->fp_handler = handler;
}
void gfserver_set_handlerarg(gfserver_t *gfs, void* arg)
{
gfs->handler_arg = (int *)arg;
}
void gfserver_serve(gfserver_t *gfs)
{
struct addrinfo hints, *servinfo, *p;
struct sockaddr_storage clntAddr; //connectors address information
socklen_t clntSize;
int yes = 1;
char s[INET6_ADDRSTRLEN];
int rv;
int rcvMsg = 0;
char recvBuff[MAX_REQUEST_LEN];
char *req_path;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM; //using stream socket instead of datagrams
hints.ai_flags = AI_PASSIVE; //use my IP
if ((rv = getaddrinfo(NULL, gfs->port, &hints, &servinfo)) != 0)
{
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop through all the results and bind to the first we can
for(p = servinfo; p != NULL; p = p->ai_next)
{
if ((gfcontext->sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1)
{
perror("server: socket");
continue;
}
//get rid of 'address already in use' error.
if (setsockopt(gfcontext->sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
{
perror("setsockopt");
exit(1);
}
if (bind(gfcontext->sockfd, p->ai_addr, p->ai_addrlen) == -1)
{
close(gfcontext->sockfd);
perror("server: bind");
continue;
}
break;
}
if (p == NULL)
{
fprintf(stderr, "server: failed to bind.\n");
return 2;
}
freeaddrinfo(servinfo); // no need of servinfo structure anymore
if (listen(gfcontext->sockfd, gfs->max_npending) == -1)
{
perror("listen");
exit(1);
}
//printf("server: waiting for connetions...\n");
while(1)
{
clntSize = sizeof(clntAddr);
gfcontext->clntSock = accept(gfcontext->sockfd, (struct sockaddr *)&clntAddr, &clntSize);
if (gfcontext->clntSock == -1)
{
perror("accept");
continue;
}
inet_ntop(clntAddr.ss_family, get_in_addr((struct sockaddr *)&clntAddr), s, sizeof(s));
//printf("server: got connection from %s\n", s);
if (!fork())
{ // this is the child process
if ((rcvMsg = recv(gfcontext->clntSock, recvBuff, MAX_REQUEST_LEN, 0)) < 0)
{
perror("recv() failed");
exit(1);
}
/*Still to parse received request...*/
//printf("Recd Header: %s, Recd %d bytes\n",recvBuff, rcvMsg);
/*Parse the received header...*/
int len = parseHeader(recvBuff, gfs, rcvMsg);
//printf("Requested Path: %s\n", gfs->fpath);
if (gfs->fp_handler(gfcontext, gfs->fpath, NULL) < 0)
{
printf("some problem...\n");
}
if ( shutdown( gfcontext->clntSock, SHUT_WR ) == -1 ) err( "socket shutdown failed" );
//close(gfcontext->clntSock);
}
}
}
//Server gf_send is being called from following function handler function:
Handler:
ssize_t handler_get(gfcontext_t *ctx, char *path, void* arg){
int fildes;
size_t file_len, bytes_transferred;
ssize_t read_len, write_len;
char buffer[BUFFER_SIZE];
printf("Path: %s\n", path);
if( 0 > (fildes = content_get(path)))
return gfs_sendheader(ctx, GF_FILE_NOT_FOUND, 0);
/* Calculating the file size */
file_len = lseek(fildes, 0, SEEK_END);
gfs_sendheader(ctx, GF_OK, file_len);
/* Sending the file contents chunk by chunk. */
int req=1;
bytes_transferred = 0;
while(bytes_transferred < file_len){
read_len = pread(fildes, buffer, BUFFER_SIZE, bytes_transferred);
if (read_len <= 0){
fprintf(stderr, "handle_with_file read error, %zd, %zu, %zu", read_len, bytes_transferred, file_len );
gfs_abort(ctx);
return -1;
}
printf("Request No: %d ", req++);
write_len = gfs_send(ctx, buffer, read_len);
if (write_len != read_len){
fprintf(stderr, "handle_with_file write error");
gfs_abort(ctx);
return -1;
}
bytes_transferred += write_len;
}
printf("Total Bytes sent to client: %zu\n", bytes_transferred);
return bytes_transferred;
}
You didn't specify, so I am assuming you are using TCP here (send/receive semantics is different with UDP),
You are suffering from a very common misconception that one send on one end of a TCP socket corresponds to one receive of sent number of bytes on the other end. This is wrong.
In fact, TCP socket is a bi-directional stream of bytes with no notion of messages. One write can correspond to many reads on the other end, and vise versa. Treat it as a stream.
You need to keep number of bytes sent and received as returned from sending and receiving system calls.
It is also important to let the other side know how much data you are sending, so it will know when, say, an image is fully transferred. This is the job of an application-level protocol that you have to either come up with or use an existing one.
Edit 0:
Here is what looks needed even before setting up any meaningful protocol between client and the server.
First the sending code:
size_t total = 0;
while ( total != len ) {
ssize_t nb = send( s, data + total, len - total, 0 );
if ( nb == -1 ) err( "send failed" );
total += nb;
}
if ( shutdown( s, SHUT_WR ) == -1 ) err( "socket shutdown failed" );
/* also need to close client socket, see below */
Then the receiving code:
char buffer[BUFFER_SIZE]; /* somewhere, might be static */
size_t total = 0; /* everything received */
while ( 1 ) {
ssize_t nb = recv( s, buffer, BUFFER_SIZE, 0 );
if ( nb == -1 ) err( "recv failed" );
if ( nb == 0 ) break; /* got end-of-stream */
if ( write( file_fd, buffer, nb ) == -1 ) err( "file write failed" );
total += nb;
}
/* send an ack here */
if ( close( s ) == -1 ) err( "socket close failed" );
if ( close( file_fd )) err( "file close failed" );
printf( "received and saved total of %zu bytes\n", total );
Then your application-level protocol might be as simple as server sending, say, 64-bit file length immediately after accepting new client connection (you need to decide what endianness to use for that), then after sending that many bytes to the client and shutting down writing on the socket, waiting for the client to acknowledge successful receipt of data. That might be that same number back, or just a single byte - up to you, then finally closing the socket. That way the client knows upfront how many bytes to expect, and the server knows that transfer was successful.
After getting this simple version working you can extend it to allow multiple file transfers per connection, and/or dive into IO multiplexing with select(2)/poll(2).
Hope this helps.
First of all: recv() does not always receive the data in the chunks that it was sent by send(), as a matter of fact - it rarely does - because of buffering (for example, you send 256-bytes receive two buffers of 128-bytes each)
Now to your error: I think the problem is that you are not be calling select() with a FD_SET to reset your socket to a "ready to receive" state before calling recv() a second time.
I have a metric-ton of winsock/c-sockets code on my site if you want to dig through it.
Let me know if I can expand on this answer, I'd be happy to provide additional assistance!
gfr->fl_handler(gfr->filecontent, BUFFER_SIZE, gfr->fDesc);
Usual problem. You're assuming the read filled the buffer. It should be:
gfr->fl_handler(gfr->filecontent, bytesRcvd, gfr->fDesc);

C- Socket : Programming a Client/Server-Application to send a file

I want to program an application to send a file with sockets:
Here my Server:
void str_server(int sock)
{
char buf[1025];
const char* filename="test.text";
FILE *file = fopen(filename, "rb");
err_abort("Test");
while (!feof(file))
{
int rval = fread(buf, 1, sizeof(buf), file);
send(sock, buf, rval, 0);
}
}
and here my client:
void RecvFile(int sock, const char* filename)
{
int rval;
char buf[0x1000];
FILE *file = fopen(filename, "wb");
while ((rval = recv(sock, buf, sizeof(buf), 0)) > 0)
{
fwrite(buf, 1, rval, file);
}
close(sock);
}
My problem is that my client create a file....but dont write the content in the file!
Add some error handling to your code, that should help you track down the problem. Also note that send(), recv(), fread() and fwrite() are not guaranteed to write/read the entire buffer you specify, so you should take that into account as well.
Also, since TCP is a byte stream, the server needs to indicate when the file ends so the client knows when to stop reading. If you don't send the file size before sending the actual file, the only option is to close the socket when the transfer is done.
Try something like this:
int send_all(int sock, const void *buf, int len)
{
const char *pbuf = (const char *) buf;
while (len > 0)
{
int sent = send(sock, pbuf, len, 0);
if (sent < 1)
{
// if the socket is non-blocking, then check
// the socket error for WSAEWOULDBLOCK/EAGAIN
// (depending on platform) and if true then
// use select() to wait for a small period of
// time to see if the socket becomes writable
// again before failing the transfer...
printf("Can't write to socket");
return -1;
}
pbuf += sent;
len -= sent;
}
return 0;
}
void str_server(int sock)
{
char buf[0x1000];
const char* filename = "test.text";
struct stat s;
if (stat(filename, &s) == -1)
{
printf("Can't get file info");
return;
}
FILE *file = fopen(filename, "rb");
if (!file)
{
printf("Can't open file for reading");
return;
}
// if you need to handle files > 2GB,
// be sure to use a 64bit integer, and
// a host-to-network function that can
// handle 64bit integers...
long size = s.st_size;
long tmp_size = htonl(size);
if (send_all(sock, &tmp_size, sizeof(tmp_size)) == 0)
{
while (size > 0)
{
int rval = fread(buf, 1, min(sizeof(buf), size), file);
if (rval < 1)
{
printf("Can't read from file");
break;
}
if (send_all(sock, buf, rval) == -1)
break;
size -= rval;
}
}
fclose(file);
}
int write_all(FILE *file, const void *buf, int len)
{
const char *pbuf = (const char *) buf;
while (len > 0)
{
int written = fwrite(pbuf, 1, len, file);
if (written < 1)
{
printf("Can't write to file");
return -1;
}
pbuf += written;
len -= written;
}
return 0;
}
int read_all(int sock, void *buf, int len)
{
char *pbuf = (char *) buf;
int total = 0;
while (len > 0)
{
int rval = recv(sock, pbuf, len, 0);
if (rval < 0)
{
// if the socket is non-blocking, then check
// the socket error for WSAEWOULDBLOCK/EAGAIN
// (depending on platform) and if true then
// use select() to wait for a small period of
// time to see if the socket becomes readable
// again before failing the transfer...
printf("Can't read from socket");
return -1;
}
if (rval == 0)
{
printf("Socket disconnected")
return 0;
}
pbuf += rval;
len -= rval;
total += rval;
}
return total;
}
void RecvFile(int sock, const char* filename)
{
int rval;
char buf[0x1000];
FILE *file = fopen(filename, "wb");
if (!file)
{
printf("Can't open file for writing");
return;
}
// if you need to handle files > 2GB,
// be sure to use a 64bit integer, and
// a network-to-host function that can
// handle 64bit integers...
long size = 0;
if (read_all(sock, &size, sizeof(size)) == 1)
{
size = ntohl(size);
while (size > 0)
{
rval = read_all(sock, buf, min(sizeof(buf), size));
if (rval < 1)
break;
if (write_all(file, buf, rval) == -1)
break;
}
}
fclose(file);
}

Resources