So I have been writing a proxy server (following Beej's guide to network programming) and now I have stumble upon a problem It seems I can't solve.. Driving me crazy..
The problem is it drops some packets due to "Connection reset by peer" when it is going to forward packets to the webclient.
Here is the full code.
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#include <string>
#include <unistd.h>
using namespace std;
string replace_string(string str, const string from, const string to) {
size_t start_pos = str.find(from);
if(start_pos == string::npos)
return str;
str.replace(start_pos, from.length(), to);
return str;
}
void sigchld_handler(int s)
{
while(waitpid(-1, NULL, WNOHANG) > 0);
}
class Server
{
private:
string PORT;
int MAXDATASIZE;
public:
Server()
{
PORT = "3490";
MAXDATASIZE = 4096;
}
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int start_server()
{
// first, load up address structs with getaddrinfo():
int socketfd, new_socketfd;
struct addrinfo hints, *servinfo, *p;
struct sockaddr_storage their_addr;
socklen_t their_addr_size, addr_size;
struct sigaction sa;
char s[INET6_ADDRSTRLEN];
int rv;
int yes = 1;
int BACKLOG = 10;
int numbytes;
unsigned char buf[MAXDATASIZE];
memset(&hints, 0, sizeof hints); // Make sure it is cleared
hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever
hints.ai_socktype = SOCK_STREAM; // TCP socket
hints.ai_flags = AI_PASSIVE; // fill in my IP for me
if ((rv = getaddrinfo(NULL, PORT.c_str(), &hints, &servinfo)) != 0) {
cerr << "getaddrinfo: " << gai_strerror(rv) << endl;
return -1;
}
// make a socket, bind it asap
for(p = servinfo; p != NULL; p = p->ai_next)
{
if ((socketfd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
//perror("server: socket");
cerr << "ERROR: Server: socket" << endl;
continue;
}
if (setsockopt(socketfd, SOL_SOCKET, SO_REUSEADDR, &yes,
sizeof(int)) == -1) {
//perror("setsockopt");
cerr << "ERROR: setsockopt" << endl;
exit(1);
}
if (bind(socketfd, p->ai_addr, p->ai_addrlen) == -1) {
close(socketfd);
//perror("server: bind");
cerr << "ERROR: server: bind" << endl;
continue;
}
break;
}
//If the binding failed
if ( p == NULL)
{
cerr << "Server: failed to bind" << endl;
return -1;
}
//Free space, we do not need it anymore.
freeaddrinfo(servinfo);
//Listen to the socket (port)
if ( listen(socketfd, BACKLOG) == -1)
{
cerr << "ERROR: listen" << endl;
}
// killing zombie processs (all dead processes)
sa.sa_handler = sigchld_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
perror("sigaction");
exit(1);
}
cout << "Server: waiting for connections ...\n"<<endl;
//Main loop
for(;;)
{
their_addr_size = sizeof their_addr;
//Create a new socket when we got a connection
if ((new_socketfd = accept(socketfd, (struct sockaddr *)&their_addr, &their_addr_size))== -1) {
continue;
}
//Converts IP address to 127.0.0.1 (or IPv6 format..) format instead of binary
inet_ntop(their_addr.ss_family,get_in_addr((struct sockaddr *)&their_addr), s, sizeof s);
if ((numbytes = recv(new_socketfd, buf, MAXDATASIZE-1, 0)) == -1) {
cerr << "ERROR: Failed to receive from user-agent" << endl;
exit(1);
}
else
{
/*Parse the header and change some things.*/
string buffer_str(reinterpret_cast<char*>(buf), MAXDATASIZE); // Convert to unsigned char array to make it easier to handle
buffer_str = replace_string(buffer_str, "Proxy-Connection: keep-alive","Connection: close"); // Make it connection Close instead of Keep-Alive
buffer_str = replace_string(buffer_str, "Connection: keep-alive","Connection: close"); // Make it connection Close instead of Keep-Alive
// removes host from GET, and saves it
int first = buffer_str.find_first_of("/");
int last = buffer_str.find_first_of("/", first+2);
int size_of_buf=buffer_str.size();
unsigned char host_request[MAXDATASIZE];
for (int a=0;a<=size_of_buf;a++)
host_request[a]=buffer_str[a];
host_request[size_of_buf]='\0';
string host_name = "";
for(int i=first+2;i<last;++i)
host_name += buffer_str[i];
buffer_str.erase(4, buffer_str.find_first_of("/", first+2)-4);
/*Set up the socket for the proxy-host */
int host_sockfd, host_numbytes;
unsigned char host_buf[MAXDATASIZE];
struct addrinfo host_hints, *host_servinfo, *host_p;
int host_rv;
char host_s[INET6_ADDRSTRLEN];
memset(&host_hints, 0, sizeof(host_hints));
host_hints.ai_family = AF_UNSPEC;
host_hints.ai_socktype = SOCK_STREAM;
if ((rv = getaddrinfo(host_name.c_str(), "80", &host_hints, &host_servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop through all the results and connect to the first we can
for(host_p = host_servinfo; host_p != NULL; host_p = host_p->ai_next) {
if ((host_sockfd = socket(host_p->ai_family, host_p->ai_socktype,
host_p->ai_protocol)) == -1) {
perror("client: socket");
continue;
}
if (connect(host_sockfd, host_p->ai_addr, host_p->ai_addrlen) == -1) {
close(host_sockfd);
perror("client: connect");
continue;
}
break;
}
if (host_p == NULL) {
fprintf(stderr, "client: failed to connect\n");
return 2;
}
inet_ntop(host_p->ai_family, get_in_addr((struct sockaddr *)host_p->ai_addr),s, sizeof s); //Converts the IP address from binary to IPv4/6-format
//printf("client: connecting to %s\n", s);
freeaddrinfo(host_servinfo); // all done with this structure
/*Send the GET request to the server*/
send_message(host_sockfd, host_request, sizeof(host_request), "Webserver");
if (!fork())
{
memset(&host_buf, 0, MAXDATASIZE);
while (recv(host_sockfd, &host_buf, MAXDATASIZE, 0) > 0 ) {
close(socketfd);
send_message(new_socketfd, (unsigned char *)host_buf, MAXDATASIZE, "Browser");
memset(&host_buf, 0, MAXDATASIZE);
}
}
close(host_sockfd);
}
//cout << "server: got connection from " << s << endl;
close(new_socketfd); // parent doesn't need this
}
return 1;
}
int send_message(int &socket,unsigned char msg[], int length, string too)
{
usleep(10);
if (send(socket, msg, length, 0) == -1)
{
cerr << "ERROR: sending to " << too << endl;
cerr << "We will lose a packet due to" << endl;
perror("send");
cerr << "-------------------MEDDELANDE-------------------\n\n" << msg << endl <<
"--------------------------------------------------\n\n";
return -1;
}
return 1;
}
};
int main()
{
Server srv;
srv.start_server();
}
Any ideas? Thanks in advance!