Ive been trying to build an SNMP trap receiver using C++ and the winsock2 library, I have a thread set up to receive UDP data across port 161... as you would expect, when using a python socket program that i quickly threw together i was able to receive UTF-8 encoded strings and print them to the console. However, when i tried generating a SNMP Trap test event using iDRAC-9 (Dell server remote management tool), i managed to receive the 400 bytes as expected, but only printed 0é☺î☻☺. Frustratingly, the recvfrom() function can only take a char * parameter to receive the data. Im hoping to be able to decode roughly the same detail of data that Wireshark is capturing. Any help would be amazing!
code sample below:
int bytes_received = 0;
BYTE serverBuf[1025]{}; //1 Kilobyte + Null Terminating Character
int serverBufLen = 1024;
struct sockaddr_in SenderAddr {};
int SenderAddrSize = sizeof(SenderAddr);
do {
//Recieve Data
bytes_received = recvfrom(serverSocket, (char*)serverBuf, serverBufLen, 0, (SOCKADDR*)&SenderAddr, &SenderAddrSize);
if (bytes_received == SOCKET_ERROR) {
printf("recvfrom failed with error %d\n", WSAGetLastError());
bytes_received = 0;
}
//Make The String Null Terminated
serverBuf[bytes_received] = '\0';
std::cout << "Bytes Received: ";
std::cout << bytes_received << std::endl;
std::cout << serverBuf << std::endl;
//Send Data Back
char sendBuf[] = "Received\0";
if (sendto(serverSocket, sendBuf, (sizeof(sendBuf) - 1), 0, (SOCKADDR*)&SenderAddr, SenderAddrSize) == SOCKET_ERROR) {
printf("Sending back response got an error: %d\n", WSAGetLastError());
}
} while (active);
Wireshark Info
Related
I need some help with a socket program with multiple clients and one server. To simplify, I create
3 socket clients
1 socket server
For each client, it opens a new connection for sending a new message and closes the connection after a response is received.
For the server, it does not need to deal with connections concurrently, it can deal with the message one by one
here is my code (runnable), compile it with /usr/bin/g++ mycode.cpp -g -lpthread -lrt -Wall -o mycode
#include <iostream>
#include <arpa/inet.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include <unordered_map>
#include <thread>
using namespace std;
void Warning(string msg) { std::cout<< msg << std::endl; }
namespace mySocket {
class Memcached {
public:
// start a server
static void controller(int port=7111) { std::thread (server, port).detach(); }
// open a new connection to send a message:
// 1. open a connection
// 2. send the message
// 3. read the message
// 4. close the connection
std::string sendMessage(string msg, string host, int port=7111) {
int sock = 0, client_fd;
struct sockaddr_in serv_addr;
char buffer[1024] = { 0 };
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
std::cout << "Socket creation error, msg: " << msg << ", host: " << host << ", port: " << port << std::endl;
exit(1);
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port);
if (inet_pton(AF_INET, host.c_str(), &serv_addr.sin_addr) <= 0) {
std::cout << "\nInvalid address/ Address not supported, kmsgey: " << msg << ", host: " << host << ", port: " << port << std::endl;
exit(1);
}
while ((client_fd = connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr))) < 0) { sleep(10*1000); }
std::cout << "client sends a message:"<<msg<<", msg size:"<<msg.size()<<std::endl;
send(sock, msg.c_str(), msg.size(), 0);
read(sock, buffer, 1024);
close(client_fd);
return std::string(buffer, strlen(buffer));
}
private:
// start a server
// 1. open a file descriptor
// 2. listen the fd with queue size 10
// 3. accept one connection at a time
// 4. deal with message in the connection
// 5. accept the next connection
// 6. repeat step 3
static void server(int port) {
int server_fd, new_socket;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
char buffer[1024] = { 0 };
unordered_map<string,string> data;
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
Warning("socket failed"); exit(1);
}
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
Warning("setsockopt failed"); exit(1);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(port);
if (bind(server_fd, (struct sockaddr*)&address, sizeof(address)) < 0) {
Warning("bind failed"); exit(1);
}
// the queue size is 10 > 3
if (listen(server_fd, 10) < 0) {
Warning("listen failed"); exit(1);
}
while(1)
{
if ((new_socket = accept(server_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen)) < 0) {
std::cout << "accept failed"; exit(1);
}
memset(&buffer, 0, sizeof(buffer)); //clear the buffer
read(new_socket, buffer, 1024);
std::string msg = std::string(buffer, strlen(buffer));
if (msg.size()==0) {
std::cout<<"I can't believe it"<<std::endl;
}
std::cout<<"received msg from the client:"<<msg<<",msg size:"<<msg.size()<<std::endl;
std::string results="response from the server:["+msg+"]";
send(new_socket, results.c_str(), results.length(), 0);
//usleep(10*1000);
}
if (close(new_socket)<0){
std::cout <<"close error"<<std::endl;
}
shutdown(server_fd, SHUT_RDWR);
}
} ;
}
void operation(int client_id) {
auto obj = new mySocket::Memcached();
for (int i=0; i<10;i++){
int id=client_id*100+i;
std::cout<<obj->sendMessage(std::to_string(id), "127.0.0.1", 7111)<<std::endl<<std::endl;
}
}
int main(int argc, char const* argv[]) {
// start a socket server
mySocket::Memcached::controller();
// start 3 socket clients
std::thread t1(operation, 1);
std::thread t2(operation, 2);
std::thread t3(operation, 3);
t1.join();
t2.join();
t3.join();
}
In the code above, the client always sends a message with a length of 3. However, the server can receive messages with a length of 0 which causes further errors.
I'm struggling with this for several days and can't figure out why it happens. I noticed
if I add a short sleep inside the server while loop, the problem is solved. (uncomment usleep(10*1000); in the code).
or if I only use one client, the problem is also solved.
Any thought helps.
You are using TCP sockets. You may want to use some application-level protocol like HTTP, websockets instead, that will be much easier, because you will not need to worry about how message is sent/received and in which sequence. If you have to stick with TCP sockets, you firstly have to understand few things:
There's two types of TCP sockets you can use: non-blocking and blocking IO (input/output). You are currently using blocking IO. That IO will be sometimes blocked and you won't be able to do anything with sockets. In blocking IO, it can be work arounded by using one socket per thread on server-side. It's not efficient, but it's relatively easy comparing to Non-blocking IO. Non-blocking IO doesn't wait for anything. While in blocking IO you wait for data, in non-blocking IO you create something like events, callbacks, that are used when there's some data. You probably have to read about these types of IO.
In your server function, would be better, if you listen for incoming connections in one thread, and when there's incoming connection, move this connection into another thread and function, that will handle other things. This may solve your problem related to multiple clients at the same time.
In function operation, instead of allocating memory using raw pointer, use static allocation or smart pointers to avoid memory leaks. If you don't want to, then at least, do delete obj; in the end of function.
And the last one thing. You can use some TCP socket wrapper like sockpp to make things a lot easier. You will have anything TCP sockets have, but in C++ style and a little bit easier to understand and maintain. If you can't use application-level protocol, I strongly suggest you to use some wrapper at least.
Update
As was stated by commenters, there are more things you need to know:
TCP sockets are streams. This means that if you send your message with length of 1024 bytes, it can be divided into several TCP data packets and you can't know if it will be divided or not, how much packets other side will receive etc. You have to read in a while loop using recv() and wait for data. There's some tricks which can help you to properly receive data:
You can send length of your message first, so other side will know how much bytes it needs to receive.
You can place some terminating symbol or sequence of terminating symbols in the end of your message and read until these will be received. This can be a little risky, because there's chance that you would not receive these symbols at all and will be reading next.
You have to join client threads only when you know, that server is already started and listening for incoming connections. You can use some variable as a flag for these purposes, but make note, that you have to pay a lot of attention, when reading/writing variable from two or more different threads. For these purposes, you can use mutexes, which are some mechanism that will allow you safely access one variable from several threads.
So i am attempting to send an already constructed packet over a RAW socket interface (these are packets that have been previously captured and i want to resend them without changing the packet integrity) and am using TCPdump to check that the packets are going over correctly (surprise they are not).
The packets are physically being sent but are always 24 bytes short of what my "sent" returns.
In wireshark my eth headers seem to be erased as my source and dest MAC addresses are "00:00:00:00:00
sock setup is as follows
sock = socket(AF_PACKET,SOCK_RAW,IPPROTO_RAW);
if(sock==-1)
{
qDebug() << "sock error";
}
int reuse = 1;
if(setsockopt(sock, IPPROTO_RAW, IP_HDRINCL, (char *)&reuse, sizeof(reuse)) < 0)
{
qDebug() << "error setting reuse"
}
else
{
"setting reuse"
}
struct sockaddr_ll sll;
struct ifreq ifr;
bzero(&sll, sizeof(sll));
bzero(&ifr, sizeof(ifr));
sll.sll_family = AF_PACKET;
sll.sll_ifindex = ifr.ifr_ifindex;
sll.sll_protocol = htons(IPPROTO_RAW);
sll.sll_halen = ETH_ALEN;
strncpy((char*)ifr.ifr_ifrn.ifrn_name,interface.toUtf8.constData(),IFNAMSIZ);
if(ioctl(sock,SIOCGIFINDEX,&ifr) == -1)
{
qDebug() << "error getting interface name";
}
strncpy((char*)ifr.ifr_ifrn.ifrn_name,interface.toUtf8.constData(),IFNAMSIZ);
if(ioctl(sock,SIOCGIFHWADDR,&ifr) == -1)
{
qDebug() << "error getting interface name";
}
if(bind(sock,(struct sockaddr *)&sll,sizeof(sll))==-1)
{
qDebug() << "error binding sock";
}
after this im using
int size = write(sock,(const void*)&packet,hdr.caplen);
i've tried sendto in the past but it would always reconfigure things so this was my next solution which also isnt working as i would like.
I'm not the most savy with TCP/IP stuff so any help would be greatly appreciated!
okay so after just trying a bunch of different stuff i landed on what seems to be my solution.
i created a second pointer that will point to the top of the packet and send that instead.
(char *)sendingPacket;
struct ethhdr *ethh = (struct ethhdr*)packet;
sendingPacket = (char*) ethh;
i don't really understand why this works but sending the other packet doesn't so if anyone has insight please share!
I try to send data via UDP from a computer to another (first Computer: Ubuntu, C++ with Eclipse, second Computer Windows 10 Matlab 2014b). The C++ computer should work as server. Sending data from C++ to Matlab works fine, but i am not able to send data in opposite direction. Every time my C++ program reaches recvfrom() it will idle at this point without doing anything anymore, even if matlab is sending data over and over againg. I tried to receive data on ubuntu via netcat while sending the packages with Matlab and that works fine as well. Even i tried something with select() but this only resulted in waiting for 10s when program reaches select() and then freezes at recvfrom again. I would be very grateful if someone can give me some help.
int Socket=socket(AF_INET, SOCK_DGRAM,0);
/*FD_ZERO(&SockSet);
FD_SET(Socket,&SockSet);
sTimeval.tv_sec=0.1;
sTimeval.tv_usec=0;
int status=select(Socket+1,&SockSet,(fd_set*)NULL,(fd_set *)NULL,&sTimeval);
cout<<status<<endl;*/
if(Socket!=-1)
cout<<"Socket created"<<endl;
else
cout<<"Socket not created"<<endl;
unsigned short port=4012;
struct in_addr serverIP;
//(void)inet_pton(AF_INET,"192.168.56.100", &clientIP);
(void)inet_pton(AF_INET,"192.168.56.101", &serverIP);
struct sockaddr_in server;
memset(&server,0, sizeof(server));
server.sin_family=AF_INET;
server.sin_addr=serverIP;
server.sin_port=htons(port);
if(bind(Socket,(struct sockaddr*)&server, sizeof(&server))!=1)
cout<<"Binding successful"<<endl;
else
cout<<"Binding failed";
struct sockaddr client;
memset(&client, 0, sizeof(client));
socklen_t clientlen=0;
struct sockaddr_in* client_in;
memset(&client_in,0,sizeof(client_in));
cout<<"warten vor recv"<<endl;
ssize_t bytesread=recvfrom(Socket, &msg, sizeof(msg), 0, &client,&clientlen);
cout<<(int)bytesread<<endl;
cout<<msg<<endl;
client_in=(struct sockaddr_in*)&client;
char* client_adr=inet_ntoa(client_in->sin_addr);
printf("%s Port%d\n", client_adr, ntohs(client_in->sin_port));
if (bytesread == -1) {
cerr << "Fehler beim empfangen" << endl;
int status = close(Socket);
if (status == 0)
cout << "Socket closed" << endl;
else if (status == -1)
cout << "Socket not closed" << endl;
return (1);
}
//Wenn Infos ueber Client nicht schon vorher aus recvfrom()
/*struct in_addr clientIP;
(void)inet_pton(AF_INET,"192.168.2.102", &clientIP);
struct sockaddr_in client;
memset(&client,0, sizeof(client));
client.sin_family=AF_INET;
client.sin_addr=clientIP;
client.sin_port=htons(portwindows);*/
char msg2[]="12345";
ssize_t bytessent=sendto(Socket,msg2,strlen(msg2),0,(struct sockaddr*)&client,sizeof(client));
cout<<(int)bytessent<< " bytes were sent"<<endl;
int status=close(Socket);
if(status==0)
cout<<"Socket closed"<<endl;
else if(status==-1)
cout<<"Socket not closed"<<endl;
After running the program in Debug mode suddenly the program is passing recvfrom, but without receiving the data which was sent. Even if i run recvfrom in a while-loop and send constantly data to the port recvfrom never get a package. If i try to run listen and accept before it (i know usally that is not necessary by udp connection) the functions both returns -1. But i can not see why my Socket is not ready to receive data. Maybe anynone have an idea to fix this problem?
I am trying to make a program that uses HTTP in winsock, but I have run into a problem where the recv function just hangs there.
int connect()
{
WSADATA t_wsa; //WSADATA structure
WORD wVers = 0x0202; //version number
int iError; //error number
wVers = MAKEWORD(2, 2); // Set the version number to 2.2
iError = WSAStartup(wVers, &t_wsa); // Start the WSADATA
if(iError != NO_ERROR || iError == 1)
{
printf("Error at WSAStartup()\n");
WSACleanup();
system("PAUSE");
return 1;
}
/* Correct version? */
if(LOBYTE(t_wsa.wVersion) != 2 || HIBYTE(t_wsa.wVersion) != 2)
{
printf("Incorrect version\n");
WSACleanup();
system("PAUSE");
return 1;
}
SOCKET sClient;
sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(sClient == INVALID_SOCKET || iError == 1)
{
printf("Invalid Socket!\n");
WSACleanup();
system("PAUSE");
return 1;
}
SOCKADDR_IN sinClient;
memset(&sinClient, 0, sizeof(sinClient));
char cIP[50];
strcpy_s(cIP, "98.139.183.24");
sinClient.sin_family = AF_INET;
sinClient.sin_addr.s_addr = inet_addr(cIP); // Where to start server
sinClient.sin_port = htons(80); //Port
if(connect(sClient, (LPSOCKADDR)&sinClient, sizeof(sinClient)) == SOCKET_ERROR)
{
/* failed at starting server */
printf("Could not connect ot the server!\n");
WSACleanup();
system("PAUSE");
return 1;
}
// Now we can send/recv data!
printf("YOU ARE CONNECTED!\r\n");
string buffer;
buffer += "GET / HTTP/1.1\r\n";
buffer += "Host: http://www.yahoo.com/\r\n";
buffer += "Connection: close\r\n\r\n";
const char *cha = buffer.c_str();
int sent;
int response;
sent = send(sClient, cha, sizeof(cha) - 1, 0);
char recvbuf[50000];
response = recv(sClient, recvbuf, 50000, 0);
recvbuf[response] = '\0';
printf("\nReceived data = %s", recvbuf);
WSACleanup();
return(0);
}
"sent" will get printed after the send function, but nothing after recv gets printed.
What am I missing here?
A possible cause is that the send() is not sending the data intended:
sent = send(sClient, cha, sizeof(cha) - 1, 0);
the sizeof(cha) - 1 is actually sizeof(char*) - 1, not the actual length of the data: use buffer.length() instead.
Note that you can construct the std::string with the string literal in a single statement instead of constructing it via several concatentations. However, as the std::string is being used to obtain a const char* only there is no reason for using std::string at all:
const char* buffer = "GET / HTTP/1.1\r\n"
"Host: http://www.yahoo.com/\r\n"
"Connection: close\r\n\r\n";
sent = send(sClient, buffer, strlen(buffer), 0);
Check the return value of send() and recv() to determine success or failure, particularly recv() as the result is being used to index an array. On failure, recv() returns SOCKET_ERROR which (I think) is -1.
Handling HTTP responses correctly requires significant effort. The receiving code needs to examine the returned HTTP headers to determine how to handle the response content. For example, a HTTP response may be chunked or not. Libraries exist for managing HTTP requests, one is cpp-netlib (which was announced on isocpp.org circa February 2013).
I'm trying to send a file from client to server using winsock2 lib.
After converting the file into char array, i'm sending this array using the send() command.
The problem: the data sent separately.
For e.g: I have file of size: 144429.
It does not send it at once, the data is split into many portions, like:
first send: 1460
second send: 21544
third send: 57136
etc..
until to whole data is sent.
so my question is: what causes it to send it by parts and not by once????
Solution I found working but not making any sense:
If i'm adding
cout << "bla bla bla";
before the send() function, it does work and send the whole 144429 by once. (but if the string given to cout is shorter, no change, send by parts)
CODE:
CLIENT SIDE
int Client::sendData(char *sendbuf, int length)
{
int iResult;
// if I remove those next few lines (until and including the cout line)
// the send will split.
char tmp[1];
// sent 1 dummy byte
iResult = send( _connectSocket, tmp, 1, 0 );
if (iResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
return closeSocket();
}
cout << "SENDING DATA..." << endl;
// THIS IS THE RELEVANT AND ACTUAL DATA I WANT TO SEND
// send the data
iResult = send( _connectSocket, sendbuf, length, 0 );
if (iResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
return closeSocket();
}
cout << "Data sent (" << iResult << " Bytes)" << endl;
return 0;
}
SERVER SIDE:
char recvbuf[DEFAULT_BUFLEN];
int recvbuflen = DEFAULT_BUFLEN;
int iResult = 0;
int totalBytesRead = 0;
// Receive until the peer shuts down the connection
do {
totalBytesRead += iResult;
iResult = recv(_clientSocket, recvbuf, recvbuflen, 0);
if (iResult > 0) {
printf("RECEIVED DATA\n");
printf("Bytes received: %d\n", iResult);
} else if (iResult == 0)
printf("Connection closing...\n");
else {
printf("recv failed: %d\n", WSAGetLastError());
closesocket(_clientSocket);
WSACleanup();
return 1;
}
} while (iResult > 0);
// store data into file
FileTransfer::binaryToFile(recvbuf, "doch.docx", totalBytesRead-1);
return 0;
}
There is no way to guarantee that send transmits some data as one unit - it just doesn't work that way. You have to add some extra information to tell the system that "Here's this much data to come" and/or "I'm done now". Even if you could convince your sending side to send of everything in one packet, assuming the receiving side isn't connected DIRECTLY with just a simple cable to the sender, you can't guarantee that the packet isn't broken up during it's passing through the network.
You just have to accept that if you are sending more than a single byte in a packet, you may have to call send multiple times. To simplify it, write a function that takes a an arbitrary size "whole packet" and calls send as many times as necessary... If you have a protocol that indicates the size of the data sent [such as in the first few bytes], you could have a receive function that does the same thing.
Depending on the socket type you are using there might be a limitation of data size in the underlying transport protocol.
In case you are using a network socket the size is limited by the maximum transfer unit (see: http://en.wikipedia.org/wiki/Maximum_transmission_unit).
If your data doesn't fit this size you will have to iterate in a loop sending portions of your data until either an error occurs or all data has been sent.