Bad file descriptor error while sending data through tcp socket - c++

I want to create data and then send to server. Data from information on each sensor should create in Network.cpp after new sensor was added (each sensor is an new network) and send with client.cpp, I use inheritance to use function add of Network class to client class or vice versa but I need help to use function correctly for my program work. When I run program I get this error:
connect failed. Error: Bad file descriptor
What am I missing?
Network.h:
class Network :public client{
public:
Network();
void add(Sensor new_sensor);
virtual ~Network();
private:
vector<Sensor> sensors;
}
Network.cpp:
void Network::add(const client &a,Sensor new_sensor) {
sensors.push_back(new_sensor);
unsigned int Header[2] = {0xe1,0xe2};
uint16_t u16;
u16 = htons(Header[2]);
memcpy(packet + 0, &u16, 2);
unsigned int SensorSn[4] = { 0x1e, 0x25, 0x71, 0x80 };
uint32_t u32;
u32 = htons(SensorSn[4]);
memcpy(packet + 2, &u32, 4);
uint32_t a32;
unsigned int SensorTemp[4] = { 0x00, 0x00, 0x00, 0x23 };
a32 = htons(SensorTemp[4]);
memcpy(packet + 6, &a32, 4);
a.send_data();
}
client.h:
class client {
public:
client();
void conn(string, int);
void send_data() const;
string receive(int);
virtual ~client();
private:
int sock;
struct sockaddr_in server_addr;
protected:
char packet[10];
};
}
client.cpp:
void client::conn(string address, int port) {
//create socket if it is not already created
if (sock == -1) {
//Create socket
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == -1) {
perror("Could not create socket");
}
cout << "Socket created\n" << endl; //doesn't show this line!!!
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(1234);
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
while(1){
int m=connect(sock, (struct sockaddr *) &server_addr, sizeof(server_addr));
if (m==-1){
perror("connect failed. Error");
continue;
}
}
cout << "Connected\n"; //doesn't show this line!!!
close(sock);
}
void client::send_data()const {
int n=send(sock, packet, sizeof(packet), 0) ;
if (n==-1){
perror("send failed. Error"); ///my program stop in this line
exit(1);
}
cout << "Data send"<<endl;
close(sock);
}

Did you remember to initialize sock to -1 in your constructor?

Related

Issue with C++ UDP Client Hanging Up

The project I am working on uses TCP and UDP to create a file transport protocol. The TCP connection generates a random port in which it returns to the client and the client then connects to the server on that port number using UDP. UDP is then used to transfer a text file four characters a time to the server and the server will send back the characters capitalized in which will then be displayed on the client. The issue is that the client is hanging up when waiting for the server to send back the capitalized version of the characters. I will leave the code below. The part of the code that is not working is commented out towards the end of the client and server files. Any help is appreciated!
Client Code
// Libraries
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <unistd.h>
using namespace std;
int main(int argc, char* argv[]) {
// Variables
int port = strtol(argv[2], NULL, 10);
string file = argv[3];
int r_port;
FILE* fp;
string fileString;
string dataBuffer;
int charCounter = 0;
char c;
// *** Declare TCP socket ***
int tcpsocket = 0;
tcpsocket = socket(AF_INET, SOCK_STREAM, 0);
if (tcpsocket == -1) {
cerr << "Can't create a socket";
return 1;
}
// Get host IP address
struct hostent *s;
s = gethostbyname(argv[1]);
// Setting destination info
struct sockaddr_in server;
memset((char *) &server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(port);
bcopy((char *) s->h_addr, (char *) &server.sin_addr.s_addr, s->h_length);
// Connect to server
int connectRes = connect(tcpsocket, (sockaddr*)&server, sizeof(server));
if (connectRes == -1) {
cerr << "Can't connect to socket";
return 1;
}
// Sending data to server
char payload[512] = "117";
int sendRes = send(tcpsocket, payload, 512, 0);
if (sendRes == -1) {
cerr << "Could not send to server";
return 1;
}
// Receive r_port from server
memset(payload, 0, sizeof(payload));
recv(tcpsocket, payload, 512, 0);
r_port = strtol(payload, NULL, 10);
close(tcpsocket);
// *** Declare UDP socket ***
int udpsocket = 0;
udpsocket = socket(AF_INET, SOCK_DGRAM, 0);
if (udpsocket == -1) {
cerr << "Can't create a socket";
return 1;
}
// Get host IP address
s = gethostbyname(argv[1]);
// Setting destination info
memset((char *) &server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(r_port);
bcopy((char *) s->h_addr, (char *) &server.sin_addr.s_addr, s->h_length);
// File manipulation
fp = fopen(file.c_str(), "r");
while (c != EOF) {
c = fgetc(fp);
fileString += c;
charCounter++;
}
fclose(fp);
// UDP file transfer
for (int i = 4; i < 8; i++) {
dataBuffer += fileString[i];
}
socklen_t slen = sizeof(server);
memset(payload, 0, sizeof(payload));
strcpy(payload, dataBuffer.c_str());
sendRes = sendto(udpsocket, payload, 32, 0, (struct sockaddr *) &server, slen);
if (sendRes == -1) {
cerr << "Could not send to server";
return 1;
}
// Receive ack
// slen = sizeof(server);
// memset(payload, 0, sizeof(payload));
// recvfrom(udpsocket, payload, 32, 0, (sockaddr*)&server, &slen);
// cout << "Capitalized data: " << payload;
close(udpsocket);
return 0;
}
Server Code
// Libraries
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <stdlib.h>
#include <unistd.h>
#include <cstdlib>
#include <time.h>
#include <ctype.h>
using namespace std;
// Variables
int r_port;
string fileData;
// Generate Random Port
int randomPort() {
srand(time(NULL));
return rand() % ((65535 - 1024) + 1) + 1024;
}
// Capitalization Function
string capitalize(char* payload) {
int i = 0;
char c;
string charArr;
while(payload[i]) {
c = payload[i];
charArr += toupper(c);
i++;
}
return charArr;
}
int main(int argc, char* argv[]) {
// Variables
int port = strtol(argv[1], NULL, 10);
// *** Declare TCP socket ***
int tcpsocket = 0;
tcpsocket = socket(AF_INET, SOCK_STREAM, 0);
if (tcpsocket == -1) {
cerr << "Can't create a socket";
return -1;
}
// Receive data
struct sockaddr_in server;
memset((char *) &server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(tcpsocket, (struct sockaddr *) &server, sizeof(server)) == -1) {
cerr << "Can't bind to IP/Port";
return -2;
}
if (listen(tcpsocket, SOMAXCONN) == -1) {
cerr << "Can't listen";
return -3;
}
struct sockaddr_in client;
char payload[512];
socklen_t clen = sizeof(client);
int clientSocket = accept(tcpsocket, (sockaddr*)&client, &clen);
if (clientSocket == -1) {
cerr << "Problem with client connecting";
return -4;
}
recv(clientSocket, payload, 512, 0);
// Check client data
if (strtol(payload,NULL,10) == 117) {
r_port = randomPort();
cout << "Handshake detected. Selected the random port " << r_port << "\n";
}
else {
cout << "Error occurred\n";
}
// Return random port
memset(payload, 0, sizeof(payload));
sprintf(payload,"%ld",r_port);
int sendRes = send(clientSocket, payload, 512, 0);
if (sendRes == -1) {
cerr << "Could not send to server\n";
return 1;
}
close(clientSocket);
close(tcpsocket);
// *** Declare UDP socket ***
int udpsocket = 0;
udpsocket = socket(AF_INET, SOCK_DGRAM, 0);
if (udpsocket == -1) {
cerr << "Can't create a socket";
return -1;
}
// Receive data
memset((char *) &server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(r_port);
server.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(udpsocket, (struct sockaddr *) &server, sizeof(server)) == -1) {
cerr << "Can't bind to IP/Port";
return -2;
}
clen = sizeof(client);
memset(payload, 0, sizeof(payload));
recvfrom(udpsocket, payload, 32, 0, (sockaddr*)&client, &clen);
fileData = capitalize(payload);
cout << "Payload: " << fileData << "\n";
// Send ack
// socklen_t slen = sizeof(server);
// memset(payload, 0, sizeof(payload));
// strcpy(payload, fileData.c_str());
// sendRes = sendto(udpsocket, payload, 32, 0, (struct sockaddr *) &server, slen);
// if (sendRes == -1) {
// cerr << "Could not send to server";
// return 1;
// }
close(udpsocket);
return 0;
}
ssize_t sendto(**int sockfd**, const void *buf, size_t len, int flags,
const struct **sockaddr *dest_addr**, socklen_t addrlen);
Reference : https://linux.die.net/man/2/sendto
Your destination address should be : (sockaddr *) &client

Sending struct over tcp socket in C++

I am trying to send struct over tcp socket. I am a newbie in socket programming, I did try the options suggested here already but those did not serve my purpose. Could someone pls help?
I have written Server.cpp and Client.cpp and both are compiling properly. However, when I am executing my Server to listen to the Client, I am not sure if the Server is able to recieve the structure from Client or not. Also, how can I read this structure once it is received?
Server.cpp
#include<iostream>
#include <cstring>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<string>
#include<stdio.h>
using namespace std;
int main()
{
struct UE
{
string Net;
int imsi;
} ;
UE UE2;
//cout<<UE1.imsi<<"\n"<<UE1.Net<<"\n";
int sock, cli, receive;
sockaddr_in server, client;
unsigned int len;
if((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("Socket:");
exit(-1);
}
server.sin_family = AF_INET;
server.sin_port = htons(10000);
//cout<<htons(10000);
server.sin_addr.s_addr = INADDR_ANY;
//cout<<INADDR_ANY;
memset(&(server.sin_zero), '\0', 8);
len = sizeof(struct sockaddr_in);
if((bind(sock, (struct sockaddr *)&server, len)) == -1)
{
perror("Bind:");
exit(-1);
}
if((listen(sock, 5)) == -1)
{
perror("Listen:");
exit(-1);
}
while(1)
{
cli = accept(sock,(struct sockaddr *)&client, &len);
if(cli == -1)
{
perror("Accept");
exit(-1);
}
receive = recv(sock, (void*)&UE2, sizeof(UE2), NULL);
cout<<UE2.imsi;
//cout<<UE2.imsi<<"\n"<<UE2.Net;
//int sent = send(cli, (const void*)&mesg, sizeof mesg, 0);
//cout<<"Sent"<<sent<<" bytes to client :<<inet_ntoa(client.sin_addr)";
close(cli);
}
}
Client.cpp
#include <arpa/inet.h>
#include<iostream>
#include <cstring>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<string>
#include<stdio.h>
using namespace std;
int main(int argc, char *argv[])
{
struct UE
{
string Net;
int imsi;
} ;
UE UE1;
UE1.Net = "4G";
UE1.imsi = htons(8649);
int sock, receive;
struct sockaddr_in server;
char mesg[200];
if((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("Socket:");
exit(-1);
}
server.sin_family = AF_INET;
server.sin_port = htons(atoi(argv[2]));
//cout<<server.sin.port;
server.sin_addr.s_addr = inet_addr(argv[1]);
//cout<<server.sin_addr.s_addr;
memset(&(server.sin_zero), '\0', 8);
if(connect(sock, (struct sockaddr*)&server, sizeof(server)) == -1)
{
perror("Connect:");
exit(-1);
}
int count = 0;
while(count = 0)
{
send(sock, &UE1, sizeof(UE1), 0);
//receive = recv(sock, (void*)&mesg, sizeof mesg, NULL);
count++;
}
cout<<"Sent "<<UE1.imsi<<" and "<<UE1.Net<<" to Server \n";
close(sock);
}
There are at least 2 problems in your code:
You cannot send objects like std::string and anything that contains it this way (formally non-POD data), you need to marshall your data. There are plenty of libraries around (like google proto buffers) or you can write your own. This topic is too wide to cover it in the answer here.
You cannot expect that you receive data from TCP stream by the same chunk you sent it, you must write code that can handle receiving data by pieces (and send it that way as well).
You should never ever write a whole struct to a file or a socket.
Always write each field separately, and read them the same way.
When doing it this way you pay some memory overhead, but it's generally a good design for performance reasons because you don't want to do a write of each value to the socket.
When sending binary data you should always take care for the following things:
Different endianness
Different padding
Differences in the bye-sizes of intrinsic types
You need some functions like the following:
virtual MESSAGE_BUFFER * GetMessageAsBinaryPtr()
{
MESSAGE_BUFFER * binaryMsg = new MESSAGE_BUFFER;
UINT8 * ptrBuffer = &(*binaryMsg)[0];
ptrBuffer = this->serializeUInt16(ptrBuffer, this->m_majorVersion);
ptrBuffer = this->serializeUInt16(ptrBuffer, this->m_minorVersion);
ptrBuffer = this->serializeUInt32(ptrBuffer, (UINT32)this->m_messageType);
ptrBuffer = this->serializeUInt64(ptrBuffer, this->m_packetID);
ptrBuffer = this->serializeDouble(ptrBuffer, this->m_timestamp);
return binaryMsg;
}
virtual void CreateFromBinary(MESSAGE_BUFFER buffer)
{
UINT8 * ptrBuffer = &buffer[0];
ptrBuffer = this->deserializeUInt16FromBuffer(ptrBuffer, &this->m_majorVersion);
ptrBuffer = this->deserializeUInt16FromBuffer(ptrBuffer, &this->m_minorVersion);
UINT32 messageType = 0;
ptrBuffer = this->deserializeUInt32FromBuffer(ptrBuffer, &messageType);
this->SetMessageType((MessageTypes)messageType);
ptrBuffer = this->deserializeUInt64FromBuffer(ptrBuffer, &this->m_packetID);
ptrBuffer = this->deserializeDoubleFromBuffer(ptrBuffer, &this->m_timestamp);
}
inline UINT8 * serializeUInt16(UINT8 * buffer, UINT16 value)
{
buffer[1] = value;
buffer[0] = value >> 8;
return buffer + 2;
}
inline UINT8 * deserializeUInt16FromBuffer(UINT8 * buffer, UINT16 * pOutput)
{
*pOutput = (*pOutput << 8) + buffer[0];
*pOutput = (*pOutput << 8) + buffer[1];
return buffer + 2;
}
When you have such functions you can serialize and deserialize your structs to a buffer and then send this buffer over your socket.
A few points to note:
The struct to send is first serialized, field by field into a buffer
MESSAGE_BUFFER is of type UINT8[1024]
The serialization routine returns a pointer to the next free byte in the buffer, which we use to compute how many bytes it serialized to
Theres no protection against buffer overflows in my routines
There are few bugs in your code.
In server.cpp
sockaddr_in --> struct sockaddr_in
Once connection request is accepted by server using accept() call, it returns new file descriptor, with that new fd you should do read and write operation not with old one.
Replace below statement
receive = recv(sock, (void*)&UE2, sizeof(UE2), NULL); /** you are receiving with old fd called sock **/
with
receive = recv(cli, (void*)&UE2, sizeof(UE2), NULL);
client.cpp
using namespace std;
int main(int argc, char *argv[])
{
struct UE
{
string Net;
int imsi;
} ;
UE UE1;
UE1.Net = "4G";
UE1.imsi = htons(8649);
int sock, receive;
struct sockaddr_in server;
char mesg[200];
sock = socket(PF_INET, SOCK_STREAM, 0);
perror("Socket:");
server.sin_family = AF_INET;
server.sin_port = htons(atoi(argv[2]));
server.sin_addr.s_addr = inet_addr(argv[1]);
memset(&(server.sin_zero), '\0', 8);
connect(sock, (struct sockaddr*)&server, sizeof(server));
perror("Connect:");
int count = 0;
send(sock, &UE1, sizeof(UE1), 0);
perror("send");
cout<<"Sent "<<UE1.imsi<<" and "<<UE1.Net<<" to Server \n";
close(sock);
}
server.cpp
using namespace std;
int main()
{
struct UE
{
string Net;
int imsi;
} ;
UE UE2;
int sock, cli, receive;
struct sockaddr_in server, client;
unsigned int len;
sock = socket(AF_INET, SOCK_STREAM, 0);
perror("Socket:");
server.sin_family = AF_INET;
server.sin_port = htons(10001);
server.sin_addr.s_addr = INADDR_ANY;
memset(&(server.sin_zero), '\0', 8);
len = sizeof(server);
bind(sock, (struct sockaddr *)&server, len);
perror("Bind:");
listen(sock, 1);
perror("Listen:");
cli = accept(sock,(struct sockaddr *)&client, &len);
perror("accept");
receive = recv(cli, ( void*)&UE2, sizeof(UE2), 0);
perror("recv");
cout << "rec = "<<receive<<endl;
cout<<UE2.imsi<<"\n";
close(sock);
perror("close");
}

C++ - Windows - recvfrom() failing with "No such file or directory" on simple server

Here is the code of the very simple server I'm trying to make:
Network.h:
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <system_error>
#include <string>
#include <iostream>
#pragma once
class WSASession
{
public:
WSASession()
{
int ret = WSAStartup(MAKEWORD(2, 2), &data);
if (ret != 0)
throw std::system_error(WSAGetLastError(), std::system_category(), "WSAStartup Failed");
}
~WSASession()
{
WSACleanup();
}
private:
WSAData data;
};
class UDPSocket
{
public:
UDPSocket()
{
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock == INVALID_SOCKET)
throw std::system_error(WSAGetLastError(), std::system_category(), "Error opening socket");
}
~UDPSocket()
{
closesocket(sock);
}
void SendTo(const std::string& address, unsigned short port, const char* buffer, int len, int flags = 0)
{
sockaddr_in add;
add.sin_family = AF_INET;
add.sin_addr.s_addr = inet_addr(address.c_str());
add.sin_port = htons(port);
int ret = sendto(sock, buffer, len, flags, reinterpret_cast<SOCKADDR *>(&add), sizeof(add));
if (ret < 0)
throw std::system_error(WSAGetLastError(), std::system_category(), "sendto failed");
}
void SendTo(sockaddr_in& address, const char* buffer, int len, int flags = 0)
{
int ret = sendto(sock, buffer, len, flags, reinterpret_cast<SOCKADDR *>(&address), sizeof(address));
if (ret < 0)
throw std::system_error(WSAGetLastError(), std::system_category(), "sendto failed");
}
sockaddr_in RecvFrom(char* buffer, int len, int flags = 0)
{
sockaddr_in from;
int size = sizeof(from);
int ret = recvfrom(sock, buffer, len, flags, reinterpret_cast<SOCKADDR *>(&from), &size);
if (ret < 0)
throw std::system_error(WSAGetLastError(), std::system_category(), "recvfrom failed");
// make the buffer zero terminated
buffer[ret] = 0;
return from;
}
void Bind(unsigned short port)
{
sockaddr_in add;
add.sin_family = AF_INET;
add.sin_addr.s_addr = htonl(INADDR_ANY);
add.sin_port = htons(port);
int ret = bind(sock, reinterpret_cast<SOCKADDR *>(&add), sizeof(add));
if (ret < 0)
throw std::system_error(WSAGetLastError(), std::system_category(), "Bind failed");
}
private:
SOCKET sock;
};
Listener server:
try
{
WSASession Session;
UDPSocket Socket;
char buffer[512];
Socket.Bind(22);
while (1)
{
sockaddr_in add = Socket.RecvFrom(buffer, sizeof(buffer));
std::string srecv(buffer);
}
}
catch (std::system_error& e)
{
std::cout << e.what();
}
All is perfect until it accepts a connection from a client. The recvfrom function fails with error "No such file or directory"
Does anyone see the problem? I know the port isn't problematic because I was listening on the same port from a .net application which works perfectly.
You have:
const std::string& address, unsigned short port, const char* buffer, int len, int flags = 0)
and
int ret = sendto(sock, buffer, len, flags, reinterpret_cast<SOCKADDR *>(&add)
The cast is invalid. A std::string isn't a SOCKADDR. You have to convert, probably by calling getaddrinfo().

send data between two client sockets

I have to make an app using C sockets on Mac-OS that sends data from one socket to other socket, like this.
Server waits for connections
Client connect to server(from 1). -> socket1
Server connects to an external server and obtains an socket. -> socket2
From now on the server job is finish. The data exchange should be made only between the client socket (from 2) and socket obtained from 3.
Current implementation:
Server makes the connection and then reads data from one socket and sends to other.
Any ides how after step 3 to pipe line the two sockets socket1 and socket2.
Well your problem can be solved in two ways:
1) You need to code the part related to the connection formation between client and external server. But this puts an extra overload on the client, because it needs to make two connections, to both the servers (and I strongly feel the middle server in this case is useless).
2) Second way of solving it is passing the sockets between the servers:
Client connects to the server, this middle server sends this socket to the external server. Now external server starts communication with the client. This can be done only if both the server processes run on the same machine. And the file-descriptors are usually passed using Unix Domain Sockets.
Here is the code which I have. You can use these two functions to either send or receive the file-descriptors. It works on my Linux machine. I don't know about Mac-OS.
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/uio.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
/* this function passes 'fd_to_send'
file descriptor via
a unix domain socket 'sfd'...
*/
void pass_fd(int sfd, int fd_to_send)
{
struct msghdr msg;
/*allocate memory to 'msg_control' field in msghdr struct */
char buf[CMSG_SPACE(sizeof(int))];
/*the memory to be allocated should include data + header..
this is calculated by the above macro...(it merely adds some
no. of bytes and returs that number..*/
struct cmsghdr *cmsg;
struct iovec ve;
/*must send/receive atleast one byte...
main purpose is to have some error
checking.. but this is completely
irrelevant in the current context..*/
char *st ="I";
/*jst let us allocate 1 byte for formality
and leave it that way...*/
ve.iov_base = st;
ve.iov_len =1;
/*attach this memory to our main msghdr struct...*/
msg.msg_iov = &ve;
msg.msg_iovlen = 1;
/*these are optional fields ..
leave these fields with zeros..
to prevent unnecessary SIGSEGVs..*/
msg.msg_name = NULL;
msg.msg_namelen = 0;
/*here starts the main part..*/
/*attach the 'buf' to msg_control..
and fill in the size field correspondingly..
*/
msg.msg_control = buf;
msg.msg_controllen = sizeof(buf);
/*actually msg_control field must
point to a struct of type 'cmsghdr'
we just allocated the memory, yet we need to
set all the corresponding fields..
It is done as follows:
*/
cmsg = CMSG_FIRSTHDR(&msg);
/* this macro returns the address in the buffer..
from where the first header starts..
*/
/*set all the fields appropriately..*/
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(fd_to_send));
/*in the above field we need to store
the size of header + data(in this case 4 bytes(int) for our fd..
this is returned by the 'CMSG_LEN' macro..*/
*(int*)CMSG_DATA(cmsg) = fd_to_send;
/*after the above three fields we keep the actual data..
the macro 'CMSG_DATA' returns pointer to this location
and we set it to the file descriptor to be sent..
*/
msg.msg_controllen = cmsg->cmsg_len;
/*now that we have filled the 'cmsg' struct
we store the size of this struct..*/
/*this one isn't required when you
pass a single fd..
but useful when u pass multiple fds.*/
msg.msg_flags = 0;
/*leave the flags field zeroed..*/
if(sendmsg( sfd, &msg, 0)==-1){ perror("snd:\n"); exit(1); }
/*send this over the UNIX deomain socoket..*/
printf("sent fd:%d\n", fd_to_send);
close(fd_to_send);
/*close the fd which was sent..*/
}
/*returns the received fd over the unix domain socket 'sfd'..*/
int recv_fd(int sfd)
{
struct msghdr msg;
/*do all the unwanted things first...
same as the send_fd function..*/
struct iovec io;
char ptr[1];
io.iov_base = ptr;
io.iov_len = 1;
msg.msg_name = 0;
msg.msg_namelen = 0;
msg.msg_iov = &io;
msg.msg_iovlen = 1;
/*-----------------------*/
char buf[CMSG_SPACE(sizeof(int))];
msg.msg_control = buf;
msg.msg_controllen = sizeof(buf);
/*reasoning is same..as above*/
/*now here comes the main part..*/
if(recvmsg( sfd, &msg, 0)==-1)
{
/*some shit has happened*/
perror("recv\n");
exit(1);
}
struct cmsghdr *cm;
cm = CMSG_FIRSTHDR(&msg);
/*get the first message header..*/
if(cm->cmsg_type != SCM_RIGHTS)
{
/*again some shit has happened..*/
perror("unknown type..\n");
exit(1);
}
/*if control has reached here.. this means
we have got the correct message..and when you
extract the fd out of this message
this need not be same as the one which was sent..
allocating a new fd is all done by the kernel
and our job is jst to use it..*/
printf("received fd:%d\n", *(int*)CMSG_DATA(cm));
return *(int*)CMSG_DATA(cm);
}
In the below example:
ClientOne and ClientTwo connect to the server.
When the server receives both ClientOne and ClientTwo's socket descriptor, it sends ClientOne's information to ClientTwo and vice-versa.
The information it sends is the IP and the client is coming from. Server shuts down.
When each client receives their info, a socket is created and they connect to eachother. The server socket is then shutdown.
Socket Class:
#include <winsock2.h>
#include <Ws2tcpip.h>
#include <windows.h>
#include <cstdint>
#include <string>
#include <stdexcept>
#include <iostream>
#include <thread>
#include <vector>
class Socket
{
private:
SOCKET socket;
std::uint32_t Port;
std::string Address;
bool Listen, Initialized, Asynchronous;
void Swap(Socket &S);
void UnInitialized();
public:
Socket();
Socket(std::uint32_t Port, std::string Address, bool Listen = false, bool Asynchronous = false);
Socket(const Socket &S) = delete;
Socket(Socket && S);
~Socket();
Socket& operator = (const Socket &S) = delete;
Socket& operator = (Socket && S);
int Recv(void* Buffer, std::uint32_t BufferLength);
int Recv(SOCKET S, void* Buffer, std::uint32_t BufferLength);
std::uint32_t RecvEx(void* Buffer, std::uint32_t BufferLength);
std::uint32_t RecvEx(SOCKET S, void* Buffer, std::uint32_t BufferLength);
int Send(void* Buffer, std::size_t BufferSize);
int Send(SOCKET S, void* Buffer, std::size_t BufferSize);
void Connect();
void Connect(std::uint32_t Port, std::string Address, bool Listen, bool Asynchronous);
SOCKET Accept(sockaddr* ClientInfo, int* ClientInfoSize);
void Close();
SOCKET GetSocket() const;
};
Socket::~Socket()
{
Close();
}
void Socket::Close()
{
if (socket)
{
shutdown(socket, SD_BOTH);
closesocket(socket);
socket = 0;
}
if (Initialized)
{
WSACleanup();
}
}
SOCKET Socket::GetSocket() const
{
return this->socket;
}
Socket::Socket(Socket && S) : socket(std::move(S.socket)), Port(std::move(S.Port)), Address(std::move(S.Address)), Listen(std::move(S.Listen)), Initialized(std::move(S.Initialized)), Asynchronous(std::move(S.Asynchronous)) {}
Socket::Socket() : socket(0), Port(0), Address(std::string()), Listen(false), Initialized(false), Asynchronous(false) {}
Socket::Socket(std::uint32_t Port, std::string Address, bool Listen, bool Asynchronous) : socket(0), Port(Port), Address(Address), Listen(Listen), Initialized(true), Asynchronous(Asynchronous)
{
Connect(Port, Address, Listen, Asynchronous);
}
void Socket::Connect()
{
UnInitialized();
Connect(Port, Address, Listen, Asynchronous);
}
void Socket::Connect(std::uint32_t Port, std::string Address, bool Listen, bool Asynchronous)
{
if (!socket)
{
this->Port = Port;
this->Address = Address;
this->Asynchronous = Asynchronous;
this->Initialized = true;
WSADATA wsaData;
struct sockaddr_in* sockaddr_ipv4;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
throw std::runtime_error("Error: WSAStartup Failed");
}
if (Address != "INADDR_ANY")
{
if (Address.find("http://") != std::string::npos)
{
Address = Address.substr(7);
}
std::size_t Position = Address.find("/");
if (Position != std::string::npos)
{
Address = Address.substr(0, Position);
}
struct addrinfo *it = nullptr, *result = nullptr;
getaddrinfo(Address.c_str(), nullptr, nullptr, &result);
for (it = result; it != nullptr; it = it->ai_next)
{
sockaddr_ipv4 = reinterpret_cast<sockaddr_in*>(it->ai_addr);
Address = inet_ntoa(sockaddr_ipv4->sin_addr);
if (Address != "0.0.0.0") break;
}
freeaddrinfo(result);
}
if ((this->socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
{
this->Close();
throw std::runtime_error("Error: Failed to create socket");
}
struct sockaddr_in SockAddr;
memset(&SockAddr, 0, sizeof(SockAddr));
SockAddr.sin_port = htons(Port);
SockAddr.sin_family = AF_INET;
SockAddr.sin_addr.s_addr = (Address == "INADDR_ANY" ? htonl(INADDR_ANY) : inet_addr(Address.c_str()));
if (Listen && (bind(this->socket, reinterpret_cast<SOCKADDR*>(&SockAddr), sizeof(SockAddr)) == SOCKET_ERROR))
{
this->Close();
throw std::runtime_error("Error: Socket binding failed");
}
if (Listen && (listen(this->socket, SOMAXCONN) == SOCKET_ERROR))
{
this->Close();
throw std::runtime_error("Error: Socket Listening Failed");
}
if(!Listen && (connect(this->socket, reinterpret_cast<SOCKADDR*>(&SockAddr), sizeof(SockAddr)) == SOCKET_ERROR))
{
if(Asynchronous && WSAGetLastError() != WSAEWOULDBLOCK)
{
this->Close();
throw std::runtime_error("Error: Socket Connection failed");
}
else if (!Asynchronous)
{
this->Close();
throw std::runtime_error("Error: Socket Connection failed");
}
}
}
}
SOCKET Socket::Accept(sockaddr* ClientInfo, int* ClientInfoSize)
{
static int Size = sizeof(sockaddr);
return accept(this->socket, ClientInfo, (ClientInfo && ClientInfoSize ? ClientInfoSize : &Size));
}
Socket& Socket::operator = (Socket && S)
{
S.Swap(*this);
return *this;
}
int Socket::Recv(void* Buffer, std::uint32_t BufferLength)
{
return recv(this->socket, reinterpret_cast<char*>(Buffer), BufferLength, 0);
}
int Socket::Recv(SOCKET S, void* Buffer, std::uint32_t BufferLength)
{
return recv(S, reinterpret_cast<char*>(Buffer), BufferLength, 0);
}
std::uint32_t Socket::RecvEx(void* Buffer, std::uint32_t BufferLength)
{
return this->RecvEx(this->socket, Buffer, BufferLength);
}
std::uint32_t Socket::RecvEx(SOCKET S, void* Buffer, std::uint32_t BufferLength)
{
UnInitialized();
char* Pointer = reinterpret_cast<char*>(Buffer);
std::uint32_t TotalRead = 0;
while (BufferLength > 0)
{
int BytesRead = recv(S, Pointer, std::min(1024 * 1024, static_cast<int>(BufferLength)), 0);
if (BytesRead < 0)
{
if ((BytesRead == SOCKET_ERROR) && (WSAGetLastError() == WSAEWOULDBLOCK))
continue;
throw std::runtime_error("Error! RecvEx: Failed To Read Bytes.");
}
if (BytesRead == 0) break;
Pointer += BytesRead;
BufferLength -= BytesRead;
TotalRead += BytesRead;
}
return TotalRead;
}
int Socket::Send(void* Buffer, std::size_t BufferSize)
{
return send(this->socket, reinterpret_cast<char*>(Buffer), BufferSize, 0);
}
int Socket::Send(SOCKET S, void* Buffer, std::size_t BufferSize)
{
return send(S, reinterpret_cast<char*>(Buffer), BufferSize, 0);
}
void Socket::Swap(Socket &S)
{
using std::swap;
swap(socket, S.socket);
swap(Port, S.Port);
swap(Address, S.Address);
swap(Listen, S.Listen);
swap(Initialized, S.Initialized);
swap(Asynchronous, S.Asynchronous);
}
void Socket::UnInitialized()
{
if (!Initialized)
{
throw std::runtime_error("\nError! Socket Not Constructed!");
std::cout << "Socket Not Constructed!\n";
ExitProcess(0);
}
}
Server.cpp:
#include "Sockets.hpp"
#define PORT 27015
#define ADDRESS INADDR_ANY
#define CLIENTCOUNT 2
typedef struct
{
std::string ip;
int port;
SOCKET sock;
} ClientInfo;
template <typename T>
inline T ReadPointer(TCHAR* &Pointer)
{
T Result = *(reinterpret_cast<T*>(Pointer));
Pointer += sizeof(T) / sizeof(TCHAR);
return Result;
}
template <typename T>
inline void WritePointer(TCHAR* &Pointer, const T& Value)
{
*(reinterpret_cast<T*>(Pointer)) = Value;
Pointer += sizeof(T) / sizeof(TCHAR);
}
bool SendClient(ClientInfo* client, ClientInfo* receiver)
{
int datasize = sizeof(client->ip.size()) + client->ip.size() + sizeof(client->port);
std::vector<char> buffer(datasize, 0);
char* ptr = &buffer[0];
WritePointer(ptr, client->ip.size());
for (std::size_t i = 0; i < client->ip.size(); ++i)
WritePointer(ptr, client->ip[i]);
WritePointer(ptr, client->port);
std::cout << "Sending: " << &buffer[0] << "\n";
return send(receiver->sock, &buffer[0], datasize, 0) == datasize;
}
bool ReadClient(SOCKET sock, ClientInfo* client)
{
std::size_t ip_size = 0;
recv(sock, (char*) &ip_size, sizeof(client->ip.size()), 0);
client->ip.resize(ip_size);
recv(sock, &client->ip[0], ip_size, 0);
recv(sock, (char*) &client->port, sizeof(int), 0);
std::cout<<client->ip<<"\n";
return true;
}
int main()
{
Socket s;
s.Connect(PORT, "localhost", true, false);
char buffer[1024] = {0};
std::vector<ClientInfo> clients;
while(true)
{
if (clients.size() < CLIENTCOUNT)
{
sockaddr_in ClientAddressInfo = {0};
SOCKET sock = s.Accept(reinterpret_cast<sockaddr*>(&ClientAddressInfo), nullptr);
char* ip = inet_ntoa(ClientAddressInfo.sin_addr);
int port = (int) ntohs(ClientAddressInfo.sin_port);
ClientInfo info = {ip, port, sock};
clients.push_back(info);
std::cout << "Client Connected From: " << ip << " on port: " << port << "\n";
}
if (ReadAsync(s, buffer))
{
std::cout << "Connected\n";
}
std::this_thread::sleep_for(std::chrono::milliseconds(100));
if (clients.size() >= CLIENTCOUNT)
{
SendClient(&clients[0], &clients[1]);
SendClient(&clients[1], &clients[0]);
return 0;
}
}
}
Client.cpp:
#define PORT 27015
#define ADDRESS INADDR_ANY
#define CLIENTCOUNT 2
typedef struct
{
std::string ip;
int port;
SOCKET sock;
} ClientInfo;
template <typename T>
inline T ReadPointer(TCHAR* &Pointer)
{
T Result = *(reinterpret_cast<T*>(Pointer));
Pointer += sizeof(T) / sizeof(TCHAR);
return Result;
}
template <typename T>
inline void WritePointer(TCHAR* &Pointer, const T& Value)
{
*(reinterpret_cast<T*>(Pointer)) = Value;
Pointer += sizeof(T) / sizeof(TCHAR);
}
bool SendClient(ClientInfo* client, ClientInfo* receiver)
{
int datasize = sizeof(client->ip.size()) + client->ip.size() + sizeof(client->port);
std::vector<char> buffer(datasize, 0);
char* ptr = &buffer[0];
WritePointer(ptr, client->ip.size());
for (std::size_t i = 0; i < client->ip.size(); ++i)
WritePointer(ptr, client->ip[i]);
WritePointer(ptr, client->port);
std::cout << "Sending: " << &buffer[0] << "\n";
return send(receiver->sock, &buffer[0], datasize, 0) == datasize;
}
bool ReadClient(SOCKET sock, ClientInfo* client)
{
std::size_t ip_size = 0;
recv(sock, (char*) &ip_size, sizeof(client->ip.size()), 0);
client->ip.resize(ip_size);
recv(sock, &client->ip[0], ip_size, 0);
recv(sock, (char*) &client->port, sizeof(int), 0);
return true;
}
bool ReadAsync(const Socket &sock, ClientInfo* client)
{
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 100000;
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(sock.GetSocket(), &rfds);
for (int i = 0; i < 600; ++i)
{
if (select(sock.GetSocket(), &rfds, &rfds, NULL, &tv))
{
return ReadClient(sock.GetSocket(), client);
}
tv.tv_sec = 0;
tv.tv_usec = 100000;
}
return false;
}
int main()
{
Socket s;
s.Connect(PORT, "localhost", false, false);
std::vector<SOCKET> clients;
ClientInfo client = {};
while(true)
{
if (ReadAsync(s, &client))
{
std::cout<<"IP: "<<client.ip<<" PORT: "<<client.port<<"\n";
s = std::move(Socket(client.port, client.ip, true, false));
}
std::this_thread::sleep_for(std::chrono::milliseconds(100));
system("CLS");
std::cout<<"Connecting..\n";
}
}

Connecting to a UDP Tracker in C++

I'm trying to connect to a UDP tracker server using the code below, but I'm not getting any responses from the tracker...
I gleaned what I could from this link:
http://xbtt.sourceforge.net/udp_tracker_protocol.html
and I thought I got it...but apparently not. The code executes fine and then hangs at the call to RecvFrom. So I'm guessing I'm either not sending the correct data, or I'm sending it to the wrong place.....
struct ConnectionIdRequest_t {
uint64_t connectionId;
uint32_t action;
int32_t transactionId;
} typedef ConnectionIdRequest;
const bool UdpTorrentTrackerComm::initiateConnection(const int amountUploaded,
const int amountDownloaded,
const int amountLeft) {
struct sockaddr_in serverAddress, clientAddress;
struct hostent * host;
struct in_addr address;
//Setup dummy client address
clientAddress.sin_family = AF_INET;
clientAddress.sin_addr.s_addr = htonl(INADDR_ANY);
clientAddress.sin_port = htons(0);
//Setup server address
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = htons(portNumber);
//SETUP in_addr server address
//If we have an IP
if (trackerAddress) {
if (isIp4Address(*trackerAddress)) {
//retrieve hostname from ip address
if (inet_aton(trackerAddress->c_str(), &address)) {
host = gethostbyaddr((const char *) &address, sizeof(address), AF_INET);
trackerHostname = new std::string(host->h_name);
}
else {
return false;
}
}
else {
return false;
}
}
else {
//retrieve ip address from hostname
host = gethostbyname(trackerHostname->c_str());
address.s_addr = ((struct in_addr *) host->h_addr_list)->s_addr;
trackerAddress = new std::string(inet_ntoa(address));
}
std::cout << *trackerAddress << std::endl;
//Convert trackerAddress to network format
if(!inet_aton(trackerAddress->c_str(), &serverAddress.sin_addr)) {
return false;
}
int sockFd = -1;
//Add IPv6 in the future
if ((sockFd = Socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
return false;
}
//Bind my address to the socket
if (Bind(sockFd, (struct sockaddr *) &clientAddress, sizeof(clientAddress)) == - 1) {
return false;
}
std::cout << "SendTo\n";
ConnectionIdRequest * idRequest = createConnectionIdRequest();
if (SendTo(sockFd, idRequest, sizeof(*idRequest), 0,
(struct sockaddr *) &serverAddress, sizeof(serverAddress)) == -1) {
return false;
}
timeRequestSent = clock();
std::cout << "Sent: " << idRequest->connectionId << "|||" << idRequest->action << "|||" << idRequest->transactionId << std::endl;
std::cout << "RecvFrom\n";
char buffer[3000];
socklen_t serverAddressLength = sizeof(serverAddress);
while(true) {
if (RecvFrom(sockFd, buffer, 3000, 0,
(struct sockaddr *) &serverAddress, &serverAddressLength) == - 1) {
break;
std::cout << "breaking...\n";
}
}
std::cout << "The buffer is: " << buffer << std::endl;
Close(sockFd);
return true;
}
ConnectionIdRequest * UdpTorrentTrackerComm::createConnectionIdRequest() {
ConnectionIdRequest * idRequest = new ConnectionIdRequest;
generatePeerId();
idRequest->connectionId = htonll(0x41727101980);
idRequest->action = htonl(CONNECT);
idRequest->transactionId = htonl(*peerId);
return idRequest;
}
EDIT: Alright I made the one change that Arvid suggested, but that didn't help any. I'm going through and making sure I'm converting all the bytes being sent are in network byte order...Maybe I'm missing something......
it looks like you're conflating transaction ID and peer ID. They are different. The transaction ID is the cookie you send in order to match returning packets to the correct request.
It also looks like you're not initializing the connectionID. You have to set it to the magic 64 bit number in the initial connect message. 0x41727101980
You can find an alternative protocol description here.
I ended up getting it to work. The problem was mostly that I was not converting all of the values I needed to be converting to big endian (network ordering), along with using outdated functions, (gethostbyname etc).
If you'd like more details just comment.
This is the code that works for me to establish a link with the tracker server:
NOTE: serverAddress and clientAddress are class fields of type: struct sockaddr_in
const bool UdpTorrentTrackerComm::initiateConnection() {
//Setup dummy client address
clientAddress.sin_family = AF_INET;
clientAddress.sin_addr.s_addr = htonl(INADDR_ANY);
clientAddress.sin_port = htons(51413);
//Setup server address
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = htons(portNumber);
//SETUP in_addr server address
//If we have an IP
if (trackerAddress) {
if (isIp4Address(*trackerAddress)) {
//Convert human readable trackerAddress to network byte order ip address and place in serverAddress.sin_addr
if (inet_pton(AF_INET, trackerAddress->c_str(), &(serverAddress.sin_addr))) {
//retrieve hostname and service type from ip address
char hostBuffer[100], serviceBuffer[100];
getnameinfo((struct sockaddr *) &serverAddress, sizeof(serverAddress),
hostBuffer, sizeof(hostBuffer),
serviceBuffer, sizeof(serviceBuffer),
NI_NAMEREQD | NI_DGRAM);
trackerHostname = new std::string(hostBuffer);
}
else {
return false;
}
}
else {
return false;
}
}
else {
//Setup structs to be used in getaddrinfo
struct addrinfo hints;
struct addrinfo * result, * resultPointer;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = 0;
hints.ai_protocol = 0;
//Convert port number to string to pass to getaddrinfo
std::stringstream ss;
ss << portNumber;
std::string portNumberString = ss.str();
//retrieve ip address from hostname--------
if (GetAddrInfo(trackerHostname->c_str(), portNumberString.c_str(), &hints, &result) != 0) {
return false;
}
//Iterate over results for IP address V4 (ADD V6 later!)
char ipBuffer[INET_ADDRSTRLEN];
for (resultPointer = result; resultPointer != NULL; resultPointer = resultPointer->ai_next) {
//If we have an IPv4 address
if (resultPointer->ai_family == AF_INET) {
//convert to presentation format and store in ipBuffer
inet_ntop(AF_INET, &((struct sockaddr_in *) resultPointer->ai_addr)->sin_addr, ipBuffer, INET_ADDRSTRLEN);
}
}
//Free result
freeaddrinfo(result);
//Convert ipBuffer to std::string and store in trackerAddress field
trackerAddress = new std::string(ipBuffer);
//Convert trackerAddress to network format
if(!inet_pton(AF_INET, trackerAddress->c_str(), &serverAddress.sin_addr)) {
return false;
}
}
int sockFd = -1;
//Add IPv6 in the future
if ((sockFd = Socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
return false;
}
//Bind my address to the socket
if (Bind(sockFd, (struct sockaddr *) &clientAddress, sizeof(clientAddress)) == - 1) {
return false;
}
//Send a request to the tracker
ConnectionIdRequest * idRequest = createConnectionIdRequest();
if (SendTo(sockFd, idRequest, sizeof(*idRequest), 0,
(struct sockaddr *) &serverAddress, sizeof(serverAddress)) == -1) {
return false;
}
timeRequestSent = clock();
//Re-send until timeout.....
ConnectionIdResponse idResponse;
socklen_t serverAddressLength = sizeof(serverAddress);
while((timeRequestSent - clock()) / 1000 < SECONDS_UNTIL_TIMEOUT) {
//Response received!
if (RecvFrom(sockFd, &idResponse, sizeof(idResponse), 0,
(struct sockaddr *) &serverAddress, &serverAddressLength) > 0) {
break;
}
}
//Set class fields that will persist
activeSocket = sockFd;
connectionId = ntohll(idResponse.connectionId);
delete idRequest;
return true;
}
Where the two structs, ConnectionIdResponse and ConnectionIdRequest are defined as:
/* Struct used to send a request for a connectionId to the tracker server.*/
struct ConnectionIdRequest_t {
uint64_t connectionId;
uint32_t action;
uint32_t transactionId;
} typedef ConnectionIdRequest;
/* Struct used in receipt of a request for a connectionId from the tracker server. */
struct ConnectionIdResponse_t {
uint32_t action;
uint32_t transactionId;
uint64_t connectionId;
} typedef ConnectionIdResponse;