I have an interesting scenario for a winsock app that seemingly will not close. The following is enough code to fully replicate the issue:
#include "stdafx.h"
#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib")
#include <WS2tcpip.h>
#include <MSTcpIP.h>
#include <ws2ipdef.h>
#include <cstdio>
#include <iostream>
using namespace std;
int main() {
WSAData wsaStartup;
WSAStartup(MAKEWORD(2, 2), &wsaStartup);
SOCKET s = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
addrinfo *result;
addrinfo hint = { 0 };
hint.ai_family = AF_INET6;
int error = getaddrinfo("localhost", "45000", &hint, &result);
if (error || !result) {
cout << "Unable to resolve host. " << WSAGetLastError() << endl;
return 1;
}
error = connect(s, result->ai_addr, result->ai_addrlen);
if (error == SOCKET_ERROR) {
cout << "Unable to connect to host. " << WSAGetLastError() << endl;
} else {
cout << "Connection successful." << endl;
}
freeaddrinfo(result);
closesocket(s);
WSACleanup();
return 0;
}
I have spent numerous hours trying to track the issue down. It seems like getaddrinfo and connect both spawn an nt thread that hangs out, and prevents the app from terminating.
The only important compiler option that I changed here is: Linker->Advanced->EntryPoint where I specified "main". If I get rid of that compiler option, and change the main signature to:
int _tmain(int argc, _TCHAR* argv[])
everything seems to work fine. In my use case, I am fine having the above _tmain function, but I am wondering if anyone has any idea what magic is going on behind the scenes of the _tmain function that is making the app close.
How do I correctly set the entry point for an exe in Visual Studio?
Perhaps you need to provide the correct signature for main() to match what the runtime is expecting.
Related
I'm developing a TCP socket client. I am trying to write a client that have individual thread for send and receive data. but when I use thread, get a runtime error.
The process goes like this:
main.cpp:
#include <iostream>
#include <thread>
#include <string>
#include <chrono>
#include <WS2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
#include "TCPConnection.h"
SOCKET sock;
void SendRecive(SOCKET *isock) {
// Do-While loop to send and recive data
char buf[4096];
while (true) {
// Prompt the user for some text
cout << "> ";
// Wait for response
ZeroMemory(buf, 4096);
auto byteRecived = recv(*isock, buf, 4096, 0);
if (byteRecived <= 0) continue;
// Echo response to console
cout << "SERVER> " << string(buf, 0, byteRecived) << endl;
}
}
using namespace std;
int main() {
TCPConnection tcpconn("192.168.1.4", 7705, &sock);
SendRecive(&sock);
return 0;
}
TCPConnection.h:
//
// Created by Hamed on 8/21/2021.
//
#ifndef TCPCLIENT_TCPCONNECTION_H
#define TCPCLIENT_TCPCONNECTION_H
#include <iostream>
#include <thread>
#include <string>
#include <WS2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
using namespace std;
class TCPConnection {
public:
SOCKET *isock;
TCPConnection(string ServerIPAddress, int ServerPort, SOCKET *sock);
~TCPConnection();
};
#endif //TCPCLIENT_TCPCONNECTION_H
TCPConnection.cpp:
#include "TCPConnection.h"
TCPConnection::TCPConnection(string ServerIPAddress, int ServerPort, SOCKET *sock) {
// Initialize WinSock
WSAData data{};
WORD ver = MAKEWORD(2, 2);
int wsResult = WSAStartup(ver, &data);
if (wsResult != 0) {
cerr << "Can't start winsock, Err #" << wsResult << endl;
return;
}
// Create socket
*sock = socket(AF_INET, SOCK_STREAM, 0);
if (*sock == INVALID_SOCKET) {
cerr << "Can't create socket, Err #" << WSAGetLastError() << endl;
WSACleanup();
return;
}
// Fill in a hint structure
sockaddr_in hint{};
hint.sin_family = AF_INET;
hint.sin_port = htons(ServerPort);
inet_pton(AF_INET, ServerIPAddress.c_str(), &hint.sin_addr);
// connect to server
int connResult = connect(*sock, (sockaddr *) &hint, sizeof(hint));
if (connResult == SOCKET_ERROR) {
cerr << "Can't connect to server, Err #" << WSAGetLastError() << endl;
closesocket(*sock);
WSACleanup();
return;
}
isock = sock;
}
TCPConnection::~TCPConnection() {
// Gracefully close down everything
closesocket(*isock);
WSACleanup();
}
this code working properly but when I change "main.cpp" to use thread like this:
int main() {
TCPConnection tcpconn("192.168.1.4", 7705, &sock);
thread DoRunTCPRecive(SendRecive,&sock);
return 0;
}
I get "Microsoft Visual C++ Runtime Library" debug error when runing app.
Update:
Actually I want to have a function for send and have another function for receive data . but when I use join, my code stay on current function and I can't run another code after that.
you should join the thread after create it
thread DoRunTCPRecive(SendRecive,&sock);
DoRunTCPRecive.join()
I am trying to create a program that downloads data from websites using c++ low level networking.
Here is the code:
#include <iostream>
#include <string>
#include <string.h>
#include <netdb.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
int status, sock;
struct addrinfo hints;
struct addrinfo *servinfo;
int main(int argc, char** argv){
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
int MAXDATASIZE = 100;
char request[] = "GET /robots.txt HTTP/1.1\n";
char buf[MAXDATASIZE];
if((status = getaddrinfo(argv[1], argv[2], &hints, &servinfo)) != 0){
std::cout << "getaddrinfo: " << gai_strerror(status) << "\n";
return 2;
}
if((sock = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol)) == -1){
std::cout << "Error creating socket\n";
return 2;
}
if(connect(sock, servinfo->ai_addr, servinfo->ai_addrlen) == -1){
std::cout << "Error connecting to host " << argv[1] << " at port " << argv[2] << "\n";
return 2;
}
if((send(sock, request,strlen(request), 0)) == -1){
std::cout << "Error communicating with website\n";
return 2;
}
if(recv(sock, buf, MAXDATASIZE, 0) == -1){
std::cout << "Error recciving data from " << argv[1] << " at port " << argv[2] << "\n";
}
std::cout << buf << std::endl;
close(sock);
freeaddrinfo(servinfo);
}
When I try to connect to google, using www.google.com as the host and 80 as the port, it hangs at the recv() call.To test whether the request was the problem, I connected to google using telnet with the same request, and it worked. I also tried binding netcat to a port on my computer, and then connected to that port using my program. The request was sent properly to netcat, and when I responded with a test message, my program reccived it.
Does anyone know why google isn't sending the data?
I'm using fedora 32, if that might help
Your software is not hanging. Rather, the server is waiting for an indication that the client has finished sending the headers, which is indicated by sending an empty line. Until the client sends the blank line, the server cannot respond.
Change your request to:
char request[] = "GET /robots.txt HTTP/1.1\r\n\r\n";
I´m building a socket client where I need to implement timeout for connections, read, writes and also timeout for the protocol itself (lack of answer, etc.).
I´m thinking of using a simple timer in a detached thread that will be started on every transaction and then cancelled on transaction completion. This same approach will be used for protocol control using a different timeout.
To test is I did the following simple code:
#include <string>
#include <sstream>
#include <map>
#include <iostream>
#include <cstring>
#include <thread>
#ifdef _WIN32
#include <io.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <Windows.h>
#else
#include <unistd.h>
#include <sys/socket.h>
#include <netdb.h>
#include <sys/types.h>
#endif
#include <stdio.h>
#include <stdlib.h>
bool timerOn = false;
int currentSocket = 0;
void Timer(int seconds)
{
int tick = seconds;
while (tick > 0)
{
std::this_thread::sleep_for(std::chrono::seconds(1));
tick--;
}
if (timerOn)
close(currentSocket);
}
void StartTimer(int seconds)
{
timerOn = true;
std::thread t(&Timer, seconds);
t.detach();
}
void StopTimer()
{
timerOn = false;
}
void Connect(std::string address, int port)
{
struct addrinfo hints;
struct addrinfo *result = NULL;
struct addrinfo *rp = NULL;
int sfd, s;
std::memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC; /* Allow IPV4 or IPV6 */
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = 0;
hints.ai_protocol = 0;
std::string portStr;
portStr = std::to_string(port);
s = getaddrinfo(address.c_str(), portStr.c_str(), &hints, &result);
if (s != 0)
{
std::stringstream ss;
ss << "Cannot resolve hostname " << address << gai_strerror(s);
throw std::runtime_error(ss.str());
}
for (rp = result; rp != NULL; rp = rp->ai_next)
{
sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (sfd == -1)
continue;
StartTimer(10);
int sts = connect(sfd, rp->ai_addr, rp->ai_addrlen);
StopTimer();
if (sts == 0)
break;
close(sfd);
}
freeaddrinfo(result); /* Object no longer needed */
if (rp == NULL)
{
std::stringstream ss;
ss << "Cannot find server address at " << address << " port " << port;
throw std::runtime_error(ss.str());
}
currentSocket = sfd;
}
int main()
{
try
{
Connect("192.168.0.187", 9090);
std::cout << "Connected to server. Congrats!!!" << std::endl;
}
catch (std::exception& ex)
{
std::cout << "Error connecting to server. Aborting." << std::endl;
std::cout << ex.what() << std::endl;
}
}
Closing the socket on timer is not canceling the 'connect' operation, forcing it to abort with error. I´ve tried also shutdown(sfd, SHUT_RDWR); with no success...
Is my approach invalid ? Why is it not working ?
How to force connect to abort with error from the detached thread ?
Closing the socket on timer is not canceling the 'connect' operation, forcing it to abort with error.
Whoa! You absolutely can't do that. There's no possible way to know that the thread is actually blocked in connect (as opposed to being about to call connect) when you close the socket. Releasing a resource in one thread while another thread is, or might be, using it is a recipe for disaster.
Imagine this happens:
A thread is about to call connect, so it arranges for a timeout.
The timeout expires and the socket is closed.
A thread in some library creates a new socket to use for some reason of its own, getting the same socket descriptor.
The thread that was about to call connect finally gets scheduled and calls connect -- connecting the library's socket! Disaster.
You have two choices:
Use a non-blocking connect operation.
Use something like a signal to interrupt the thread that calls connect.
But I have to wonder why you are bothering. Why do you need to abort the connect? If you need to do something else if the connect hasn't succeeded before the timeout, just go ahead and do it.
I want develop some irDA sockets applications, I am using:
compiler: visual c++ 2013.
platform: windows 7 x64
It seem s to me that something went wrong:
#include <iostream>
#include <winsock2.h>
#include <af_irda.h>
using std::cout;
using std::endl;
#pragma comment(lib,"ws2_32.lib")
int main()
{
WSADATA wSaData;
WSAStartup(MAKEWORD(2,2),&wSaData);
int sockServ = socket(AF_IRDA, SOCK_STREAM, 0);
if(sockServ == SOCKET_ERROR) //this condition succeeds which means creating socket failed!??
cout<<"Failed to create socket! " << WSAGetLastError() << endl;
DEVICELIST devLst;
devLst. = 0;
int len = sizeof(devLst;);
int rc = getsockopt(sockServ,SOL_IRLMP,IRLMP_ENUMDEVICES,(char*)&devLst,&devLst);
//rc also = -1;
WCE_IAS_QUERY wceIasQuery; // Error: WCE_IAS_QUERY is undefined
//...
return 0;
}
I'd like explanation:
1- why socket creation failed?
2- why getsockopt failed?
3- why WCE_IAS_QUERY is undeclared identifier?
4- what are the pre-requisites for irSock programming?
thank you guys!
I have this weird problem where whenever I #include "SDL/SDL.h", my windows socket program doesn't execute. It compiles but it doesn't do anything when run. When I remove the #include "SDL/SDL.h" header, compile and run, it starts working again??.
I'm trying to make both SDL and my original socket program work but I don't understand whats wrong this.
//#include "SDL/SDL.h"
#define _WIN32_WINNT 0x501
#include <iostream>
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <string.h>
#include <ws2tcpip.h>
#define MAXLEN 80
using namespace std;
const int winsockVersion = 2;
int main( int argc, char* args[] ) {
WSADATA wsadata;
if ( (WSAStartup(MAKEWORD(2,0),&wsadata)) == 0){
cout<<"-[ WSAStartup Initialized. ]" << endl;
char PORT[MAXLEN];
char SERVER[MAXLEN];
cout <<"Server: ";
cin>>SERVER;
cout <<"Port: ";
cin>>PORT;
struct addrinfo hints, *res;
int sockfd;
memset(&hints,0,sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if (getaddrinfo(SERVER,PORT,&hints,&res) != 0){
cout<<"-Getaddrinfo unsuccessful." << endl;
}
if ( (sockfd = socket(res->ai_family,res->ai_socktype,res->ai_protocol)) == -1 ){
cout<<"-Unable to create socket." << endl;
}
if ( (connect(sockfd,res->ai_addr,res->ai_addrlen)) != -1 ){
cout<<"-[ Connection Established. ]" << endl;
}
cout<<"-[ Client connecting to: ]" << res->ai_addr << endl;
while(true){
string text_buff;
cout<<"Send: ";
getline(cin,text_buff);
if( (send(sockfd,text_buff.c_str(),text_buff.length()+1,0)) != -1 ){
cout<<"-----------------------------------> Data sent!." << endl;
}
if ( text_buff == "quit" ){
break;
}
}
}else{
cout<<"-WSAStartup Initialization failed." << endl;
if(WSACleanup()!=0){
cout<<"-WSACleanup Successful." << endl;
}else{
cout<<"-WSACleanup Failed." << endl;
}
}
return 0;
}
compiling with
g++ -o draft.exe draft.cpp -I"C:\compilers and libs\Libs\SDL\SDL devep\SDL-1.2.15\include" -L"C:\compilers and libs\Libs\SDL\SDL devep\SDL-1.2.15\lib" -lmingw32 -lSDLmain -lSDL -lws2_32
As far as I know SDL rewrites the main function with some silly #define main trick, it intercepts program main like that.
Therefore, main might not be getting called at all.
If I remember right, your main function (arguments) should be exactly int main(int argc, char *argv[]).