I have this code:
#include <cstring>
#include <cstdio>
#include <cerrno>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string>
#include <stdlib.h>
#include <unistd.h>
#include <cstdlib>
#include <iostream>
#include <thread>
#include "STUN.h"
bool do_work = true;
using namespace std;
void receiver(int sock) {
//boost::asio::io_service& s
sockaddr_in from_adr;
std::cout << "START: receiver\n";
size_t blen = 2048;
char * buf = new char[blen];
unsigned slen = sizeof(from_adr);
if (recvfrom(sock, (void *) buf, blen, 0, (sockaddr*) &from_adr, &slen)
< 0) {
std::cout << "Recv problem\n";
exit(0);
}
do_work = false;
std::cout << "STOP: receiver\n";
}
void sender(sockaddr_in * to, int sock) {
std::cout << "START: sender\n";
while (do_work) {
if (sendto(sock, "OK", 3, 0, (sockaddr*) to, sizeof(sockaddr)) < 0) {
std::cout << "SEND PROBLEM\n";
return;
}
sleep(1);
}
std::cout << "RECEIVED!!!\n\n\n";
exit(0);
}
int main(int argc, char* argv[]) {
if (argc != 2) {
std::cerr << "Usage: udp-flood-test <port>\n";
return 1;
}
ippd stun_adr;
stun_adr.addr = "64.233.161.127";
stun_adr.port = 19302;
STUN stun(stun_adr);
std::string eip;
uint16_t epp;
uint16_t lp = std::atoi(argv[1]);
ippd sti = stun.getSTUN(lp);
std::cout << "External address: " << sti.addr << ":" << sti.port << "\n";
std::cout << "Internal address: " << "127.0.0.1:" << lp << "\n";
std::cout << "Write external ip: ";
std::cin >> eip;
std::cout << "\n";
std::cout << "Write external port: ";
std::cin >> epp;
std::cout << "\n";
std::cout << "OK. I'll send data to " << eip << ":" << epp << "\n";
int m_sock; // дескриптор сокета
sockaddr_in m_addr; // переменная адреса интерфейса
std::string my_addr = "0.0.0.0"; // Адрес локального интерфейса
/* Создание сокета и присвоение значения дескриптору сокета для UDP пакетов
* PF_INET - IP protocol family
* SOCK_DGRAM - Raw protocol interface */
if ((m_sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket");
return -1;
}
/* Обнуляем переменную m_addr и забиваем её нужными значениями */
memset(&m_addr, 0, sizeof(m_addr));
m_addr.sin_family = AF_INET; // обязательно AF_INET!
m_addr.sin_port = htons(lp); // 0 - выдать порт автоматом
/* Переводим адрес в нужный нам формат */
if (inet_aton(my_addr.c_str(), &m_addr.sin_addr) == 0) {
perror("inet_aton");
close(m_sock);
return -1;
}
/* Биндим сокет */
if (bind(m_sock, (struct sockaddr*) &m_addr, sizeof(m_addr)) < 0) {
perror("bind");
close(m_sock);
return -1;
}
sockaddr_in to_addr;
memset(&to_addr, 0, sizeof(to_addr));
to_addr.sin_family = AF_INET;
to_addr.sin_port = htons(epp);
if (inet_aton(eip.c_str(), &to_addr.sin_addr) == 0) {
perror("inet_aton");
close(m_sock);
return -1;
}
std::thread inp(receiver, m_sock);
std::thread oup(sender, &to_addr, m_sock);
oup.detach();
inp.detach();
while (1) {
sleep(1);
}
return 0;
}
It's a simple test program to get external ip and port over STUN and send data from peer A to peer B (and from B to A).
So program works fine if I set IPs and ports as 127.0.0.1:port or local_network_ip:port.
If I set IP received from STUN server peer A will send UDP packets to peer B. And B will send packets to A. But A and B haven't any incoming packets. In Wireshark I can see outgoing packets too, but no incoming.
Network connection diagram:
A (pc with active test program) - NAT (home router) - ... - NAT (internet provider) - internet - NAT (another internet provider) - ... - NAT (another home router) - B (another pc with active test program)
Maybe I'm doing something wrong?..
Where can I find a problem?
Problem is in double NAT. Home routers (from network diagram) rejecting packets if you have no configured port forwarding.
Follow this steps to work over double NAT:
select local port to receive packets.
try to bind port. (if failed then return to step 1)
configure port forwarding in home router using NAT-PMP or UPnP IGD.
use STUN to get your external IP and port
share data from step 4 to another program instance
send and/or receive UDP packets
Related
I am currently trying to create a C++ TCP IP Client that can send a specific string to a server, which makes the server send back a string with some numbers I need to use.
Specifically I need to send the string "getpos", and only that.
This works perfectly on the first loop, but on the second loop and onward. Whenever I try to send "getpos" again, it will overlap "getpos" with the numbers I previously recieved from the server and send that like:
"getpos20,123,24"
It's like the buffer or something hasn't cleared.
My program works perfectly when connecting to a Python server, but not a C++ server.
I have looked through others with similar issues, and tried various fixes. Nothing has worked so far.
Here is my current client code (on Linux):
#include <iostream>
#include <sys/types.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <string.h>
#include <string>
int main()
{
// Create a socket
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == -1)
{
return 1;
}
// Create a hint structure for the server we're connecting with
int port = PORTHERE;
std::string ipAddress = "IPNUMBERHERE";
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(port);
inet_pton(AF_INET, ipAddress.c_str(), &hint.sin_addr);
std::cout << "listening" << std::endl;
// Connect to the server on the socket
int connectRes = connect(sock, (sockaddr*)&hint, sizeof(hint));
if (connectRes == -1)
{
return 1;
}
std::cout << "connected" << std::endl;
// While loop:
char buf[4096];
int buflen = 1024;
while(true){
// Send to server
std::string getmypos = "getpos";
int sendRes = send(sock, getmypos.c_str(), getmypos.size(), 0);
if (sendRes == -1){
std::cout << "Could not send to server! Whoops!" << std::endl;
continue;
}
// Wait for response
memset(buf, 0, 4096);
int bytesReceived = recv(sock, buf, buflen, 0);
if (bytesReceived == -1)
{
std::cout << "There was an error getting response from server" << std::endl;
}
else
{
// Display response
std::cout << "SERVER> " << std::string(buf, bytesReceived) << std::endl;
sleep(1);
}
}
// Close the socket
close(sock);
return 0;
}
I'm currently working on an instant messaging system that require a server and a client to communicate between each other.
I tried it in C++ using the default socket API.
The problem is that even if both programs (server & client) compile fine, there isn't any socket sent from the client that reaches the server.
I don't know what did I do wrong here (I went over my code like 5 times and even did it again from scratch, no success).
I used "debugs" messages to locate the problems and they all concern the processing loops that I use.
// code from the server
#include <stdio.h>
#include <tchar.h>
#include <winsock2.h>
#include <stdlib.h>
#include <iostream>
#include <thread>
#include <vector>
#include <Ws2tcpip.h>
#include <string>
int main()
{
std::locale::global(std::locale("fr-FR"));
WSAData wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
std::cout << "Error initializing winsock";
return -1;
}
SOCKET server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (server == INVALID_SOCKET)
{
std::cout << "Error initializing the socket ";
return -2;
}
const unsigned short port = 9999;
sockaddr_in addr;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(port);
addr.sin_family = AF_INET;
int res = bind(server, (sockaddr*)&addr, sizeof(addr));
if (res != 0)
{
std::cout << "Error when binding";
return -3;
}
res = listen(server, SOMAXCONN);
if (res != 0)
{
std::cout << "Error on calling listen";
return -4;
}
std::cout << "Server successfully launched" << std::endl;
char buffer[1025];
while (true)
{
sockaddr_in from = { 0 };
int addrlen = sizeof(from);
SOCKET newClient = accept(server, (SOCKADDR*)(&from), &addrlen);
if (newClient != SOCKET_ERROR)
{
std::cout << "Client connected successfully" << std::endl;
int Bytes = recv(newClient, buffer, 1024, 0);
if (Bytes <= 0)
{
break;
}
std::cout << "Message received from client : " << buffer << std::endl;
send(newClient, buffer, 1024, 0); // send it back to client
}
}
return 0;
}
// code from the client
#include <stdio.h>
#include <tchar.h>
#include <winsock2.h>
#include <stdlib.h>
#include <iostream>
#include <thread>
#include <vector>
#include <Ws2tcpip.h>
#include <string>
#define _WINSOCK_DEPRECATED_NO_WARNINGS
void sendMessage(SOCKET s);
void recvMessage(SOCKET s);
int main()
{
std::locale::global(std::locale("fr-FR"));
WSAData wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
std::cout << "Error initializing winsock";
return -1;
}
SOCKET server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (server == INVALID_SOCKET)
{
std::cout << "Error initializing the socket ";
return -2;
}
sockaddr_in addr;
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_family = AF_INET;
addr.sin_port = htons(9999);
int res = bind(server, (sockaddr*)&addr, sizeof(addr));
if (res != 0)
{
std::cout << "Error when binding";
return -3;
}
if (connect(server, (const sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR)
{
std::cout << "Erreur when connecting : " << WSAGetLastError() << std::endl;
return -4;
}
std::cout << "You are connected to server" << std::endl;
std::thread sending(sendMessage, server);
std::thread receiving(recvMessage, server);
sending.detach();
receiving.detach();
while (true)
{ }
return 0;
}
void sendMessage(SOCKET s)
{
while (true)
{
std::string buff;
std::cout << "Type your message :" << std::endl;
std::getline(std::cin, buff);
std::cout << std::endl;
int Bytes = send(s, buff.c_str(), 1024, 0);
if (Bytes <= 0)
{
break;
}
}
}
void recvMessage(SOCKET s)
{
while (true)
{
char buffer[1025];
int Bytes = recv(s, buffer, 1024, 0);
if (Bytes <= 0)
{
break;
}
std::cout << "The server sent : " << buffer << std::endl;
}
}
The server should display the message that a client has connected when the client is launched and displays the chat command, but the only thing displayed in the server console is the message saying that the server has launched correctly... Yet the client displays the message supposedly "received" by the server.
PS : I'm aware the code doesn't need that many "include" statements, it's just I didn't remember which ones contained which functions so I'd rather include more than not enough for anybody wanting to compile the code.
Several Things:
First, this is wrong:
send(s, buff.c_str(), 1024, 0)
You're basically telling send that the buffer it addresses is a full 1kb, and to send it all. It hasn't a clue how much memory there is actually valid, and knows nothing about terminated strings.
Second, the client setup is wrong. Don't bind to a client socket; connect is sufficient. Notice these:
int res = bind(server, (sockaddr*)&addr, sizeof(addr));
if (res != 0)
{
std::cout << "Error when binding";
return -3;
}
if (connect(server, (const sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR)
{
std::cout << "Erreur when connecting : " << WSAGetLastError() << std::endl;
return -4;
}
That bind shouldn't be there. The connect will bind to the socket if the connection can be made. Removing the bind section of the client, fixing the buffer management to be correct, and putting closesocket calls where they belong, and your program will be much further down the road to functional. There are still some question logic workflows, but at least the connectivity will be setup better.
I'm new to C++ and am trying to setup a connection to a remote server but having problems getting it to work. Spec: Ubuntu 16.04, pre-installed g++ compiler and when I run the following code it returns "pre-standard C++":
if( __cplusplus == 201103L ) std::cout << "C++11\n" ;
else if( __cplusplus == 19971L ) std::cout << "C++98\n" ;
else std::cout << "pre-standard C++\n" ;
My code is as follows:
#include <iostream>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <netdb.h>
using namespace std;
int main() {
int client;
int portNum = 80;
bool isExit = false;
int bufsize = 1024;
char buffer[bufsize];
const char ip[] = "216.58.210.36"; //google ip for test connection
const char req[] = "GET / HTTP/1.1\nHost: www.google.com"; //test
char res[bufsize];
struct sockaddr_in server_addr;
client = socket(AF_INET, SOCK_STREAM, 0);
if (client < 0) {
cout << "\nError establishing socket..." << endl;
exit(1);
}
cout << "\n=> Socket client has been created..." << endl;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(portNum);
inet_aton(ip, &server_addr.sin_addr);
if (connect(client,(struct sockaddr *)&server_addr, sizeof(server_addr)) == 0){
cout << "=> Connection to the server port number: " << portNum << endl;
}
send(client, req, bufsize, 0);
cout << "=> Awaiting confirmation from the server..." << endl;
recv(client, buffer, bufsize, 0);
cout << "=> Connection confirmed, response:" << buffer << endl;
cout << res << endl;
close(client);
return 0;
}
The client is created and the socket connects but the code hangs on the call to recv() and no response is received. I'm assuming that's because the request I'm sending is in the wrong format/data type/etc. Can anyone advise where I'm going wrong? Cheers!
You haven't sent a complete HTTP request so the server is waiting for more data.
You need to use \r\n as your line separator and your request has to end in a blank line:
const char req[] = "GET / HTTP/1.1\r\nHost: www.google.com\r\n\r\n";
Plus as others have commented you need to check for errors.
You are also sending 1024 bytes of data from a buffer which is much smaller.
I'm using libev + non-blocking sockets to send a request to a server. I'm using Keep Alive because I need to send future requests to the destination over this same connection.
Behavior
Run the program and it fetches the URL and logs to console, as expected.
After doing this, wait and don't push ctrl+c to exit the program.
Expected
App should stay open because event loop is waiting for future responses but should not console log anything after the initial response.
Actual
Leave the app running. After 30+ seconds, it will start to console log the same response over and over and over again without end.
Question
Why is libev calling my callback (example_cb) repeatedly when no new request was sent and no new response data was received? How can I fix this?
#include <ev.h>
#include <stdio.h>
#include <iostream>
#include <ctype.h>
#include <cstring>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <unistd.h>
#include <sstream>
#include <fstream>
#include <string>
using namespace std;
void sendRequest(int sockfd)
{
puts("------");
puts("sendRequest() was called");
stringstream ss;
ss << "GET /posts/11 HTTP/1.1\r\n"
<< "Host: jsonplaceholder.typicode.com\r\n"
<< "Accept: application/json\r\n"
<< "\r\n";
string request = ss.str();
if (send(sockfd, request.c_str(), request.length(), 0) != (int)request.length()) {
cout << "Error sending request." << endl;
exit(1);
}
cout << "Request sent. No err occured." << endl;
}
static void delay_cb(EV_P_ ev_timer *w, int revents)
{
puts("------");
puts("delay_cb() was called");
sendRequest(3);
}
static void example_cb(EV_P_ ev_io *w, int revents)
{
puts("------");
puts("example_cb() was called");
int sockfd = 3;
size_t len = 80*1024, nparsed; // response must be <= 80 Kb
char buf[len];
ssize_t recved;
recved = recv(sockfd, &buf, len, 0);
if (recved < 0) {
perror("recved was <1");
}
// don't process keep alives
if (buf[0] != '\0') {
std::cout << buf << std::endl;
}
// clear buf
buf[0] = '\0';
std::cout << "buf after clear attempt: " << buf << std::endl;
}
int example_request()
{
std::string hostname = "jsonplaceholder.typicode.com";
int PORT = 80;
struct sockaddr_in client;
struct hostent * host = gethostbyname(hostname.c_str());
if (host == NULL || host->h_addr == NULL) {
cout << "Error retrieving DNS information." << endl;
exit(1);
}
bzero(&client, sizeof(client));
client.sin_family = AF_INET;
client.sin_port = htons( PORT );
memcpy(&client.sin_addr, host->h_addr, host->h_length);
// create a socket
int sockfd = socket(PF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
cout << "Error creating socket." << endl;
exit(1);
}
cout << "Socket created" << endl;
// enable keep alive
int val = 1;
setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof val);
if (connect(sockfd, (struct sockaddr *)&client, sizeof(client)) < 0) {
close(sockfd);
cout << "Could not connect" << endl;
exit(1);
}
cout << "Socket connected" << endl;
// make non-blocking
int status = fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL, 0) | O_NONBLOCK);
if (status == -1) {
perror("ERROR making socket non-blocking");
}
std::cout << "Socket set to non-blocking" << std::endl;
std::cout << "Sockfd is: " << sockfd << std::endl;
return sockfd;
}
int main(void)
{
// establish socket connection
int sockfd = example_request();
struct ev_loop *loop = EV_DEFAULT;
ev_io example_watcher;
ev_io_init(&example_watcher, example_cb, sockfd, EV_READ);
ev_io_start(loop, &example_watcher);
// used to send the request 2 sec later
ev_timer delay_watcher;
ev_timer_init(&delay_watcher, delay_cb, 2, 0.0);
ev_timer_start(loop, &delay_watcher);
ev_run(loop, 0);
return 0;
}
Edit: Code updated with suggestions from comments
The source of the problem is that you do not check recved == 0 condition which corresponds to the other side closing the connection. When that happens the OS sets the socket into "closed mode" which (at least under linux) is always ready for reading and subsequent calls to recv will always return 0.
So what you need to do is to check for that condition, call close(fd); on the file descriptor (possibly with shutdown before) and ev_io_stop on the associated watcher. If you wish to continue at that point then you have to open a new socket and eo_io_start new watcher.
this is my second go at this, I've written a server application as below which outputs whatever the client sends. I have one server.exe version where it listens to anything using INADDR_ANY, Having done that I can use my client and connect to the server if I specify the client connect to localhost (Which all works fine).
but if I use my own IP address instead of localhost for the client, I cannot connect to the server?. Shouldn't I be able to connect to the server this way?.
I used another server.exe which was hard-coded to use my IP address without having INADDR_ANY but it wasn't able to bind() or listen() to incoming connections. I'm confused as to how to proceed.
(I'm running the server and client on the same machine, is that an issue?)
server
#include <iostream>
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
using namespace std;
#define PORT 3490
#define IP "118.93.0.164"
#define BACKLOG 10
const int winsockversion = 2;
int main(void){
WSADATA wsadata;
if ( (WSAStartup(MAKEWORD(winsockversion,0),&wsadata)) == 0){
cout<<"-WSAStartup Initialized." << endl;
struct sockaddr_in serv;
memset(&serv,0,sizeof serv);
serv.sin_family = AF_INET;
serv.sin_port = htons(PORT);
serv.sin_addr.s_addr = inet_addr(IP);//INADDR_ANY;//inet_addr(IP);
//---------------------------------------
struct addrinfo serv_addrinfo;
serv_addrinfo.ai_family = AF_INET;
serv_addrinfo.ai_socktype = SOCK_STREAM;
serv_addrinfo.ai_protocol = IPPROTO_TCP;
serv_addrinfo.ai_addrlen = sizeof(serv);
serv_addrinfo.ai_addr = (sockaddr*)&serv;
//---------------------------------------
SOCKET serv_con;
serv_con = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if (serv_con != INVALID_SOCKET){
cout<<"-Server Socket created." << endl;
}
if (bind(serv_con,serv_addrinfo.ai_addr,serv_addrinfo.ai_addrlen) != -1){
cout<<"-Binding Successful." << endl;
}
if( listen(serv_con,BACKLOG) != -1){
cout<<"-Listening for incoming connections." << endl;
}
//--------------------------------------------------------------------
SOCKET recv_socket;
struct sockaddr_in client_info;
int client_info_size = sizeof(client_info);
char *con_addr = inet_ntoa(client_info.sin_addr);
recv_socket = accept(serv_con,(sockaddr*)&client_info,&client_info_size);
if( recv_socket != INVALID_SOCKET ){
cout<<"-Connection Established!. " << endl;
cout<<"-Connected to: [" << con_addr << "] " << endl;
//----------------------------------------------------------------------
char buffer[80];
int bytes_in;
while(true){
bytes_in = recv(recv_socket,buffer,sizeof(buffer),0);
if ( bytes_in > 0 ){
cout<<"[" << con_addr << "]" << buffer << endl;
}
if (bytes_in == 0 ){
cout<<"[" << con_addr << "] has disconnected." << endl;
break;
}
if (bytes_in == -1 ){
cout<<"-Possible Abrupt disconnecton from [" << con_addr << "]" << endl;
break;
}
}
closesocket(recv_socket);
closesocket(serv_con);
}
}else{
cout<<"-WSAStartup Initialization failed." << endl;
}
if( WSACleanup()!= -1){
cout<<"-WSACleanp Successful." << endl;
}
WSAGetLastError();
return 0;
}
client
/*client*/
#define _WIN32_WINNT 0x501
#include <iostream>
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
using namespace std;
#define PORT "3490"
#define SERVER "118.93.0.164" // and localhost
const int winsockVersion = 2;
int main(void){
WSADATA wsadata;
if ( (WSAStartup(MAKEWORD(2,0),&wsadata)) == 0){
cout<<"-WSAStartup Initialized." << endl;
struct addrinfo hints, *res;
int sockfd;
memset(&hints,0,sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if (getaddrinfo(SERVER,PORT,&hints,&res) != 0){
cout<<"-getaddrinfo unsuccessful." << endl;
}
if ( (sockfd = socket(res->ai_family,res->ai_socktype,res->ai_protocol)) == -1 ){
cout<<"-Unable to create socket." << endl;
}
if ( (connect(sockfd,res->ai_addr,res->ai_addrlen)) != -1 ){
cout<<"-Connection Established." << endl;
}
cout<<"-Client connecting to: " << res->ai_addr << endl;
while(true){
string text_buff;
cout<<"Enter text: ";
getline(cin,text_buff);
if( (send(sockfd,text_buff.c_str(),text_buff.length()+1,0)) != -1 ){
cout<<"-text_buff sent!." << endl;
}
}
}else{
cout<<"-WSAStartup Initialization failed." << endl;
if(WSACleanup()!=0){
cout<<"-WSACleanup Successful." << endl;
}else{
cout<<"-WSACleanup Failed." << endl;
}
}
return 0;
}
If you have a router you will have to set up Port forwarding. It really depends on what kind of router you have, so you will have to look it up for your specific one.
You cannot bind to your ISP's IP address, since you do not own it (the router does). You have to bind to an IP address that your computer actually owns, which is found via ipconfig /all in windows. Then make sure to forward traffic in your router for your servers portnumber, to the internal ipaddress that your computer has.
When you're trying to connect back to the server, are you using localhost/127.0.0.1, or the IP address you're listening on?
It may be that trying to connect to 'localhost' attempts to use the loopback interface, which your program isn't listening on. I'm not 100% sure how it works in Windows.
Can I ask a more important question that may prompt you to change your design: why do you want to bind to a particular IP (and localhost)?
you may try using cmd to ping to server IP from your client side to see whether it is a connection problem.
Furthermore, i think this
#define PORT "3490"
in client side is wrong since port should be an integer.