Why am i getting "direct://" as output for my program? - c

I am in the early stages of writing a proxy server in c for class and while debugging, my program gives me a weird output simpley with two lines of
direct://
direct://
what does this mean? I've never had this happen before. The program even outputs this when i dont provide 3 arguments which i required for this program to execute.
#include <pthread.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <time.h>
#include <string.h>
int main (int argc, char *argv[]){
if(argc!=3){
printf("Usage: proxy <IP address> <port no.>");
exit(1);
}
int csock, ssock, clen, slen;
int csocka, ssocka;
int rc, fd, ttl;
char method[40];
char uri[80];
char prot[40];
char cbuf[100];
time_t logtime;
char * pch;
struct sockaddr_in caddr;
struct sockaddr_in caddr2;
struct sockaddr_in saddr;
struct sockaddr_in saddr2;
csock = socket(AF_INET, SOCK_STREAM, 0);
caddr.sin_family = AF_INET;
caddr.sin_addr.s_addr = inet_addr(argv[1]);
caddr.sin_port = htons(atoi(argv[2]));
clen = sizeof(caddr);
rc = bind(csock, (struct sockaddr *) &caddr, clen);
if(rc < 0){
printf("bind failed");
exit(1);
}
rc = listen(csock, 5);
if(rc < 0){
printf("listen failed");
exit(1);
}
printf("hey");
csocka = accept(csock, (struct sockaddr *) &caddr2, &clen);
if(csocka < 0){
printf("accept failed");
exit(1);
}
while(1){
read(csocka,&cbuf,sizeof(cbuf));
time(&logtime); //time of req.
if(cbuf==NULL){
cerror("400 Bad Request: empty request");
write(csocka, &errbuf, sizeof(errbuf));
continue;
}
ttl = strlen(cbuf);
while(cbuf[ttl-1] == '\n' || cbuf[ttl-1] == '\r'){
cbuf[ttl--] = '\0';
}
if(sscanf(cbuf,"%[^ ] %[^ ] %[^ ]", method, uri, prot) != 3){
cerror("400 Bad Request: Unexpected number of arguments");
write(csocka, &errbuf, sizeof(errbuf));
continue;
}
if(method!="GET" || method !="HEAD"){
cerror("405 Method Not Allowed: GET/HEAD only");
write(csocka, &errbuf, sizeof(errbuf));
continue;
}
if(uri == (char*) 0){
cerror("400 Bad Request: empty url");
write(csocka, &errbuf, sizeof(errbuf));
continue;
}
printf("%s \n", cbuf);
}
close(csocka);
}

The most probable reason is that you aren't running your program, but some system program.
If you are on a Linux machine, type:
which <program name>
to find out which executable you are actually running.
type:
./<program name>
to run your program instead (provided that you are in the same directory as your executable).

Why are you ignoring the return value of read? What makes you think read is null-terminating cbuf for you? If read isn't null terminating cbuf, then what makes you think it's safe to pass buf to strlen? You're invoking undefined behaviour by passing something that isn't a string to strlen... The behaviour that follows may seem strange or inconsistent, but that's the nature of undefined behaviour.
int len = read(csocka,&cbuf,sizeof(cbuf));
if (len <= 0) {
/* something went wrong in read().
* report an error and stop here... */
break;
}
/* Once error checking is performed, len is the number of bytes recieved by read. */
Consider the code above. Do you need the line ttl=strlen(cbuf);, if you correctly check for errors?
printf("%s \n", cbuf); is wrong, because cbuf isn't a string. Consider fwrite(cbuf, len, stdout); putchar('\n'); or printf("%.*s\n", len, stdout);.
write(csocka, &errbuf, sizeof(errbuf)); also looks wrong, but I'll leave that in your hands. If you need us to fix these kinds of errors for you, then your method of learning isn't working very well. Which book are you reading?

Related

linux TCP multiclient echo server in c

I am currently studying TCP multiclient echo server and client using fork, thread, multiplexing IO and so on.
Below are the simple server and client using fork().
server_fork.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <arpa/inet.h>
static const int BUFSIZE = 1024;
int readn(int fd, char *buf, short n);
int main(void)
{
int cnt = 0;
int listenFD, connectFD;
struct sockaddr_in listenSocket, connectSocket;
char buffer [BUFSIZE];
if ((listenFD = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket() error\n");
exit(0);
}
if (setsockopt(listenFD, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof(int)) < 0) {
perror("sockopt error\n");
exit(0);
}
memset(&listenSocket, 0, sizeof(listenSocket));
listenSocket.sin_family = AF_INET;
listenSocket.sin_addr.s_addr = inet_addr("0.0.0.0");
listenSocket.sin_port = htons(7777);
if (bind(listenFD, (struct sockaddr *)&listenSocket, sizeof(listenSocket)) < 0) {
perror("bind() error\n");
exit(0);
}
if (listen(listenFD, 1) < 0) {
perror("listen() error\n");
exit(0);
}
signal(SIGCHLD, SIG_IGN);
int connectSocketLen;
short readLen;
pid_t pid;
while (1) {
connectSocketLen = sizeof(connectSocket);
if ((connectFD = accept(listenFD, (struct sockaddr *)&connectSocket,
&connectSocketLen)) < 0) {
perror("accept() error\n");
exit(0);
}
pid = fork();
cnt++;
if (pid == 0) {
close(listenFD);
while (1) {
memset(buffer, 0, BUFSIZE);
if (readn(connectFD, buffer, 2) == 0) {
break;
}
readLen = (*(short *)&buffer);
if(readLen != 12)
printf("[%d] : %d\n", cnt, readLen);
if (readn(connectFD, buffer, readLen) == 0) {
break;
}
buffer[readLen] = 0;
int n;
if ((n = write(connectFD, buffer, readLen)) <= 0) {
perror("!!");
}
sleep(0);
}
close(connectFD);
exit(0);
}
else if (pid > 0) {
close(connectFD);
}
else {
perror("fork() error\n");
exit(0);
}
}
close(listenFD);
return 0;
}
int readn(int fd, char *buf, short n)
{
short sp = 0, readed;
while (n) {
readed = read(fd, buf + sp, n);
if (readed <= 0) {
return 0;
}
n -= readed;
sp += readed;
}
return 1;
}
client.c
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
static const int bufSize = 1024;
int main(int argc,char *argv[])
{
signal(SIGCHLD, SIG_IGN);
fork();
fork();
fork();
fork();
fork();
fork();
fork();
fork();
//fork();
//fork();
char length[2], recvBuf[bufSize];
char buf[]="hello, world\0";
short len = strlen(buf);
sprintf(length,"%c",len);
int client_sockfd, size, i, n, state;
uint64_t delta_us = 0;
struct sockaddr_in server_addr;
struct timespec start, end;
client_sockfd = socket(PF_INET, SOCK_STREAM, 0);
memset(&server_addr, 0, sizeof server_addr);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(7777);
inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr.s_addr);
state = connect(client_sockfd, (struct sockaddr *)&server_addr,
sizeof server_addr);
if (state < 0) {
perror("connect err");
exit(1);
}
for (i=0;i<10;i++) {
clock_gettime(CLOCK_MONOTONIC_RAW, &start);
n = write(client_sockfd, length, sizeof length);
if (n<=0) {
perror("write err");
exit(1);
}
n = write(client_sockfd, buf, *((short *)&length));
if (n<=0) {
perror("write err");
exit(1);
}
n = read(client_sockfd, recvBuf, *((short *)&length));
if (n<=0) {
perror("read err");
exit(1);
}
clock_gettime(CLOCK_MONOTONIC_RAW, &end);
delta_us += (end.tv_sec - start.tv_sec) * 1000000 +
(end.tv_nsec - start.tv_nsec)/1000;
printf("%lu\n", delta_us);
sleep(1);
}
return 0;
}
The client first transmits the length of the message represented by 2 bytes.
Then client sends a "hello, world" message to the server in buf.
The server first reads 2 bytes through readn () and reads the message as much.
But in all cases (fork, thread, multiplexing IO... whatever), I have a common difficulty.
The problem is that : In the above source code, the length of the message("hello, world" is 12. so it is expected to read 12 in the first readn () of the server.
In fact, when the number of clients is small (the number of forks on the client is 7 or less), it works fine.
However, if the number of clients increases, the value of readLen will be 25960 on some connections. 25960 is the value that represents "he" in hex.
Why is this problem happening when there are many clients?
I wonder if it is the same as sending a TCP packet at one time and dividing it two times.
Below is a tcpdump capture of the above problem situation.
I'm sorry that I could not upload the image right away.
tcpdump
On the client side, you have multiple problems surrounding how you send the message length. Starting here:
char length[2], recvBuf[bufSize];
char buf[]="hello, world\0";
short len = strlen(buf);
sprintf(length,"%c",len);
Your sprintf format promises that the third argument will be of type char (promoted to int), and instructs it to output the corresponding character into the string. In fact, the argument is a short (promoted to int), and this mismatch produces undefined behavior.
In practice, the overall sprintf call is probably equivalent to this:
length[0] = (char)(int)len;
length[1] = '\0';
That has implementation-defined characteristics if char is a signed type, but in any event, it cannot capture a length greater than the maximum value that can be represented by an unsigned char.
The client goes on to do this:
n = write(client_sockfd, length, sizeof length);
That's not inherently wrong, but it does fail to accommodate the possibility of a short write. Moreover, the server does not interpret this part of the message in a manner consistent with the way it was prepared:
if (readn(connectFD, buffer, 2) == 0) {
break;
}
readLen = (*(short *)&buffer);
As it turns out, that combination might happen to work if the server uses a 16-bit, little-endian representation for type short (subject to the restriction I already described on representable message length) and an execution character set compatible with the client's, but those are not safe assumptions for network software in general.
In part, you seem to be missing an important point about read() and write() and char pointers: a char * can be used to read the representation of an object of any type, so you do not need to move your data into a char array in order to send or receive it.
Overall, this would be a more appropriate approach:
// Client:
uint16_t len = strlen(buf); // risk: buf may be too long
uint16_t len_n = htons(len);
int n = writen(client_sockfd, &len_n, 2); // a write() analog of readn()
// ... handle possible error ...
// Sever:
uint16_t len_n;
int n = readn(connectFD, &len_n, 2);
// ... possible handle error ...
uint16_t readLen = ntohs(len_n);
Note that there is no need to copy the length into a separate char array to send it, nor to receive it into a char array. On the other hand, note also the use of a specified-size data type (uint16_t) on both sides, and the use of htons() and ntohs() to ensure that the client and server interpret the bytes of the data the same way. Furthermore, note the use of a write analog of readn() to send the data, which otherwise could be sent incompletely.
By the same token the client and server should both use the (hypothetical) writen() function to send the text of the message, and just like the server, the client should use readn() to read it. Failing to account for the possibility of short reads and writes is a significant flaw, especially in a protocol such as yours whose message boundaries are not easily distinguishable from data. An unnoticed short read or write will cause your client and server to fall out of sync, with no easy way to recover.
Apart from the problems already noticed by #JohnBollinger, you only use a listen window of 1 in server.c when all your forked client processes try to connect at the same time. It caused plenty of connect : conn reset by peer errors in my tests. I had to use a window greater than 64 on my FreeBSD (no errors at 256) to get rid of them :
if (listen(listenFD, 256) < 0) {
perror("listen() error\n");
exit(0);
}

Bug with char* realloc in loop

I'm trying to dev a little tool in C which includes HTTP Requests, but I have a problem I can't solve because I can't exactly find my error :/
This is a little part of my tool and I think that the function "http_request" has a problem with some HTML response.
Sometimes I have a segfault, sometimes a "free invalid next size" ... I'm thinking that my pointer has not correctly used.
I've try to reproduce the bug with very long string but nothing is happening..
(I think my problem is in the part /* receive the response */)
Here's the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#define BUF_SIZE 256
char *http_request(char *host, int port, char *r_http)
{
struct hostent *server;
struct sockaddr_in serv_addr;
int sockfd;
/* create the socket */
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) printf("ERROR opening socket");
/* lookup the ip address */
server = gethostbyname(host);
if (server == NULL)
{
printf("ERROR, no such host");
return NULL;
}
/* fill in the structure */
memset(&serv_addr,0,sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port);
memcpy(&serv_addr.sin_addr.s_addr,server->h_addr,server->h_length);
/* connect the socket */
if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
{
printf("ERROR connecting");
return NULL;
}
/* send the request */
int sent = 0,total = strlen(r_http), bytes, received;
do {
bytes = write(sockfd,r_http+sent,total-sent);
if (bytes < 0)
printf("ERROR writing message to socket");
if (bytes == 0)
break;
sent+=bytes;
} while (sent < total);
/* receive the response */
char *response = malloc(sizeof(char)*BUF_SIZE), *tmp_response = malloc(sizeof(char)*BUF_SIZE), rec_data[BUF_SIZE]={0};
// unsigned int new_size = BUF_SIZE;
size_t new_size = BUF_SIZE;
while((bytes = read(sockfd,rec_data,BUF_SIZE)))
{
/* Check if error or end of receipt */
if (bytes < 0 || bytes == 0)
{
if(bytes < 0)
printf("ERROR reading response from socket");
break;
}
/* Process vars */
if(new_size == BUF_SIZE)
snprintf(response,(BUF_SIZE+1),"%s",rec_data);
else {
tmp_response = realloc(tmp_response,sizeof(char)*strlen(response));
memset(tmp_response,0,sizeof(tmp_response));
snprintf(tmp_response,(new_size+1),"%s",response);
response = realloc(response,sizeof(char)*strlen(tmp_response)+sizeof(char)*strlen(rec_data));
memset(response,0,sizeof(response));
snprintf(response,(new_size+1),"%s%s",tmp_response,rec_data);
}
new_size+=BUF_SIZE;
memset(rec_data,0,sizeof(rec_data));
}
/* close the socket */
close(sockfd);
/* free space */
free(r_http);
free(tmp_response);
// free(response);
return response;
}
char *http_get(char *host, int port, char *get_request)
{
char *base_http = "GET %s HTTP/1.0\r\n\r\n", *r_http = malloc(sizeof(char)*strlen(base_http)+sizeof(char)*strlen(get_request));
sprintf(r_http,base_http,get_request);
return http_request(host,port,r_http);
}
int main(int argc, char *argv[], char *envp[])
{
char *resp = http_get("127.0.0.1",80,"/test.html");
printf("Response: |%s|\n",resp);
return 0;
}
The main problem: Your realloc sizes are consistently one off - You forgot that snprintf will need to have space for the 0 byte at the string end (strlen will always give you one byte less than you actually need to store the string)
Other (more marginal) problems:
You let snprintf (which is quite an expensive function) do the job of a simple memcpy
I don't really see the purpose for having a secondary buffer tmp_response - you could simply use rec_data for that. You would also get rid of one realloc call in your code.
Also quite some of the memset (which is used with wrong arguments anyhow) is unnecessary - Just copy the string over, there is not much purpose for clearing the buffers to 0 first, as long as you make sure you copy the string end around consistently.
Thanks all for you attention!
I've try to refactor my code with your adivce but I've some problem..
I've bug with little response I don't have the last char and sometime the response is in double (concat with the response header)
I've replace snprintf by memcpy and strncat, remove tmp buffer, send my var by reference into memset and add 1 byte space allocation for 0x00 at end of string.
If you see any error even small please tell me :)
My memset is correctly used now?
This is my new loop:
while((bytes = read(sockfd,rec_data,BUF_SIZE)))
{
/* Check if error or end of receipt */
if (bytes < 0 || bytes == 0)
{
if(bytes < 0)
error("ERROR reading response from socket");
break;
}
/* Process vars */
if(new_size == BUF_SIZE)
{
memcpy(response,rec_data,strlen(rec_data)+1);
response[strlen(response)-1]=0x00;
}else
{
response = realloc(response,new_size+1);
strncat(response,rec_data,BUF_SIZE);
memset(&rec_data,0,BUF_SIZE);
}
new_size += BUF_SIZE;
}

C program-server function error

I am trying to learn C and I can't get these apps working. I am creating 2 apps client/server, where the client connects to a server via specified port, and sends a file name (text) to the server. The server then takes the file name, runs it through a word count function and then responds to the client with filename/line/word/character count. I have gotten the client and the server to connect and communicate but my problem is that I can't seem to pass the client input to the wordcount function properly. Also, I'm not sure my function will return properly as I haven't found an appropriate method of returning a crafted string. Any help would be appreciated. Thanks!
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
void error(const char *msg){
perror(msg);
exit(1);
}
char * wordcount(char *cfile){
int i = 0;
int ccount = 0;
int wcount = 0;
int lcount = 0;
char *fn = malloc(strlen(cfile+7));
sprintf(fn, "/Files/%s", cfile);
FILE *cfilename = fopen (fn, "r");
while ((i = fgetc(cfilename)) != EOF){
if (i == '\n') {
lcount++;
}
if (i == '\t' || i == ' '){
wcount++;
}
ccount++;
}
printf("%c contains %d words, %d characters and %d lines.\n", cfile, wcount, ccount, lcount);
return 0;
}
int main(int argc, char *argv[]){
int sock, newSock, portno, n;
struct sockaddr_in serv_addr, cli_addr;
socklen_t clilen;
char buffer[256];
int index = 5;
int lowPortNum = 2500 + (10 * index);
int highPortNum = 2500 + (10 * index) + 9;
/* Check for proper amount of args */
if (argc < 2){
fprintf(stderr, "ERROR: No port specified. Exiting...\n");
printf("NOTE: Port must be between %d & %d.\n",lowPortNum,highPortNum);
exit(1);
}
/* Create socket by using args to form components */
sock = socket(AF_INET , SOCK_STREAM , 0);
if (sock < 0){
error("ERROR: Could not create socket");
}
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if(bind(sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0){
error("ERROR: Binding failed.");
return 1;
}
/* Start listening on socket */
listen(sock, 5);
puts("Server is waiting for connection...");
clilen = sizeof(cli_addr);
/* Accept connection from incoming client */
newSock = accept(sock, (struct sockaddr *) &cli_addr, &clilen);
if (newSock < 0){
error("ERROR: Accept failed.");
}
/* Read message from the client */
bzero(buffer, 256);
if (read(newSock, buffer, 255) < 0){
error("ERROR: Cannot read from socket.");
}
//debug
printf("client msg read: %s\n",buffer);
/* Send message to the client */
//wordcount(buffer);
if (write(newSock , wordcount(buffer) , 100) < 0){
error("ERROR: Cannot write to socket.");
}
close(newSock);
close(sock);
return 0;
}
Firstly, I think you've made a mistake here:
char *fn = malloc(strlen(cfile+7));
sprintf(fn, "/Files/%s", cfile);
You probably meant this:
char fn[strlen(cfile) + 8];
sprintf(fn, "/Files/%s", cfile);
You might notice that I've rearranged it a little; I think you wanted to add 7 to the return value of strlen, not to the argument of strlen. I've written 8 instead, because the extra 1 is for a '\0' which goes at the end of your string; that's extremely important. When you're crafting strings, always remember to make space for the '\0'.
Additionally, I've changed your malloc to a variable-length array. You really don't need to use dynamic storage duration (e.g. malloc) for this; try to prefer automatic storage duration unless you absolutely need dynamic storage duration.
Especially considering that your code leaks memory (which is the precise reason to avoid it unless you absolutely need it). Perhaps valgrind would be a useful tool in your development environment? Always remember to free any memory you have mallocd.
There's another error here:
FILE *cfilename = fopen (fn, "r");
while ((i = fgetc(cfilename)) != EOF){
Supposing fopen returns NULL (probably to indicate that the file doesn't exist), the calls to fgetc following it are clearly going to fail in disastrous ways. I think you meant something like this:
FILE *cfilename = fopen (fn, "r");
if (cfilename == NULL) {
/* XXX: HANDLE THIS ERROR! We'll get to this later... */
}
while ((i = fgetc(cfilename)) != EOF){
... and similarly, you've forgotten to fclose that file that was fopend. Always remember to fclose files that you have fopend.
... my problem is that I can't seem to pass the client input to the wordcount function properly
Providing the mistakes mentioned earlier are fixed, you should be able to safely pass the message received from your socket to wordcount as you have in your comment, without crashes or resource leaks: wordcount(buffer);...
You can try that if you like, but bear with me for a moment longer because you have other requirements to assess.
I'm not sure my function will return properly as I haven't found an appropriate method of returning a crafted string.
Think about how standard library functions handle this. You've used one of them here: sprintf(fn, "/Files/%s", cfile);. By accepting the destination (fn) for the string as an argument, sprintf allows you to use whichever storage duration you like. Additionally, this allows sprintf to return some other int value (which you can look up in the sprintf manual in your own time)...
If you design your function to write to a destination pointed to by an argument, like sprintf (and others) do, you'll be able to use your function however you like (e.g. automatic or dynamic storage duration?), too. You'll be able to return an int value indicating success or failure (e.g. when the fopen call fails), too.
Consider the following function, which doesn't even need a return value because there are no error modes:
typedef unsigned long long ullong;
void fcount(FILE *f, ullong *char_count, ullong *word_count, ullong *line_count)
{
rewind(f);
*char_count = 0;
*word_count = 0;
*line_count = 0;
for (;;) {
int c = fgetc(f);
switch (c) {
case EOF: return;
case '\n': (*line_count)++;
case '\t':
case ' ': (*word_count)++;
default: (*char_count)++;
}
}
}
Now consider this wrapper of that function, which does require a return value
int count(char *destination, char *filename) {
char fn[strlen(filename) + 8];
sprintf(fn, "/files/%s", filename);
FILE *f = fopen(fn, "r");
if (f == NULL) {
/* Note: This exit code is defined within <stdlib.h> */
return EXIT_FAILURE;
}
ullong char_count, word_count, line_count;
count(f, &char_count, &word_count, &line_count);
fclose(f);
sprintf(destination, "%s contains %llu words, %llu characters and %llu lines.\n", filename, word_count, char_count, line_count);
return EXIT_SUCCESS;
}
Now you can tell if your function fails or succeeds, just like many of the standard library functions! Yay!
char buf[128];
count(buf, file_name);
printf("%s", buf);
You can also access the string you intended to write... Is this all flowing together?

C pointer segmentation fault

I have this C code:
#include <errno.h>
#include <sys/errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include<fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
char *buf;
int c,s; int port=45678;
int recv_m(int c,char *buf);
void get(){
char fileNameBuf[20];
int i=0;
char *s = buf;
if (*s=='/') {
s++;
while (*s!=' ') {
fileNameBuf[i]=*s;
*s++;
i++;
}
fileNameBuf[i]='\0';
}
}
int main(){
//server connected
while ((c = accept(s, (struct sockaddr *) &client, (socklen_t *) &clientlen)) > 0){
// Do whatever a web server does.
char recv_buf[50];
char *r=recv_buf;
while(recv(c, r , 1, 0)!=0){
//stores the received message in recv_buf
}
recv_buf[i]='\0';
if (strncmp(recv_buf, "GET ", 4)==0){
buf=recv_buf+4;
get();
}
}
return (0);
}
*buf points to string /index.html HTTP/1.0. At the end of the function, fileNameBuf should store the string index.html.
The number of times in the while loop should be 10. When I run this code, i = 381 and I get a segmentation fault (core dump).
What am I doing wrong?
Here is the whole code, so *buf is the problem?
Either your assumptions about what is in buf must be faulty — or we're faulty in our interpretation of what you mean when you say:
*buf points to string "/index.html HTTP/1.1".
If you declared char **buf; and set:
char *str = "/index.html HTTP/1.1";
char **buf = str;
Then *buf points to the start of the string. This is why creating an SSCCE (Short, Self-Contained, Correct Example) is important; it removes the ambiguities.
An SSCCE
This code:
#include <stdio.h>
const char *buf = "/index.html HTTP/1.1";
static
void get(void)
{
char fileNameBuf[10];
int i=0;
if (*buf=='/')
{
buf++;
while (*buf!=' ')
{
fileNameBuf[i]=*buf;
buf++;
i++;
printf("%d\n", i);
}
}
printf("%.*s\n", (int)sizeof(fileNameBuf), fileNameBuf);
}
int main(void)
{
get();
return 0;
}
produces this output:
1
2
3
4
5
6
7
8
9
10
index.html
Granted, I had to take care not to print beyond the end of the array. Your array is minimally sized; it cannot hold a string containing the file name (no space for the null terminator). But it should not crash — if char *buf = "/index.html HTTP/1.1";!
Completed code — stage 1
This is closely based on what was submitted as the program. It compiles cleanly — I've not tried running it.
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/socket.h>
char *buf;
int c, s; int port = 45678;
struct sockaddr_in server, client;
char *ipaddress = "127.0.0.1";
int clientlen = sizeof(client);
int portset = 0;
int recv_m(int c, char *buf);
static
void get(void)
{
printf("in get method\n");
char fileNameBuf[20];
int i = 0;
printf("%s\n", buf);
char *s = buf;
if (*s == '/')
{
printf("buf==/\n");
s++;
while (*s != ' ')
{
// printf("%c\n",*buf);
// printf("in while\n");
fileNameBuf[i] = *s;
s++;
i++;
printf("%d\n", i);
}
fileNameBuf[i]='\0';
printf("<<%s>>\n", fileNameBuf);
}
else
{
printf("!= '/'\n");
}
}
int main(void)
{
bzero(&server, sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(port);
// if (!inet_aton(ipaddress, &server.sin_addr))
// fprintf (stderr, "inet_addr() conversion error\n");
s = socket(AF_INET, SOCK_STREAM, 0); // Create socket
if (!s) {
perror("socket");
exit(0);
}
if (bind(s, (struct sockaddr *) &server, sizeof(server)) < 0) {
perror("bind");
exit(0);
}
printf("binded\n");
if (listen(s, SOMAXCONN) < 0) {
perror("listen");
exit(0);
}
printf("Waiting for connection\n");
while ((c = accept(s, (struct sockaddr *) &client, (socklen_t *) &clientlen)) > 0)
{
// Do whatever a web server does.
printf("got connected\n");
char recv_buf[50];
char el[4] = "\r\n\r\n";
int h = 0; int i = 0;
char *r = recv_buf;
while (recv(c, r, 1, 0) != 0)
{
if (h == 4) break;
if (*r == el[h]) {
h++;
}
r++;
i++;
if (h == 4) break;
}
recv_buf[i] = '\0';
printf("%s\n", recv_buf);
if ( strncmp(recv_buf, "GET ", 4) == 0) {
printf("check get\n");
buf = recv_buf+4;
printf("%s\n", buf);
get();
}
}
return(0);
}
This is not an SSCCE. All the code related to setting up the socket and reading from the socket should be tangential to the problem at hand.
Reduced Code — Stage 2
The reduction process involves eliminating the inessential.
#include <stdio.h>
#include <string.h>
char *buf;
static void get(void)
{
printf("in get method\n");
char fileNameBuf[20];
int i = 0;
printf("%s\n", buf);
char *s = buf;
if (*s == '/')
{
printf("buf==/\n");
s++;
while (*s != ' ')
{
fileNameBuf[i] = *s;
s++;
i++;
printf("%d\n", i);
}
fileNameBuf[i]='\0';
printf("<<%s>>\n", fileNameBuf);
}
else
{
printf("!= '/'\n");
}
}
int main(void)
{
char recv_buf[50];
strcpy(recv_buf, "GET /index.html HTTP/1.1\r\n\r\n");
printf("<<%s>>\n", recv_buf);
if (strncmp(recv_buf, "GET ", 4) == 0)
{
printf("check get\n");
buf = recv_buf+4;
printf("%s\n", buf);
get();
}
return(0);
}
This too compiles cleanly; unfortunately, it also runs successfully for me (GCC 4.8.1, Mac OS X 10.8.4):
<<GET /index.html HTTP/1.1
>>
check get
/index.html HTTP/1.1
in get method
/index.html HTTP/1.1
buf==/
1
2
3
4
5
6
7
8
9
10
<<index.html>>
This happens sometimes; you are too ruthless in your clean-up. So, you have to go back to the previous code and remove things more slowly.
Retrenching — Stage 3
Let's take the full code from Stage 1 and run it locally. The browser can connect to localhost:45678/index.html and the output is:
binded
Waiting for connection
got connected
GET /index.html HTTP/1.1
Host: localhost:45678
check get
/index.html HTTP/1.1
Host: localhost:45678
in get method
/index.html HTTP/1.1
Host: localhost:45678
buf==/
1
2
3
4
5
6
7
8
9
10
<<index.html>>
There is nothing sent back to the waiting browser (it's still waiting, but will time out shortly). The code loops back to the next accept; it isn't clear that it shuts up shop properly, but it didn't crash on the first cycle.
So, this has been a somewhat fruitless exercise...your code seems to work OK. It should still be improved — starting off by making every one of those global variables into a local in main(), and then passing buf to a modified get() with the signature void get(char *buf).
Does the code you showed really crash for you? If so, what does the debugger say about why it crashes?
Bullet-proofing — Stage 4
After establishing that the string pointed to by buf was actually "/index.html\r\n\r\n" and not"/index.html HTTP/1.1\r\n\r\n"`, it is clear that I was remiss in not ensuring that the code would not read past the end of null terminated strings nor write past the ends of buffers. However, this is precisely why an SSCCE is so important, and why diagnostic printing is so important. If the question had included the actual string that was being scanned, it would have been a lot simpler to spot the issue.
This code is more nearly bullet-proof. Amongst other major changes, it attempts to read the request in a single recv() operation, rather than reading the request byte by byte. This puts the onus on avoiding an overflow on recv(). All the global variables are gone; buf is passed to get() as an argument. get() has been written to detect EOS and overlong names, as well as handling names up to the first space. It still has the debug code for each character in the file name. The code in main() has been dolled up to send back a response that is valid HTTP — or valid enough HTTP — with a bit of HTML that changes each time it is handled. It's interesting seeing the requests the browser makes. There's also an error reporting function that writes to standard error, takes a format string and arguments as with printf() et al, and also adds the correct error number and message for the system error, and then exits with a failure status. This makes error reporting less painful; a one-line call suffices for each error, instead of 3 or 4 lines (depending on your choice of formatting). The errors can be more expressive than perror() too.
#include <ctype.h>
#include <errno.h>
#include <netinet/in.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/socket.h>
#include <unistd.h>
static void err_exit(const char *fmt, ...);
static
void get(char *buf)
{
printf("in get method\n");
char fileNameBuf[256];
size_t i = 0;
printf("%s\n", buf);
char *s = buf;
if (*s == '/')
{
printf("buf==/\n");
s++;
while (*s != '\0' && *s != ' ' && i < sizeof(fileNameBuf))
{
printf("i = %3d: c = %3d = 0x%.2X = '%c'\n",
(int)i, *s, *s & 0xFF, isprint(*s) ? *s : '.');
fileNameBuf[i++] = *s++;
}
fileNameBuf[i]='\0';
printf("<<%s>>\n", fileNameBuf);
}
else
{
printf("!= '/'\n");
}
}
int main(void)
{
char *buf;
int fd;
int s;
int port = 45678;
struct sockaddr_in server, client;
int clientlen = sizeof(client);
int msgnum = 314159;
bzero(&server, sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(port);
s = socket(AF_INET, SOCK_STREAM, 0);
if (!s)
err_exit("socket()\n");
if (bind(s, (struct sockaddr *) &server, sizeof(server)) < 0)
err_exit("bind()\n");
printf("bound to address\n");
if (listen(s, SOMAXCONN) < 0)
err_exit("listen()\n");
printf("Waiting for connection\n");
while ((fd = accept(s, (struct sockaddr *) &client, (socklen_t *) &clientlen)) > 0)
{
printf("got connection\n");
char recv_buf[4096];
char el[5] = "\r\n\r\n";
ssize_t length;
/* Read message in one go; leave space for a null at the end */
if ((length = recv(fd, recv_buf, sizeof(recv_buf)-1, 0)) > 0)
{
recv_buf[length] = '\0';
if (strstr(recv_buf, el) == 0)
err_exit("Incomplete message (%d bytes and no CRLF, CRLF pair)\n", length);
printf("%d: <<%s>>\n", (int)length, recv_buf);
if (strncmp(recv_buf, "GET ", 4) == 0)
{
printf("check get\n");
buf = recv_buf + 4;
printf("<<%s>>\n", buf);
get(buf);
char message[256];
char format1[] =
"<html><head><title>Hello World!</title></head>"
"<body><h1>This is no fun at all (%d).</h1></body></html>\r\n\r\n";
int msg_len = snprintf(message, sizeof(message), format1, msgnum++);
char format2[] =
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n"
"Content-Length: %d\r\n"
"Content-Encoding: UTF-8\r\n\r\n%s";
char response[1024];
size_t nbytes = snprintf(response, sizeof(response), format2,
msg_len, message);
write(fd, response, nbytes);
}
}
close(fd);
}
return(0);
}
static void err_exit(const char *fmt, ...)
{
int errnum = errno;
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
fprintf(stderr, "%d: %s\n", errnum, strerror(errnum));
exit(1);
}
It appears that buf is a char array. If so, you should access the buf using a char pointer. Try this:
int main () {
char buf[] = "/index.html HTTP/1.0";
char fileNameBuf[10];
int i=0;
char *s = buf;
if (*s=='/') {
s++;
while (*s!=' ') {
fileNameBuf[i]=*s;
*s++;
i++;
printf("%d\n",i);
}
}
}
If buf is an array of char and even though arrays and pointers have several things in common, doing buf++ is not legal by C.Here is a text from Kernighan/Ritchie C book. You have probably buf declared as an array as well.
There is one difference between an array name and a pointer that must be kept in mind. A pointer is a variable, so pa=a and pa++ are legal. But an array name is not a variable; constructions like a=pa and a++ are illegal.
Due to this reason, doing "arr++" would be an error in the following code.
int main() {
int arr[10];
int *ptr = arr;
arr++; // Would be illegal.
ptr++; // This is okay.
}

Transmission of audio file using c sockets

I am trying to send audio file from one computer to other using socket programming in c. When I send simple string without any framing information such as header or tailer it gets sent perfectly. But when I try to send the same information with some header information like size of the socket_data or packet_no. it doesn't get sent properly. Even the terminal output is SAME on both the machines but the file which gets created is totally different and unplayable. I have used serializing concept to send packet. Am attaching codes. Please comment whats going wrong.
Server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
void set_socket(struct sockaddr_in *socket, int type, int host_short, int addr_type)
{
socket -> sin_family = type;
socket -> sin_port = htons(host_short);
socket -> sin_addr.s_addr = htonl(addr_type);
}
void serialize(char *buffer, int count, char *data)
{
int i=0, j=0;
char temp1[20];
sprintf(temp1, "%d", count);
while(temp1[i] != '\0')
{
buffer[j++] = temp1[i++];
}
buffer[j++]=' ';
for(i=0; data[i] != '\0'; i++)
{
buffer[j++] = data[i];
}
buffer[j] = '\0';
printf("BUFFER =%ld\n", sizeof(buffer));
}
int main()
{
int sid = 0, bid = 0, fp;
char *send_data = (char *)malloc(1024*sizeof(char));
char temp[1024];
char *receive_data = (char *)malloc(1024*sizeof(char));
int fd, count, cnt=0;
struct sockaddr_in server_socket, client_socket;
int size = sizeof(client_socket);
if((sid = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
{
printf("Connection error..\n");
exit(1);
}
set_socket(&server_socket, AF_INET, 6000, INADDR_ANY);
if((bid = bind(sid, (struct sockaddr *)&server_socket, sizeof(struct sockaddr))) == -1)
{
printf("Binding error..\n");
exit(1);
}
printf("I am waiting for client..\n");
recvfrom(sid, receive_data, 1024, 0,(struct sockaddr *)&client_socket, &size);
printf("received data is : %s\n", receive_data);
fd = open(receive_data, O_RDONLY);
printf("size = %ld\n", sizeof(send_data));
while((count=read(fd, temp, 500)) != 0)
{
printf("I am inside the loop : %d\n", cnt++);
serialize(send_data, count, temp);
printf("Serialized : %s\n", send_data);
sendto(sid, send_data, 1024, 0, (struct sockaddr *)&client_socket, size);
}
printf("I am outside the loop : %d\n", count);
strcpy(temp, "ENDOFFILE");
serialize(send_data, sizeof(temp), temp);
sendto(sid, send_data, 1024, 0, (struct sockaddr *)&client_socket, size);
fcloseall();
close(sid);
close(fd);
return 0;
}
Client.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <fcntl.h>
void set_socket(struct sockaddr_in *socket, int type, int host_short)
{
socket -> sin_family = type;
socket -> sin_port = htons(host_short);
}
void deserialize(char *buffer, int *size, char *data)
{
int i=0, j=0;
char temp1[20];
while(buffer[i] != ' ')
{
temp1[j++] = buffer[i++];
}
temp1[j] = '\0';
printf("\nINT : %s\n", temp1);
*size = atoi(temp1);
i++;
j=0;
while(buffer[i] != '\0')
{
data[j++] = buffer[i++];
}
data[j++] = '\0';
}
int main()
{
int sid = 0, bid = 0, con = 0;
char *send_data = (char *)malloc(1024*sizeof(char));
char *receive_data = (char *)malloc(1024*sizeof(char));
char *temp = (char *)malloc(1024*sizeof(char));
struct hostent *host;
struct sockaddr_in server_socket;
int size = sizeof(server_socket);
if((sid = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
{
printf("Connection error at client side..\n");
exit(1);
}
set_socket(&server_socket, AF_INET, 6000);
if (inet_aton("127.0.0.1", &server_socket.sin_addr)==0)
{
fprintf(stderr, "inet_aton() failed\n");
exit(1);
}
printf("Enter the name of the file you want to see : ");
scanf("%s", send_data);
int fd = open("sanket.mp3", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IXUSR);
sendto(sid, send_data, 1024, 0, (struct sockaddr *)&server_socket, size);
printf("================= Contents of the File =====================\n");
while(1)
{
int size;
recvfrom(sid, temp, 1024, 0, (struct sockaddr *)&server_socket, &size);
printf("Deserialize it : %s\n",temp);
deserialize(temp, &size, receive_data);
if(!strcmp(receive_data, "ENDOFFILE"))
{
printf("============================================================\n");
break;
}
else
write(fd, receive_data, size);
}
fcloseall();
close(sid);
return 0;
}
When I checked the size of the sent and received file, sizes are same but the contents are different, thus I am unable to play received audio file.
You seem to be reading from a binary data-file, yet inside your serialize function you are treating the data as-if it were null-terminated string data. For instance, this loop inside serialize:
for(i=0; data[i] != '\0'; i++)
{
buffer[j++] = data[i];
}
will terminate on the first zero-value it encounters. If this is true binary data from your audio file though, then I'm sure you'll get 0 values that are actual audio data rather than indicating the end of the buffer. Instead of terminating on a NULL-value, you should be terminating on the size of the buffer that you're passing to serialize that was read in your call to read in the while-loop. That way you can be sure you are getting all the data that was read from your read call packed into your send-buffer.
Secondly, printing sizeof(buffer), when buffer is a pointer, will only print the size of a pointer-type, not the size of the actual buffer the pointer is pointing to. Again, you're going to have to explicitly pass that value to your serialize function.
Third, you're terminating the buffer with a null-value ... again, that's not going to be a good idea based on the first point about this being raw binary data and not null-terminated strings. You should either come up with some type of string to indicate the end-of-transmission in the buffer that would be a set of values that would be impossible to be part of the data, or you should explicitly read the number of bytes that are in the "count" that you've embedded in the packet data.
Finally, you're not really serializing your data ... the concept of serializing typically means to transfer the data in a platform-independent way. You're simply packing up the bytes read and sending them across the network, assuming that the receiving side has the same endianness, etc. A fairly simple serialization approach would do something like creating ASCII strings from all the data-values, with the downside that this will create quite a bit of data-bloat. There are other cross-platform standards for serialized data such as JSON, SOAP, etc.

Resources