Connecting QSslSocket with OpenSSL server - c++

I'm trying to connect SSL sockets between my Qt application (using QSslSockets) and my c++ server running SSL sockets (using openssl)..
Server Code:
int create_socket(int port)
{
int s;
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
s = socket(AF_INET, SOCK_STREAM, 0);
if (s < 0) {
perror("Unable to create socket");
exit(EXIT_FAILURE);
}
if (bind(s, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
perror("Unable to bind");
exit(EXIT_FAILURE);
}
if (listen(s, 1) < 0) {
perror("Unable to listen");
exit(EXIT_FAILURE);
}
return s;
}
void init_openssl()
{
SSL_load_error_strings();
OpenSSL_add_ssl_algorithms();
}
void cleanup_openssl()
{
EVP_cleanup();
}
SSL_CTX *create_context()
{
const SSL_METHOD *method;
SSL_CTX *ctx;
method = SSLv23_server_method();
ctx = SSL_CTX_new(method);
if (!ctx) {
perror("Unable to create SSL context");
ERR_print_errors_fp(stderr);
exit(EXIT_FAILURE);
}
return ctx;
}
void configure_context(SSL_CTX *ctx)
{
if(SSL_CTX_use_certificate_file(ctx, "/root/myCA/server_crt.pem", SSL_FILETYPE_PEM) > 0)
{
std::cout<<"Cert found"<<std::endl;
}
if (SSL_CTX_use_PrivateKey_file(ctx, "/root/myCA/server_key.pem", SSL_FILETYPE_PEM) > 0 ) {
std::cout<<"Key found"<<std::endl;
}
if(SSL_CTX_check_private_key(ctx) > 0)
{
std::cout<<"Key valid"<<std::endl;
}
}
int main(int argc, char **argv)
{
int sock;
SSL_CTX *ctx;
init_openssl();
ctx = create_context();
configure_context(ctx);
sock = create_socket(3000);
while(1) {
struct sockaddr_in addr;
uint len = sizeof(addr);
SSL *ssl;
const char reply[] = "test\n";
int client = accept(sock, (struct sockaddr*)&addr, &len);
if (client > 0) {
std::cout<<"Client accepted..."<<std::endl;
}
else
{
perror("Unable to accept");
exit(EXIT_FAILURE);
}
ssl = SSL_new(ctx);
SSL_set_fd(ssl, client);
if (SSL_accept(ssl) <= 0) {
ERR_print_errors_fp(stderr);
}
else {
SSL_write(ssl, reply, strlen(reply));
}
SSL_free(ssl);
close(client);
}
close(sock);
SSL_CTX_free(ctx);
cleanup_openssl();
}
Qt Client Code:
SSLSOCKET::SSLSOCKET(QObject *parent):QObject(parent)
{
connect(&client,SIGNAL(encrypted()),this,SLOT(ConnectionEstablished()));
connect(&client,SIGNAL(sslErrors(const QList<QSslError>&)),this,SLOT(ErrorOccured(const QList<QSslError> &)));
QList<QSslCertificate>
trusted_ca=QSslCertificate::fromPath("/Users/test/Desktop/server_crt.pem");
if(trusted_ca.empty())
{
qDebug()<<"Error not trusted Ca.";
}
client.setCaCertificates(trusted_ca);
client.connectToHostEncrypted(*my ip address*,3000);
}
void SSLSOCKET::ErrorOccured(const QList<QSslError> &error)
{
qDebug()<<"ERROR HERE----:";
qDebug()<<error;
}
void SSLSOCKET::ConnectionEstablished()
{
qDebug()<<"CONNECTION WORKED------:";
if(!client.waitForEncrypted())
{
qDebug()<<client.errorString();
}
else
{
qDebug()<<"Encrypted Connection Established...";
}
}
I can see the connection being made between the client and server, however the client.waitForEncrypted() is showing 'Unknown Error'..
Any ideas?

You are calling waitForEncrypted() inside of your connected() handler. The client hasn't actually initiated the SSL handshake yet, so you can't wait on it yet. Per the connectToHostEncrypted() documentation:
Starts an encrypted connection to the device hostname on port, using mode as the OpenMode. This is equivalent to calling connectToHost() to establish the connection, followed by a call to startClientEncryption(). The protocol parameter can be used to specify which network protocol to use (eg. IPv4 or IPv6).
QSslSocket first enters the HostLookupState. Then, after entering either the event loop or one of the waitFor...() functions, it enters the ConnectingState, emits connected(), and then initiates the SSL client handshake. At each state change, QSslSocket emits signal stateChanged().
If you want to handle connected() like this, you will have to use connectToHost() instead of connectToHostEncrypted(), and then call startClientEncryption() separately:
SSLSOCKET::SSLSOCKET(QObject *parent):QObject(parent)
{
connect(&client, SIGNAL(connected()), this, SLOT(ConnectionEstablished()));
...
client.connectToHost(*my ip address*, 3000);
}
void SSLSOCKET::ConnectionEstablished()
{
client.startClientEncryption();
if (!client.waitForEncrypted())
...
}
EDIT: scratch that. I thought you were handling the connected() signal, but I see now that you are handling the encrypted() signal instead. In that case:
If the SSL handshake is successful, QSslSocket emits encrypted().
So you don't need to use waitForEncrypted() at all:
void SSLSOCKET::ConnectionEstablished()
{
qDebug()<<"CONNECTION WORKED------:";
qDebug()<<"Encrypted Connection Established...";
}
Even if you did call it, it should simply return true:
Waits until the socket has completed the SSL handshake and has emitted encrypted(), or msecs milliseconds, whichever comes first. If encrypted() has been emitted, this function returns true; otherwise (e.g., the socket is disconnected, or the SSL handshake fails), false is returned.
So, unless the socket is being disconnected after the handshake completes, or encrypted() is being emitted before the encrypted state is actually changed, or some other unforeseen error is occurring, I don't see any reason for waitForEncrypted() to return false inside of the encrypted() handler.

Related

C++ sockets: accept() hangs when client calls connect(), but accept() responds to HTTP GET request

I'm trying to write a demo server/client program in C++. I first ran my server program on my Macbook, with ngrok on and forwarding a public address on the Internet to a local address on my machine. I'm seeing something that I don't understand when I try to run my client program to connect to the server:
If the client tries to connect to localhost at the local port defined in the server program, the server accepts as expected and the client successfully connects,
If the client tries to connect to the ngrok server address at port 80 (default for ngrok), then the client connects, but the server is still blocked at the accept call. (This I don't understand!)
If I send an HTTP GET request to the ngrok server address, the server successfully accepts the connection.
Why do I see these? In the ideal case, I want my server to accept connections from my client program, not just respond to the HTTP GET request.
Here's my code if that helps: For the client,
#include "helpers.hh"
#include <cstdio>
#include <netdb.h>
// usage: -h [host] -p [port]
int main(int argc, char** argv) {
const char* host = "x.xx.xx.xx"; // use the server's ip here.
const char* port = "80";
// parse arguments
int opt;
while ((opt = getopt(argc, argv, "h:p:")) >= 0) {
if (opt == 'h') {
host = optarg;
} else if (opt == 'p') {
port = optarg;
}
}
// look up host and port
struct addrinfo hints, *ais;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6
hints.ai_socktype = SOCK_STREAM; // use TCP
hints.ai_flags = AI_NUMERICSERV;
if (strcmp(host, "ngrok") == 0) {
host = "xxxx-xxxx-xxxx-1011-2006-00-27b9.ngrok.io";
}
int r = getaddrinfo(host, port, &hints, &ais);
if (r != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(r));
exit(1);
}
// connect to server
int fd = -1;
for (auto ai = ais; ai && fd < 0; ai = ai->ai_next) {
fd = socket(ai->ai_family, ai->ai_socktype, 0);
if (fd < 0) {
perror("socket");
exit(1);
}
r = connect(fd, ai->ai_addr, ai->ai_addrlen);
if (r < 0) {
close(fd);
fd = -1;
}
}
if (fd < 0) {
perror("connect");
exit(1);
}
freeaddrinfo(ais);
//
printf("Connection established at fd %d\n", fd);
FILE* f = fdopen(fd, "a+");
fwrite("!", 1, 1, f);
fclose(f);
while (true) {
}
}
And for the server:
#include "helpers.hh"
void handle_connection(int cfd, std::string remote) {
(void) remote;
printf("Received incoming connection at cfd: %d\n", cfd);
usleep(1000000);
printf("Exiting\n");
}
int main(int argc, char** argv) {
int port = 6162;
if (argc >= 2) {
port = strtol(argv[1], nullptr, 0);
assert(port > 0 && port <= 65535);
}
// Prepare listening socket
int fd = open_listen_socket(port);
assert(fd >= 0);
fprintf(stderr, "Listening on port %d...\n", port);
while (true) {
struct sockaddr addr;
socklen_t addrlen = sizeof(addr);
// Accept connection on listening socket
int cfd = accept(fd, &addr, &addrlen);
if (cfd < 0) {
perror("accept");
exit(1);
}
// Handle connection
handle_connection(cfd, unparse_sockaddr(&addr, addrlen));
}
}
Contrary to the typical port forwarding done in the local router, ngrok is not a port forwarder at the transport level (TCP) but it is a request forwarder at the HTTP level.
Thus if the client does a TCP connect to the external ngrok server nothing will be forwarded yet. Only after the client has send the HTTP request the destination will be determined and then this request will be send to the ngrok connector on the internal machine, which then will initiate the connection to the internal server and forward the request.

How to get a socket id and a list of connections from OpenSSL?

I'm working with OpenSSL and I'm trying to figure out how to view the ID's of current socket connections:
My code that listens for connections:
while(1)
{
struct sockaddr_in adds;
unit len = sizeof(addr);
int client = accept(sock, (struct sockaddr*) &addr, &len);
if(client > 0)
{
std::cout<<"Client incoming";
}
ssl = SSL_new(ctx);
SSL_set_fd(ssl, client);
if(SSL_accept(ssl) <= 0)
{
std::cout<<"Handshake error";
}
else
{
//Do Stuff with connection
}
SSL_free(ssl);
close(client);
}
How can I get a socket id and a list of connections from openssl?
Additionally 'int client' is also being set to '4', despite the documentation stating it should either be 1, 0 or <0?

can a windows service run a TCP server?

I created 2 programs in c++ using visual studio 2008: a windows service based on this service which i added tcp server code to and a client program using MFC, which has a listbox that displays the ip address and hostname of the computer thats running the service. The user then chooses a server and clicks a connect button. Since there will be many servers running, I used some PHP script on a web host site. The service sends its ip address and host name to the web host, the web host puts the information into a list and the client then accesses this list.
all this works fine with the server code but when i put the server code into the windows service, the client program freezes and doesn't respond when the connect button is clicked. The ip address and host name still appear in the client listbox, i just can't connect to the server i select.
is the windows service stopping the server code from working?
here is the cpp file that contains the server code in the service program:
char* WebPost(char Website[], char Webpage[], char Request[], int RetLen)
{
// Sends an HTTP Post request with POST Data...
SOCKET WebSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct hostent *WebHost;
WebHost = gethostbyname(Website);
if (WebHost == NULL)
{
if (WSAGetLastError() == WSANOTINITIALISED)
printf("Error Not Connected!");
else
printf("Error: %d", WSAGetLastError());
Sleep(1000);
exit(0);
}
SOCKADDR_IN SockAddr;
SockAddr.sin_port = htons(80);
SockAddr.sin_family = AF_INET;
SockAddr.sin_addr.s_addr = *((unsigned long*)WebHost->h_addr);
connect(WebSocket, (SOCKADDR*)(&SockAddr), sizeof(SockAddr));
char PostRequest[1024];
sprintf(PostRequest,
"POST %s HTTP/1.1\r\n"
"Host: %s\r\n"
"Content-Length: %hu\r\n"
"Content-Type: application/x-www-form-urlencoded\r\n"
"\r\nD=%s\0",
Webpage, Website,
strlen(Request)+2, Request
);
send(WebSocket, PostRequest, strlen(PostRequest), 0);
// Get return data
char* Data = new char[RetLen];
recv(WebSocket, Data, 4, 0);
for (;;)
{ // Skip HTTP headers
Data[0] = Data[1];
Data[1] = Data[2];
Data[2] = Data[3];
recv(WebSocket, &Data[3], 1, 0);
if (Data[0] == '\r' && Data[1] == '\n'
&& Data[2] == '\r' && Data[3] == '\n')
break;
}
int DataLen = recv(WebSocket, Data, RetLen, 0);
Data[DataLen] = '\0'; // Return the data
shutdown(WebSocket, 2);
closesocket(WebSocket);
return Data;
}
void ServStart()
{
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0)
{
printf("WSAStartup failed with error %ld.\n", WSAGetLastError());
exit(0);
}
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
{
printf("The dll do not support the Winsock version %u.%u!\n", LOBYTE(wsaData.wVersion),HIBYTE(wsaData.wVersion));
WSACleanup();
exit(0);
}
//Start listening
ListeningSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ListeningSocket == INVALID_SOCKET)
{
printf("Error at socket, error code: %ld.\n", WSAGetLastError());
WSACleanup();
exit(0);
}
ServerAddr.sin_family = AF_INET;
ServerAddr.sin_port = htons(Port);
ServerAddr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(ListeningSocket, (SOCKADDR *)&ServerAddr, sizeof(ServerAddr)) == SOCKET_ERROR)
{
printf("bind failed. Error code: %ld.\n", WSAGetLastError());
closesocket(ListeningSocket);
WSACleanup();
exit(0);
}
if (listen(ListeningSocket, 5) == SOCKET_ERROR)
{
printf("listen: Error listening on socket %ld.\n", WSAGetLastError());
closesocket(ListeningSocket);
WSACleanup();
exit(0);
}
char ac[80];
if (gethostname(ac, sizeof(ac)) == SOCKET_ERROR)
{
printf("Error when getting local host name: ", WSAGetLastError());
exit(0);
}
struct hostent *phe = gethostbyname(ac);
if (phe == 0)
{
printf("Error: ", WSAGetLastError());
exit(0);
}
struct in_addr addr;
memcpy(&addr, phe->h_addr_list[0], sizeof(struct in_addr)); // use the first ip-address
printf("IP used by Server: %s\n", inet_ntoa(addr)); // inet_ntoa(addr) provides the local address.
MyIP = inet_ntoa(addr);
char SendBuf[32];
// * is used as a separator, because it's not allowed in the hostname.
//So it won't interfere with it.
sprintf(SendBuf, "%hhu|%s*%s", cAddIP, MyIP, ac); // Send the server the IP and host name
WebPost(WEBSITE, WEBPAGE, SendBuf, 0);
printf("listening for connections...\n\n");
}
void ShutDown() // Shut down the server (tells the web server I am offline)
{
char SendBuf[32]; // Remove my IP from the list of online servers...
char ac[80];
if (gethostname(ac, sizeof(ac)) == SOCKET_ERROR)
{
printf("Error when getting local host name: ", WSAGetLastError());
exit(0);
}
sprintf(SendBuf, "%hhu|%s*%s", cRemIP, MyIP,ac);
WebPost(WEBSITE, WEBPAGE, SendBuf, 0);
printf("Successful shutdown\n");
Sleep(1000);
WSACleanup();
}
void ServLoop()
{
SOCKADDR_IN SenderInfo;
SOCKET NewConnection;
int ByteReceived, nlen;
char recvbuff[1024];
for (;;)
{
//Main program loop
NewConnection = SOCKET_ERROR;
while(NewConnection == SOCKET_ERROR)
{
NewConnection = accept(ListeningSocket, NULL, NULL); // this is a blocking function
printf("New client got connected, ready to receive and send data...\n\n");
ByteReceived = recv(NewConnection, recvbuff, sizeof(recvbuff), 0);
if (ByteReceived > 0)
{
getsockname(ListeningSocket, (SOCKADDR *)&ServerAddr, (int *)sizeof(ServerAddr));
memset(&SenderInfo, 0, sizeof(SenderInfo));
nlen = sizeof(SenderInfo);
getpeername(NewConnection, (SOCKADDR *)&SenderInfo, &nlen);
}
}
if (shutdown(NewConnection, 2) != 0)
printf("there is something wrong with the shutdown. The error code: %ld\n", WSAGetLastError());
else
printf("shutdown is working...\n");
}
}
// --------------------------------------------
BOOL ConsoleProc(DWORD Msg)
{
switch (Msg)
{
case CTRL_CLOSE_EVENT:
case CTRL_LOGOFF_EVENT:
case CTRL_SHUTDOWN_EVENT:
ShutDown();
return false;
}
return false;
}
// -----------------------------------------------------
CSampleService::CSampleService(PWSTR pszServiceName,
BOOL fCanStop,
BOOL fCanShutdown,
BOOL fCanPauseContinue) :
CServiceBase(pszServiceName, fCanStop, fCanShutdown, fCanPauseContinue),
m_dwTimeout(10 * 1000)
{
// Create a manual-reset event that is not signaled at first to indicate
// the service is stopping.
m_hStoppingEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (m_hStoppedEvent == NULL)
{
throw GetLastError();
}
// Create a manual-reset event that is not signaled at first to indicate
// the stopped signal of the service.
m_hStoppedEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (m_hStoppedEvent == NULL)
{
throw GetLastError();
}
}
CSampleService::~CSampleService(void)
{
if (m_hStoppedEvent)
{
CloseHandle(m_hStoppedEvent);
m_hStoppedEvent = NULL;
}
if (m_hStoppingEvent)
{
CloseHandle(m_hStoppingEvent);
m_hStoppingEvent = NULL;
}
}
void CSampleService::OnStart(DWORD dwArgc, LPWSTR *lpszArgv)
{
WriteErrorLogEntry(L"CSampleService::Start: function entry");
// Log a service start message to the Application log.
WriteEventLogEntry(L"CppWindowsService in OnStart", EVENTLOG_INFORMATION_TYPE);
// Queue the main service function for execution in a worker thread.
CThreadPool::QueueUserWorkItem(&CSampleService::ServiceWorkerThread, this);
WriteErrorLogEntry(L"CSampleService::Start: function exit");
}
void CSampleService::ServiceWorkerThread(void)
{
WriteErrorLogEntry(L"CSampleService::ServiceWorkerThread: running");
// Periodically check if the service is stopping.
while (WaitForSingleObject(m_hStoppingEvent, m_dwTimeout) == WAIT_TIMEOUT)
{
// Perform main service function here...
// Handle console events
SetConsoleCtrlHandler((PHANDLER_ROUTINE)ConsoleProc, TRUE);
ServStart(); // Main loop is in another thread
ServLoop(); // The never returning server loop
}
// Signal the stopped event.
SetEvent(m_hStoppedEvent);
WriteErrorLogEntry(L"CSampleService::ServiceWorkerThread: done");
}
void CSampleService::OnStop()
{
ShutDown(); //shut down server
SetServiceStatus(SERVICE_STOP_PENDING, ERROR_SUCCESS, 30 * 1000);
WriteErrorLogEntry(L"CSampleService::Stop: function entry");
// Log a service stop message to the Application log.
WriteEventLogEntry(L"CppWindowsService in OnStop", EVENTLOG_INFORMATION_TYPE);
// Indicate that the service is stopping and wait for the finish of the
// main service function (ServiceWorkerThread).
SetEvent(m_hStoppingEvent);
if (WaitForSingleObject(m_hStoppedEvent, INFINITE) != WAIT_OBJECT_0)
{
SetServiceStatus(SERVICE_STOP_PENDING, ERROR_INVALID_DATA, 30 * 1000);
WriteErrorLogEntry(L"OnStop: Service Start", GetLastError());
throw GetLastError();
}
WriteErrorLogEntry(L"CSampleService::Stop: function exit");
}
The answer to your specific question is, yes, a windows service can run a TCP server.
The answer to why yours does not work is not clear. At first glance the service code looks reasonable. It's possible connections to your service are being blocked by your OS firewall (i.e. your console one is in the accept list but your service one is not). You might convert some of your error printf logic into something that prints to a file instead (e.g. fprintf?) so you can take a look at what's going on...
Sure, of course it can. Why would it not be possible?

Source for a Cpp OpenSSL server with errors

I have a problem with some source code regarding OpenSSL and Cpp. For some reason it runs fine but doesn't open a socket! When I try to connect to it using s_client I get 'Connect: No Error". When I run netstat I get no open port. It should open a port on 12120. I even disabled my firewall temporarly and it didn't help! BTW I'm using Windows 7. Thanks for your consideration! My program just says everythings fine and it starts blocking at the second *BIO_do_accept( abio );*
#include "stdio.h"
#include "string.h"
#include "openssl/bio.h"
#include "openssl/ssl.h"
#include "openssl/err.h"
int password_callback(char *buf, int size, int rwflag, void *userdata)
{
/* For the purposes of this demonstration, the password is "dw" */
printf("*** Callback function called\n");
strcpy(buf, "dw");
return 1;
}
int main()
{
SSL_CTX *ctx;
SSL *ssl;
BIO *bio, *abio, *out, *sbio;
int (*callback)(char *, int, int, void *) = &password_callback;
printf("Secure Programming with the OpenSSL API, Part 4:\n");
printf("Serving it up in a secure manner\n\n");
SSL_load_error_strings();
ERR_load_BIO_strings();
SSL_library_init();
ERR_load_SSL_strings();
OpenSSL_add_all_algorithms();
printf("Attempting to create SSL context... ");
ctx = SSL_CTX_new( SSLv23_server_method() );
if(ctx == NULL)
{
printf("Failed. Aborting.\n");
return 0;
}
printf("\nLoading certificates...\n");
SSL_CTX_set_default_passwd_cb(ctx, callback);
if(!SSL_CTX_use_certificate_file(ctx, "certificate.pem", SSL_FILETYPE_PEM))
{
ERR_print_errors_fp(stdout);
SSL_CTX_free(ctx);
return 0;
}
if(!SSL_CTX_use_PrivateKey_file(ctx, "private.key", SSL_FILETYPE_PEM))
{
ERR_print_errors_fp(stdout);
SSL_CTX_free(ctx);
return 0;
}
printf("Attempting to create BIO object... ");
bio = BIO_new_ssl(ctx, 0);
if(bio == NULL)
{
printf("Failed. Aborting.\n");
ERR_print_errors_fp(stdout);
SSL_CTX_free(ctx);
return 0;
}
printf("\nAttempting to set up BIO for SSL...\n");
BIO_get_ssl(bio, &ssl);
SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
abio = BIO_new_accept("12120");
BIO_set_accept_bios(abio, bio);
printf("Waiting for incoming connection...\n");
if(BIO_do_accept(abio) <= 0)
{
ERR_print_errors_fp(stdout);
SSL_CTX_free(ctx); SSL_library_init();
BIO_free_all(bio);
BIO_free_all(abio);
return 0;
}
if(BIO_do_accept(abio) <= 0)
{
ERR_print_errors_fp(stdout);
SSL_CTX_free(ctx);
BIO_free_all(bio);
BIO_free_all(abio);
return 0;
}
out = BIO_pop(abio);
if(BIO_do_handshake(out) <= 0)
{
printf("Handshake failed.\n");
ERR_print_errors_fp(stdout);
SSL_CTX_free(ctx);
BIO_free_all(bio);
BIO_free_all(abio);
return 0;
}
BIO_puts(out, "Hello\n");
BIO_flush(out);
BIO_free_all(out);
BIO_free_all(bio);
BIO_free_all(abio);
SSL_CTX_free(ctx);
}
What exactly are you expecting here? You should see port 12120 in LISTENING state. Your client should then be able to connect. Your server then does another accept, which will prevent it reading any I/O on the accepted port, and will ultimately block your client too. I don't know why you are doing two accept's in a row but it's your code.
From the OpenSSL Documentation for BIO_do_accept():
BIO_do_accept() serves two functions. When it is first called, after
the accept BIO has been setup, it will attempt to create the accept
socket and bind an address to it. Second and subsequent calls to
BIO_do_accept() will await an incoming connection, or request a retry
in non-blocking mode.

Getting "Transport endpoint is not connected" in UDP socket programming in C++

I am getting Transport endpoint is not connected error in UDP server program, while I am try to
shutdown the socket via shutdown(m_ReceiveSocketId, SHUT_RDWR);
Following is my code snippet:
bool UDPSocket::receiveMessage()
{
struct sockaddr_in serverAddr; //Information about the server
struct hostent *hostp; // Information about this device
char buffer[BUFFERSIZE]; // Buffer to store incoming message
int serverlen; // to store server address length
//Open a datagram Socket
if((m_ReceiveSocketId = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
Utility_SingleTon::printLog(LOG_ERROR,"(%s %s %d) UDP Client - socket() error",__FILE__,__func__, __LINE__);
pthread_exit(NULL);
return false;
}
//Configure Server Address.
//set family and port
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(m_ListeningPort);
if (bind(m_ReceiveSocketId, (struct sockaddr *) &serverAddr,sizeof(struct sockaddr_in)) < 0 )
{
Utility_SingleTon::printLog(LOG_ERROR,"(%s %s %d) UDP Client- Socket Bind error=%s",__FILE__,__func__, __LINE__,strerror(errno));
pthread_exit(NULL);
return false;
}
//TODO Re-Route Mechanism.
if((serverAddr.sin_addr.s_addr = inet_addr(m_ServerIPStr.c_str())) == (unsigned long)INADDR_NONE)
{
/* Use the gethostbyname() function to retrieve */
/* the address of the host server if the system */
/* passed the host name of the server as a parameter. */
/************************************************/
/* get server address */
hostp = gethostbyname(m_ServerIPStr.c_str());
if(hostp == (struct hostent *)NULL)
{
/* h_errno is usually defined */
/* in netdb.h */
Utility_SingleTon::printLog(LOG_ERROR,"%s %d %s %s %d", "Host Not found", h_errno,__FILE__,__func__, __LINE__);
pthread_exit(NULL);
return false;
}
memcpy(&serverAddr.sin_addr, hostp->h_addr, sizeof(serverAddr.sin_addr));
}
serverlen = (int )sizeof(serverAddr);
// Loop and listen for incoming message
while(m_RecevieFlag)
{
int receivedByte = 0;
memset(buffer, 0, BUFFERSIZE);
//receive data from the server
receivedByte = recvfrom(m_ReceiveSocketId, buffer, BUFFERSIZE, 0, (struct sockaddr *)&serverAddr, (socklen_t*)&serverlen);
if(receivedByte == -1)
{
Utility_SingleTon::printLog(LOG_ERROR,"[%s:%d#%s] UDP Client - receive error",__FILE__,__LINE__,__func__);
close(m_ReceiveSocketId);
pthread_exit(NULL);
return false;
}
else if(receivedByte > 0)
{
string rMesg;
rMesg.erase();
for(int loop = 0; loop < receivedByte; loop++)
rMesg.append(1, buffer[loop]);
Utility_SingleTon::printLog(LOG_DEBUG,"[%s:%d#%s] received message=%d",__FILE__,__LINE__,__func__, rMesg.length());
QOMManager_SingleTon::getInstance()->setReceivedMessage(rMesg);
raise(SIGUSR1);
}
}
close(m_ReceiveSocketId);
pthread_exit(NULL);
return true;
}
Any help would be appreciated.
Thanks Yuvi.
You don't need to call shutdown() for a UDP socket. From the man page:
The shutdown() call causes all or part of a full-duplex connection on the socket
associated with sockfd to be shut down.
If you call shutdown() on a UDP socket, it will return ENOTCONN
(The specified socket is not connected) because UDP is a connectionless protocol.
All you need to do is close the socket and set the socket to INVALID_SOCKET. Then in your destructor check whether the socket has already been set to INVALID_SOCKET before closing it.