Related
I am trying to write data from struct into a a file. For instance the data is found in newpackets.data. I am trying to write that into a file, but keep getting segfault. I have looked at other questions on here, but could not find a solution. Adding my code below. How can i solve this issue ? Thank you
to run server do ./server 8500 1
to run client do ./client 127.0.0.1 8500 500 3 ex.txt exout.txt
ex.txt will need to be made and then write random words into it. for instance can be like 85 characters
//server side
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/socket.h>
#include <stdint.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netinet/in.h>
#include <errno.h>
#include "sys/un.h"
#define MAXLINE 32768
struct ackdata
{
int ack;
};
struct packetdata
{
int seqnumber;
int lenght;
char data[MAXLINE];
int type;
};
void dg_echo (int sockfd, struct sockaddr *pcliaddr, socklen_t clilen);
int
main (int argc, char *argv[])
{
int sockfd;
struct sockaddr_in servaddr, cliaddr;
int SERV_PORT = atoi (argv[1]); ///This will grab the port to listen to
int dropc = atoi (argv[2]);
if (SERV_PORT <= 1023)
{
fprintf (stderr, "Error: Port given can not be less than 1023\n");
exit (1);
}
if (SERV_PORT > 65535)
{
fprintf (stderr,
"Error: Port given can not be more than 65535 or less than 1024\n");
exit (1);
}
sockfd = socket (AF_INET, SOCK_DGRAM, 0);
bzero (&servaddr, sizeof (servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htons (INADDR_ANY);
servaddr.sin_port = htons (SERV_PORT);
int bb = bind (sockfd, (struct sockaddr *) &servaddr, sizeof (servaddr));
if (bb < 0)
{
fprintf (stderr, "Binding failure");
}
dg_echo (sockfd, (struct sockaddr *) &cliaddr, sizeof (cliaddr));
close (sockfd);
return 0;
}
void
dg_echo (int sockfd, struct sockaddr *pcliaddr, socklen_t clilen)
{
int n;
FILE *outfile = NULL;
socklen_t len;
char mesg[MAXLINE];
struct packetdata newpackets;
char filename[MAXLINE];
recvfrom (sockfd, filename, MAXLINE, 0, pcliaddr, &len);
printf ("Name: %s", filename);
for (;;)
{
len = clilen;
//printf("HERe");
if ((outfile = fopen (filename, "a")) == NULL)
{
fprintf (stderr, "\nwriting File was not opened\n");
exit (1);
}
ssize_t rlen =recvfrom(sockfd, &newpackets, sizeof (newpackets), 0, pcliaddr, &len);
if (rlen ==-1){
printf ("failed recv");
return 1;
}
printf ("\nData: %s\n", newpackets.data);
//fprintf(outfile, "%d",newpackets.data );
fwrite(newpackets.data,rlen,1,outfile);
// sendto(sockfd, mesg, n, 0, pcliaddr, len);
}
}
Here is the client code:
//client side
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/socket.h>
#include <stdint.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netinet/in.h>
#include <errno.h>
#include <math.h>
#include <sys/time.h>
#include <string.h>
#include <time.h>
#define MAXLINE 4096
#define totaltries 3
struct packetdata data (int seqnumber, int lenght, char*data);
struct packetdata
{
int seqnumber;
int lenght;
char data[MAXLINE];
int type;
};
struct ackdata
{
int ack;
int type;
};
int main (int argc, char *argv[])
{
int sockfd;
struct sockaddr_in servaddr;
FILE *infile = NULL;
int countpackets;
float calc;
int tries = 0;
int base = 0;
int sequencenumber = 0;
int datasize =0;
int winsz = atoi (argv[4]); //this is for the window size
int mtu = atoi (argv[3]); //for mtu
int SERV_PORT = atoi (argv[2]); // the port to listen to
char sendline[MAXLINE], recvline[MAXLINE];
struct packetdata forpackets;
if (mtu <= 0)
{
fprintf (stderr, "MTU Error: mtu can not be less than or equal to 0\n");
exit (1);
}
//you shouldnt use any ports from 0-1023
//1024-65535 are fines
if (SERV_PORT <= 1023)
{
fprintf (stderr, "Port Error: Port given can not be less than 1023\n");
exit (1);
}
if (SERV_PORT > 65535)
{
fprintf (stderr,
"Port Error: Port given can not be more than 65535 or less than 1024\n");
exit (1);
}
bzero (&servaddr, sizeof (servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons (SERV_PORT);
if (inet_pton (AF_INET, argv[1], &servaddr.sin_addr) <= 0)
{
fprintf (stderr, "Inet Pton error");
return 1;
}
if ((sockfd = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
{
fprintf (stderr, "\nsocket error\n");
return 1;
}
if ((infile = fopen (argv[5], "r")) == NULL)
{
fprintf (stderr, "\nReading File was not opened\n");
return 1;
}
//file name sending
char filename[MAXLINE];
strcpy(filename, argv[6]);
//printf("Filename: %c", filename);
sendto(sockfd, filename, MAXLINE, 0, (struct sockaddr * ) & servaddr, sizeof(servaddr));
//this is for calculations
fseek (infile, 0, SEEK_END);
countpackets = ftell (infile);
fseek (infile, 0, SEEK_SET);
// printf("countpackets %d\n",countpackets);
// printf("\nMTU %d\n",mtu);
calc = countpackets / mtu; //how many buffer is
if (countpackets % mtu)
{
calc++;
}
printf("\nCalc %f\n",calc);
char fordata[mtu];
//while(1){
while (calc>=sequencenumber && sequencenumber-base<=winsz){
fread(forpackets.data, sizeof(recvline), 1, infile);
//printf("%s", forpackets.data);
// strcpy(fordata, forpackets.data);
strncpy(fordata,(sequencenumber*mtu+forpackets.data),mtu);
printf("%s", fordata);
forpackets = data(sequencenumber,datasize, fordata );
printf("\nSending Packet: %d\n", sequencenumber);
if (sendto(sockfd, &forpackets, sizeof(forpackets), 0, (struct sockaddr * ) & servaddr, sizeof(servaddr)) == -1) {
printf("failed sending");
return 1;
}else{
sequencenumber++;
}
}
// }
close(sockfd);
fclose(infile);
}
struct packetdata data (int seqnumber, int lenght, char*data){
struct packetdata dataa;
dataa. seqnumber = seqnumber;
dataa. lenght = lenght;
dataa. type = 1;
memset(dataa.data, 0, MAXLINE);
strcpy(dataa.data, data);
return dataa;
}
Okay, just to recap the comments:
outfile was missing an fopen call, so the server fwrite would segfault
After the fix, the output file would get extraneous zeros because the length given to fwrite was the whole size rather than the returned value of recvfrom
Actually, the correct length is the length value inside the packet
You're on the right track. The struct you devised has the right things in it (e.g. sequence number, type, length, data field).
I've refactored the server and client code.
An additional issue is that the server didn't know when to stop writing the output file. There are several ways to do this. But, the one I chose was for the client to send an extra data packet with a length field of 0.
I've adjusted both client and server to do this.
Here is the refactored server code:
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/socket.h>
#include <stdint.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netinet/in.h>
#include <errno.h>
#include <sys/un.h>
#define MAXLINE 32768
struct ackdata {
int ack;
};
struct packetdata {
int seqnumber;
int length;
char data[MAXLINE];
int type;
};
void dg_echo(int sockfd, struct sockaddr *pcliaddr, socklen_t clilen);
int
main(int argc, char *argv[])
{
int sockfd;
struct sockaddr_in servaddr, cliaddr;
#if 1
if (argc < 2) {
printf("usage: serv_port\n");
exit(1);
}
#endif
int SERV_PORT = atoi(argv[1]); // /This will grab the port to listen to
#if 0
int dropc = atoi(argv[2]);
#endif
if (SERV_PORT <= 1023) {
fprintf(stderr, "Error: Port given can not be less than 1023\n");
exit(1);
}
if (SERV_PORT > 65535) {
fprintf(stderr, "Error: Port given can not be more than 65535 or less than 1024\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htons(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
int bb = bind(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr));
if (bb < 0) {
fprintf(stderr, "Binding failure");
}
dg_echo(sockfd, (struct sockaddr *) &cliaddr, sizeof(cliaddr));
close(sockfd);
return 0;
}
void
dg_echo(int sockfd, struct sockaddr *pcliaddr, socklen_t clilen)
{
int n;
FILE *outfile = NULL;
socklen_t len;
char mesg[MAXLINE];
struct packetdata newpackets;
char filename[MAXLINE];
recvfrom(sockfd, filename, MAXLINE, 0, pcliaddr, &len);
#if 0
printf("Name: %s", filename);
#else
printf("Name: %s\n", filename);
outfile = fopen(filename,"w");
#endif
for (;;) {
len = clilen;
// printf("HERe");
if (recvfrom(sockfd, &newpackets, sizeof(newpackets), 0, pcliaddr, &len) == -1) {
printf("failed recv");
break;
}
printf("DEBUG: seqnumber=%d type=%d length=%d\n",
newpackets.seqnumber,newpackets.type,newpackets.length);
// end of file
if (newpackets.length == 0)
break;
//printf("\nData: %s\n", newpackets.data);
fwrite(newpackets.data, newpackets.length, 1, outfile);
// sendto(sockfd, mesg, n, 0, pcliaddr, len);
}
if (outfile != NULL)
fclose(outfile);
}
And, here is the refactored client code. I cleaned it up a bit.
I changed the code to do the fread directly into the packet struct's data field.
I changed the data function to take a pointer arg to the packet rather than returning one. This eliminates some unnecessary copying
I added an extra zero length data packet to indicate EOF
I changed the primary data read/write loop to look at the returned length from fread rather than (pre)calculate the number of packets.
//client side
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/socket.h>
#include <stdint.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netinet/in.h>
#include <errno.h>
#include <math.h>
#include <sys/time.h>
#include <string.h>
#include <time.h>
#define MAXLINE 4096
#define totaltries 3
struct packetdata {
int seqnumber;
int length;
char data[MAXLINE];
int type;
};
struct ackdata {
int ack;
int type;
};
void
data(struct packetdata *pkt,int seqnumber, int length, char *data)
{
pkt->seqnumber = seqnumber;
pkt->length = length;
pkt->type = 1;
if ((length > 0) && (data != NULL))
memcpy(pkt->data, data, length);
}
int
main(int argc, char *argv[])
{
int sockfd;
struct sockaddr_in servaddr;
FILE *infile = NULL;
int countpackets;
float calc;
int tries = 0;
int base = 0;
int sequencenumber = 0;
int datasize = 0;
int winsz = atoi(argv[4]); // this is for the window size
int mtu = atoi(argv[3]); // for mtu
int SERV_PORT = atoi(argv[2]); // the port to listen to
char sendline[MAXLINE],
recvline[MAXLINE];
struct packetdata forpackets;
if (mtu <= 0) {
fprintf(stderr, "MTU Error: mtu can not be less than or equal to 0\n");
exit(1);
}
// you shouldnt use any ports from 0-1023
// 1024-65535 are fines
if (SERV_PORT <= 1023) {
fprintf(stderr, "Port Error: Port given can not be less than 1023\n");
exit(1);
}
if (SERV_PORT > 65535) {
fprintf(stderr, "Port Error: Port given can not be more than 65535 or less than 1024\n");
exit(1);
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(SERV_PORT);
if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0) {
fprintf(stderr, "Inet Pton error");
return 1;
}
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
fprintf(stderr, "\nsocket error\n");
return 1;
}
if ((infile = fopen(argv[5], "r")) == NULL) {
fprintf(stderr, "\nReading File was not opened\n");
return 1;
}
// file name sending
char filename[MAXLINE];
strcpy(filename, argv[6]);
// printf("Filename: %c", filename);
sendto(sockfd, filename, MAXLINE, 0, (struct sockaddr *) &servaddr,
sizeof(servaddr));
// this is for calculations
fseek(infile, 0, SEEK_END);
countpackets = ftell(infile);
fseek(infile, 0, SEEK_SET);
// printf("countpackets %d\n",countpackets);
// printf("\nMTU %d\n",mtu);
calc = countpackets / mtu; // how many buffer is
if (countpackets % mtu) {
calc++;
}
printf("\nCalc %f\n", calc);
// while(1){
#if 0
while (calc >= sequencenumber && sequencenumber - base <= winsz) {
#else
while (1) {
#endif
ssize_t rlen = fread(forpackets.data, 1, sizeof(forpackets.data),
infile);
data(&forpackets,sequencenumber, rlen, NULL);
printf("\nSending Packet: %d rlen=%d\n", sequencenumber,rlen);
if (sendto(sockfd, &forpackets, sizeof(forpackets), 0,
(struct sockaddr *) &servaddr, sizeof(servaddr)) == -1) {
printf("failed sending");
return 1;
}
else {
sequencenumber++;
}
if (rlen == 0)
break;
}
// }
close(sockfd);
fclose(infile);
return 0;
}
Note that the client and server are "one-shots". That is, the server exits after receiving a given file.
Also, one change I didn't make was to send/receive the filename within a packet (with a different type field).
I'd change the programs to send only packet structs.
Then, the server could have an outer loop, to service new/different requests (e.g. it could receive a file, then send a file, etc.)
With various type fields (e.g.):
send file to server (data is filename)
send file to client (data is filename)
file data (sent by client and/or server and length of 0 indicates EOF)
close connection (sent by client to server)
This may be a bit of overkill for the scope of your project ...
The server could look at the IP address from recvfrom and keep some state in a "connection" struct, based on a match to the client IP address. For example, the connection struct could hold the outfile stream (instead of a single instance).
Then, the server could handle multiple/many client streams, interspersed on the same/single socket descriptor.
UPDATE:
Hey craig. TYSM. But is there a way, where the server is not one shot go? –
juststruggle
It starts by adding my suggestion about sending the filename inside a packet with a type.
And, having the server loop do a switch (pkt.type).
I've added the ruminants of that in the code below. The client is very similar in function to before. The server will now loop after file transfer, waiting for other packets.
Note that there is a bunch of similar code between server and client. I moved some of that to a common.c file. Note that this is crude. I'd like to have a common.h for definitions and function prototypes and a common.c for common functions. But, IRL, I am being "summoned" :-) so I don't have time to fix that.
I moved the struct definition to that file. In the process, I notice that the size of the data element is different between client and server. That's a bug because type is at the end and would be elided/truncated because of the differing lengths of data
Here's common.c:
// common.c -- common code
#define MAXLINE 1024
#define totaltries 3
#ifdef DEBUG
#define dbgprt(_fmt...) printf(_fmt)
#else
#define dbgprt(_fmt...) do { } while (0)
#endif
struct packetdata {
int type;
int seqnumber;
int length;
char data[MAXLINE];
};
struct ackdata {
int ack;
int type;
};
enum {
TYPE_TOSVR,
TYPE_TOCLI,
TYPE_DATA
};
void
pktprep(struct packetdata *pkt,int type,int seqnumber, int length, char *data)
{
pkt->type = type;
pkt->seqnumber = seqnumber;
pkt->length = length;
if ((length > 0) && (data != NULL))
memcpy(pkt->data, data, length);
dbgprt("pktprep: SENDPKT seq=%d type=%d length=%d\n",
seqnumber,type,length);
}
Here is server.c:
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/socket.h>
#include <stdint.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netinet/in.h>
#include <errno.h>
#include <sys/un.h>
#include "common.c"
void dg_echo(int sockfd, struct sockaddr *pcliaddr, socklen_t clilen);
int
main(int argc, char *argv[])
{
int sockfd;
struct sockaddr_in servaddr, cliaddr;
#if 1
if (argc < 2) {
printf("usage: serv_port\n");
exit(1);
}
#endif
int SERV_PORT = atoi(argv[1]); // /This will grab the port to listen to
#if 0
int dropc = atoi(argv[2]);
#endif
if (SERV_PORT <= 1023) {
fprintf(stderr, "Error: Port given can not be less than 1023\n");
exit(1);
}
if (SERV_PORT > 65535) {
fprintf(stderr, "Error: Port given can not be more than 65535 or less than 1024\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htons(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
int bb = bind(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr));
if (bb < 0) {
fprintf(stderr, "Binding failure");
}
dg_echo(sockfd, (struct sockaddr *) &cliaddr, sizeof(cliaddr));
close(sockfd);
return 0;
}
void
dg_echo(int sockfd, struct sockaddr *pcliaddr, socklen_t clilen)
{
int n;
FILE *outfile = NULL;
socklen_t len;
char mesg[MAXLINE];
struct packetdata pkt;
char filename[MAXLINE];
for (;;) {
len = clilen;
// printf("HERe");
if (recvfrom(sockfd, &pkt, sizeof(pkt), 0, pcliaddr, &len) == -1) {
printf("failed recv");
break;
}
dbgprt("DEBUG: seqnumber=%d type=%d length=%d\n",
pkt.seqnumber,pkt.type,pkt.length);
switch (pkt.type) {
case TYPE_TOSVR:
dbgprt("TOSVR: %s\n", pkt.data);
if (outfile == NULL)
outfile = fopen(pkt.data,"w");
break;
case TYPE_DATA:
// end of file
if (pkt.length == 0) {
if (outfile != NULL) {
fclose(outfile);
outfile = NULL;
}
break;
}
//dbgprt("\nData: %s\n", pkt.data);
if (outfile != NULL)
fwrite(pkt.data, pkt.length, 1, outfile);
break;
}
}
if (outfile != NULL)
fclose(outfile);
}
And, here is client.c:
//client side
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/socket.h>
#include <stdint.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netinet/in.h>
#include <errno.h>
#include <math.h>
#include <sys/time.h>
#include <string.h>
#include <time.h>
#include "common.c"
int
main(int argc, char *argv[])
{
int sockfd;
struct sockaddr_in servaddr;
FILE *infile = NULL;
int countpackets;
float calc;
int tries = 0;
int base = 0;
int sequencenumber = 0;
int datasize = 0;
int winsz = atoi(argv[4]); // this is for the window size
int mtu = atoi(argv[3]); // for mtu
int SERV_PORT = atoi(argv[2]); // the port to listen to
char sendline[MAXLINE],
recvline[MAXLINE];
struct packetdata pkt;
if (mtu <= 0) {
fprintf(stderr, "MTU Error: mtu can not be less than or equal to 0\n");
exit(1);
}
// you shouldnt use any ports from 0-1023
// 1024-65535 are fines
if (SERV_PORT <= 1023) {
fprintf(stderr, "Port Error: Port given can not be less than 1023\n");
exit(1);
}
if (SERV_PORT > 65535) {
fprintf(stderr, "Port Error: Port given can not be more than 65535 or less than 1024\n");
exit(1);
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(SERV_PORT);
if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0) {
fprintf(stderr, "Inet Pton error");
return 1;
}
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
fprintf(stderr, "\nsocket error\n");
return 1;
}
if ((infile = fopen(argv[5], "r")) == NULL) {
fprintf(stderr, "\nReading File was not opened\n");
return 1;
}
// file name sending
char filename[MAXLINE];
pktprep(&pkt,TYPE_TOSVR,sequencenumber++,strlen(argv[6]) + 1,argv[6]);
// printf("Filename: %c", filename);
#if 0
sendto(sockfd, filename, MAXLINE, 0, (struct sockaddr *) &servaddr,
sizeof(servaddr));
#else
sendto(sockfd, &pkt, sizeof(pkt), 0,
(struct sockaddr *) &servaddr, sizeof(servaddr));
#endif
// this is for calculations
fseek(infile, 0, SEEK_END);
countpackets = ftell(infile);
fseek(infile, 0, SEEK_SET);
// printf("countpackets %d\n",countpackets);
// printf("\nMTU %d\n",mtu);
calc = countpackets / mtu; // how many buffer is
if (countpackets % mtu) {
calc++;
}
dbgprt("\nCalc %f\n", calc);
// while(1){
#if 0
while (calc >= sequencenumber && sequencenumber - base <= winsz) {
#else
while (1) {
#endif
ssize_t rlen = fread(pkt.data, 1, sizeof(pkt.data),
infile);
pktprep(&pkt,TYPE_DATA,sequencenumber, rlen, NULL);
if (sendto(sockfd, &pkt, sizeof(pkt), 0,
(struct sockaddr *) &servaddr, sizeof(servaddr)) == -1) {
printf("failed sending");
return 1;
}
else {
sequencenumber++;
}
if (rlen == 0)
break;
}
// }
close(sockfd);
fclose(infile);
return 0;
}
Compile server.c and client.c with -DDEBUG to start.
I’m working on a socket programming thing for implementing a file transfer through UDP in C. Both the server and the client codes execute without reporting any errors: when I run the codes, both sockets are created and bound, and I’m prompted to input file name on client side. But after I enter it, nothing else happens. Both sides stay blank, whereas I’m supposed to get a "file name received" output on server side and then a prompt to enter an encryption key. I’m not getting that, and I’m not sure why. I tried several iterations of code and even tried code suggestions online, but I had no luck. What is the problem?
Here’s the server code
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#define SA struct sockaddr
#define PORT 12345
#define SIZE 256
#define EMP "the file does not exist"
char encrypt(char c, char k){
return c ^ k;
}
int sendfl(FILE *fp, char *buff, int l, char k){
int i, len;
if(fp == NULL){
strcpy(buff, EMP);
len = strlen(EMP);
buff[l] = EOF;
for(i = 0; i < len; i++)
buff[i] = encrypt(buff[i], k);
return 1;
}
char c1, c2;
for(i = 0; i < l; i++) {
c1 = fgetc(fp);
c2 = encrypt(c1, k);
buff[i] = c2;
if(c1 == EOF)
return 1;
}
return 0;
}
int main(){
int sockid, len, e, n;
char key;
char flname[SIZE];
char buff[SIZE];
FILE *fp;
struct sockaddr_in servaddr;
len = sizeof(servaddr);
sockid = socket(AF_INET, SOCK_DGRAM, 0);
if(sockid < 0){
perror("failed to create socket");
exit(0);
}
printf("socket created! \n");
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(PORT);
servaddr.sin_addr.s_addr = INADDR_ANY;
e = bind(sockid, (SA*)&servaddr, len);
if(e == -1){
perror("failed to bind");
exit(1);
}
printf("bind successful, \n");
while (1) {
printf("waiting for file name... \n");
bzero(flname, SIZE);
n = recvfrom(sockid, flname, sizeof(flname), 0, (SA*)&servaddr, &len);
printf("file name recieved \t%s\n", flname);
fp = fopen(flname, "r");
if(fp == NULL){
perror("failed to open file");
exit(1);
}
printf("file opened...");
printf("enter encryption key \t");
scanf("%c\n", &key);
while (1) {
if(sendfl(fp, buff, SIZE, key)){
sendto(sockid, buff, SIZE, 0, (SA*)&servaddr, len);
break;
}
sendto(sockid, buff, SIZE, 0, (SA*)&servaddr, len);
bzero(buff, SIZE);
}
if(fp != NULL)
fclose(fp);
}
return 0;
}
Here’s the client code
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#define SA struct sockaddr
#define PORT 12345
#define IPA "127.0.0.1"
#define SIZE 256
#define EMP "the file does not exist"
char decrypt(char c, char k){
return c ^ k;
}
int recfl(char *buff, int l, char k){
int i;
char c1, c2;
for(i = 0; i < l; i++) {
c1 = buff[i];
c2 = decrypt(c1, k);
if(c2 == EOF)
return 1;
else
printf("%c", c2);
}
return 0;
}
int main(){
int sockid, len, n;
char key;
char flname[SIZE];
char buff[SIZE];
FILE *fp;
struct sockaddr_in servaddr;
len = sizeof(servaddr);
sockid = socket(AF_INET, SOCK_DGRAM, 0);
if(sockid < 0){
perror("failed to create socket");
exit(0);
}
printf("\nsocket created!\n");
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(PORT);
servaddr.sin_addr.s_addr = inet_addr(IPA);
while (1) {
bzero(flname, SIZE);
printf("\nenter file name:\t");
scanf("%s\n", flname);
sendto(sockid, flname, sizeof(flname), 0, (SA*)&servaddr, len);
printf("\nfile recieved\n");
printf("\nenter encryption key\t");
scanf("%c\n", &key);
printf("\n--------------------DATA RECIEVED--------------------\n");
while (1) {
bzero(buff, SIZE);
n = recvfrom(sockid, buff, SIZE, 0, (SA*)&servaddr, &len);
if(recfl(buff, SIZE, key)){
break;
}
}
printf("\n-----------------------------------------------------\n");
}
return 0;
}
Foremost you overlooked what the \n does in scanf("%s\n", flname); here's the description from the C standard:
A directive composed of white-space character(s) is executed by reading input up to the
first non-white-space character (which remains unread), or until no more characters can
be read.
So, the waiting for more input is what you perceive as nothing else happens.
Together with the suggestion from chux, you get one step further if you remove the \n.
I'm trying to implement C code on a UNIX platform which sends all files data to the client, and uploading a file from the client to the server.
The first part is working but for the second part I've encountered an issue.
After some debugging I've found out that the server side jams the client when I'm using recv the second time in the code [I've marked it for your convenience].
I've tried to look up on guides or what I'm doing wrong but I couldn't find the issue for what causing the program to get stuck.
For de-bugging purposes I'm now trying to send an int from client to the server
server side
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <dirent.h>
#include <fcntl.h>
#define PORT 0x0da2
#define IP_ADDR 0x7f000001
#define QUEUE_LEN 20
int main(void)
{
//char directory[1024];
//chdir("server");
//getcwd(directory, sizeof(directory));
//printf("%s",directory);
DIR* directory;
struct dirent* ent;
int fd;
char buffer[1000] = {0};
char convert[100] = {0};
size_t array_size = 0;
struct stat fileStat;
if ((directory = opendir ("server")) == NULL)
{
perror ("Cannot open .");
return 1;
}
while ((ent = readdir(directory)) != NULL)
{
if (!( !strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) )
{
fd = openat(dirfd(directory), ent->d_name, 0);
if (fd == -1)
{
perror ("Can't get stats.");
return 1;
}
if(fstat(fd, &fileStat)== -1)
{
perror ("Can't get stats.");
return 1;
}
strcat(buffer,ent->d_name);
sprintf(convert,"%lld", (long long) fileStat.st_size);
strcat(buffer, " ");
strcat(buffer,convert);
strcat(buffer,"\n");
}
}
int listenS = socket(AF_INET, SOCK_STREAM, 0);
if (listenS < 0)
{
perror("socket");
return 1;
}
struct sockaddr_in s = {0};
s.sin_family = AF_INET;
s.sin_port = htons(PORT);
s.sin_addr.s_addr = htonl(IP_ADDR);
if (bind(listenS, (struct sockaddr*)&s, sizeof(s)) < 0)
{
perror("bind");
return 1;
}
if (listen(listenS, QUEUE_LEN) < 0)
{
perror("listen");
return 1;
}
struct sockaddr_in clientIn;
int clientInSize = sizeof clientIn;
while (1)
{
int newfd = accept(listenS, (struct sockaddr*)&clientIn, (socklen_t*)&clientInSize);
if (newfd < 0)
{
perror("accept");
return 1;
}
if (send(newfd, &buffer, strlen(buffer), 0) < 0)
{
perror("send");
return 1;
}
char namebuff[100] = {0};
char sizebuff[256] = {0};
//int size;
ssize_t nrecv;
int error = 0;
int fsize;
//int dataleft;
if ((nrecv = recv(newfd, &namebuff, sizeof(namebuff), 0)) < 0)
{
perror("recv");
return 1;
}
if((strstr(buffer,namebuff) != NULL))
{
error = -1;
if (send(newfd, &error, sizeof(int), 0) < 0)
{
perror("send");
return 1;
}
}
/*if ((nrecv = recv(newfd, &fsize, sizeof(int), 0)) < 0) //this line is what jams the program
{
perror("recv");
return 1;
}*/
if(error != -1) //
{
if ((nrecv = recv(newfd, &sizebuff, sizeof(sizebuff), 0)) < 0)
{
perror("recv");
return 1;
}
fsize = atoi(sizebuff);
}
printf("%s\n",namebuff);
printf("%d\n",fsize);
close(newfd);
}
close(listenS);
return 0;
}
client side
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <fcntl.h>
#define PORT 0x0da2
#define IP_ADDR 0x7f000001
int ctoi(char c) {
return c-'0';
}
int main(void)
{
int sock = socket(AF_INET, SOCK_STREAM, 0);
ssize_t nrecv;
struct sockaddr_in s = {0};
s.sin_family = AF_INET;
s.sin_port = htons(PORT);
s.sin_addr.s_addr = htonl(IP_ADDR);
if (connect(sock, (struct sockaddr*)&s, sizeof(s)) < 0)
{
perror("connect");
return 1;
}
printf("Successfully connected.\n");
char buffer[1000] = {0};
if ((nrecv = recv(sock, &buffer, sizeof(buffer), 0)) < 0)
{
perror("recv");
return 1;
}
printf("./client list-files\n%s\n", buffer); //nrcev gives the size of the data is recived
int fd;
//int i;
//ssize_t nwrite, nread;
char sizebuff[256];
struct stat file_stat;
int numcheck = 0;
//char buffer2[4096];
char namebuff[100] = "coolfile.txt";
fd=open("coolfile.txt",O_RDONLY);
if (send(sock, &namebuff, strlen(namebuff), 0) < 0)
{
perror("send");
return 1;
}
/*if ((nrecv = recv(sock, &numcheck, sizeof(int), 0)) < 0)
{
perror("recv");
return 1;
}*/
if (numcheck == -1)
{
printf("file already exists in the server\n");
return 1;
}
if (fstat(fd, &file_stat) < 0)
{
printf("error");
return 1;
}
sprintf(sizebuff, "%ld", file_stat.st_size);
//printf("%s\n",sizebuff);
/*int number = 5;
if(send(sock, &number, sizeof(int), 0) < 0)
{
printf("error");
return 1;
}*/
if(send(sock, &sizebuff, strlen(sizebuff), 0) < 0);
{
printf("error");
return 1;
}
/*
nread = read(fd, buffer2, 4096);
for (i = 0; i < nread; i += nwrite)
{
nwrite = write(sock, buffer2 + i, nread - i);
}
} while (nread != 0);*/
return 0;
}
Thanks for your help!
I am developing a script for sending and receiving data through the ICMP Protocol. I cut, encrypt, code in base64, and forge packets. My code works fine but if I try to send large file, ICMP packets are not sent anymore (around the 1021th packets, it seems that I have reached the maximum segment size 65495 bytes.
Here is the screenshot of a wireshark capture when the event appears:
If it may help here is my C implementation for forging and sending packets (I read from files the data to send):
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/socket.h>
#include <resolv.h>
#include <netdb.h>
#include <string.h>
#include <netinet/in.h>
#include <netinet/ip_icmp.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <dirent.h>
#include <errno.h>
#include <limits.h>
#include <time.h>
#define PACKET_SIZE 128
struct packet
{
struct icmphdr hdr;
char msg[PACKET_SIZE-sizeof(struct icmphdr)];
};
int pid=-1;
struct protoent *proto=NULL;
/*--------------------------------------------------------------------*/
/*--- checksum - standard 1s complement checksum ---*/
/*--------------------------------------------------------------------*/
unsigned short checksum(void *b, int len)
{ unsigned short *buf = b;
unsigned int sum=0;
unsigned short result;
for ( sum = 0; len > 1; len -= 2 )
sum += *buf++;
if ( len == 1 )
sum += *(unsigned char*)buf;
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
result = ~sum;
return result;
}
/*--------------------------------------------------------------------*/
/*--- listener - separate process to listen for and collect messages--*/
/*--------------------------------------------------------------------*/
void listener(void)
{ int sd;
struct sockaddr_in addr;
unsigned char buf[1024];
sd = socket(AF_INET, SOCK_RAW, proto->p_proto);
if ( sd < 0 )
{
perror("socket");
exit(0);
}
for (;;)
{ int bytes, len=sizeof(addr);
bzero(buf, sizeof(buf));
bytes = recvfrom(sd, buf, sizeof(buf), 0, (struct sockaddr*)&addr, &len);
if ( bytes > 0 )
printf("***Got Reply***\n");
else
perror("recvfrom");
}
exit(0);
}
/*--------------------------------------------------------------------*/
/*--- ping - Create message and send it. ---*/
/*--------------------------------------------------------------------*/
int my_ping(struct sockaddr_in *addr, char *pkt, int cnt)
{
const int val=255;
int i, u, sd;
struct packet pckt;
struct sockaddr_in r_addr;
sd = socket(AF_INET, SOCK_RAW, proto->p_proto);
if ( sd < 0 )
return 1;
if ( setsockopt(sd, SOL_IP, IP_TTL, &val, sizeof(val)) != 0)
return 2;
if ( fcntl(sd, F_SETFL, O_NONBLOCK) != 0 )
return 3;
int len=sizeof(r_addr);
bzero(&pckt, sizeof(pckt));
pckt.hdr.type = ICMP_ECHO;
pckt.hdr.un.echo.id = pid;
for(i = 0; pkt[i]; i++){
pckt.msg[i] = pkt[i];
}
u = i;
for ( i = u; i < sizeof(pckt.msg); i++ )
pckt.msg[i] = '0';
//pckt.msg[i] = 0;
pckt.hdr.un.echo.sequence = cnt++;
pckt.hdr.checksum = checksum(&pckt, sizeof(pckt));
if ( sendto(sd, &pckt, sizeof(pckt), 0, (struct sockaddr*)addr, sizeof(*addr)) <= 0 )
return 4;
return 0;
}
/*--------------------------------------------------------------------*/
/*--- ping - Create message and send it. ---*/
/*--------------------------------------------------------------------*/
int sending(struct sockaddr_in *addr, char* folderPath)
{
int status, packetSent = 0, nbTries = 0;
FILE *entry_file;
char buffer[BUFSIZ];
struct dirent **namelist;
char pathFile[PATH_MAX + 1];
int i,n;
char pkt[2048];
char *pktTemp;
int nbPkts = 1;
/* Scanning the in directory */
n = scandir(folderPath, &namelist, 0, alphasort);
printf("n == %d \n", n);
if (n < 0){
fprintf(stderr, "Scan directory can not be performed\n");
return(3);
}else {
for (i = 0; i < n; i++) {
/* On linux/Unix we don't want current and parent directories
* * On windows machine too, thanks Greg Hewgill
* */
if (!strcmp (namelist[i]->d_name, ".") || !strcmp (namelist[i]->d_name, ".."))
continue;
pathFile[0] = '\0';
strncat(pathFile, folderPath,PATH_MAX);
strncat(pathFile, "/",PATH_MAX);
strncat(pathFile, namelist[i]->d_name, PATH_MAX);
printf("\n----------------\n");
printf("File path read: %s \n", pathFile);
entry_file = fopen(pathFile, "r");
if (entry_file == NULL)
{
fprintf(stderr, "Failed to open entry file \n");
return(3);
}
pkt[0] = '\0';
packetSent = 0;
while((pktTemp = fgets(buffer, BUFSIZ, entry_file)) != NULL){
strncat(pkt,pktTemp, 2048);
}
printf("Sending Packet %d with message : \"%s\" \n", nbPkts, pkt);
printf("----------------\n");
while(packetSent == 0 && nbTries < 3){
if((status = my_ping(addr, pkt, nbPkts)) == 0){
packetSent = 1;
nbPkts++;
}else {
nbTries++;
}
usleep(50000);
}
if(packetSent == 0){
fprintf(stderr, "Connection has been lost, check if the host is alived\n");
}
/* When you finish with the file, close it */
fclose(entry_file);
free(namelist[i]);
}
free(namelist);
}
return 0;
}
/*--------------------------------------------------------------------*/
/*--- main - look up host and start ping processes. ---*/
/*--------------------------------------------------------------------*/
int main(int argc, char *argv[])
{
struct hostent *hname;
struct sockaddr_in addr;
if ( argc != 3 )
{
printf("usage: %s <addr>\n", argv[0]);
exit(0);
}
if ( argc > 2 )
{
pid = getpid();
proto = getprotobyname("ICMP");
hname = gethostbyname(argv[1]);
bzero(&addr, sizeof(addr));
addr.sin_family = hname->h_addrtype;
addr.sin_port = 0;
addr.sin_addr.s_addr = *(long*)hname->h_addr;
if ( fork() == 0 )
listener();
else
sending(&addr, argv[2]);
wait(0);
}
else
printf("Usage: ./bin <hostname> <folderPath>\n");
return 0;
}
I have write a programming about transfer files from server to client.But problem is that I can only transfer 2G files if file is bigger than 2G ,only 2G transfer successfully.
client
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <fcntl.h>
#include <math.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define MAXLINE 1000
#define SA struct sockaddr
typedef struct
{
int oft;
int len;
char data[MAXLINE];
}Mem;
Mem Dat;
int main(int argc,char *argv[])
{
int sockfd = socket(AF_INET,SOCK_STREAM,0);
int complete;
struct sockaddr_in cli;
ssize_t recv_l,send_l;
size_t block_len;
socklen_t len;
char buf[MAXLINE];
char filename[MAXLINE];
FILE *fp;
bzero(&cli,sizeof(cli));
cli.sin_family = AF_INET;
if (argv[1] == NULL)
argv[1] = "172.16.42.22";
cli.sin_port = htons(5001);
inet_pton(AF_INET,argv[1],&cli.sin_addr.s_addr);
bind(sockfd,(struct sockaddr*)&cli,sizeof(cli));
if (connect(sockfd,(SA*)&cli,sizeof(cli)) == -1)
{
perror("connect");
close(sockfd);
exit(1);
}
//接收文件名列表
while((recv_l = recv(sockfd,buf,sizeof(buf),0)) > 0)
{
buf[recv_l] = '\0';
fputs(buf,stdout);
if(strcmp(buf+recv_l-5,"name\n") == 0)
break;
}
// exit(0);
bzero(filename,sizeof(filename));
while(fgets(filename,sizeof(filename),stdin) != NULL)
// while(gets(filename) != NULL)
{
int i = 0;
for(i = strlen(filename) - 1;i >= 0;i --)
if(filename[i] == '\n'){
filename[i] = '\0';
break;
}
send_l = send(sockfd,filename, strlen(filename),0);
recv_l = recv(sockfd,buf, sizeof(buf),0);
buf[recv_l] = '\0';
puts(buf);
if (strcmp(buf,"success") == 0)
break;
fputs(buf,stdout);
}
puts("filename send success");
//接收文件
if ((fp = fopen(filename,"wb")) == NULL)
{
perror("fopen");
exit(1);
}
while((recv_l = recv(sockfd,&Dat,sizeof(Dat),MSG_WAITALL)))
{
if (recv_l < 0){
perror("recv");
exit(1);
}
fwrite(Dat.data,sizeof(char),Dat.len,fp);
}
puts("file receive success");
fclose(fp);
close(sockfd);
return 0;
}
server
#include <sys/types.h>
#include <errno.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <fcntl.h>
#include <math.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define MAXLINE 1000
#define SA struct sockaddr
typedef struct
{
int oft;
int len;
char data[MAXLINE];
}Mem;
Mem Dat;
long long sum = 0;
int sendall(int sockfd, void *buf, int *len)
{
int total = 0; // how many bytes we've sent
int bytesleft = *len; // how many we have left to send
int n;
while(total < *len) {
n = send(sockfd, buf+total, bytesleft, 0);
sum += n;
if(sum >= 1073741824){
puts("1G");
sum = 0;
}
if (n != bytesleft) return -1;
if (n == -1) {
break; }
total += n;
bytesleft -= n;
}
*len = total; // return number actually sent here
return n==-1?-1:0; // return -1 on failure, 0 on success
}
int main(int argc,char *argv[])
{
int sockfd = socket(AF_INET,SOCK_STREAM,0);
socklen_t len;
size_t block_len;
int complete;
ssize_t send_l,recv_l;
struct sockaddr_in serv,cli;
char buf[MAXLINE];
char filename[100];
FILE *fp;
bzero(&serv,sizeof(serv));
serv.sin_family = AF_INET;
if (argv[1] == NULL)
argv[1] = "5001";
serv.sin_port = htons(atoi(argv[1]));
serv.sin_addr.s_addr = htonl(0);
bind(sockfd,(SA*)&serv,sizeof(serv));
listen(sockfd,5);
// for( ; ; )
{
len = sizeof(cli);
complete = accept(sockfd,(SA*)&cli,&len);
//发送文件名列表
fp = popen("ls","r");
while( fgets(buf,MAXLINE,fp) != NULL)
{
send(complete,buf,strlen(buf),0);
}
strcpy(buf,"input file name\n");
send(complete,buf, strlen(buf),0);
puts("send list success");
pclose(fp);
//exit(0);
//获取文件名
while( (recv_l = recv(complete,filename,sizeof(filename),0) ) > 0)
{
filename[recv_l] = '\0';
if ((fp = fopen(filename,"rb")) == NULL)
{
strcpy(buf,"filename error please input again");
puts("filename error");
send(complete,buf,strlen(buf),0);
}else{
puts("get filename success");
break;
}
}
//文件名对了
strcpy(buf,"success");
send(complete,buf,strlen(buf),0);
puts("get correct filename");
//传文件
int all = 0;
long long sa = 0;
int len = sizeof(Dat);
while((block_len = fread(Dat.data,sizeof(char),MAXLINE,fp)) > 0)
{
Dat.len = block_len;
if (sendall(complete,&Dat,&len) < 0){
puts("send error");
exit(1);
}
// if (send(complete,&Dat ,sizeof(Dat),0) < 0)
// {
// perror("send");
// exit(1);
// }
}
printf("%lld\n",sum);
printf("%s Tranfer finished\n",filename);
fclose(fp);
close(complete);
}
return 0;
}
on 32 bit systems, the maximum file size is 2 GB by default.
you can compile your program with the switch -D_FILE_OFFSET_BITS=64 to create files larger than 2 GB or use 64 bit.