I am using sys/socket.h for sending heartbeats to a server repeatedly.
Connection work fine. Problem occurs when server restart.
This is my code.
bool HbClient::start(const char *address, int port)
{
//create socket if it is not already created
if(sock == -1)
{
sock = socket(AF_INET , SOCK_STREAM , 0);
if (sock == -1)
{
printf("Could not create socket object");
return false;
}
printf("Socket object created\n");
}
server.sin_addr.s_addr = inet_addr( address );
server.sin_family = AF_INET;
server.sin_port = htons( port );
return connect_to_server();
}
bool HbClient::connect_to_server()
{
int status = connect(sock , (struct sockaddr *)&server , sizeof(server));
cout << "returned status: " << status << endl << flush;
if (status < 0)
{
cout << "Error. Connection failed." << endl << flush;
return false;
}
cout << "Connected to server" << endl << flush;
return true;
}
bool HbClient::send_data(const char *data)
{
int res = send(sock , data , strlen(data) , MSG_NOSIGNAL);
if( res < 0)
{
cout << "Data sending failed, status: " << res << endl << flush;
start("127.0.0.1", 9090);
return false;
}
cout << "Data send" << endl << flush;
return true;
}
send_data() function is invoked repeatedly. Until server restart this works fine. But when server restart these outputs were printed repeatedly.
Data sending failed, status: -1
returned status: -1
Error. Connection failed.
I am using Ubuntu 16.04 OS and g++ compiler. Can you point out what the issue here?
Close socket and set it to -1 before reconnecting. So modify your send_data function like this:
close(sock);
sock = -1;
start("127.0.0.1", 9090);
Also socket function always return -1 on failure. You should print errno instead of returned code
Related
void TCPConnectionV5::startServer()
{
/* Initialize Winsock */
int start;
sockaddr_in SERVER;
SERVER.sin_family = AF_INET;
SERVER.sin_addr.s_addr = INADDR_ANY;
//SERVER.sin_port = htons(stoi(DEFAULT_PORT));
SERVER.sin_port = htons(1787);
start = WSAStartup(MAKEWORD(2, 2), &_wsaData);
if (start != 0)
{
cout << "Error on WSAStartup: " << start << endl;
}
/* Create socket that will connect to server */
_listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
_socketCollection.push_back(_listener);
if (_listener == INVALID_SOCKET)
{
cout << "Error creating socket to connect to server: " << WSAGetLastError() << endl;
WSACleanup();
}
/* Bind the socket */
start = bind(_listener, (sockaddr*)&SERVER, sizeof(SERVER));
if (start == SOCKET_ERROR)
{
cout << "Error on bind:" << WSAGetLastError() << endl;
closesocket(_listener);
WSACleanup();
}
/* Create the listener socket */
start = listen(_listener, 16);
if (start == SOCKET_ERROR)
{
cout << "Error on entering the listening state: " << start << endl;
closesocket(_listener);
WSACleanup();
}
printTime();
cout << "Server entered listening state" << endl;
/* Create the thread */
sockaddr_in client;
int clientSize = sizeof(client);
while (true)
{
SOCKET messager = accept(_listener, (struct sockaddr*)&client, &clientSize);
_socketCollection.push_back(messager);
locker.lock();
printTime();
if (messager != SOCKET_ERROR)
{
cout << "Client Connection success!" << endl;
cout << "Messager: " << messager << endl;
locker.unlock();
std::thread newThread([&] {this->exchange(messager); });
newThread.detach();
}
else
{
locker.unlock();
}
}
}
DWORD TCPConnectionV5::exchange(SOCKET messager)
{
int bytesSent = sendMessage(messager, msg);
if (bytesSent <= 0)
{
closesocket(messager);
return -1;
}
int bytesReceived = receiveMessage(messager);
if (bytesReceived <= 0)
{
closesocket(messager);
return -1;
}
}
I noticed that when the server connects with multiple clients, that there sometimes appear to be duplicate messages that send to some clients, which is accompanied by missing messages to another client application. I have mutex lock/unlock in place for sending/receiving messages, but what's causing these duplicate/missing messages? Is there some underlying issue I have to address regarding the threads?
I am working on a remote client program for Windows that sends data from a sensor unit to a server application over ethernet / internet connection. The client logs into the server with a username and password. Per the protocol the client then sends data one way to the server without ever expecting a response from the server. All works fine untill the wireless internet connection at a client gets broken. In my first version of the client I retried making a connect attept each loop but very often would run out of ports as Windows standard timeout was 4 minutes. I tried changing one client the other day. I set Windows registry to "TcpTimedWaitDelay" to 1 and rewrote the client app to close its socket on error then wait 1 second before attempting a reconnect. This seemed to be working but I did loose that client for a while today. I can't be certain if the wireless went down for the whole time it was offline or not.
I'm looking for advise on a good method when using this type of client that can be used reliably. Is there another way to prevent port exhaustion within the application code or is modifing Windows registry almost always needed? I can add pieces of my code but I have gone over my code itself in a recent question here. I'm looking for a more broad suggestion here.
void checkConnect(NTRIP& server)
{
time_f functionTime = getTimePrecise();
//1st check for recv or gracefully closed socket
char databuf[SERIAL_BUFFERSIZE];
fd_set Reader, Writer, Err;
TIMEVAL Timeout;
Timeout.tv_sec = 1; // timeout after 1 seconds
Timeout.tv_usec = 0;
FD_ZERO(&Reader);
FD_ZERO(&Err);
FD_SET(server.socket, &Reader);
FD_SET(server.socket, &Err);
int iResult = select(0, &Reader, NULL, &Err, &Timeout);
if(iResult > 0)
{
if(FD_ISSET(server.socket, &Reader) )
{
int recvBytes = recv(server.socket, databuf, sizeof(databuf), 0);
if(recvBytes == SOCKET_ERROR)
{
cout << "socket error on receive call from server " << WSAGetLastError() << endl;
closesocket(server.socket);
server.connected_IP = false;
}
else if(recvBytes == 0)
{
cout << "server closed the connection gracefully" << endl;
closesocket(server.socket);
server.connected_IP = false;
}
else //>0 bytes were received so read data if needed
{
cout << "received " << recvBytes << " bytes of data" << endl;
}
}
if(FD_ISSET(server.socket, &Err))
{
cout << "ip thread select returned socket in error group" << endl;
closesocket(server.socket); //what if dont close this socket, leave open for another loop
server.connected_IP = false;
}
}
else if(iResult == SOCKET_ERROR)
{
cout << "ip thread select returned SOCKET_ERROR " << WSAGetLastError() << endl;
closesocket(server.socket);
server.connected_IP = false;
}
//2nd check hard disconnect
if(server.connected_IP == true && functionTime - timer_send_keepalive >= 15.0)
{
timer_send_keepalive = functionTime;
char buf1[] = "hello";
cout << "checking send for error" << endl;
iResult = send(server_main.socket, buf1, sizeof(buf1), 0);
if(iResult == SOCKET_ERROR)
{
int lasterror = WSAGetLastError();
if(lasterror == WSAEWOULDBLOCK)
{
cout << "server send WSAEWOULDBLOCK" << endl;
}
else if(lasterror != WSAEWOULDBLOCK)
{
cout << "server testing connection send function error " << lasterror << endl;
closesocket(server.socket);
server.connected_IP = false;
}
}
else
{
cout << "sent out keep alive " << iResult << " bytes" << endl;
}
}//end send keep alive
}
send function
bool sendData(CHAR_MESSAGE& data)
{
bool check = false;
if(data.flag_toSend == true)
{
if(WaitForSingleObject(data.mutex, 0) != WAIT_FAILED)
{
if(server_main.connected_IP == true)
{
int iResult = send(server_main.socket, data.buffer, data.bufferLength, 0);
if(iResult == SOCKET_ERROR)
{
int lasterror = WSAGetLastError();
if(lasterror == WSAEWOULDBLOCK)
{
cout << "main server send WSAEWOULDBLOCK" << endl;
check = false;
}
if(lasterror != WSAEWOULDBLOCK)
{
cout << "server main send error " << lasterror << endl;
closesocket(server_main.socket);
server_main.connected_IP = false;
check = false;
}
}
else
{
check = true;
server_main.lastDataSendTime = getTimePrecise();
//{cout << "sent data to main server" << endl;}
}
}
if(server_backup.connected_IP == true)
{
int iResult = send(server_backup.socket, data.buffer, data.bufferLength, 0);
if(iResult == SOCKET_ERROR)
{
int lasterror = WSAGetLastError();
if(lasterror == WSAEWOULDBLOCK)
{
cout << "backup server send WSAEWOULDBLOCK" << endl;
//check = false;
}
if(lasterror != WSAEWOULDBLOCK)
{
cout << "server backup send error " << lasterror << endl;
closesocket(server_backup.socket);
server_backup.connected_IP = false;
}
}
else
{
server_backup.lastDataSendTime = getTimePrecise();
//{cout << "sent data to backup server" << endl;}
}
}
data.flag_toSend = false;
ReleaseMutex(data.mutex);
}//end obtained mutex
}//end data flag to send is true
return check;
}
login function
bool loginServer(NTRIP& datasource )
{
std::string sLogin = buildLogin(datasource);
char databuf[1030];
int iResult = send(datasource.socket, sLogin.c_str(), sLogin.length(), 0);
if(iResult == SOCKET_ERROR)
{
cout << "Send error = " << WSAGetLastError() << endl;
closesocket(datasource.socket);
return false;
}
else //not socket error
{
int flags = 0;
fd_set Read, Err;
TIMEVAL Timeout;
FD_ZERO(&Read);
FD_ZERO(&Err);
FD_SET(datasource.socket, &Read);
FD_SET(datasource.socket, &Err);
Timeout.tv_sec = 1;
Timeout.tv_usec = 0;
iResult = select(0, &Read, NULL, &Err, &Timeout);
if(iResult == 0)
{
cout << "loginServer function, select timeout" << endl;
closesocket(datasource.socket);
return false;
}
else if(FD_ISSET(datasource.socket, &Read) )
{
int recvBytes = recv(datasource.socket, databuf, sizeof(databuf), flags);
if(recvBytes == SOCKET_ERROR)
{
cout << "loginServer function, Error recv call " << WSAGetLastError() << endl;
closesocket(datasource.socket);
return false;
}
else if(recvBytes == 0) //server closed connection
{
cout << "loginServer function, server reclosed connection" << endl;
closesocket(datasource.socket);
return false;
}
else if(recvBytes > 0) //process response
{
std::string tempString;
for(int n=0; n<recvBytes; n++)
{
tempString += databuf[n];
}
if(tempString.compare(CONNECT_OK) || tempString.compare(HTTP_OK) )
{
cout << "server connected" << endl;
return true;
}
else if(tempString.compare(ERROR_1))
{
MessageBox(NULL, ERROR_1, "NTRIP connect Error", MB_OK);
closesocket(datasource.socket);
return false;
}
else if(tempString.compare(ERROR_2))
{
MessageBox(NULL, ERROR_2, "NTRIP connect Error", MB_OK);
closesocket(datasource.socket);
return false;
}
else if(tempString.compare(ERROR_3))
{
MessageBox(NULL, ERROR_3, "NTRIP connect Error", MB_OK);
closesocket(datasource.socket);
return false;
}
else if(tempString.compare(ERROR_4))
{
MessageBox(NULL, ERROR_4, "NTRIP connect Error", MB_OK);
closesocket(datasource.socket);
return false;
}
}
}
else if(FD_ISSET(socket, &Err) )
{
cout << "loginServer function, select call error" << endl;
closesocket(datasource.socket);
return false;
}
}//end not socket error on send login
closesocket(datasource.socket);
return false;
}
open a new socket
bool clientOpenSocket_connectServer(SOCKET& Socket, const char* serverADDR, const char* serverPORT)
{
int check;
if(Socket != INVALID_SOCKET) //if not closed then close socket
{
closesocket(Socket);
Socket = INVALID_SOCKET;
}
time_f timer = getTimePrecise();
while(getTimePrecise() - timer < 5.0){} //wait 5 second before reconnect attempt
//set Windows reg to 1 second TcpTimedWaitDelay
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET; //use IPv4
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
//get socket memory address info
check = getaddrinfo(serverADDR , serverPORT, &hints, &result);
if ( check != 0)
{
printf("Winsock getaddrinfo failed. %d\n", WSAGetLastError());
return false;
}
//prepare socket, sets IP4 or IP6, sock type and protocol used
for(ptr=result; ptr!=NULL; ptr=ptr->ai_next)
{
Socket = socket( result->ai_family, result->ai_socktype, result->ai_protocol);
if (Socket == INVALID_SOCKET)
{
printf("Socket failed initializing %d %d.\n", Socket, WSAGetLastError());
freeaddrinfo (result);
return false;
}
//now have a valid socket
check = ioctlsocket(Socket, FIONBIO, &NonBlock);
if (check == SOCKET_ERROR)
{
printf("client socket could not set nonblocking, with error: %d\n", WSAGetLastError());
closesocket(Socket);
freeaddrinfo(result);
return false;
}
//set sockets to no-linger on close
char value = 0;
check = setsockopt( Socket, SOL_SOCKET, SO_DONTLINGER, &value, sizeof( value ) );
if (check == SOCKET_ERROR)
{
cout << "client socket could not set options no-linger " << WSAGetLastError() << endl;
}
//disable nagle algorithym
if(disableNagleSockets == true)
{
value = 1;
check = setsockopt( Socket, IPPROTO_TCP, TCP_NODELAY, &value, sizeof( value ) );
if (check == SOCKET_ERROR)
{
cout << "client socket could not set options " << WSAGetLastError() << endl;
}
else{cout << "Nagle Sockets set disabled" << endl;}
value = 0;
check = setsockopt( Socket, IPPROTO_TCP, SO_SNDBUF, &value, sizeof( value ) );
if (check == SOCKET_ERROR)
{
cout << "client socket could not set options " << WSAGetLastError() << endl;
}
}
//attempt connect
cout << "attempting connect" << endl;
check = connect(Socket, ptr->ai_addr, ptr->ai_addrlen);
if(check == SOCKET_ERROR )
{
check = WSAGetLastError();
if(check == WSAEWOULDBLOCK) // then set a timeout
{
fd_set Write, Err;
TIMEVAL Timeout;
int TimeoutSec = 10; // timeout after 10 seconds
FD_ZERO(&Write);
FD_ZERO(&Err);
FD_SET(Socket, &Write);
FD_SET(Socket, &Err);
Timeout.tv_sec = TimeoutSec;
Timeout.tv_usec = 0;
check = select(0, NULL, &Write, &Err, &Timeout);
if(check == 0)
{
printf("connect call to server, select call timeout elapsed\r\n");
closesocket(Socket);
freeaddrinfo(result);
return false;
}
else
{
if(FD_ISSET(Socket, &Write) )
{
freeaddrinfo(result);
cout << "socket opened to server, after wait" << endl;
return true;
}
if(FD_ISSET(Socket, &Err) )
{
printf("connect call to server, select call error state\r\n");
closesocket(Socket);
freeaddrinfo(result);
return false;
}
}
}
else if(check == WSAECONNREFUSED)
{
cout << "no server program at requested address " << serverADDR << endl;
closesocket(Socket);
freeaddrinfo(result);
return false;
}
else if(check == WSAEHOSTDOWN || check == WSAETIMEDOUT)
{
cout << "no server present at requested address " << serverADDR << endl;
closesocket(Socket);
freeaddrinfo(result);
return false;
}
else
{
cout << "connect call WSA error code " << check << endl;
closesocket(Socket);
freeaddrinfo(result);
return false;
}
}//end socket error
//else instant connection is good
cout << "socket opened to server" << endl;
freeaddrinfo(result);
return true;
}//end search for a socket address to use
freeaddrinfo(result); //no socket opened here
return false;
}//end of setup TCP port
So as of now it waits 5 seconds snce the last failed connection before attempting another. My earlier version tried a new connection each loop untill it connected. It seems right now that it may be working with the 5 second delay and setting Windows registry to close a port after 1 second.
Use the connection until it breaks, and then create another one.
If it breaks so often that you encounter port exhaustion you have a network problem, not a programming problem.
If you get a connect error you should sleep for increasing amounts of time on each failure, e.g. 1,2,4,8,... seconds.
When I run this code, it always returns no available open ports. How do I solve this?
for(y=1; y<20000; y++ ) {
sock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
Info.sin_addr.s_addr = inet_addr(IPaddress);
Info.sin_family = AF_INET;
Info.sin_port = htons(y);
x = connect (sock, NULL, NULL);
if(x != SOCKET_ERROR ){
cout << "Port" << y << "- OPEN ! " << endl;
}
closesocket(sock);
}
WSACleanup();
cout << "Port scan has finished " << endl;
system("pause");
I am learning socket programming for use in an upcoming project, and I have researched the issue pretty extensively. Basically, all this program needs to is on a client computer (locally, i.e. my computer) needs to connect to a remote server and send a command (which it has done, I have gotten it to read back Apache server stats to me).
What is happening is this: I believe I have the socket set right, but the server receives random garbage buffers (one of which consisted of " '>Z"). I have tried various socket settings, different bindings, etc.
I have in the process of starting it will initialize winsock, create a socket, bind the network, and then do a listen loop and while(1) recv data.
I have yet to get the server (on a remote computer, hosted at a datacenter) to output the message. This is my only goal for the time being. I appreciate everyone's help in advance, and the code is before (this is the entire code, sorry for the length).
Client Code:
char *host = "127.0.0.1";
SOCKET clientsock;
struct sockaddr_in server_address;
struct hostent *host_info;
WSADATA WSAData;
if(WSAStartup(MAKEWORD(2,2), &WSAData) != -1) {
cout << "WINSOCK2 Initialized" << endl;
if((clientsock = socket(AF_INET, SOCK_STREAM, 0)) != SOCKET_ERROR) {
cout << "Socket Created" << endl;
char opt[2];
opt[0] = 0;
opt[1] = 1;
//setsockopt(clientsock, SOL_SOCKET, SO_BROADCAST, opt, sizeof(opt));
host_info = gethostbyname(host);
server_address.sin_family = AF_INET;
server_address.sin_addr = *((struct in_addr *)host_info->h_addr);
server_address.sin_port = htons(80);
if(connect(clientsock, (struct sockaddr *)&server_address, sizeof(struct sockaddr)) == 0) {
cout << "Connected to host" << endl;
char COMMAND[22] = "SVR --WINSOCK-VERIFY\0";
if(send(clientsock, COMMAND, sizeof(COMMAND), 0)) {
cout << "Command Sent" << endl;
closesocket(clientsock);
}
else {
cout << "ERROR - Could not send command. " << "Error: " << WSAGetLastError() << endl;
closesocket(clientsock);
WSACleanup();
}
}
else {
cout << "ERROR - Could not connect to host. " << "Error: " << WSAGetLastError() << endl;
closesocket(clientsock);
WSACleanup();
}
}
else {
cout << "ERROR - Could not create the socket. " << "Error: " << WSAGetLastError() << endl;
WSACleanup();
}
}
else {
cout << "ERROR - Could not initialize WINSOCK2. " << "Error: " << WSAGetLastError() << endl;
WSACleanup();
}
Server Code:
SOCKET serversock;
char *server = "127.0.0.1";
//char *server = "50.31.1.180";
struct sockaddr_in server_address;
WSADATA WSAData;
if(WSAStartup(MAKEWORD(2,2), &WSAData) != -1) {
cout << "WINSOCK2 Initialized" << endl;
if((serversock = socket(PF_INET, SOCK_DGRAM, PF_UNSPEC)) != SOCKET_ERROR) {
cout << "Socket Created" << endl;
unsigned long NB = 1;
ioctlsocket(serversock, FIONBIO, &NB);
server_address.sin_family = AF_INET;
server_address.sin_addr = *((struct in_addr *)server);
server_address.sin_port = htons(21578);
if(bind(serversock, (struct sockaddr*)&server_address, sizeof(struct sockaddr) == 0)) {
cout << "Network bound" << endl;
cout << "Listening..." << endl;
listen(serversock, 5);
while(1) {
int size = sizeof((struct sockaddr *)server);
SOCKET clientsock = accept(serversock, (struct sockaddr *)server, &size);
char INCOMMAND[20];
if(clientsock >= 0) {
if(recv(clientsock, INCOMMAND, sizeof(INCOMMAND), 0)) {
int i = 0;
if(INCOMMAND == "SVR --WINSOCK-VERIFY\0") {
cout << "SVR receieved" << endl;
}
while(INCOMMAND[i] != '\0') {
cout << INCOMMAND[i];
i++;
}
cout << endl;
}
else {
cout << "ERROR - Could not receive command" << endl;
break;
}
}
}
}
else {
cout << "ERROR - Could not bind network. " << "Error: " << WSAGetLastError() << endl;
closesocket(serversock);
WSACleanup();
}
}
else {
cout << "ERROR - Could not create the socket. " << "Error: " << WSAGetLastError() << endl;
WSACleanup();
}
}
else {
cout << "ERROR - Could not initialize WINSOCK2. " << "Error: " << WSAGetLastError() << endl;
WSACleanup();
}
Calls to send/recv may not send/receive the amount of bytes you indicate in their third argument, in fact, most of the time they will send/receive less bytes than you expect. You usually have to loop until the entire data has been sent/received. Also note that doing this:
char buffer[100];
recv(clientsock, buffer, sizeof(buffer), 0);
cout << buffer;
Will most surelly print garbage, since you don't have a null terminator in your char array(whatch out for buffer overflows when appending it), and you're not checking the return value of recv. It might be reading 1 byte only(or none if an error ocurred). You're printing your buffer the same way in your server app.
In this case, you are actually sending the null-terminator, but since you might read less bytes than you expect, this character might not be received by the other application, thus printing it will print garbage chars.
Edit: You should have a look at the structure of a sockaddr struct. You can have a look at it here. In your code you are using this convertion:
int size = sizeof((struct sockaddr *)"127.0.0.1");
const char *, which is the type of "127.0.0.1", cannot be casted to a sockaddr pointer, they're incompatible. Here you should use getaddrinfo in order to resolve the IP address(note that you could use a domain name, and this function would resolve it). There are lots of tutorials online on how to use this function, just search for "getaddrinfo".
I'm trying to get this code to work:
#include <stdio.h>
#include <tchar.h>
#include <iostream>
#include <WinSock2.h>
#pragma comment( lib, "ws2_32.lib" )
#include <Windows.h>
using namespace std;
int port = 5012;
SOCKET listen_sock;
SOCKET client_sock;
char FR_recv_buf [1048576] = "";
char recv_buf [102400] = "";
int Receive();
int Listen();
//function to initialize winsock
bool InitializeWinsock()
{
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if(iResult != 0)
{
cout << "WSAStartup failed with error: " << iResult << endl;
return false;
}
else
{
cout << "WSAStartup successfully initialized." << endl;
return true;
}
}
int ForwardResponse()
{
if (send(client_sock, FR_recv_buf, sizeof(FR_recv_buf), 0) == SOCKET_ERROR)
{
cout << "Forward Response: send() failed with error: " << WSAGetLastError() << endl;
closesocket(client_sock);
//WSACleanup();
return 0;
}
else
{
cout << "Forward Response: send() success.\n";
//go back to begginning again?
Receive();
//CreateThread(0,0,(LPTHREAD_START_ROUTINE)Receive, 0, 0 ,0);
}
}
//Function to parse hostname from http request
string ParseHostname(char * buf)
{
size_t pos;
//string to hold hostname substring
string hostname_t;
//copy request to string for easier parsing
string httpheader = buf;
pos = httpheader.find("Host: ");//find "Host: " line
hostname_t = httpheader.substr(pos + 6);//copy to substring, not including "Host: ", just the hostname
pos = hostname_t.find("\r\n");// find end of line
hostname_t.erase(pos);//erase the rest of the string which is unwanted
return hostname_t;
}
//Function to forward HTTP request from browser to webserver
int ForwardRequest()
{
int bytes_received;
SOCKADDR_IN Dest;
SOCKET frecv_sock;
hostent *Host;
//parse hostname from http request
string hostname = ParseHostname(recv_buf);
if((Host=gethostbyname(hostname.c_str()))==NULL)
{
DWORD dwError = WSAGetLastError();
if (dwError != 0)
{
if(dwError == WSAHOST_NOT_FOUND)
{
cout << "Host " << hostname.c_str() << " not found.\n";
WSACleanup();
return FALSE;
}
else if (dwError == WSANO_DATA)
{
cout << "No data record found.\n";;
WSACleanup();
return FALSE;
}
else
{
cout << "Function failed with error: " << dwError << endl;
WSACleanup();
return FALSE;
}
}
}
else
{
cout << "Successfully connected to host: " << hostname.c_str() << endl;
//privmsg(wsockdl.sock,sendbuf,curchan);
}
Dest.sin_family=AF_INET;
Dest.sin_port=htons(80);
memcpy(&Dest.sin_addr,Host->h_addr,Host->h_length);
// Create a SOCKET for connecting to server
if((frecv_sock = socket(AF_INET,SOCK_STREAM,0))==INVALID_SOCKET)
{
cout << "Forward Request: Error at socket(), error code: " << WSAGetLastError() << endl;
closesocket(frecv_sock);
WSACleanup();
return FALSE;
}
// Connect to server
if(connect( frecv_sock,(SOCKADDR*)&Dest,sizeof(Dest))==SOCKET_ERROR)
{
cout << "Forward Request: connect() failed, error code: " << WSAGetLastError() << endl;
closesocket( frecv_sock);
WSACleanup();
return FALSE;
}
//send intercepted request to server
if (send(frecv_sock, recv_buf, strlen(recv_buf), 0) == SOCKET_ERROR)
{
cout << "Forward Request: send() failed with error: " << WSAGetLastError() << endl;
closesocket(frecv_sock);
WSACleanup();
return 0;
}
else
{
cout << "Forward Request: send() success.\n";
}
//receive request from server
do{
bytes_received = recv(frecv_sock,FR_recv_buf,sizeof(FR_recv_buf),0);
if (bytes_received > 0){
strcat (FR_recv_buf, "\0");
cout << "Forward Request: recv() success. Bytes received: " << bytes_received << endl;
CreateThread(0, 0, (LPTHREAD_START_ROUTINE)ForwardResponse, 0 ,0 ,0);
//ForwardResponse();
}
else if ( bytes_received == 0 ){
cout << "Forward Request: Connection closed\n";
closesocket(frecv_sock);
}
else if ( bytes_received == SOCKET_ERROR){
cout << "Forward Request: recv() failed with error: " << WSAGetLastError() << endl;
closesocket(frecv_sock);
WSACleanup();
return 0;
}
}while (bytes_received > 0);
}
//Function to accept connection and receive data from browser
int Receive()
{
SOCKADDR_IN csin;
int csin_len = sizeof(csin);
int iResult;
//accept client connection
client_sock = accept(listen_sock , (LPSOCKADDR)&csin, &csin_len);//pauses here to wait for connection from client
if (client_sock == INVALID_SOCKET) {
cout << "accept failed with error: "<< WSAGetLastError() << endl;
closesocket(client_sock);
WSACleanup();
return 1;
}
else{
cout << "Client connection from IP: " << inet_ntoa(csin.sin_addr) << ":" << csin.sin_port << endl;
}
CreateThread(0, 0 , (LPTHREAD_START_ROUTINE)Receive, 0 , 0 ,0); //Start another thread to accept.
do {
iResult = recv(client_sock, recv_buf, sizeof(recv_buf), 0);
if (iResult == SOCKET_ERROR) {
closesocket(client_sock);
WSACleanup();
cout << "Receive: recv() failed with error: "<< WSAGetLastError() << endl;
}
else if (iResult > 0){
//null terminate receive buffer
//recv_buf[iResult] = '\0';
strcat(recv_buf, "\0");
cout <<"Receive: Bytes received: " << iResult << endl;
//forward HTTP request from browser to web server
cout << recv_buf << endl;
HANDLE pChildThread = CreateThread(0, 0 , (LPTHREAD_START_ROUTINE)ForwardRequest, 0 , 0 ,0);
WaitForSingleObject(pChildThread,60000); //Wait for connection between proxy and remote server
CloseHandle(pChildThread);
}
else if ( iResult == 0 ){
cout << "Receive: Connection closed\n";
}
}while ( iResult > 0 );
return 0;
}
//Function which listens for incoming connections to the proxy
int Listen()
{
SOCKADDR_IN local;
memset(&local,0,sizeof(local));
local.sin_family = AF_INET;
local.sin_port = htons(port);
local.sin_addr.s_addr = INADDR_ANY;
//create socket for listening to
listen_sock = socket(AF_INET, SOCK_STREAM, 0);
//bind function associates a local address with a socket.
if (bind(listen_sock, (LPSOCKADDR)&local, sizeof(local)) == 0)
{
if (listen(listen_sock, 10) == 0)
{
cout << "Listening on: " << port << endl;
}
else
{
cout << "Error listening on socket.\n";
}
}
else{
cout << "bind() failed with error: "<< WSAGetLastError() << endl;
}
//accept and start receiving data from broswer
CreateThread(0, 0 , (LPTHREAD_START_ROUTINE)Receive, 0 , 0 ,0);
return 0;
}
int CloseServer()
{
closesocket(client_sock);
WSACleanup();
return 1;
}
int _tmain(int argc, _TCHAR* argv[])
{
InitializeWinsock();
Listen();
cin.get();
return 0;
}
But it seems like the connection ends too early, or the recv() or send() functions fail. Nothing is displayed on my browser except that it couldn't connect. Can anyone spot the problem?
One major problem is that you only have one client socket. Each thread you create share the same client socket so if two connections are made before the first one is done, the first socket will be over-written with the second connection. Remember that threads share all memory in the process, including things like global variables.
Edit: Since you are using C++, why don't you encapsulate variables and functions in a class? And instead of allocating memory for buffers statically like you do, create them on the heap with new.
Edit 2
Simple multi-threaded server:
class Connection
{
public:
Connection()
: buffer(0), buffer_size(0)
{ }
void run(SOCKET sock);
privat:
SOCKET input_socket; // Socket we read from
SOCKET output_socket; // Socket we write to
char *buffer; // Buffer we read data into, and write data from
size_t buffer_size; // Total size of buffer (allocated memory)
size_t read_size; // Number of bytes read
void connect();
void recv();
void send();
};
void Connection::run(SOCKET sock)
{
input_socket = sock;
if (buffer == 0)
{
// Allocate buffer
}
// Connect to the real server
connect();
for (;;)
{
try
{
recv();
send();
}
catch (exception &e)
{
std::cerr << "Error: " << e.what() << '\n';
break;
}
}
// Clean up
delete [] buffer;
closesocket(output_socket);
closesocket(input_socket);
}
void Connection::recv()
{
// Read data into the buffer, setting "read_size"
// Like: read_size = recv(input_socket, buffer_size, 0);
// Throw exception on error (includes connection closed)
// NOTE: If error is WSAEWOULDBLOCK, set read_size to 0, don't throw exception
}
void Connection::send()
{
if (read_size > 0)
{
// Send data from the buffer
// Like: send(output_socket, buffer, read_size, 0))
// Throw exception on error
}
}
void Connection::connect()
{
// Connect to the real server
// Set the output_socket member variable
}
DWORD client_thread(LPVOID param)
{
SOCKET socket = (SOCKET) param;
// Make socket nonblocking
int mode = 1;
ioctlsocket(socket, FIONBIO, &mode)
// Main thread stuff
Connection connection;
connection.run(socket);
}
int main()
{
// Create master socket, and other initialization
for (;;)
{
SOCKET client_socket = accept(...);
CreateThread(0, 0 , (LPTHREAD_START_ROUTINE) client_thread,
(LPVOID) client_socket , 0 ,0);
}
// Clean up
}
Another major problem is that you are appending '\0' to the received buffer in the apparent expectation that send() will recognize it and stop sending from there, even though the size parameter to send() is sizeof(FR_recv_buf), which is what it will really respect. Another problem is that data items such as FR_recv_buf are instance variables instead of local variables, so you can't handle multuple concurrent connections.