Tried this code to send/receive with Asio UDP sockets (boost less version)
asio::io_service service;
asio::ip::udp::socket sock(service);
asio::ip::udp::endpoint endpoint(asio::ip::address::from_string("127.0.0.1"), 20100);
sock.connect(endpoint);
sock.send(buffer("testing\n"));
std::string buffer;
size_t length = sock.receive(asio::buffer(buffer)); <--- spawn exception
but got following error:
An existing connection was forcibly closed by the remote host
Something wrong here? Thanks for any help!
I don't know how you build your udp server, but I guess something wrong with it. I write an example program to explain the error message you get:
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main()
{
struct sockaddr_in addr;
int fd, cnt, ret;
if ((fd=socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
printf("error");
exit(1);
}
memset(&addr, 0, sizeof(addr));
addr.sin_family=AF_INET;
addr.sin_addr.s_addr=inet_addr("127.0.0.1");
addr.sin_port=htons(9090); // address which is not bound
ret = connect(fd,(struct sockaddr *)&addr,sizeof(addr));
char buf[512];
cnt = send(fd, "hello", sizeof("hello"), 0);
if(cnt < 0)
perror("send:");
cnt = recv(fd, buf, 512, 0); // error: Connection refused
if(cnt < 0)
perror("recv:");
return 0;
}
I try to send data to udp port 9090 at localhost or any host which no udp socket is bound to port 9090. the send() succeeds but the recv() fails. According to man page for udp:
All fatal errors will be passed to the
user as an error return even when the
socket is not connected. This includes
asynchronous errors received from the
network. You may get an error for an
earlier packet that was sent on the
same socket. This behaviour differs
from many other BSD socket
implementations which don't pass any
errors unless the socket is connected.
Linux's behaviour is mandated by
According to the rfc 1122
which says:
UDP MUST pass to the application layer all ICMP error messages that it receives from the IP layer. Conceptually at least, this may be accomplished with an upcall to the ERROR_REPORT routine
the send() succeeds, but it causes an ICMP error message(you can see it with tcpdump), then recv() sees this error(You may get an error for an earlier packet that was sent on the same socket), so it fails.
Related
I am trying to create a simple HTTP server in C++. I want each request to be handled simultaneously in separate threads, but when I create a thread and put a simple sleep(10) at the start to cause some delay, another request to the server cannot be made until the first thread finishes. What am I doing wrong?
Here is my code so far:
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string>
#include <ostream>
#include <iostream>
#include <thread>
using namespace std;
void send_response (int socket)
{
sleep (10);
char buffer[2048] = {0};
int request = recv (socket, buffer, 2048, 0);
if (request == -1) {
perror ("error");
}
string message = "Hello from server";
string length = to_string (message.length ());
string hello = "HTTP/1.1 200 OK\nContent-Type: text/plain\nContent-Length: " + length + "\n\n" + message;
send (socket, hello.c_str (), hello.length (), 0);
close (socket);
}
int main(int argc, char const *argv[])
{
struct sockaddr_in address;
int opt = 1;
socklen_t addrlen = sizeof (address);
int server_fd = socket (AF_INET, SOCK_STREAM, 0);
if (server_fd == 0) {
perror ("socket failed");
exit (EXIT_FAILURE);
}
if (setsockopt (server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof (opt))) {
perror ("setsockopt");
exit (EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons (8080);
if (bind (server_fd, (struct sockaddr *)(&address), sizeof (address)) < 0) {
perror ("bind failed");
exit (EXIT_FAILURE);
}
if (listen (server_fd, 3) < 0) {
perror ("listen");
exit (EXIT_FAILURE);
}
while (true) {
int new_socket = accept (server_fd, (struct sockaddr *)(&address), &addrlen);
if (new_socket < 0) {
perror ("accept");
exit (EXIT_FAILURE);
}
thread response (&send_response, new_socket);
response.detach ();
cout << "request handled" << endl;
}
return 0;
}
I don't need to wait for the thread to finish or get any data back from the thread, I just want it to start, do some work, and send something back to the client. I expect each thread will be doing a decent amount of work, that's why I used sleep.
Edit: It seems the loop is ready and waiting for a second connection and will successfully accept a new connection and create a new thread to handle it, but only if the second connection is from a different IP address. So if I visit the server at 127.0.0.1:8080 and from a different local IP address like 192.168.1.91, both connections will go through with two threads running simultaneously. However, if I simply open two tabs, both at 127.0.0.1:8080, only one connection will be accepted at a time, the other will stall. It seems I need the code to handle multiple connections from the same IP address, but a search for that kind of problem on Google hasn't given me any good results.
Ok, my bad, everything is working as expected. Using wget to send multiple requests from the same IP causes multiple threads to be created and for the requests to be processed simultaneously. In Chrome, for some reason opening multiple tabs from the same IP causes them to be sent in serial, but in Firefox they are sent in parallel and arrive and are processed at the same time. That is weird, but I'll chock it up to an oddity of Chrome.
I'm having issues working with a UDP socket in Windows. I have a separate application I'm trying to communicate with that outputs on port 1625 and receives on port 26027. I tried to make a simple executable that reads one message and sends one message. The read works fine, but the send ends up with a WSAEADDRNOTAVAIL (10049) error.
To troubleshoot I also tried the equivalent code in Linux with (using Windows Subsystem for Linux) on the same machine and it works fine. So I can't figure out what the issue is. I also tried disabling Windows Firewall but that didn't make a difference. Any suggestions would be appreciated.
The Windows Visual C++ code:
#pragma comment(lib, "Ws2_32.lib")
#include <iostream>
#include <WS2tcpip.h>
#define MAXLINE 1024
int main()
{
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
// Define local port address.
sockaddr_in local_port;
memset(&local_port, 0, sizeof(local_port));
local_port.sin_family = AF_INET;
local_port.sin_addr.s_addr = INADDR_ANY;
local_port.sin_port = htons(1625);
// Bind local socket.
int socket_id = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
bind(socket_id, (const struct sockaddr *)&local_port, sizeof(local_port));
// Receive UDP Port message.
char in_buffer[MAXLINE];
int num_bytes = recv(socket_id, (char *)in_buffer, MAXLINE, 0);
in_buffer[num_bytes] = '\0';
printf("Received : %s\n", in_buffer);
// Set up send destination port.
sockaddr_in dest_port;
memset(&dest_port, 0, sizeof(dest_port));
dest_port.sin_family = AF_INET;
dest_port.sin_addr.s_addr = INADDR_ANY;
dest_port.sin_port = htons(26027);
// Send UDP message to specific UDP port.
char out_buffer[] = "Test message";
int result = sendto(
socket_id, out_buffer, strlen(out_buffer), 0, (struct sockaddr *)&dest_port, sizeof(dest_port));
printf("Send result : %d -- WSA Error : %d\n", result, WSAGetLastError());
closesocket(socket_id);
return 0;
}
Terminal output from running this executable is:
Received : 5e4009df*755=-0.0028:761=0.6942
Send result : -1 -- WSA Error : 10049
The WSL linux C++ code (the same source code except for WSA includes and error output):
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define MAXLINE 1024
int main()
{
// Define local port address.
sockaddr_in local_port;
memset(&local_port, 0, sizeof(local_port));
local_port.sin_family = AF_INET;
local_port.sin_addr.s_addr = INADDR_ANY;
local_port.sin_port = htons(1625);
// Bind local socket.
int socket_id = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
bind(socket_id, (const struct sockaddr *)&local_port, sizeof(local_port));
// Receive UDP Port message.
char in_buffer[MAXLINE];
int num_bytes = recv(socket_id, (char *)in_buffer, MAXLINE, 0);
in_buffer[num_bytes] = '\0';
printf("Received : %s\n", in_buffer);
// Set up send destination port.
sockaddr_in dest_port;
memset(&dest_port, 0, sizeof(dest_port));
dest_port.sin_family = AF_INET;
dest_port.sin_addr.s_addr = INADDR_ANY;
dest_port.sin_port = htons(26027);
// Send UDP message to specific UDP port.
char out_buffer[] = "Test message";
int result = sendto(
socket_id, out_buffer, strlen(out_buffer), 0, (struct sockaddr *) &dest_port, sizeof(dest_port));
printf("Send result : %d\n", result);
close(socket_id);
return 0;
}
Terminal output from running this executable is:
Received : 5e4009df*755=-0.0028:761=0.6942
Send result : 12
I can also validate that the output to port 26027 via this Linux implementation is received by the other application and can also see it in Wireshark.
EDIT:
After Remy's answer below I was able to get this working as per the comments below. To clarify my network:
My network if I view it with Wireshark now looks like:
127.0.0.1 UDP 50223 → 1625 Len=32
127.0.0.1 UDP 1625 → 26027 Len=12
Where my node binds to 1625 where it can recv() UDP from some unknown port number (50223 in this case), and sendto() port 26027.
You can't use recv() with a UDP socket unless you first call connect() to statically assign the peer's IP/port to the socket, which you are not doing. So recv() will fail, but you are not checking for that. You need to use recvfrom() instead.
Also, no matter what, you can't send packets to INADDR_ANY (0.0.0.0) as you are. That is why you are getting the send error.
sendto Function
WSAEADDRNOTAVAIL
The remote address is not a valid address, for example, ADDR_ANY.
Windows Sockets Error Codes
WSAEADDRNOTAVAIL
10049
Cannot assign requested address. The requested address is not valid in its context. This normally results from an attempt to bind to an address that is not valid for the local computer. This can also result from connect, sendto, WSAConnect, WSAJoinLeaf, or WSASendTo when the remote address or port is not valid for a remote computer (for example, address or port 0).
You need to send to an actual IP/port, such as to the peer's IP/port that is reported by recvfrom() when it receives a packet.
I'm trying to get a little SSDP client / server up and running. So far the server is working just fine, responding to my M-SEARCH (according to wireshark). The client code is written in Visual Studio using Winsock2 (see code below). The problem is that the response never reaches my recv call when i send the search to the multicast address.
I already tried sending and receiving directly to the server ip address, which will generate a response that reaches my recv call correctly. However, when i change the ip to the multicast addess, it doesn't work (even though i can see the response on Wireshark!). So for some reason the socket (on OS level?) refuses to pass it on to the application.
I should note that the response is always unicast.
Here's my code:
#include <Winsock2.h> // before Windows.h, else Winsock 1 conflict
#include <Ws2tcpip.h> // needed for ip_mreq definition for multicast
#include <Windows.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define SERVERPORT 1900
char buff[] = "M-SEARCH * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nMAN: ssdp:discover\r\nST: ssdp:all\r\n\r\n";
int main()
{
char rcvdbuff[1000];
int len, Ret = 2;
WSADATA wsaData;
if (WSAStartup(0x0101, &wsaData)) {
perror("WSAStartup");
return 1;
}
struct sockaddr_in their_addr;
SOCKET sock;
sock = socket(AF_INET, SOCK_DGRAM, 0);
their_addr.sin_family = AF_INET;
////THIS APPROACH DOES NOT WORK
their_addr.sin_addr.s_addr = inet_addr("239.255.255.250");
//THIS APPROACH WORKS - SOMEHOW THE SOCKET IS BOUND TO THIS IP AND CAN THUS RECEIVE
//their_addr.sin_addr.s_addr = inet_addr("192.168.3.90");
their_addr.sin_port = htons(SERVERPORT);
len = sizeof(struct sockaddr_in);
while (1)
{
printf("buff:\n%s\n", buff);
Ret = sendto(sock, buff, strlen(buff), 0, (struct sockaddr*)&their_addr, len);
if (Ret < 0)
{
printf("error in SENDTO() function");
closesocket(sock);
return 0;
}
//Receiving Text from server
printf("\n\nwaiting to recv:\n");
memset(rcvdbuff, 0, sizeof(rcvdbuff));
Ret = recvfrom(sock, rcvdbuff, sizeof(rcvdbuff), 0, (struct sockaddr *)&their_addr, &len);
if (Ret < 0)
{
printf("Error in Receiving");
return 0;
}
rcvdbuff[Ret - 1] = '\0';
printf("RECEIVED MESSAGE FROM SERVER\t: %s\n", rcvdbuff);
//Delay for testing purpose
Sleep(3 * 1000);
}
closesocket(sock);
WSACleanup();
}
I tried one interesting thing (without restarting the application!):
1) First send to the direct ip address (192.168.3.90)
2) Get response
3) Now send to the multicast address
4) Now the response gets back just fine!
It's as if the socket somehow 'knows' the unicast address from the first send/recv call.
Does anyone know what to do or how to debug?
I think I've found the solution to the question: Windows Firewall.
Here's a quote over from Quora:
Only connections that are explicitly allowed, using firewall rules, are permitted. Windows Firewall, by default, allows all outboundconnections, and permits only established inbound connections (that is, an inbound connection that is in direct response to an outbound connection initiated from your computer or network).
This is exactly the situation: We've not established an outbound connection, and thus it's blocked by Windows Firewall!
In the other case, when I first send directly, Windows Firewall opens up for that exact inbound connection and therefore the subsequent multicast send gets a response.
I'm using winsocks and I am coding an IDS/Honeypot, this is just a small section of it, because at the moment I want the server to listen on multiple sockets (7) and accept the connections, but I've tried to dynamically create the sockets with an array (and the listener etc) but I am still having trouble - I've tried it multiple ways but so far, all I've managed to do is get it working successfully on ONE socket, and LISTEN to all sockets, but not accept them.
So, this was my last attempt but not sure, maybe I need to use threads or declare the sockets differently?
So far, in this small test code, I want:
Initialize server
listen on all 7 ports (1111,2222 ...etc)
Accept an incoming connection on ANY of them
display both messages on client/server
drop the connection
and continue
It's a little sloppy I know, but here is the code so far and I think you can see where I am going with it:
#include <iostream>
#include <winsock2.h>
#include <string>
#pragma comment(lib, "ws2_32.lib")
int main()
{
std::cout<<"Honeypot server [test #1] by Dreamwalker"<<std::endl;
WSADATA wsa;
SOCKET s[7] , new_socket[7];
struct sockaddr_in server , client;
int c, port[7] = {1111,2222,3333,4444,5555,6666,7777};
char *message;
std::cout<<"\nInitialising Winsock and other components...";
if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
{
std::cout<<"Failed. Error Code :"<<WSAGetLastError()<<std::endl;
return 1;
}
//!IMPORTANT: create multiple new sockets on different ports
int i = 0;
for( i = 0; i < 7; i++)
{
//Create socket
if((s[i] = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
{
std::cout<<"Could not create socket : "<< WSAGetLastError()<<std::endl;
}
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( port[i] );
//Bind
if( bind(s[i] ,(struct sockaddr *)&server , sizeof(server)) == SOCKET_ERROR)
{
std::cout<<"Bind failed with error code : "<< WSAGetLastError()<<std::endl;
}
/*!ALL CREATION CHECKING DONE, now create multiple sockets on the server
and listen for connections*/
c = sizeof(struct sockaddr_in);
listen(s[i] , SOMAXCONN);
}
///ALL INITIALIZED
std::cout<<"DONE!"<<std::endl;
//Listen/accept incoming connections
std::cout<<"Now listening for connections"<<std::endl;
new_socket[i] = accept(s[i] , (struct sockaddr *)&client, &c);
if (new_socket[i] == INVALID_SOCKET)
{
std::cout<<"accept failed with error code : "<< WSAGetLastError()<<std::endl;
}
//Accepted connection
else{
std::cout<<"Someone has connected to this machine!"<<std::endl;
message = "Hello Client , I have received your connection.\n";
send(new_socket[i] , message , strlen(message) , 0);
closesocket(s[i]);
}
std::cout<<"FINISHED"<<std::endl;
WSACleanup();
getchar();
return 0;
}
And now it's throwing a runtime error as well:
WSAENOTSOCK
10038
Socket operation on nonsocket.
An operation was attempted on something that is not a socket. Either the socket handle parameter did not reference a valid socket,
or for select, a member of an fd_set was not valid.
Which (including debugging) indicates that the socket isn't declared properly when creating on an array, advice?
You code to create/bind/listen is all good. Then:
new_socket[i] = accept(s[i] , (struct sockaddr *)&client, &c);
Firstly, by the time this runs you're outside the loop, and i is 7 which is past the end of the array of sockets, which is why you get the not-a-socket error.
Secondly, accept() is a blocking call, so you can't just call accept() on all the sockets from the same thread the way you did for listen. You need to either have a separate thread block in accept() for each of the ports, or find out which one has a client connection attempt in progress using e.g. select (or epoll - does Windows have that?), then accept() a client on that specific socket (but then you've still got to either create a thread to handle the client read/recvs and write/sends or use select/epoll to find out when there's input ready to read, or more space in output buffers for transmission). There's also a race condition to be wary of if you use select/epoll - a listening socket might signal readiness for accepting a client connection, but by the time you call accept() that connection attempt's failed and forgotten, then if the listening socket hasn't been set to non-blocking mode it'll hang there waiting for another client to connect to that specific socket. IMHO, this is a case where threading is actually easier.
I think it's more "Windowsy" to use IO Completion Ports (you might want to Google), but AFAIK they're totally unportable. Winsock's not an exact match for BSD sockets, but the porting or dual-support effort's small.
Below is the following basic socket code I came up with:
//General includes:
#include <iostream>
#include <stdio.h>
#include <string>
//Network related includes:
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
//Target host details:
#define PORT 1234
#define HOST "74.74.74.74"
using namespace std;
//Function prototypes:
string MessageFormat(int, char**);
void MessageSend(string);
int main(int argc, char *argv[])
{
//Parse arguments and format message:
string message = MessageFormat(argc, argv);
//Send the message out:
MessageSend(message);
return 0;
}
string MessageFormat(int argc, char *argv[])
{
//Massage the command line parameters
// into my desired payload format.
return message;
}
void MessageSend(string message)
{
int sd, ret;
struct sockaddr_in server;
struct in_addr ipv4addr;
struct hostent *hp;
sd = socket(AF_INET,SOCK_DGRAM,0);
server.sin_family = AF_INET;
inet_pton(AF_INET, HOST, &ipv4addr);
hp = gethostbyaddr(&ipv4addr, sizeof ipv4addr, AF_INET);
//hp = gethostbyname(HOST);
bcopy(hp->h_addr, &(server.sin_addr.s_addr), hp->h_length);
server.sin_port = htons(PORT);
connect(sd, (const sockaddr *)&server, sizeof(server));
send(sd, (char *)message.c_str(), strlen((char *)message.c_str()), 0);
}
This is quite basic, and does in fact work. HOWEVER, it's sending UDP packets instead of TCP packets, so the target host expecting TCP rejects these. Also, by inspecting connect/send values and watching my interfaces with ngrep I can 100% verify the packet is going out, so that's not the issue.
I'm only interested in modifying what I have, not creating a full featured server with boost asio. How can I tweak this so that it operates in terms of TCP instead of UDP?
Following are changes you need to make to transfer data via TCP
While creating socket pass correct parameters .In above example you passed SOCK_DGRAM instead pass SOCK_STREAM.
After binding server should go into listen mode (check the manual page of listen)
while Client Side should connect after socket creation.
Then accept in server side after listen.
Final Read and write to transfer data
Diagram attached will give you a clear picture of TCP connection
You can check manual pages for detailed info on all functions or refer beej's guide for socket programming ( use this link )
Replace SOCK_DGRAM with SOCK_STREAM.
Also, read the manual or get a good book.