I am very new to socket programming and I have troubles with it. I want to implement a server that answers depending on a certain client request. In my case, either GET, HEAD or an error else. Consider following code
If I print the answer before calling send() (see server side code below), the message is correct. But let's say from the client I send
GET
HEAD
GET
test
GET
, the answer printed from the client side is
You want GET
You want HEAD
You want GETD
HTTP/1.1 400 Bad Request
You want GET Bad Request
So it seems like that the message sent from the server is kind of 'overwritten', but how is this avoidable? Is it possible to 'clear the server buffer' if that is the problem at all?
Here is the full server side code
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#define BUFSIZE 1024
#define MAXPENDING 100
int main(){
char get[] = "GET";
char head[] = "HEAD";
int serverSocket = socket(PF_INET, SOCK_STREAM, 0);
struct sockaddr_in serverAddress;
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = htons(8080);
serverAddress.sin_addr.s_addr = htonl(INADDR_ANY);
memset(&serverAddress.sin_zero, '\0', 8);
bind(serverSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress));
listen(serverSocket, MAXPENDING);
for(;;){
struct sockaddr_in clientAddress;
int clientAddressLength = sizeof(clientAddress);
int clientSocket;
clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddress, &clientAddressLength);
char buf[BUFSIZE];
int bytesRec;
bytesRec = recv(clientSocket, buf, BUFSIZE, 0);
while(bytesRec > 0){
char *result;
result = strtok(buf, " ");
printf("result %s\n", result);
if(strcmp(&buf, &get) == 0){
char answer[] = "You want GET";
send(clientSocket, answer, strlen(answer), 0);
}else{
if(strcmp(&buf, &head) == 0){
char answer[] = "You want HEAD";
send(clientSocket, answer, strlen(answer), 0);
}else{
char answer[] = "HTTP/1.1 400 Bad Request";
send(clientSocket, answer, strlen(answer), 0);
}
}
bytesRec = recv(clientSocket, buf, BUFSIZE, 0);
}
return 0;
}
and the client side
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
int main(){
int clientSocket = socket(PF_INET, SOCK_STREAM, 0);
struct sockaddr_in clientAddress;
clientAddress.sin_family = AF_INET;
clientAddress.sin_port = 0;
clientAddress.sin_addr.s_addr = htonl(INADDR_ANY);
memset(&clientAddress.sin_zero, '\0', 8/*sizeof(clientAddress.sin_zero)*/);
bind(clientSocket, (struct sockaddr*)&clientAddress, sizeof(clientAddress));
struct sockaddr_in serverAddress;
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = htons(8080);
serverAddress.sin_addr.s_addr = inet_addr("127.0.0.1");
memset(&serverAddress.sin_zero, '\0', 8);
if(connect(clientSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) == -1){
printf("error in connecting!\n");
return 0;
}
char* serverReply[1024];
for(;;){
char request[100];
printf("Enter your request: ");
scanf("%s", &request);
send(clientSocket, request, strlen(msg), 0);
if(recv(clientSocket, serverReply, strlen(serverReply), 0) < 0){
printf("failure in receiving from server!\n");
}else{
printf("%s\n", serverReply);
}
}
close(clientSocket);
return 0;
}
send(clientSocket, request, strlen(msg), 0);
This sends only the string characters and does not include the terminating NULL. The receive buffer does not terminate the received string on the server side.
This is why you are still seeing the 'D' character from the previous message.
You want GETD <-- 'D' is from the previous 'HEAD'
Either terminate the received string on the server,
buf[bytesRec] = '\0';
Edit: as #Zan points out, don't do this:
or send the NULL terminator from the client.
send(clientSocket, request, strlen(msg) + 1, 0);
Your strcmp() in if are wrong
(1) instead of buf you need to compare with result as I can understand from you question, do like: (you says in comment that result printed as GET)
if(strcmp(result, get) == 0){
(2) As #phihag answered it should be
if(strcmp(buf, get) == 0){
^ ^remove &
similar error you have on every strcmp(), because buf, get, head all are charter arrays.
(3) recv() doesn't terminates the read buffer so its better to add null (\0) before you work with it (as i can notice you are using buff as string)
do like:
bytesRec = recv(clientSocket, buf, BUFSIZE, 0);
buf[bytesRec] = '\0'
infect you should read only BUFSIZE-1 bytes left one for null '\0' symbol like:
ytesRec = recv(clientSocket, buf, BUFSIZE-1, 0);
buf[bytesRec] = '\0'
Related
I have a piece of C code that should connect to www.google.com and make a HTTP GET request, but when I run it, it stays on "Connecting.." for about 30 seconds before returning "Connection Failed" and an exit return value of 255. What am I doing wrong?
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define PORT 8000
struct hostent *hostinfo;
int main(void) {
int sock = 0, valread;
struct sockaddr_in serv_addr;
char *hostname = "www.google.com";
char *request = "GET / HTTP/1.1\r\nHost: www.google.com\r\n\r\n";
hostinfo = gethostbyname(hostname);
char *ip = inet_ntoa(*(struct in_addr*)hostinfo->h_addr_list[0]);
char buffer[1024] = {0};
printf("Creating socket...\n");
if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0){
printf("\n Socket creation error \n");
return -1;
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
printf("Checking address...\n");
if(inet_pton(AF_INET, ip, &serv_addr.sin_addr) <= 0){
printf("\n Invalid IP/Address not supported \n");
return -1;
}
printf("Connecting to host %s...\n", ip);
if(connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0){
printf("\n Connection Failed \n");
return -1;
}
send(sock, request, strlen(request), 0);
printf("Message sent\n");
valread = read(sock, buffer, 1024);
printf("%s\n", buffer);
return 0;
}
I see two major problems.
You use the wrong port. Use port 80 for http.
Your read and printf is a dangerous combination that could easily cause access out of bounds (and undefined behavior). What you read from the socket will not be null terminated. You could instead do something like this:
...
printf("Message sent\n");
while((valread = read(sock, buffer, sizeof(buffer))) > 0) {
fwrite(buffer, valread, 1, stdout);
}
This will however block when everything has been read. See non-blocking I/O or consider using select, epoll or poll to wait for available data on sockets.
If you are only interested in getting the response and then disconnect, you could however use Connection: close to close the connection after the server has sent the response. Full code below:
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define PORT 80
int main(void) {
int sock = 0, valread;
struct hostent *hostinfo;
struct sockaddr_in serv_addr;
const char *hostname = "www.google.com";
const char *request = "GET / HTTP/1.1\r\n"
"Host: www.google.com\r\n"
"Connection: close\r\n\r\n"; // <- added
hostinfo = gethostbyname(hostname);
char *ip = inet_ntoa(*(struct in_addr*)hostinfo->h_addr_list[0]);
char buffer[1024] = {0};
printf("Creating socket...\n");
if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0){
printf("\n Socket creation error \n");
return -1;
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
printf("Checking address...\n");
if(inet_pton(AF_INET, ip, &serv_addr.sin_addr) <= 0){
printf("\n Invalid IP/Address not supported \n");
return -1;
}
printf("Connecting to host %s...\n", ip);
if(connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0){
perror("connect()");
return -1;
}
send(sock, request, strlen(request), 0);
printf("Message sent\n");
while((valread = read(sock, buffer, sizeof(buffer))) > 0) {
fwrite(buffer, valread, 1, stdout);
}
}
I would like to convert a string to an integer, but the string will have a whitespace (maximum 9 characters). Here is an example of what I'm trying to do:
char* pointer = (char *) malloc(10);
int num = 10, newnum;
sprintf(pointer, "%10d", num);
//Convert pointer to integer here, assign it to newnum variable;
printf("New integer is: %d", newnum);
Output:
New integer is 10
I have tried using the atoi function but it is returning zero every time for some reason. If you need me to include the code in which it is returning zero, I'd be happy to do so, as this could very much be my error and not on the function. Here is the code (this is a reverse shell, so there is a client and a server, the problem is in the server, but it could be the client, I don't know):
Server
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#define PORT 4583
int main(){
int sock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in server;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(PORT);
server.sin_family = AF_INET;
bind(sock, (struct sockaddr *) &server, sizeof(server));
listen(sock, 2);
int client = accept(sock, NULL, NULL);
ssize_t size;
int i, length;
while (1){
char * command = (char *) malloc(75);
char * output = (char * ) malloc (10001);
char* lengths = (char *) malloc(11);
printf(">> ");
fgets(command, 75, stdin);
send(client, command, strlen(command), 0);
recv(client, lengths, 11, 0);
printf("Length: %s\n", lengths);
length = atoi(lengths);
printf("%d", length);
recv(client, output, length+1, 0);
printf("%s\n", output);
free(command);
free(output);
free(lengths);
}
return 0;
}
Client
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define PORT 4583
int main(){
int sock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in server;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(PORT);
server.sin_family = AF_INET;
connect(sock, (struct sockaddr *) &server, sizeof(server));
int commandlen;
while (1){
char* command = (char *) malloc(75);
char* output = (char *) malloc (5000);
recv(sock, command, 75, 0);
commandlen = strlen(command);
if (*command == 'c' && *(command+1) == 'd'){
command[commandlen-1] = '\0';
int stat = chdir(command+3);
if (stat != 0){
output = strerror(errno);
send(sock, output, 5000, 0);
}
}else{
char* fullmsg = (char *) malloc(10001);
char* length = (char *) malloc(11);
FILE * cmd = popen(command, "r");
while (fgets(output, 5000, cmd) != NULL){
strcpy(fullmsg+(strlen(fullmsg)), output);
}
sprintf(length, "%10zu", strlen(fullmsg));
send(sock, length, 11, 0);
send(sock, fullmsg, 10001, 0);
pclose(cmd);
free(length);
free(fullmsg);
}
free(output);
free(command);
}
return 0;
}
The problem is that the client sends more data than the server reads:
In client code:
send(sock, fullmsg, 10001, 0);
In server code:
recv(client, output, length+1, 0);
^^^^^^^^
Less than 10001
The client should only send the valid bytes - something like:
send(sock, fullmsg, strlen(fullmsg) + 1, 0);
There are many problems in your code. To start with, you did not point pointer to any valid memory, so attempt to write into the memory will invoke undefined behaviour. You must make the pointer point to a valid block of memory long enough to hold the final result.
That said, you should check for the return value of the function call (specially library functions) to ensure they are successful, before using the return value / buffers filled by them.
I'm trying to send a modified string over sockets. The goal is to take a string from the client, add something to it, then send it back. The strings are passed in command line arguments. Right now, I can receive the message from the client, but for some reason my recvfrom function is returning -1 which causes the client to get hung up and not receive the sendto from the server. It seems like the server is modifying the string fine, but I can't get it to receive correctly on the other side. I have print statements in my code for testing purposes. The command line arguments for the client are server name, port number, string. The command line arguments for the server are port number, string to concatenate. Below is my code:
headerFiles.h:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/wait.h>
server.c:
#include "headerFiles.h"
int main(int argc, char* argv[])
{
int s;
int len;
char buffer[256];
struct sockaddr_in servAddr;
struct sockaddr_in clntAddr;
int clntAddrLen;
int serverPort;
char catStringMeow[256];
serverPort = atoi(argv[1]);
strcpy(catStringMeow, argv[2]);
// Build local (server) socket address
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_port = htons(serverPort);
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
// Create socket
if((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("Error: socket failed!");
exit(1);
}
// Bind socket to local address and port
if((bind(s, (struct sockaddr*)&servAddr, sizeof(servAddr)) < 0))
{
perror("Error: bind failed!");
exit(1);
}
for(;;) // Runs forever
{
printf("buffer = %s\n", buffer);
printf("In for\n");
// Receive String
len = recvfrom(s, buffer, sizeof(buffer), 0, (struct sockaddr*)&clntAddr, &clntAddrLen);
printf("Received %d bytes\n", len);
printf("buffer = %s\n", buffer);
strcat(buffer, " ");
strcat(buffer, catStringMeow);
printf("New string = %s\n",buffer);
printf("buffer size = %d\n", (int)strlen(buffer));
len = (int)strlen(buffer);
// Send String
sendto(s, buffer, len, 0, (struct sockaddr*)&clntAddr, sizeof(clntAddr));
printf("Sent %d bytes\n", len);
}
}
client.c:
#include "headerFiles.h"
int main (int argc, char* argv[]) // Three arguments to be checked later
{
int s; // Socket descriptor
int len; // Length of string to be echoed
char* servName; // Server name
int servPort; // Server port
char* string; // String to be echoed
char buffer[256+1]; // Data buffer
struct sockaddr_in servAddr; // Server socket address
// Check and set program arguments
if(argc != 4)
{
printf("Error: three arguments are needed!\n");
exit(1);
}
servName = argv[1];
servPort = atoi(argv[2]);
string = argv[3];
// Build server socket address
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = AF_INET;
inet_pton(AF_INET, servName, &servAddr.sin_addr);
servAddr.sin_port = htons(servPort);
// Create socket
if((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("Error: Socket failed!");
exit(1);
}
// Send echo string
len = sendto(s, string, strlen(string), 0, (struct sockaddr*) &servAddr, sizeof(servAddr));
printf("Sent %d bytes\n", len);
// Receive echo string
len = recvfrom(s, buffer, len, 0, NULL, NULL);
printf("Received\n");
//Print and verify echoed string
buffer[len] = '\0';
printf("Echo string received: ");
fputs(buffer, stdout);
printf("\n");
// Close the socket
close(s);
// Stop the program
exit(0);
}
do
// Receive echo string
len = recvfrom(s, buffer, sizeof(buffer), 0, NULL, NULL);
printf("Received\n");
and make buffer bigger.
You're passing an uninitizlied clntAddrLen value to recvfrom, which is resulting in the Invalid argument error code. According to the documentation:
The argument addrlen is a value-result argument, which the caller should initialize before the call to the size of the buffer associated with src_addr, and modified on return to indicate the actual size of the source address.
So you need to initialize it with:
clntAddrLen = sizeof(clntAddr);
Make sure you initialize the client address length variable before using it in sendto or recvfrom.
The problem is that on the first calling to sendto from client.c, the servers sees the client's ip as 0.0.0.0, after that on the second, third,... calls the client.c get an ip and have a legal ip such as 127.0.0.3:3212.
You can see that second, third, ... clients work.
Initialize length variable to sizeof(struct sockaddr_in)
I'm writing a simple proxy using socket programming and C.
I have a problem in getting HTTP response from the webserver. When I run this code and try to visit cisco.com website, my program gives me a segmentation fault error.
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
int main()
{
int serverSocket;
char ip[INET_ADDRSTRLEN];
int i;
int j;
serverSocket = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in serverAddress ;
char pageFilter[] = "HTTP/1.1 302 Found\n\n<html><head><title>this web page is filter !..!</title></head><body><h1>This page in filter</h1><p><h3>Please Leave This site and get out of here!</h3></p></body></html>";
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = htons(9090);
bind(serverSocket, (struct sockaddr *)&serverAddress, sizeof(serverAddress));
listen(serverSocket, 20);
while (1)
{
int clientSocket ;
int size;
struct sockaddr_in clientAddress;
char * pch;
char * site;
char buffer[9000];
size = sizeof(clientAddress);
clientSocket = accept(serverSocket, (struct sockaddr *)&clientAddress, &size);
recv(clientSocket, buffer, sizeof(buffer), 0);
site = strstr(buffer, "yahoo.com");
if(site != NULL)
{
send(clientSocket, pageFilter, sizeof(pageFilter) ,0);
close(clientSocket);
}
else
{
int middleSocket;
char buf[128];
char response[10000];
struct sockaddr_in middleAddress;
struct hostent *he;
struct in_addr **addr_list;
char site[] = "cisco.com";
middleSocket = socket(AF_INET, SOCK_STREAM, 0);
middleAddress.sin_family = AF_INET;
middleAddress.sin_port = htons(80);
he = gethostbyname(site);
addr_list = (struct in_addr **)he -> h_addr_list;
middleAddress.sin_addr.s_addr = inet_addr(inet_ntoa(*addr_list[0]));
connect(middleSocket, (struct sockaddr *)&middleAddress, sizeof(middleAddress));
send(middleSocket, buffer, sizeof(buffer),0);
while((unsigned)strlen(buf) != 0)
{
recv(middleSocket, buf, sizeof(buf), 0);
strcat(response,buf);
}
send(clientSocket, response, strlen(response),0);
close(clientSocket);
}
}
return 0;
}
First, capture the return value of recv, which either indicates an error, or the number of bytes received.
ssize_t n;
n = recv(middleSocket, buf, sizeof(buf) - 1);
Note that you shouldn't pass sizeof(buf), since you need room to guarantee zero-termination of buf.
Check for errors.
if (n == -1) { /* handle error */ }
else if (n == 0) { /* handle empty response */ }
And zero-terminate buf.
buf[n] = '\0';
Your segmentation fault is probably occurring because you call strstr on an unbounded string.
A segmentation fault is caused by invalid memory access. Read more: http://en.wikipedia.org/wiki/Segmentation_fault
Use GDB to find the where exactly the program is executing when the error occurs. After this, you should see the problem in your code.
I'm trying to write simple client and server based on sockets in C.
The client sends the size of the char array (including last cell for '\0') and then array of chars.
Server gets the size and tries to allocate memory for the array of chars from the client.
After this, the server looks for a space and copy the characters from index 0 to space, pastes it at the end of the array and sends it back to the client (if there is no space, then the server sends doubled array).
I've noticed that sometimes I'm getting
--
|00|
|02|
--
char at the end of the received array from the server.
I've run the server and the client using valgrind and it showed that problem is in the server.
Code below.
Client:
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
int
main ()
{
int sockfd;
socklen_t len;
struct sockaddr_in address;
int result;
char ch;
char *string;
int i;
sockfd = socket (AF_INET, SOCK_STREAM, 0);
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr ("127.0.0.1");
address.sin_port = htons (9734);
len = sizeof (address);
result = connect (sockfd, (struct sockaddr *) &address, len);
if (result == -1)
{
perror ("oops: netclient");
exit (1);
}
string = (char*)malloc(sizeof(char));
for (i =0; ch = getchar(); i++)
{
string = (char*)realloc(string, (i+1)*sizeof(char));
if(ch != '\n')
string[i] = ch;
else if (ch == '\n')
{
string[i]='\0';
break;
}
}
printf("%s\n", string);
printf("%d\n", i);
i=i+1;
write (sockfd, &i, 4);
write (sockfd, string, i);
read (sockfd, &i, 4);
string = (char*)realloc(string, i*sizeof(char));
read (sockfd, string, i);
printf("String recieved: %s\n", string);
close (sockfd);
free(string);
exit (0);
}
And server:
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
int
main ()
{
int server_sockfd, client_sockfd;
socklen_t server_len, client_len;
struct sockaddr_in server_address;
struct sockaddr_in client_address;
server_sockfd = socket (AF_INET, SOCK_STREAM, 0);
server_address.sin_family = AF_INET; /*ipv4*/
server_address.sin_addr.s_addr = htonl (INADDR_ANY);
server_address.sin_port = htons (9734);
server_len = sizeof (server_address);
bind (server_sockfd, (struct sockaddr *) &server_address, server_len);
listen (server_sockfd, 5);
signal (SIGCHLD, SIG_IGN);
while (1)
{
char *string;
int i, j, k, l=0; /*variables to iteration*/
printf ("server waiting\n");
client_len = sizeof (client_address);
client_sockfd = accept (server_sockfd,
(struct sockaddr *) &client_address,
&client_len);
if (fork () == 0)
{
read (client_sockfd, &i, 4);
printf("recieved int %d\n", i);
string = (char*)malloc(sizeof(char) * (i));
read (client_sockfd, string, i);
printf("\nSTRING recieved: %s \n", string);
for(j=0; string[j]!='\0'; j++)
{
if(string[j] == ' ')
{
i = i+j; /*size to enlarge*/
break;
}
}
/*sending new size*/
write(client_sockfd, &i, 4);
/*enlarge the string*/
string = (char*)realloc(string, i*sizeof(char));
for (k = i-j-1; k < i-1 ; k ++)
{
string[k] = string[l];
l++;
}
string[k+1] = '\0';
write(client_sockfd, string, i);
close (client_sockfd);
free(string);
exit (0);
}
else
{
close (client_sockfd);
}
}
}
Your code ignores the return value of read():
read (client_sockfd, &i, 4);
You must not ignore this value. The socket interface does not guarantee that just because you asked for 4 bytes, that you will actually get 4 bytes back. The socket interface only guarantees that you will get at least one byte back. You must continue calling read() until you get all the bytes that you want.
The same goes for when you read the string a couple of lines later.
Even though your program may appear to work now, this is the sort of problem that will suddenly appear in unpredictable situations like a busy machine or network, you won't be able to reproduce it, and your program will become unreliable.