Send HTTP response using C socket - c

I`m trying to send HTTP response to browser
char *reply =
"HTTP/1.1 200 OK\n"
"Date: Thu, 19 Feb 2009 12:27:04 GMT\n"
"Server: Apache/2.2.3\n"
"Last-Modified: Wed, 18 Jun 2003 16:05:58 GMT\n"
"ETag: \"56d-9989200-1132c580\"\n"
"Content-Type: text/html\n"
"Content-Length: 15\n"
"Accept-Ranges: bytes\n"
"Connection: close\n"
"\n"
"sdfkjsdnbfkjbsf";
int sd = socket(PF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr;
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(8081);
addr.sin_addr.s_addr = INADDR_ANY;
if(bind(sd,&addr,sizeof(addr))!=0)
{
printf("bind error\n");
}
if (listen(sd, 16)!=0)
{
printf("listen error\n");
}
for(;;)
{
int size = sizeof(addr);
int client = accept(sd, &addr, &size);
if (client > 0)
{
printf("client connected\n");
send(client, reply, sizeof(reply), 0);
}
}
but my browser cant understand this, waits for a long time and then print smth strange. I guess my response is wrong, but I dont know how to fix. Any ideas?

sizeof(reply) evaluates to the size of a char *, aka size of a pointer. Use strlen.
send(client, reply, strlen(reply), 0);

Related

GET request to obtain page's content

I am trying to perform the C equivalent of the python's:
requests.get('http://test.com')
I am first using getaddrinfo() to resolve the hostname (it has 4 ips) to ip then server.sin_addr.s_addr = inet_addr(ip); and it connects successfully (doesn't give an error). But when I try to display the page by sending "GET / HTTP/1.1\r\n\r\n request, it basically returns 404 error (page not found) content. Here is the function:
void foo ()
{
struct addrinfo hints;
struct addrinfo *result = NULL;
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
char host[256], port [256];
strcpy(host, "www.test.com");
strcpy(port, "80");
getaddrinfo(host, port, &hints, &result);
struct sockaddr_in *sockaddr_ipv4 = (struct sockaddr_in *)result->ai_addr;
char ip [256];
strcpy(ip, inet_ntoa(sockaddr_ipv4->sin_addr));
struct sockaddr_in server;
SOCKET s = socket(AF_INET , SOCK_STREAM , 0 );
char *message , server_reply[2000];
int recv_size;
server.sin_addr.s_addr = inet_addr(ip);
server.sin_family = AF_INET;
server.sin_port = htons( 80 );
if (connect(s , (struct sockaddr *)&server , sizeof(server)) < 0)
{
puts("connect error");
return 1;
}
message = "GET / HTTP/1.1\r\n\r\n";
if( send(s , message , strlen(message) , 0) < 0)
{
puts("Send failed");
return 1;
}
if((recv_size = recv(s , server_reply , 2000 , 0)) == SOCKET_ERROR)
{
puts("recv failed");
}
server_reply[recv_size] = '\0';
puts(server_reply);*/
system("PAUSE");
}
Result
HTTP/1.1 404 Not Found Date: Fri, 15 Sep 2017 03:19:41 GMT
Content-Type: text/html; charset=UTF-8 Server: ghs Content-Length:
1561 X-XSS-Protection: 1; mode=block X-Frame-Options: SAMEORIGIN
Error 404 (Not Found)!!1
{margin:0;padding:0}html,code{font:15px/22px arial,sans-serif}html{backgrou
nd:#fff;color:#222;padding:15px}body{margin:7% auto
0;max-width:390px;min-height :180px;padding:30px 0 15px} >
body{background:url(//www.google.com/images/error s/robot.png) 100%
5px no-repeat;padding-right:205px}p{margin:11px 0 22px;overflo
w:hidden}ins{color:#777;text-decoration:none}a img{border:0}#media
screen and (m
ax-width:772px){body{background:none;margin-top:0;max-width:none;padding-right:0
}}#logo{background:url(//www.google.com/images/branding/googlelogo/1x/googlelogo
_color_150x54dp.png) no-repeat;margin-left:-5px}#media only screen and (min-reso
lution:192dpi){#logo{background:url(//www.google.com/images/branding/googlelogo/
2x/googlelogo_color_150x54dp.png) no-repeat 0% 0%/100%
100%;-moz-border-image:ur
l(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png)
0}}#media only screen and
(-webkit-min-device-pixel-ratio:2){#logo{background:ur
l(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png)
no-repeat;-webkit-background-size:100%
100%}}#logo{display:inline-block;height:5 4px;width:150px}
404. Thata?Ts an error. The requested URL
/ was not found on this server. Thata? Ts all we
know.
What am I doing wrong? How must I approach this?
Within HTTP/1.1 you need to specify a Host header. Within HTTP/1.0 you do not. Therefore, you must either change this to be:
GET / HTTP/1.0\r\n\r\n
or
GET / HTTP/1.1\r\n
Host: the.hostname.com\r\n\r\n
This change was made since virtual hostnames had become so prevalent.

Error send post data in C with socket

I want to send post data to php script, but php never get my post data. Here my code :
#include<stdio.h>
#include<winsock2.h>
#include <string.h>
#pragma comment(lib,"ws2_32.lib") //Winsock Library
int main(int argc , char *argv[])
{
WSADATA wsa;
SOCKET s;
struct sockaddr_in server;
char message[1024] , server_reply[2000];
int recv_size;
printf("\nInitialising Winsock...");
if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
{
printf("Failed. Error Code : %d",WSAGetLastError());
return 1;
}
printf("Initialised.\n");
//Create a socket
if((s = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
{
printf("Could not create socket : %d" , WSAGetLastError());
}
printf("Socket created.\n");
server.sin_addr.s_addr = inet_addr("127.0.0.1");
server.sin_family = AF_INET;
server.sin_port = htons( 80 );
//Connect to remote server
if (connect(s , (struct sockaddr *)&server , sizeof(server)) < 0)
{
puts("connect error");
return 1;
}
puts("Connected");
// Work well with Get Method
// strcat(message, "GET /voleur/receiver.php?arg1=Hello HTTP/1.1\n");
strcpy(message, "POST /voleur/receiver.php HTTP/1.1\r\n");
strcat(message, "Host: 127.0.0.1:80\r\n");
strcat(message, "Content-Type: application/x-www-form-urlencoded\r\n");
strcat(message, "Content-Length: 10\r\n");
strcat(message, "Accept-Charset: utf-8\r\n\r\n");
strcat(message, "arg1=Hello");
if( send(s , message , strlen(message) , 0) < 0)
{
puts("Send failed");
return 1;
}
puts("Data Send\n");
//Receive a reply from the server
if((recv_size = recv(s , server_reply , 2000 , 0)) == SOCKET_ERROR)
{
puts("recv failed");
}
puts("Reply received\n");
//Add a NULL terminating character to make it a proper string before printing
server_reply[recv_size] = '\0';
puts(server_reply);
return 0;
}
This the php script :
<?php
echo "POST DATA : ".json_encode($_POST);
?>
Here the response :
Reply received
HTTP/1.1 200 OK
Date: Fri, 18 Nov 2016 10:34:21 GMT
Server: Apache/2.4.18 (Win32) OpenSSL/1.0.2e PHP/7.0.8
X-Powered-By: PHP/7.0.8
Content-Length: 14
Content-Type: text/html; charset=UTF-8
POST DATA : []
When i try send data throught GET method thats work well, but for POST method, PHP script doesn't receive any data from client.
Thankyou for David Schwartz, this the right code :
#include<stdio.h>
#include<winsock2.h>
#include <string.h>
#pragma comment(lib,"ws2_32.lib") //Winsock Library
int main(int argc , char *argv[])
{
WSADATA wsa;
SOCKET s;
struct sockaddr_in server;
char message[1024] , server_reply[2000];
int recv_size;
printf("\nInitialising Winsock...");
if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
{
printf("Failed. Error Code : %d",WSAGetLastError());
return 1;
}
printf("Initialised.\n");
//Create a socket
if((s = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
{
printf("Could not create socket : %d" , WSAGetLastError());
}
printf("Socket created.\n");
server.sin_addr.s_addr = inet_addr("127.0.0.1");
server.sin_family = AF_INET;
server.sin_port = htons( 80 );
//Connect to remote server
if (connect(s , (struct sockaddr *)&server , sizeof(server)) < 0)
{
puts("connect error");
return 1;
}
puts("Connected");
// Work well with Get Method
// strcat(message, "GET /voleur/receiver.php?arg1=Hello HTTP/1.1\n");
strcpy(message, "POST /voleur/receiver.php HTTP/1.1\r\n");
strcat(message, "Host: 127.0.0.1:80\r\n");
strcat(message, "Content-Type: application/x-www-form-urlencoded\r\n");
strcat(message, "Content-Length: 16\r\n");
strcat(message, "Accept-Charset: utf-8\r\n\r\n");
strcat(message, "arg1=Hello World");
if( send(s , message , strlen(message) , 0) < 0)
{
puts("Send failed");
return 1;
}
puts("Data Send\n");
//Receive a reply from the server
if((recv_size = recv(s , server_reply , 2000 , 0)) == SOCKET_ERROR)
{
puts("recv failed");
}
puts("Reply received\n");
//Add a NULL terminating character to make it a proper string before printing
server_reply[recv_size] = '\0';
puts(server_reply);
return 0;
}

Send HTTP Post Request in C

I want to create an HTTP post request in C. I have success to send Get Method but, when I try with Post, program is just stopped.
Here the code :
#include<stdio.h>
#include<winsock2.h>
#include <string.h>
#pragma comment(lib,"ws2_32.lib") //Winsock Library
int main(int argc , char *argv[])
{
WSADATA wsa;
SOCKET s;
struct sockaddr_in server;
char *message , server_reply[2000];
int recv_size;
printf("\nInitialising Winsock...");
if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
{
printf("Failed. Error Code : %d",WSAGetLastError());
return 1;
}
printf("Initialised.\n");
//Create a socket
if((s = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
{
printf("Could not create socket : %d" , WSAGetLastError());
}
printf("Socket created.\n");
server.sin_addr.s_addr = inet_addr("127.0.0.1");
server.sin_family = AF_INET;
server.sin_port = htons( 80 );
//Connect to remote server
if (connect(s , (struct sockaddr *)&server , sizeof(server)) < 0)
{
puts("connect error");
return 1;
}
puts("Connected");
// Work well with Get Method
// strcat(message, "GET /voleur/receiver.php?arg1=Hello HTTP/1.1\n");
strcat(message, "POST /voleur/receiver.php HTTP/1.1\n");
strcat(message, "Host: 127.0.0.1\n");
strcat(message, "Connection: close\n");
strcat(message, "Content-Type:application/octet-stream\n");
strcat(message, "Content-Encoding:binary\n");
strcat(message, "Content-Length:16\n");
strcat(message, "Accept-Charset: utf-8\n\n");
if( send(s , message , strlen(message) , 0) < 0)
{
puts("Send failed");
return 1;
}
// My argument
char *data = "arg1=Hello";
send(s , data , strlen(data), 0);
puts("Data Send\n");
//Receive a reply from the server
if((recv_size = recv(s , server_reply , 2000 , 0)) == SOCKET_ERROR)
{
puts("recv failed");
}
puts("Reply received\n");
//Add a NULL terminating character to make it a proper string before printing
server_reply[recv_size] = '\0';
puts(server_reply);
return 0;
}
First:
You should reformat your HTTP header:
strcat(message, "Content-Type:application/octet-stream\n");
strcat(message, "Content-Encoding:binary\n");
strcat(message, "Content-Length:16\n");
should be
strcat(message, "Content-Type: application/octet-stream\n");
strcat(message, "Content-Encoding: binary\n");
strcat(message, "Content-Length: 16\n");
Second:
As far as I can see, your problem lies within the following lines:
strcat(message, "Content-Length: 16\n");
[...]
char *data = "arg1=Hello";
send(s , data , strlen(data), 0);
because you declare there will be 16 bytes of data - but you only send 10 bytes, which will cause the server to wait for the remaining 6 bytes.

C-code, simple web server (Code OK)

I have a problem with my code about web server
#include<netinet/in.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<unistd.h>
int main() {
int create_socket, new_socket;
socklen_t addrlen;
int bufsize = 1024;
char *buffer = malloc(bufsize);
struct sockaddr_in address;
if ((create_socket = socket(AF_INET, SOCK_STREAM, 0)) > 0){
printf("The socket was created\n");
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(15000);
if (bind(create_socket, (struct sockaddr *) &address, sizeof(address)) == 0){
printf("Binding Socket\n");
}
while (1) {
if (listen(create_socket, 10) < 0) {
perror("server: listen");
exit(1);
}
if ((new_socket = accept(create_socket, (struct sockaddr *) &address, &addrlen)) < 0) {
perror("server: accept");
exit(1);
}
if (new_socket > 0){
printf("The Client is connected...\n");
}
recv(new_socket, buffer, bufsize, 0);
printf("%s\n", buffer);
write(new_socket, "hello world\n", 12);
close(new_socket);
}
close(create_socket);
return 0;
}
this is a little code to create a web server that at the port 15000 reply with "hello wordl" . Now i would that my server at a request (for example) "http://127.0.0.1:15000/luigi" reply with the text "luigi",that is with the phrase after " / ". Thanks!
After recv function, you will have something like
GET /luigi HTTP/1.1
in buffer.This is the request sent by browser.
Text after GET is the relative url to your base address (127.0.0.1:15000). Now you can parse the buffer and do whatever you want.You can go to http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html for more details.
To add up to what user3864685 said, you can use 'strtok' function to get the string after "GET /".

UDP Sockets in C: client1 to server to client2

I have a UDP client/server that sends a message to a server in lower or uppercase. The server receives the message and relays it back with switched cases. I can't figure out how I would instead of having the server relay it back to the first client, instead sending it to a client2. If my client2 sends a message the server receives and sends it back to client2 and same thing with client1. I want what client1 says to be sent to the server and then the server send that to client2. I've tried everything i can think of but cant figure out.
Server:
/*
Simple udp server
*/
#include<stdio.h> //printf
#include<string.h> //memset
#include<stdlib.h> //exit(0);
#include<arpa/inet.h>
#include<sys/socket.h>
#include<ctype.h>
#define BUFLEN 512 //Max length of buffer
#define PORT 8888 //The port on which to listen for incoming data
void die(char *s)
{
perror(s);
exit(1);
}
int main(void)
{
struct sockaddr_in si_me, si_other, si_other2;
int s, i, slen = sizeof(si_other) , recv_len;
char buf[BUFLEN];
//create a UDP socket
if ((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
{
die("socket");
}
// zero out the structure
memset((char *) &si_me, 0, sizeof(si_me));
si_me.sin_family = AF_INET;
si_me.sin_port = htons(PORT);
si_me.sin_addr.s_addr = htonl(INADDR_ANY);
//bind socket to port
if( bind(s , (struct sockaddr*)&si_me, sizeof(si_me) ) == -1)
{
die("bind");
}
//keep listening for data
while(1)
{
printf("Waiting for data...");
fflush(stdout);
//try to receive some data, this is a blocking call
if ((recv_len = recvfrom(s, buf, BUFLEN, 0, (struct sockaddr *) &si_other, &slen)) == -1) // read datagram from server socket
{
die("recvfrom()");
}
//print details of the client/peer and the data received
printf("Received packet from %s:%d\n", inet_ntoa(si_other.sin_addr), ntohs(si_other.sin_port)); printf("Data: %s\n" , buf);
//now reply to server socket/the client with the same data
if (sendto(s, buf, recv_len, 0, (struct sockaddr*) &si_other, slen) == -1)
{
die("sendto()");
}
}
close(s);
return 0;
}
The Client:
/*
Simple udp client
*/
#include<stdio.h> //printf
#include<string.h> //memset
#include<stdlib.h> //exit(0);
#include<arpa/inet.h>
#include<sys/socket.h>
#include<ctype.h>
#define SERVER "192.x.x.x"
#define BUFLEN 512 //Max length of buffer
#define PORT 8888 //The port on which to send data
void die(char *s)
{
perror(s);
exit(1);
}
int main(void)
{
struct sockaddr_in si_other;
int s, s2, i, slen=sizeof(si_other);
char buf[BUFLEN];
char message[BUFLEN];
if ( (s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) // create a client socket
{
die("socket");
}
memset((char *) &si_other, 0, sizeof(si_other));
si_other.sin_family = AF_INET;
si_other.sin_port = htons(PORT);
if (inet_aton(SERVER , &si_other.sin_addr) == 0) // Create datagram with server IP and port.
{
fprintf(stderr, "inet_aton() failed\n");
exit(1);
}
while(1)
{
printf("Enter message : ");
gets(message);
int a;
char message2[BUFLEN];
for(a=0;a<=BUFLEN-1;a++)
{
if(message[a] >= 97 && message[a] <= 122)
message2[a] = toupper(message[a]);
else
message2[a] = tolower(message[a]);
}
if (sendto(s, message2, strlen(message2) , 0 , (struct sockaddr *) &si_other, slen)==-1)
{
die("sendto()");
}
//receive a reply and print it
//clear the buffer by filling null, it might have previously received data
memset(buf,'\0', BUFLEN);
//try to receive some data, this is a blocking call
if (recvfrom(s, buf, BUFLEN, 0, (struct sockaddr *) &si_other, &slen) == -1) // read datagram from client socket
{
die("recvfrom()");
}
puts(buf);
}
close(s);
return 0;
}
It seems instead of a UDP server, you want to have a forwarder of packets like from client->server->client2, so you need to tell your server the ipaddress/port of client2, for this kindly configure client2 ip/port in server either using commandline arguments or read any input file, then before the sendto statement in server code, fill the si_other structure with client2 information as teken from command line or input file.
After you read() or recvfrom() your message, you process your data and then sendto() twice: one to the address returned by recvfrom() (the original sender) and other to the other client's address (which must be provided or detected somehow by your server).
Something along this (proper error checking not being performed):
char data[100];
struct sockaddr_in address;
socklen_t length = sizeof address;
/* Receive data from any client. */
ssize_t result = recvfrom(server, data, sizeof data, 0, &address, &length);
/* Process the data (change cases). */
process_data(data, result);
/* Send back to the first client. */
sendto(server, data, result, 0, &address, sizeof address);
/* Check who's the sender and relay to the other. */
if (address.sin_addr.s_addr == CLIENT1_ADDRESS)
address.sin_addr.s_addr = CLIENT2_ADDRESS;
else
address.sin_addr.s_addr = CLIENT1_ADDRESS;
/* Send to the other client. */
sendto(server, data, result, 0, &address, sizeof address);
In this example, the addresses are statically defined.

Resources