My teacher want us to do an exercise on raw socket in c ++ on Windows (for learning tcp communication).
I have got a problem with it. I saw a lot of documentation but I don't know how to solve it.
int raw()
{
WSADATA WSAData;
SOCKET sock;
SOCKADDR_IN sin,din;
WSAStartup(MAKEWORD(2, 2), &WSAData);
char datagram[MAX_PACKET_SIZE];
struct iphdr *iph = (struct iphdr *)datagram;
struct tcphdr *tcph = (struct tcphdr *)((UCHAR *)iph + sizeof(tcphdr));
char new_ip[sizeof "255.255.255.255"];
sock = socket(PF_INET, SOCK_RAW, IPPROTO_TCP);
if (sock == INVALID_SOCKET)
cout << "failled init socket" << endl ;
else{
memset(datagram, 0, MAX_PACKET_SIZE); // Clear the data
setup_ip_header(iph);
setup_tcp_header(tcph);
sin.sin_family = AF_INET;
sin.sin_port = htons(8888);
sin.sin_addr.s_addr = inet_addr("192.168.1.10"); //source ip
din.sin_family = AF_INET;
din.sin_port = htons(DEST_PORT);
din.sin_addr.s_addr = inet_addr(TARGET_SERV_IP); //ip serv to connect
tcph->port_dest = htons(DEST_PORT);
iph->ip_dest = din.sin_addr.s_addr;
iph->ip_source = sin.sin_addr.s_addr;
iph->ip_dest = inet_addr(TARGET_SERV_IP); //ip serv to connect
iph->ip_source = inet_addr("192.168.1.10"); //source ip
//iph->checksum = csum((unsigned short *)datagram, iph->tot_len >> 1);
iph->checksum = csum((unsigned short *)datagram, sizeof(struct iphdr));
int one = 1;
const int *val = &one;
if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char *)val, sizeof(one)) < 0)
printf("failled set socket option IP_HDRINCL");
else{
if (sendto(sock, /* our socket */
datagram, /* the buffer containing headers and data */
ntohs( iph->tot_len), /* total length of our datagram */
0, /* routing flags, normally always 0 */
(struct sockaddr *) &sin, /* socket addr, just like in */
sizeof(sin)) < 0) /* a normal send() */
cout << stderr << "sendto() error!!!.\n " << WSAGetLastError() << endl;
else
cout << "packet send\n" << endl;
}
closesocket(sock);
}
}
My error occurs at the sendto(). it return 10022 error = WSAEINVAL
I saw that can be a new windows protection?
Have you any idea to fix my problem or bypass the protection (go deeper, driver, etc)
You don't set iph->tot_len in your code.
My recommendation for networking code using c++ would be to use std::string or std::vector:
std::vector<uint8_t> packet(MAX_PACKET_SIZE, 0);
...
packet.resize(real_size);
then use the address (&packet[0]) for your pointer manipulations.
Related
Simple code first:
#include "NetFunc.h"
#include <iostream>
#include <string>
#include <thread>
#include <chrono>
using namespace std;
void test()
{
// SOCKET listenfd = OpenListenFD("127.0.0.1", "19287");
SOCKET connfd = OpenClientFD("127.0.0.1", "12389", "127.0.0.1", "19287");
send(connfd, "test", 5, 0);
close(connfd);
using namespace std::chrono_literals;
this_thread::sleep_for(100ms);
connfd = OpenClientFD("127.0.0.1", "12389", "127.0.0.1", "19287");
send(connfd, "test2", 6, 0);
close(connfd);
// close(listenfd);
cout << "over" << endl;
return;
}
int main()
{
SOCKET listenfd = OpenListenFD("127.0.0.1", "12389");
sockaddr_storage clientaddr;
socklen_t clientlen = sizeof clientaddr;
// SOCKET connfd = 0;
const int maxNameLen = 0x800;
char* buffer = new char[0x800 + 1];
char* hostname = new char[maxNameLen + 1], * port = new char[maxNameLen + 1];
std::thread newThread{&test};
newThread.detach();
SOCKET connfd;
while (true)
{
if ((connfd = accept(listenfd, (sockaddr*)&clientaddr, &clientlen)) < 0)
{
std::cerr << "Not accept correctly at InteractWithClients" << std::endl;
}
else{
getnameinfo((sockaddr*)&clientaddr, clientlen, hostname, maxNameLen, port, maxNameLen, NI_NUMERICHOST);
std::string completeAddr = string(hostname) + ":" + string(port);
std::cout << "Addr : " << completeAddr << std::endl;
recv(connfd, buffer, 0x800, 0);
std::cout << buffer << std::endl;
}
close(connfd);
}
delete[] buffer; delete[] hostname; delete[]port;
return 0;
}
Here, the NetFunc.h has necessary headers and #define SOCKET int. It corresponds with NetFunc.cpp, which has two functions for server&client as below:
(Note that I'm trying to generate a client with a specific port, for I just need two address-port to connect rather than to distinguish a server from a client. Besides, I already use SO_REUSEADDR.)
#include "NetFunc.h"
#include <iostream>
#include <string.h>
SOCKET OpenListenFD(const char* addr, const char* port)
{
struct addrinfo hints, * listp, * p;
SOCKET listenfd;
int optval = 1;
/* Get a list of potential server addresses */
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_socktype = SOCK_STREAM; /* Accept connections */
hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; /* ... on any IP address */
hints.ai_flags |= AI_NUMERICSERV; /* ... using port number */
hints.ai_family = AF_INET;
getaddrinfo(addr, port, &hints, &listp);
/* Walk the list for one that we can bind to */
for (p = listp; p; p = p->ai_next) {
/* Create a socket descriptor */
if ((listenfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0)
continue; /* Socket failed, try the next */
/* Eliminates "Address already in use" error from bind */
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, //line:netp:csapp:setsockopt
(setsockopt_ptr)&optval, sizeof(int));
/* Bind the descriptor to the address */
if (bind(listenfd, p->ai_addr, p->ai_addrlen) == 0)
{
break; /* Success */
}
closesocket(listenfd); /* Bind failed, try the next */
}
/* Clean up */
freeaddrinfo(listp);
if (!p) /* No address worked */
return -1;
/* Make it a listening socket ready to accept connection requests */
if (listen(listenfd, LISTENQ) < 0) {
closesocket(listenfd);
return -1;
}
return listenfd;
}
SOCKET OpenClientFD(const char* serverAddr, const char* port, const char* localAddr, const char* localPort)
{
struct sockaddr_in my_addr, my_addr1;
SOCKET client = socket(AF_INET, SOCK_STREAM, 0);
if (client < 0)
std::cerr<<"Error in client creating\n";
else
std::cout << "Client Created\n";
int optval = 1;
setsockopt(client, SOL_SOCKET, SO_REUSEADDR, //line:netp:csapp:setsockopt
(setsockopt_ptr)&optval, sizeof(int));
my_addr.sin_family = AF_INET;
my_addr.sin_addr.s_addr = INADDR_ANY;
my_addr.sin_port = htons(atoi(port));
// This ip address will change according to the machine
inet_pton(AF_INET, serverAddr, &my_addr.sin_addr.s_addr);
// Explicitly assigning port number 12010 by
// binding client with that port
my_addr1.sin_family = AF_INET;
my_addr1.sin_addr.s_addr = INADDR_ANY;
my_addr1.sin_port = htons(atoi(localPort));
// This ip address will change according to the machine
inet_pton(AF_INET, localAddr, &my_addr1.sin_addr.s_addr);
if (bind(client, (struct sockaddr*)&my_addr1, sizeof(struct sockaddr_in)) == 0)
std::cout << "Binded Correctly\n";
else
{
std::cerr << "Unable to bind\n";
return -1;
}
socklen_t addr_size = sizeof my_addr;
int con = 0;
do { con = connect(client, (struct sockaddr*)&my_addr, sizeof my_addr); } while (con != 0);
if (con == 0)
std::cout << "Client Connected\n";
else
std::cerr << "Error in Connection\n";
return client;
}
My OS is Ubuntu20.04 and such code will work with normal output. However, when I remove comments in test() for listenfd, it will output Unable to bind infinitely.
I'm really a newbie in socket and network. I have no idea why that will happen. Also, is there a way for an address-port to be both server and client at the same time? (Maybe to be exact, can an address-port both connect actively & accept others' connection passively?) Thank you!
my_addr1.sin_family = AF_INET;
my_addr1.sin_addr.s_addr = INADDR_ANY;
my_addr1.sin_port = htons(atoi(localPort));
// This ip address will change according to the machine
inet_pton(AF_INET, localAddr, &my_addr1.sin_addr.s_addr);
if (bind(client, (struct sockaddr*)&my_addr1, sizeof(struct sockaddr_in)) == 0)
std::cout << "Binded Correctly\n";
This code binds a listening socket to port 19287, localPort is 19287.
// SOCKET listenfd = OpenListenFD("127.0.0.1", "19287");
And so does the commented-out code. Un-commenting it out results in two sockets attempting to listen on the same port. Surprise, surprise: this doesn't work.
The fact that the first socket that binds this port uses SO_REUSEADDR is irrelevant, and makes no difference. With or without SO_REUSEADDR, no two sockets can listen on the same port.
SO_REUSEADDR does not allow you to have multiple sockets listening on the same port, at the same time. All that SO_REUSEADDR does is allow a listening socket to be bound on a port that's temporarily "take out of commission", in specific edge cases, until a prescribed timeout expires. It allows a port to be bound as long as nothing else is listening on it, even if it's sitting in a "timeout room".
But it still won't allow you to have two different sockets listening on the same port, at the same time.
I am trying to build a UDP file transfer system with C++ that will allow the client to send four characters of a text file to the server at a time. The server will then take the four characters and add them to a new file on the server. I am confused on how to actually implement this. I know that a loop of some kind will have to be created on the client and server to continuously send data from the client and receive data on the server I just don't know how to implement it. I will post the code that I have so far for the client and server below. Any help is appreciated!
Client Code
// *** 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
socklen_t slen = sizeof(server);
memset(payload, 0, sizeof(payload));
strcpy(payload, dataBuffer.c_str());
sendRes = sendto(udpsocket, payload, 512, 0, (struct sockaddr *) &server, slen);
if (sendRes == -1) {
cerr << "Could not send to server";
return 1;
}
close(udpsocket);
return 0;
Server Code
// *** 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, 512, 0, (sockaddr*)&client, &clen);
cout << "Payload: " << payload << "\n";
close(udpsocket);
return 0;
}
1) I am trying to make a simple game server using UDP. Would my code be the correct way to check if there is any reads from a single socket?
2) I want to recieve data from one user on a request ( he wants to move left), then update where the server thinks he or she is located, then broadcast the x , y coordinates. How would I implement a multicast reply with a different socket?
void run()
{
//logging file
ofstream log;
log.open("server_log.txt", ios::out | ios::app);
struct sockaddr_in myaddr; // our address
struct sockaddr_in remaddr; // remote address
socklen_t addrlen = sizeof(remaddr);
int recvlen;
int fd; // server socket that listens
int fd_reply; // this will be used to reply to all users
char buf[BUFSIZE]; // receive buffer
memset((char *)&myaddr, 0, sizeof(myaddr));
myaddr.sin_family = AF_INET;
myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
myaddr.sin_port = htons(PORT);
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
std::time_t result = std::time(nullptr);
log << "Error: cannot create socket! " << "TIMESTAMP: " << std::asctime(std::localtime(&result)) << endl;
log.close();
return 0;
}
if (bind(fd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) {
std::time_t result = std::time(nullptr);
log << "Error: bind failed " << "TIMESTAMP: " << std::asctime(std::localtime(&result)) << endl;
log.close();
return 0;
}
pollfd fds;
memset(fds, 0, sizeof(fds));
fds[0].fd = fd;
fds[0].events = POLLIN;
while (1)
{
int rv = poll(ufds, 1, 3500);
if (rv == -1)
{
// error occured
}
else if (rv == 0)
{
//time out
}
else
{
//check for events on fd
if (fds.revents & POLLIN)
{
recvlen = recvfrom(fd, buf, BUFSIZE, 0, (struct sockaddr *)&remaddr, &addrlen);
}
}
}
}
Yes it looks okay.
Keep a list of all clients, and then in a loop send to all of them. To populate this list, all clients need to contact the server the first thing they do.
I have two programs, on is server and only listening and the client is talking. I send 1mbytes of data in chunks of 64bytes each. I will get the first chunk of 64byte but then my server exits because it failed to get other data. My client is sending all of the data.
void ServerLinux::Receive(){
int sock = 0;
struct sockaddr_in server;
char buffer[this->packageLength];
if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
this->Die("Failed to create socket");
}
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl(INADDR_ANY);
server.sin_port = htons(this->port);
if(bind(sock, (struct sockaddr *) &server, sizeof(server)) < 0){
this->Die("Failed to bind the server socket");
}
if(listen(sock, 1) < 0){
this->Die("Failed to listen on server socket");
}
int clientSocket = 0;
struct sockaddr_in client;
socklen_t size = sizeof(client);
if((clientSocket = accept(sock, (struct sockaddr *) &client, &size)) < 0){
this->Die("Failed to accept client");
}
int received = -1;
//This is fine data is recived
if((received = recv(clientSocket, buffer, this->packageLength,0)) < 0){
this->Die("Failed to receive initial bytes from client");
}
std::cout << "Received!" << std::endl;
//Data is not received in this while loop
while(received > 0){
if((received = recv(sock, buffer, this->packageLength,0)) < 0){
this->Die("Failed to receive additional bytes frin client");
}
std::cout << "Received!" << std::endl;
}
}
Why don't you use the same arguments for recv?
works: recv(clientSocket, buffer, this->packageLength,0)
doesn't work recv(sock, buffer, this->packageLength,0)
Change sock to clientSocket.
Ok. So I have a simple client program sending images over UDP to a specified IP address. At the specified IP a server program is listening and should receive the images.
When I try both programs on localhost (i.e. they are both running at 127.0.0.1) it works and the server receives the images. When I try to put the client and the server programs on different PCs in the same network it does not work.
147.232.24.163 is the server IP, 147.232.24.150 is the client IP.
Here is my client program:
// Initialize UDP.
struct sockaddr_in server;
int n_sent;
int socketId = socket(AF_INET, SOCK_DGRAM, 0);
if (socketId < 0)
{
cout << "Problem creating socket." << endl;
}
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr("147.232.24.163");
// Establish the server port number - we must use network byte order!
server.sin_port = htons(42001);
for ( int iter = 0; iter < 60; iter++ )
{
// load image into jpegBuf
n_sent = sendto(socketId, reinterpret_cast<char*> (&jpegBuf[0]), jpegBuf.size(), 0, (struct sockaddr*) &server, sizeof(server));
if (n_sent < 0) {
cout << "Problem sending data." << endl;
}
}
close(socketId);
Here is my server program:
int main()
{
int bufferSize = 1024000;
int iSockFd = -1;
int iLength = 0;
struct sockaddr_in servAddr, cliAddr;
char buff[bufferSize];
iSockFd=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
memset(&servAddr, 0, sizeof(servAddr));
memset(&cliAddr, 0, sizeof(cliAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = inet_addr("147.232.24.163");
servAddr.sin_port = htons(42001);
int cliAddrLen = sizeof(struct sockaddr_in);
int bindRet = bind(iSockFd, (struct sockaddr*)&servAddr, sizeof(servAddr));
cout << "Bind returned " << bindRet << endl;
int i = 0;
while (true)
{
int iRcvdBytes=recvfrom(iSockFd, buff, bufferSize, 0,
(struct sockaddr*)&cliAddr, (socklen_t*)&cliAddrLen);
if (0 == i % 5)
{
cout << "Received " << iRcvdBytes << " bytes from the client" << endl;
}
i++;
}
close(iSockFd);
return 0;
}
Any ideas why it does not work? I don't get any error messages.
This is not a solution but your code should be checking iRcvdbytes for error in the same way as the send code checks the result of sendto.
A return of 0 means the socket was closed gracefully (if connection-oriented - that should not apply here), SOCKET_ERROR means an error (in WinSock2 at least).
The socket on the send side needs to be created with IPPROTO_UDP, not 0. This could definitely be causing your failure.