C++ Socket API "Heartbeat" - c++

I'm trying to make a simple heartbeat check from client to server and vice-versa, if connection on either is broken off unexpectedly it prints a message and calls closesocket.
I spent 8 hours on this and it still isn't acceptable to my mentor. Right now I got something that works, but if breakpoint is placed before while loop and connected client is forcefully closed, trying to go past breakpoint causes crash when it should break the loop and write out error.
Server side code:
int main(int argc, char *argv[])
{
SOCKET s, sa;
WSAData oWSAData;
WORD wVersion = 0x0001;
WSAStartup(wVersion, &oWSAData);
s = socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in srv_address;
memset(&srv_address, 0, sizeof(srv_address));
srv_address.sin_family = AF_INET;
srv_address.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
srv_address.sin_port = htons(1099);
bind(s, (sockaddr*) &srv_address, sizeof(srv_address));
int l = listen(s, 10);
if (l < 0)
printf("Listen error\n");
else
{
printf("Listen OK. Listening on port %u\n",
htons(srv_address.sin_port));
sa = accept(s, NULL, NULL);
while (true)
{
char buffer[1000];
int nRecvLen = recv(sa, buffer, 999, 0);
buffer[nRecvLen] = '\0';
int r = recv(sa, NULL, 0, 0);
if (r == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET)
{
printf("Konekcija je naglo prekinuta!\n");
break;
}
else
{
if (nRecvLen > 0)
{
for (int i = 0; i < nRecvLen; i++)
{
cout << buffer[i];
}
}
}
}
closesocket(sa);
closesocket(s);
}
WSACleanup();
return 0;
}
and client side:
int main()
{
SOCKET s;
WSAData oWSAData;
WORD wVersion = 0x0001;
WSAStartup(wVersion, &oWSAData);
s = socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in srv_address;
memset(&srv_address, 0, sizeof(srv_address));
srv_address.sin_family = AF_INET;
srv_address.sin_addr.S_un.S_un_b.s_b1 = xxx;
srv_address.sin_addr.S_un.S_un_b.s_b2 = xxx;
srv_address.sin_addr.S_un.S_un_b.s_b3 = x;
srv_address.sin_addr.S_un.S_un_b.s_b4 = xxx;
srv_address.sin_port = htons(1099);
int c = connect(s, (sockaddr*) &srv_address, sizeof(srv_address));
if (c < 0)
{
printf("Connection error\n");
cout << (WSAGetLastError());
}
else
{
string l = "Heartbeat\n";
int p = l.size();
char buff[1000];
strcpy_s(buff, l.c_str());
printf("Connected\n");
while (true)
{
if (send(s, buff, p, 0) > 0)
{
Sleep(1000);
}
else
{
printf("Konekcija je naglo prekinuta\n");
shutdown(s, SD_BOTH);
closesocket(s);
break;
}
}
WSACleanup();
return 0;
}
}

Related

Connection between DTLS server and client not working

I am developing a DTLS server and client. But there is no handshake between them.
PS I made a cut from the project in order to reduce the amount of code. If you forgot something - do not kick ...
a common part
static int dtls_verify_callback(int ok, X509_STORE_CTX* ctx) {
return ok;
}
static int generate_cookie(SSL* ssl, unsigned char* cookie, unsigned int* cookie_len) {
unsigned int i;
for (i = 0; i < COOKIE_LEN; i++, cookie++)
*cookie = i;
*cookie_len = COOKIE_LEN;
return 1;
}
static int verify_cookie(SSL* ssl,
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
const
#endif
unsigned char* cookie,
unsigned int cookie_len) {
unsigned int i;
if (cookie_len != COOKIE_LEN)
return 0;
for (i = 0; i < COOKIE_LEN; i++, cookie++) {
if (*cookie != i)
return 0;
}
return 1;
}
Server side
int main() {
int iTimeout = 1000;
ADDRINFOW* pAddressInfo;
ADDRINFOW AddressHints;
WSADATA WinsockData;
LPCWSTR lpwszAddress = L"";
SOCKET socket;
union {
struct sockaddr_storage ss;
struct sockaddr_in s4;
struct sockaddr_in6 s6;
} server_addr, client_addr;
const TIMEVAL Timeout = { iTimeout / 1000, (iTimeout % 1000) * 1000 };
if (1 != OPENSSL_init_ssl(0
| OPENSSL_INIT_NO_LOAD_CONFIG
| OPENSSL_INIT_ASYNC
| OPENSSL_INIT_ENGINE_DYNAMIC
| OPENSSL_INIT_ENGINE_ALL_BUILTIN
| OPENSSL_INIT_NO_ATEXIT
| OPENSSL_INIT_LOAD_SSL_STRINGS
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS
, nullptr))
{
return 1;
}
WSAStartup(MAKEWORD(2, 2), &WinsockData);
auto ctx = unique_ptr_c<SSL_CTX>(SSL_CTX_new(DTLS_server_method()), SSL_CTX_free);
auto cert_store = unique_ptr_c<X509_STORE>(X509_STORE_new(), X509_STORE_free);
X509_STORE_load_locations(cert_store.get(), "certs/ca-cert.pem", nullptr);
SSL_CTX_set1_verify_cert_store(ctx.get(), cert_store.get());
if (!SSL_CTX_use_certificate_chain_file(ctx.get(), "certs/server-cert.pem"))
{
ERR_print_errors_fp(stderr);
}
if (!SSL_CTX_use_PrivateKey_file(ctx.get(), "certs/server-key.pem", SSL_FILETYPE_PEM))
{
ERR_print_errors_fp(stderr);
}
if (!SSL_CTX_check_private_key(ctx.get()))
{
ERR_print_errors_fp(stderr);
}
SSL_CTX_set_verify(ctx.get(), SSL_VERIFY_PEER, dtls_verify_callback);
SSL_CTX_set_read_ahead(ctx.get(), 1);
SSL_CTX_set_cookie_generate_cb(ctx.get(), generate_cookie);
SSL_CTX_set_cookie_verify_cb(ctx.get(), verify_cookie);
memset(&AddressHints, 0, sizeof(AddressHints));
AddressHints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
AddressHints.ai_family = AF_UNSPEC;
AddressHints.ai_socktype = SOCK_DGRAM;
AddressHints.ai_protocol = 0;
iResult = GetAddrInfoW(lpwszAddress, 12345, &AddressHints, &pAddressInfo);
if (0 != iResult)
{
}
else
{
for (const ADDRINFOW* pCurrentAddressInfo = pAddressInfo; nullptr != pCurrentAddressInfo; pCurrentAddressInfo = pCurrentAddressInfo->ai_next)
{
socket = socket(pCurrentAddressInfo->ai_family, pCurrentAddressInfo->ai_socktype, pCurrentAddressInfo->ai_protocol);
if (INVALID_SOCKET == CurrentSocket) { continue; }
if (SOCKET_ERROR == bind(CurrentSocket, pCurrentAddressInfo->ai_addr, static_cast<int>(pCurrentAddressInfo->ai_addrlen)))
{
(void)closesocket(CurrentSocket);
continue;
}
if (SOCKET_ERROR == setsockopt(CurrentSocket, SOL_SOCKET, SO_SNDTIMEO, reinterpret_cast<const char*>(&iTimeout), sizeof(iTimeout))) { }
break;
}
}
for (;;)
{
if (SOCKET_ERROR == select(0, &socket, nullptr, nullptr, &Timeout)) {}
memset(&client_addr, 0, sizeof(struct sockaddr_storage));
auto bio = BIO_new_dgram(socket, BIO_NOCLOSE);
auto ssl = unique_ptr_c<SSL>(SSL_new(ctx.get()), SSL_close_and_free);
SSL_set_bio(ssl.get(), bio, bio);
SSL_set_options(ssl.get(), SSL_OP_COOKIE_EXCHANGE);
while (iResult <= 0) {
iResult = DTLSv1_listen(ssl.get(), (BIO_ADDR*)&client_addr);
if (iResult <= 0) { }
}
BIO_set_fd(SSL_get_rbio(ssl.get()), socket, BIO_NOCLOSE);
BIO_ctrl(SSL_get_rbio(ssl.get()), BIO_CTRL_DGRAM_SET_CONNECTED, 0, &client_addr);
iResult = SSL_accept(ssl.get());
if (iResult != 1) {
printf("%s\n", ERR_error_string(ERR_peek_last_error(), NULL));
printf("%s\n", ERR_error_string(ERR_get_error(), buf));
}
else
{
// I didn't cut the code further, since it never goes here
}
}
}
Client side
int main() {
ADDRINFOW AddressHints;
SOCKET ClientSocket = INVALID_SOCKET;
memset(&AddressHints, 0, sizeof(AddressHints));
AddressHints.ai_family = AF_UNSPEC;
AddressHints.ai_socktype = SOCK_DGRAM;
AddressHints.ai_protocol = 0;
int iResult = GetAddrInfoW(lpwszHost, wszPort, &AddressHints, &pAddressInfo);
if (0 != iResult)
{
}
else
{
unique_ptr_c<SSL_CTX> ctx;
unique_ptr_c<SSL> ssl;
BIO* bio;
if (1 != OPENSSL_init_ssl(0
| OPENSSL_INIT_NO_LOAD_CONFIG
| OPENSSL_INIT_ASYNC
| OPENSSL_INIT_ENGINE_DYNAMIC
| OPENSSL_INIT_ENGINE_ALL_BUILTIN
| OPENSSL_INIT_NO_ATEXIT
| OPENSSL_INIT_LOAD_SSL_STRINGS
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS
, nullptr))
{
return 1;
}
ctx = unique_ptr_c<SSL_CTX>(SSL_CTX_new(DTLS_client_method()), SSL_CTX_free);
auto cert_store = unique_ptr_c<X509_STORE>(X509_STORE_new(), X509_STORE_free);
X509_STORE_load_locations(cert_store.get(), "certs/ca-cert.crt", nullptr);
SSL_CTX_set1_verify_cert_store(ctx.get(), cert_store.get());
iResult = SSL_CTX_use_certificate_chain_file(ctx.get(), "certs/client-cert.pem");
if (!iResult)
{
ERR_print_errors_fp(stderr);
}
iResult = SSL_CTX_use_PrivateKey_file(ctx.get(), "certs/client-key.pem", SSL_FILETYPE_PEM);
if (!iResult)
{
ERR_print_errors_fp(stderr);
}
if (!SSL_CTX_check_private_key(ctx.get()))
{
ERR_print_errors_fp(stderr);
}
SSL_CTX_set_verify(ctx.get(), SSL_VERIFY_PEER, dtls_verify_callback);
SSL_CTX_set_read_ahead(ctx.get(), 1);
SSL_CTX_set_cookie_generate_cb(ctx.get(), generate_cookie);
SSL_CTX_set_cookie_verify_cb(ctx.get(), verify_cookie);
ssl = unique_ptr_c<SSL>(SSL_new(ctx.get()), SSL_close_and_free);
for (pCurrentAddressInfo = pAddressInfo; nullptr != pCurrentAddressInfo; pCurrentAddressInfo = pCurrentAddressInfo->ai_next)
{
ClientSocket = socket(pCurrentAddressInfo->ai_family, pCurrentAddressInfo->ai_socktype, pCurrentAddressInfo->ai_protocol);
if (INVALID_SOCKET == ClientSocket)
{
continue;
}
iResult = connect(ClientSocket, pCurrentAddressInfo->ai_addr, static_cast<int>(pCurrentAddressInfo->ai_addrlen));
if (SOCKET_ERROR == iResult)
{
}
else
{
break;
}
if (SOCKET_ERROR == closesocket(ClientSocket))
{
}
}
if (nullptr != pCurrentAddressInfo)
{
if (SOCKET_ERROR == setsockopt(ClientSocket, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast<const char*>(&iTimeout), sizeof(iTimeout)))
{
iResult = WSAGetLastError();
}
else
{
bio = BIO_new_dgram(ClientSocket, BIO_NOCLOSE);
BIO_ctrl(bio, BIO_CTRL_DGRAM_SET_CONNECTED, 0, remote_address.get());
SSL_set_bio(ssl.get(), bio, bio);
iResult = SSL_connect(ssl.get()); // Trying 5 handshakes fails with an SSL_ERROR_SYSCALL error
if (iResult <= 0) {
char buf[BUFFER_SIZE];
//print_errors_stderr();
ERR_print_errors_fp(stderr);
printf("%s\n", ERR_error_string(ERR_peek_last_error(), NULL));
printf("%s\n", ERR_error_string(ERR_get_error(), buf));
switch (SSL_get_error(ssl.get(), iResult)) {
...
case SSL_ERROR_SYSCALL:
ERR_print_errors_fp(stderr);
DBG_MSG((DBG_ERR, L"DTLSClient::Send: SSL_connect failed with SSL_ERROR_SYSCALL"));
break;
...
}
fprintf(stderr, "%s\n", ERR_error_string(ERR_get_error(), NULL));
ERR_print_errors_fp(stderr);
}
else
{
// I didn't cut the code further, since it never goes here
}
}
// Close the socket
if (SOCKET_ERROR == closesocket(ClientSocket))
{
}
}
}
}
The client tries 5 times to make a handshake with the server but it doesn't work.
An error occurs from the client side on the line iResult = SSL_connect(ssl.get()) - an error occurs:
error:00000000:lib(0)::reason(0)
ERR: DTLSClient::Send: SSL_connect failed with SSL_ERROR_SYSCALL
An error occurs on the server at the line iResult = SSL_accept(ssl.get()) - with the error:
SSL_accept: No error
error:00000000:lib(0)::reason(0)
Based on traffic
enter image description here
Client sends - Client Hello
The server replies to this - Hello verify Request
And then the client tries to answer something back. Now I don't know what to do next. Are there any ideas?
I tried to do it as in the examples from OpenLL and other examples on github.

Multi threaded HTTP server socket hangs with CLOSE_WAIT

I have a C++ server application. The server application is acting as a HTTP
server in this case. With the large number of requests socket move to the
CLOSE_WAIT state.With small number of requests its working fine.
void *task1(void *);
static int connFd;
int noThread = 0;
int main()
{
int pId, portNo, listenFd;
socklen_t len; //store size of the address
bool loop = false;
struct sockaddr_in svrAdd, clntAdd;
pthread_t threadA[500];
portNo = 9898 ;
cout<<"td::string::npos = "<<std::string::npos<<endl;
if((portNo > 65535) || (portNo < 2000))
{
cout<<"Please enter a port number between 2000 - 65535";
return 0;
}
//create socket
listenFd = socket(AF_INET, SOCK_STREAM, 0);
if(listenFd < 0)
{
cout<< "Cannot open socket"<<endl;
return 0;
}
bzero((char*) &svrAdd, sizeof(svrAdd));
svrAdd.sin_family = AF_INET;
svrAdd.sin_addr.s_addr = INADDR_ANY;
svrAdd.sin_port = htons(portNo);
//bind socket
if(bind(listenFd, (struct sockaddr *)&svrAdd, sizeof(svrAdd)) < 0)
{
cout<<"Cannot bind"<<endl;;
return 0;
}
listen(listenFd, 5);
len = sizeof(clntAdd);
while (noThread < 500)
{
cout<<"Listening"<<endl;
//this is where client connects. svr will hang in this mode until client conn
connFd = accept(listenFd, (struct sockaddr *)&clntAdd, &len);
if (connFd < 0)
{
cout<<"Cannot accept connection"<<endl;
return 0;
}
else
{
cout<<"Connection successful" <<endl;
}
//pthread_create(&threadA[noThread], NULL, test::task1, NULL);
//thr_create(&threadA[noThread], NULL, task1, NULL);
pthread_create(&threadA[noThread], NULL, task1, NULL);
noThread++;
cout<<"Number of noThread :"<< noThread;
}
for(int i = 0; i < 500; i++)
{
pthread_join(threadA[i], NULL);
//thr_join(threadA[i], NULL);
cout<<"inside join"<<i;
}
}
void *task1 (void *dummyPt)
{
cout<<"Thread No: " << pthread_self();
char test[1000];
bzero(test, 1001);
bool loop = false;
int t=0;
while(t==0)
{
bzero(test, 1001);
read(connFd, test, 1001);
string t1(test);
if(tester.find("connection_request")!=std::string::npos){
if(connFd)
{
cout<<"T1 :"<<t1<<endl;
send(connFd, "HTTP/1.0 200 OK\n\n", 17, 0);
write(connFd,"Test Response",13);
}
else
cout << "Problem With collection FD";
t=1;
}
}
cout<<"Closing thread and conn"<<endl;
close(connFd);
noThread--;
return NULL;
}

Improve server to deal with multiple clients

I'm trying to create a server that talks with 2 clients, 1 in each time. After the talking with one client, the server sends a message to both clients.
I found a basic code of a server, and I tried to upgrade it to accept multiple number of connections, and I saw 2 ways of it : threads, or doing array of sockets, but I couldn't understand it.
Can someone explain me how to use threads and give examples please?
This is the code :
int main()
{
WSADATA WsaDat;
if (WSAStartup(MAKEWORD(2, 2), &WsaDat) != 0)
{
std::cout << "WSA Initialization failed!\r\n";
WSACleanup();
system("PAUSE");
return 0;
}
SOCKET Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (Socket == INVALID_SOCKET)
{
std::cout << "Socket creation failed.\r\n";
WSACleanup();
system("PAUSE");
return 0;
}
SOCKADDR_IN serverInf;
serverInf.sin_family = AF_INET;
serverInf.sin_addr.s_addr = INADDR_ANY;
serverInf.sin_port = htons(8888);
if (bind(Socket, (SOCKADDR*)(&serverInf), sizeof(serverInf)) == SOCKET_ERROR)
{
std::cout << "Unable to bind socket!\r\n";
WSACleanup();
system("PAUSE");
return 0;
}
listen(Socket, 1);
SOCKET TempSock = SOCKET_ERROR;
while (TempSock == SOCKET_ERROR)
{
std::cout << "Waiting for incoming connections...\r\n";
TempSock = accept(Socket, NULL, NULL);
}
// If iMode!=0, non-blocking mode is enabled.
u_long iMode = 1;
ioctlsocket(Socket, FIONBIO, &iMode);
Socket = TempSock;
std::cout << "Client connected!\r\n\r\n";
// Main loop
for (;;)
{
char *szMessage = "Welcome to the server!\r\n";
send(Socket, szMessage, strlen(szMessage), 0);
int nError = WSAGetLastError();
if (nError != WSAEWOULDBLOCK&&nError != 0)
{
std::cout << "Winsock error code: " << nError << "\r\n";
std::cout << "Client disconnected!\r\n";
// Shutdown our socket
shutdown(Socket, SD_SEND);
// Close our socket entirely
closesocket(Socket);
break;
}
Sleep(1000);
}
WSACleanup();
system("PAUSE");
return 0;
}
To do so you need one server socket and a clientsocket array like this:
SERVER:
ACCEPT:
int clientsock[2];
minsocks = 0;
numsocks = 2;
while(minsock < numsocks)
{
clientsock[minsock] = accept(serversock,
(struct sockaddr *) &clientaddr,
(socklen_t *)&clientaddrlen);
minsock++;
}
RECIEVE:
char message[6];
int data;
int limit = 6;
for(int i = 0; i < NUMSOCK; i++)
{
int in = recv(clientsock[i], &message[index], limit, 0);
if(in > 0)
{
index += in;
limit -= in;
}
else if ( in == 0 )
printf("Connection closed\n");
else
printf("recv failed: %d\n", WSAGetLastError());
}
This should be a good beginning for you to start with.
Threads - C version
pthread_t sniffer_thread;
if( pthread_create( &sniffer_thread , NULL , connection_handler , (void*) new_sock) < 0)
{
perror("could not create thread");
return 1;
}
//Now join the thread , so that we dont terminate before the thread
//pthread_join( sniffer_thread , NULL);
puts("Handler assigned");
}
/*
* This will handle connection for each client
* */
void *connection_handler(void *socket_desc)
{
//Get the socket descriptor
int sock = *(int*)socket_desc;
int read_size;
char *message , client_message[2000];
while(in != 0)
{
int in = recv(socket_desc, &client_message[index], limit, 0);
if(in > 0)
{
index += in;
limit -= in;
}
else
printf("recv failed: %d\n", WSAGetLastError());
}
//Free the socket pointer
free(socket_desc);
return 0;
}

C non-blocking send not working

I'm trying to send the large amount of data to the server which should accept the data and parse it. So as I know, when you send() the data in blocking mode in one call, it splits data into chunks and then sends the chunks to the target. But I need to mark each chunk with a small identifier in the beginning of the data (let's say I'm placing a header in each chunk), so I decided to use non- blocking send. I thought, when I do non-blocking send, it sends the max the buffer allows and then returns, leaving the chunking work for me, but it seems that's not happening.
My code is:
struct sockaddr_in target;
SOCKET connection = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
target.sin_family = AF_INET;
target.sin_addr.s_addr = inet_addr(host);
target.sin_port = htons(port);
ULONG NonBlock;
NonBlock = 1;
if (ioctlsocket(connection, FIONBIO, &NonBlock) == SOCKET_ERROR)
{
return WSAGetLastError();
}
fd_set write_fds;
FD_ZERO(&write_fds);
FD_SET(connection, &write_fds);
struct timeval tv;
tv.tv_sec=1;
tv.tv_usec=0;
int result = connect(connection,(SOCKADDR*)&target,sizeof(target));
if(result==SOCKET_ERROR)
{
while(true)
{
result= select(connection+1,NULL,&write_fds,NULL,&tv);
printf("connect: result=%d\r\n",result);
if(result== -1)
{
return WSAGetLastError();
}
else break;
}
}
//later on
fd_set write_set;
int bytes_sent= 0;
int total_sent = 0;
int length = 0;
char *tmp = malloc(sizeof(header)+data_size); //data_size is the size of the large buffer
memcpy(tmp,packet,sizeof(header));
memcpy(tmp+sizeof(header),data,data_size);
int result;
FD_ZERO(&write_set);
FD_SET(connection,&write_set);
struct timeval time_out;
time_out.tv_sec=0;
time_out.tv_usec=1500;
while(total_sent < data_size)
{
length= (data_size+sizeof(my_header))-total_sent;
result = select(connection+1,NULL,&write_set,NULL,&time_out);
if(result== SOCKET_ERROR) return -1;
if(result!=0 && FD_ISSET(connection, &write_set))
{
bytes_sent = send(connection,tmp,length,0);
}
if(bytes_sent == SOCKET_ERROR)
{
return SOCKET_ERROR;
}
if(bytes_sent > 0)
{
//here i need to append a header to the new chunk
}
else break;
}
So basically my question is: why the send on non-blocking socket, still blocks and doesn't return after sending the first chunk, and acts just like regular blocking send? What i want to achieve is send() sending one chunk of data of the length that the system allows, so i put the length of the whole data, assuming that non-blocking send will return after sending the first chunk, because the buffer is to big, to be sent as one block.
UPDATE some runnable code:
#include <windows.h>
#include <winsock.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <types.h>
typedef struct hdr{
uint8_t super_id;
}my_header,*pmy_header;
SOCKET connection;
int start_winsock()
{
WSADATA check;
int result = WSAStartup(MAKEWORD(2,2),&check);
return result;
}
int create_connection(char* host,int port)
{
struct sockaddr_in target;
connection = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
target.sin_family = AF_INET;
target.sin_addr.s_addr = inet_addr(host);
target.sin_port = htons(port);
int result = UnblockSocket();
if(result!=0) return WSAGetLastError();
fd_set write_fds;
FD_ZERO(&write_fds);
FD_SET(connection, &write_fds);
struct timeval tv;
tv.tv_sec=1;
tv.tv_usec=0;
result = connect(connection,(SOCKADDR*)&target,sizeof(target));
if(result==SOCKET_ERROR)
{
while(true)
{
result= select(connection+1,NULL,&write_fds,NULL,&tv);
if(result== -1)
{
return WSAGetLastError();
}
else break;
}
}
return 0;
}
int UnblockSocket()
{
ULONG NonBlock;
NonBlock = 1;
if (ioctlsocket(connection, FIONBIO, &NonBlock) == SOCKET_ERROR)
{
return WSAGetLastError();
}
return 0;
}
int SendMyData(pmy_header header,char * data,int data_size)
{
fd_set write_set;
int bytes_sent= 0;
int total_sent = 0;
int length = 0;
char *tmp = malloc(sizeof(my_header)+data_size);
memcpy(tmp,packet,sizeof(my_header));
memcpy(tmp+sizeof(my_header),data,data_size);
int result;
FD_ZERO(&write_set);
FD_SET(connection,&write_set);
struct timeval time_out;
time_out.tv_sec=0;
time_out.tv_usec=1500;
header->super_id=0xdead;
while(total_sent < data_size)
{
length= (data_size+sizeof(my_header))-total_sent;
if(result== SOCKET_ERROR) return -1;
if(result!=0 && FD_ISSET(connection, &write_set))
{
bytes_sent = send(connection,tmp,length,0);
}
printf("bytes sent per iteration=%d\n",bytes_sent);
if(bytes_sent == SOCKET_ERROR)
{
return SOCKET_ERROR;
}
if(bytes_sent > 0)
{
total_sent+= bytes_sent-sizeof(my_header);
tmp = realloc(tmp,sizeof(my_header)+(data_size-total_sent));
memcpy(tmp,header,sizeof(my_header));
memcpy(tmp+sizeof(my_header),data,data_size-total_sent);
}
else break;
}
free(tmp);
return total_sent;
}
int main(int argc, char *argv[])
{
start_winsock();
int result = create_connection("2.2.2.2",88);
if(result!=0) { printf("Cannot connect\n"); return 0; }
pmy_header *header = malloc(sizeof(my_header));
int buf_size = 500000;
char buffer_test[buf_size];
ZeroMemory(buffer_test,buf_size);
int count=0;
for(count;count<buf_size;count++)
{
strcat(buffer_test,"4");
}
result = SendMyData(header,buffer_test,buf_size);
}
send() is not guaranteed to send everything you ask it to send. It may send less. You MUST take the return value into account. If it is less than the amount you requested, you have to call send() again to re-send the remaining bytes, before then sending new bytes. And in the case of non-blocking, you have to take WSAEWOULDBLOCK into account as well.
And you don't put on a header on each chunk that send() sends. You put a header on each chunk you tell send() to send. You do your own chunking, don't worry about the chunking that TCP does internally. That is a network implementation, it does not affect your protocol. The receiver should be paying attention to your chunk headers, calling recv() as many times as needed to receive your full header and data to account for TCPs chunking.
Try something more like this instead:
SOCKET connection = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (connection == INVALID_SOCKET)
{
return WSAGetLastError();
}
ULONG NonBlock = 1;
in result = ioctlsocket(connection, FIONBIO, &NonBlock);
if (result == SOCKET_ERROR)
{
result = WSAGetLastError();
closesocket(connection);
return result;
}
struct sockaddr_in target;
memset(&target, 0, sizeof(target));
target.sin_family = AF_INET;
target.sin_addr.s_addr = inet_addr(host);
target.sin_port = htons(port);
result = connect(connection, (SOCKADDR*)&target, sizeof(target));
if (result == SOCKET_ERROR)
{
result = WSAGetLastError();
if (result != WSAEWOULDBLOCK)
{
closesocket(connection);
return result;
}
fd_set write_fds;
FD_ZERO(&write_fds);
FD_SET(connection, &write_fds);
struct timeval tv;
tv.tv_sec = 5;
tv.tv_usec = 0;
result = select(0, NULL, &write_fds, NULL, &tv);
if (result == SOCKET_ERROR)
{
result = WSAGetLastError();
closesocket(connection);
return result;
}
if (result == 0)
{
closesocket(connection);
return WSAETIMEDOUT;
}
}
char *tmp_data = data;
int data_remaining = data_size;
while (data_remaining > 0)
{
int pkt_data_size = min(data_remaining, 1024); // replace 1024 with whatever maximum chunk size you want...
int pkt_size = sizeof(header) + pkt_data_size;
char *pkt = malloc(pkt_size);
if (!pkt) return -1;
// fill header as needed...
memcpy(pkt+sizeof(header), tmp_data, pkt_data_size);
tmp_data += pkt_data_size;
data_remaining -= pkt_data_size;
char *tmp_pkt = pkt;
while (pkt_size > 0)
{
result = send(connection, tmp_pkt, pkt_size, 0);
if (result == SOCKET_ERROR)
{
result = WSAGetLastError();
if (result != WSAEWOULDBLOCK)
{
free(pkt);
return -1;
}
fd_set write_set;
FD_ZERO(&write_set);
FD_SET(connection, &write_set);
struct timeval time_out;
time_out.tv_sec = 5;
time_out.tv_usec = 0;
result = select(0, NULL, &write_set, NULL, &time_out);
if (result != 1)
{
free(pkt);
return -1;
}
continue;
}
tmp_pkt += result;
pkt_size -= result;
}
free(pkt);
}

Server does not respond to new clients using select(), cpp

I followed this nice tutorial to create a simple non-blocking server using select() function. Here's what I have:
void setNonBlocking(int socketFD) {
int x;
x = fcntl(socketFD,F_GETFL,0);
fcntl(socketFD,F_SETFL,x | O_NONBLOCK);
return;
}
int initialize(char * port) {
int yes = 1;
listener = socket(PF_INET,SOCK_STREAM, 0);
if (listener < 0) {
perror("listener");
exit(EXIT_FAILURE);
}
if (setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1) {
perror("setsockopt");
exit(EXIT_FAILURE);
}
setNonBlocking(listener);
struct sockaddr_in server_address;
memset((char *) &server_address, 0, sizeof(server_address));
server_address.sin_family = AF_INET;
// server_address.sin_addr.s_addr = htonl(INADDR_ANY);
inet_aton("132.65.151.39",&(server_address.sin_addr));
server_address.sin_port = htons(atoi(port));
if (bind(listener, (struct sockaddr *) &server_address,
sizeof(server_address)) < 0 ) {
perror("bind");
close(listener);
exit(EXIT_FAILURE);
}
listen(listener,BACKLOG);
maxSocket = listener;
memset((char *) &clientQueue, 0, sizeof(clientQueue));
return 0;
}
void readSockets() {
int i;
cout << "in readSockets()" << endl;
if (FD_ISSET(listener,&sockets))
createConnection();
for (i = 0; i < 5; i++) {
if (FD_ISSET(clientQueue[i],&sockets))
readData(i);
} /* for (all entries in queue) */
}
int main(int argc, char* argv[]) {
if (argc != 2) {
fprintf(stderr,"usage: server port\n");
exit(EXIT_FAILURE);
}
if (initialize(argv[1]) != 0) {
exit(EXIT_FAILURE);
}
struct timeval timeout;
int value;
printf("server: waiting for connections...\n");
while(1) { // main accept() loop
build_select_list();
timeout.tv_sec = 1;
timeout.tv_usec = 0;
value = select(maxSocket, &sockets, (fd_set *) 0,(fd_set *) 0, &timeout);
if (value == -1) {
perror("select");
exit(EXIT_FAILURE);
}
if (value == 0) {
printf("%d",value);
fflush(stdout);
} else{
cout << "Value is " << value << endl;
readSockets();
}
}
return EXIT_SUCCESS;
}
My problem is simple - select always returns 0, meaning it does not get or does not respond to a new connection. I checked my client a day ago with a blocking more simple server and it did work, so I don't think its the porblem.
You'll notice that I tried both IP addresses:
server_address.sin_family = AF_INET;
// server_address.sin_addr.s_addr = htonl(INADDR_ANY);
Can anyone please help me? I feel lost :)
Please refer to man select, first parameter should be number of highest descriptor + 1, so in your case:
value = select(maxSocket + 1, &sockets, (fd_set *) 0,(fd_set *) 0, &timeout);