Running.Pig Running.Pig - 3 months ago 30
C Question

Segmentation fault when send HTTP request and get response in C

I made a client socket that connect to a server. Then I wanna send HTTP Request to it.

GET /index.html HTTP/1.1\r\n
Host: www.google.com\r\n
\r\n


This is my code:

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
#include <netdb.h>

#define MAX 4096

int main(int argc, char **argv){
char *host;
strcpy(host, argv[1]);

char *request = "GET ";
strcat(request, argv[3]);
strcat(request, " HTTP/1.1\r\nHost: ");
strcat(request, argv[2]);
strcat(request, "\r\n\r\n");

char *response;

int port;
port = atoi(argv[2]);

int sockfd;
struct sockaddr_in servaddr;
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
perror("Failed to create socket!");
exit(1);
}

memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(port);

struct hostent *server;
server = gethostbyname(host);
if (server == NULL) perror("Failed to get host name!");

memcpy(&servaddr.sin_addr.s_addr, server->h_addr, server->h_length);

if(connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0){
perror("Failed to connect!");
exit(1);
}

while(fgets(request, MAX, stdin) != NULL){
send(sockfd, request, strlen(request), 0);
if(recv(sockfd, response, MAX, 0) == 0){
perror("Failed to recieve!");
exit(1);
}

printf("Response:/n");
fputs(response, stdout);
}


When I run it, it got a segmentation fault. Then I use GDB to trace it.

#0 strcmp () at ../sysdeps/x86_64/multiarch/../strcmp.S:132
#1 0x00007ffff7deb1a5 in _dl_name_match_p (name=0x4004e9 "libc.so.6", map=0x7ffff7ffe1c8) at dl-misc.c:289
#2 0x00007ffff7de402f in do_lookup_x (new_hash=new_hash@entry=479433942, old_hash=old_hash@entry=0x7fffffffe950,
result=result@entry=0x7fffffffe960, scope=<optimized out>, i=<optimized out>, i@entry=0, flags=flags@entry=1,
skip=skip@entry=0x0, undef_map=undef_map@entry=0x7ffff7ffe1c8) at dl-lookup.c:462
#3 0x00007ffff7de4961 in _dl_lookup_symbol_x (undef_name=0x40056b "strcat", undef_map=0x7ffff7ffe1c8,
ref=ref@entry=0x7fffffffea18, symbol_scope=0x7ffff7ffe520, version=0x7ffff7ff9a10, type_class=type_class@entry=1, flags=1,
skip_map=skip_map@entry=0x0) at dl-lookup.c:737
#4 0x00007ffff7de9527 in _dl_fixup (l=<optimized out>, reloc_arg=<optimized out>) at ../elf/dl-runtime.c:111
#5 0x00007ffff7df04d5 in _dl_runtime_resolve () at ../sysdeps/x86_64/dl-trampoline.S:45
#6 0x0000000000400b18 in main ()


The error message really made me confused. Where exactly I made mistakes?

Answer
char *request = "GET ";
/* you can't do this */
strcat(request, argv[3]);
strcat(request, " HTTP/1.1\r\nHost: ");
strcat(request, argv[2]);
strcat(request, "\r\n\r\n");

As request points to constant string, you cannot append more characters to it. You need to allocate more memory for it and then append more strings to it.

Similarly for response. Allocate memory for it before reading data into it.

In - general add

request = malloc(sizeof(char) * MAX);
response = malloc(sizeof(char) * MAX);

Then

strcpy(request, "GET ");
strcat(request, argv[3]);
strcat(request, " HTTP/1.1\r\nHost: ");
strcat(request, argv[2]);
strcat(request, "\r\n\r\n");

Better to use strncat etc function to be safe.