Related
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;
}
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?
I'm learning C almost one year and it's my first time that I got that warnings.
This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>
#include <windows.h>
#include <string.h>
int socket_creation(FILE* fp){
int s;
s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s == INVALID_SOCKET){
printf("Error occurred while creating socket: %d\n", WSAGetLastError());
fprintf(fp, "Error occurred while creating socket: %d\n", WSAGetLastError());
}
else{
printf("Socket creation was successful.\n");
fprintf(fp, "Socket creation was successful.\n");
}
return s;
}
void connect_to_server(int s, struct sockaddr_in ClientService, FILE* fp){
int cResult;
cResult = connect(s, (struct sockaddr*) &ClientService, sizeof(ClientService));
if (cResult == SOCKET_ERROR){
printf("connection to the server has been failed: %d\n", WSAGetLastError());
fprintf(fp, "connection to the server has been failed: %d\n", WSAGetLastError());
cResult = closesocket(s);
if (cResult == SOCKET_ERROR){
printf("error occurred while trying to close socket. \n");
fprintf(fp, "error occurred while trying to close socket. \n");
}
WSACleanup();
}
else{
printf("Connection to serevr has been made successfully. \n");
fprintf(fp, "Connection to serevr has been made successfully. \n");
}
}
int send_to_serv(char buffer[], int s){
int sendto;
sendto = send(s, buffer, 1024, 0);
if (sendto == -1)
printf("\nError: couldn't send the Code.\n", buffer);
else printf("\nCode: <%s> SENT.\n", buffer);
return sendto;
}
int recv_from_serv(int s, int* numberLines, FILE *fp){
int recvfrom;
char buffer[1024] = "";
recvfrom = recv(s, buffer, 1024, 0);
if (recvfrom == -1)
printf("\nError: couldn't receive Code. !\n");
else printf("\nRespond: <%s>, RECEIVED. \n", buffer);
fprintf(fp, "\n");
fprintf(fp, buffer);
*numberLines = atoi(buffer + 3);
return recvfrom;
}
int main() {
WSADATA info;
int error, s;
int sResults, sendError, recvError,convert2;
char buffer[1024] = "";
char recvbuf[1024] = "";
int numberLines, i, temp, convert;
char converted_num[1024] = "";
struct sockaddr_in ClientService;
FILE *fp = fopen("stored_data.txt", "w");
char* lines_array;
error = WSAStartup(MAKEWORD(2, 0), &info);
if (error != 0){
printf("WSAstartup failed with error: %d\n", error);
exit(1);
}
for (i=0; i <=numberLines; i++) {
lines_array[i]=NULL;
}
s = socket_creation(fp);
ClientService.sin_family = AF_INET;
ClientService.sin_addr.s_addr = inet_addr("54.209.143.42");
ClientService.sin_port = htons(6714);
connect_to_server(s, ClientService, fp);
strcpy(buffer, "100");
sendError = send_to_serv(buffer, s);
recvError = recv_from_serv(s, &numberLines, fp);
strcpy(buffer, "400");
sendError = send_to_serv(buffer, s);
recvError = recv_from_serv(s, &numberLines, fp);
printf("\nNumber of Lines are: %d\n", numberLines);
lines_array = malloc(sizeof(char*)*numberLines);
temp = numberLines;
for (i = 0; i < temp; i++){
convert = 5000001 + i;
_itoa(convert, converted_num, 10);
sendError = send_to_serv(converted_num, s);
convert2=atoi(convert);
convert=convert%10000;
if(convert2==0) {
for(i=0; i<=1024; i++) {
buffer[i]=0;
}
lines_array= (convert);
recv_from_serv(s, &numberLines, fp);
}
else{
for(i=0; i<=1024; i++) {
buffer[i]=0;
}
}
}
close(fp);
//system("PkAUSE>nul");
system("PAUSE");
return 0;
}
This is that output that my compiler (MinGW) giving to me:
finalproject1.c: In function main': finalproject1.c:87: warning:
assignment makes integer from pointer without a cast
finalproject1.c:113: warning: passing arg 1 ofatoi' makes pointer
from integer without a cast finalproject1.c:119: warning: assignment
makes pointer from integer without a cast finalproject1.c:133:3:
warning: no newline at end of file
Please help me I don't know what to do and my guid told me to "Google it" when I asked him to help me.
The line that triggers the warning is:
lines_array[i]=NULL;
and this variable is declared like so:
char* lines_array;
so you're cramming a pointer (the NULL macro expands to a pointer-type value on your system) into a single char, which won't fit and is a very strange thing to be doing.
Probably you wanted an array of character pointers, i.e.
char **lines_array;
but then you must of course allocate the array once you know how many lines you're going to be dealing with.
First of all, i can see you are using an integer numberLines as a condition in your for loop without initializing it first:
int numberLines;
for (i=0; i <=numberLines; i++) {
lines_array[i]=NULL;
}
Simply if you want to initialize your array to null you can initialize it as:
char* lines_array = null;
Try this and let me know if the warnings still exist.
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.
}
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?