Can one reliably connect a TCP socket to itself? - sockets

I am wondering whether it is possible to reliably connect a TCP socket to itself -- that is, to get just one socket where whatever you send() on you receive back through recv(). I saw that this can happen (e.g., here, here, and here), but none of these posts explain how to do this programmatically and reliably (i.e., this is usually touted as a curiosity, rather than a feature one would use deliberately). I'm interested in a solution for Windows, Mac, and Linux.
Just for completeness, please let me explain why I'm interested in this. I'm writing a cloud-based application where servers can send messages to other servers, including themselves. Each server uses one socket to talk to other servers, and so, to unify the code and make certain threading issues simpler, it would be good if the server could talk to itself using just one socket as well.
EDIT: #Rufflewind suggested connecting to the loopback adapter. I tried that using the code below, both with and without the call to listen. In all cases, however, I got an error (either "Invalid argument" or "Operation not supported"). What am I doing wrong?
#include <iostream>
#include <netinet/tcp.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
void die(const char* const message) {
perror(message);
exit(0);
}
#define CHECK(operation,message) \
if ((operation) != 0) \
die(message)
int main(int argc, char* argv[]) {
sockaddr_in local;
local.sin_family = AF_INET;
local.sin_port = htons(40000);
inet_aton("127.0.0.1", &local.sin_addr);
int sck = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
CHECK(bind(sck, (struct sockaddr *)&local, sizeof(local)), "Error while binding the socket to an address");
// CHECK(listen(sck, 1), "Error while listening.");
CHECK(connect(sck, (struct sockaddr *)&local, sizeof(local)), "Error while connecting the socket to self");
std::cout << "Succeeded in connecting sockets!" << std::endl;
const char* message = "ABCDEFGH";
const size_t messageLength = ::strlen(message) + 1;
const char* currentSend = message;
ssize_t leftToSend = messageLength;
while (leftToSend != 0) {
const ssize_t sent = send(sck, currentSend, leftToSend, 0);
if (sent == -1)
die("Can't send.");
currentSend += sent;
leftToSend -= sent;
}
std::cout << "Sent the message!" << std::endl;
char buffer[256];
char* currentRead = buffer;
size_t leftToRead = messageLength;
while (leftToRead != 0) {
const ssize_t read = recv(sck, currentRead, leftToRead, 0);
if (read == -1)
die("Can't read.");
currentRead += read;
leftToRead -= read;
}
std::cout << "Received message: " << buffer << std::endl;
return 0;
}

The most straightforward approach would be to bind to the loopback adapter. Just listen to 127.0.0.1 on some arbitrary port and the connect to that.
The problem with this approach is that the port is global on the machine, so that means other programs can connect to it too, and if you have multiple programs you might run into conflicts or conceivably exhaust all the possible ports.
Another approach is to use Unix domain sockets, but this is not supported on Windows.

Related

Unable to authenticate bluemix connection using eclipse paho c libraries

I am using the eclipse paho mqtt c library to connect to bluemix. Have done my part on the bluemix cloud and created an IoT device and registered the same, have generated API keys. But when i try to connect to the device using the below code, my code exits with an rc state of 5.
And i see log messages on the cloud saying "Closed connection, unable to authenticate".
I have tried a lot, but rc is always 5.
Appreciate your assistance.
I am using the below code, with my organization ID, device type, space ID and authentication token (on bluemix i have created a IoT device on watson).
#include <iostream>
#include <sstream>
#include <fstream>
#include <string.h>
#include "MQTTClient.h"
#define CPU_TEMP "/sys/class/thermal/thermal_zone0/temp"
using namespace std;
#define ADDRESS "tcp://<org_ID>.messaging.internetofthings.ibmcloud.com:1883"
#define CLIENTID "d:<org_ID>:<Device_type>:<space_ID>"
#define AUTHMETHOD "use-token-auth"
#define AUTHTOKEN "<authentication_token>"
#define TOPIC "iot-2/evt/status/fmt/json"
#define QOS 1
#define TIMEOUT 10000L
float getCPUTemperature(){
int CPUTemp;
fstream fs;
fs.open(CPU_TEMP, fstream::in);
fs >> CPUTemp;
fs.close();
return (((float)CPUTemp)/1000);
}
int main(int argc, char* argv[]) {
MQTTClient client;
MQTTClient_connectOptions opts = MQTTClient_connectOptions_initializer;
MQTTClient_message pubmsg = MQTTClient_message_initializer;
MQTTClient_deliveryToken token;
MQTTClient_create(&client, ADDRESS, CLIENTID, MQTTCLIENT_PERSISTENCE_NONE, NULL);
opts.keepAliveInterval = 20;
opts.cleansession = 1;
opts.username = AUTHMETHOD;
opts.password = AUTHTOKEN;
int rc;
if ((rc = MQTTClient_connect(client, &opts)) != MQTTCLIENT_SUCCESS)
{
cout<<"Failed to connect "<<rc<<endl;
return -1;
}
stringstream message;
message <<"{\"d\":{\"Temp\":"<<getCPUTemperature()<<"}}";
pubmsg.payload = (char*) message.str().c_str();
pubmsg.payloadlen = message.str().length();
pubmsg.qos = QOS;
pubmsg.retained = 0;
MQTTClient_publishMessage(client, TOPIC, &pubmsg, &token);
cout<< "Waiting for " << (int) (TIMEOUT/1000) << "seconds for pub of"<<message.str()<<"\non topic"<<TOPIC<<"for ClientID:"<<CLIENTID<<endl;
rc = MQTTClient_waitForCompletion(client, token, TIMEOUT);
cout<<"Message with token"<< (int)token<<"delivered"<<endl;
MQTTClient_disconnect(client,10000);
MQTTClient_destroy(&client);
return rc;
}
Apparently there are 2 connection types on bluemix, TLS and non TLS.
So i was accessing TLS type using my code meant for non-TLS connections.
Hence the authent

UDP Socket communication using different ports between two hosts

I have a device that listen to UDP packets on port IN_PORT and echo the message on port OUT_PORT. I can communicate with it using a test software like Packet Sender.
I have to write a C++ library (Win32 at the moment) to communicate with the device. I made several tests but I still wasn't able to communicate. My guess is to use this workflow:
create socket
fill sockaddr_in structure with the device address, AF_INET family and the listeng port (OUT_PORT)
bind the socket
change sockaddr_in.sin_port with IN_PORT and send a packet (using sendto)
wait for an answer (using recvfrom)
repeat from 4
This works if I simulate the device with the Packet Sender utility working locally (device address = 127.0.0.1). I can't use the same workflow to connect to a remote address, even in the same subnet (e.g. my PC address: 192.168.1.2, remote PC address 192.168.1.5), since I get WSAEADDRNOTAVAIL error.
I've tested several different workflows, and read several discussions on the topic here and there, but none works, awfully.
Can someone give me some hints on the subject.
Thanks!
MIX
Your work flow is slightly wrong. It should be more like this instead:
create socket
fill sockaddr_in structure with the address of the local network adapter that is communicating with the device, AF_INET family, and the listenig port (OUT_PORT)
bind the socket
change sockaddr.sin_addr with device address, and sockaddr_in.sin_port with IN_PORT, and send a packet (using sendto)
wait for an answer (using recvfrom)
repeat from 4
I changed my code following Remy Lebeau hints. It works now. If someone will like to have a look and spot some weak points, or suggest improvements, I'll be glad (a code that "just works" is never enough; it must also "shine"!). Comments mark the previous (wrong) version of the code.
#pragma comment (lib, "Ws2_32.lib")
#include <winsock2.h>
#include <stdlib.h>
#include <stdio.h>
#include <STRING>
#define IN_PORT 18
#define OUT_PORT 17
#define LOCAL_IP "10.0.10.108"
#define DEVICE_IP "10.0.10.104"
#define DEFAULT_BUFLEN 1024
int main(int argc, char *argv[])
{
WSADATA wsaData;
SOCKET sck;
struct sockaddr_in sckAddrInfo;
bool terminate;
char dataBuffer[DEFAULT_BUFLEN];
int rcvDataLength;
int sckAddrInfoLength;
WSAStartup(MAKEWORD(2,2), &wsaData);
sck = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
memset((&sckAddrInfo), 0, sizeof(sckAddrInfo));
sckAddrInfo.sin_family = AF_INET;
sckAddrInfo.sin_port = htons(IN_PORT);
//sckAddrInfo.sin_addr.s_addr = inet_addr(DEVICE_IP); // WRONG! Must bind local address
sckAddrInfo.sin_addr.s_addr = inet_addr(LOCAL_IP);
bind(sck, (struct sockaddr*)(&sckAddrInfo), sizeof(sckAddrInfo));
terminate = false;
sckAddrInfoLength = sizeof(sckAddrInfo);
while(!terminate)
{
printf("Write echo request: ");
gets(dataBuffer);
sckAddrInfo.sin_addr.s_addr = inet_addr(DEVICE_IP); // Must set device address, too, not just output port
sckAddrInfo.sin_port = htons(OUT_PORT);
sendto(sck, dataBuffer, strlen(dataBuffer), 0, (struct sockaddr*)(&sckAddrInfo), sizeof(sckAddrInfo));
memset(dataBuffer, '\0', DEFAULT_BUFLEN);
rcvDataLength = recvfrom(sck, dataBuffer, DEFAULT_BUFLEN, 0, (struct sockaddr*)(&sckAddrInfo), &sckAddrInfoLength);
printf("Device answer: %s\n", dataBuffer);
if(strcmp(dataBuffer, "quit") == 0)
terminate = true;
}
closesocket(sck);
WSACleanup();
return 0;
}

Using multicast addresses and groups

For a week or so I have been researching methods to send datagrams to multiple clients from a single source, and found that the IP supports multicasting over the range of 224.0.0.0 and 234.255.255.255. I have read a few documents that describe the technology, but am finding nothing that has helped me understand how to use them.
From what I have gathered, it seems that a program asks the OS kernel to join a non-associated multicast group, then starts sending data over a socket via UDP to the multicast address. Everything else is handled by WAN without needing anything something physically at the address being sent to.
This line of thinking has been vaguely supported by what I've read, but has not been confirmed at all. Is this thinking correct? What is mistaken if there are issues with it?
This is essentially correct.
On the receiver side, you first open up a socket listening on a particular port. Then you join a multicast address on a given network interface. Doing so causes the OS to send out IGMP messages to the network informing routers that is joining a group.
On the sender side, you open a socket, then configure the outgoing network interface for multicast. Once you do that, you can send packets to any multicast address.
Here's an example sender in C:
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <strings.h>
#include <arpa/inet.h>
int main(int argc, char *argv[])
{
struct sockaddr_in sin;
struct in_addr out_addr;
char mes[255], ttl;
int sock;
printf("Enter message: ");
fgets(mes, sizeof(mes), stdin);
bzero(&sin,sizeof(sin));
sin.sin_family=AF_INET;
sin.sin_addr.s_addr=inet_addr(argv[1]);
sin.sin_port=htons(atoi(argv[2]));
if ((sock=socket(AF_INET,SOCK_DGRAM,0))==-1) {
perror("Error creating socket");
exit(1);
}
out_addr.s_addr=inet_addr(argv[3]);
if (setsockopt(sock,IPPROTO_IP,IP_MULTICAST_IF,(char *)&out_addr,sizeof(out_addr))== -1) {
perror("Error setting outgoing interface");
close(sock);
exit(1);
}
if (sendto(sock,mes,strlen(mes),0,(struct sockaddr *)&sin,sizeof(sin))==-1) {
close(sock);
perror("Send error");
}
close(sock);
}
And here's a sample receiver in C:
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main(int argc, char *argv[])
{
int addr_len;
struct sockaddr_in sin,sin_recv;
struct ip_mreq multi;
char mes[255];
int sock;
bzero(&sin,sizeof(sin));
multi.imr_multiaddr.s_addr=inet_addr(argv[1]);
multi.imr_interface.s_addr=inet_addr(argv[2]);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(atoi(argv[3]));
if ((sock=socket(AF_INET,SOCK_DGRAM,0))==-1) {
perror("Error creating socket");
exit(1);
}
if (setsockopt(sock,IPPROTO_IP,IP_ADD_MEMBERSHIP,(char *)&multi,sizeof(multi))== -1) {
perror("Error joining multicast group");
close(sock);
exit(1);
}
if (bind(sock,(struct sockaddr *)&sin,sizeof(sin))==-1) {
perror("Error binding socket");
close(sock);
exit(1);
}
while (1) {
bzero(mes,sizeof(mes));
bzero(&sin_recv,sizeof(sin_recv));
addr_len=sizeof(sin_recv);
printf("Waiting for packet...\n");
if (recvfrom(sock,mes,sizeof(mes),0,(struct sockaddr *)&sin_recv,&addr_len)==-1) {
perror("error recving socket");
close(sock);
exit(1);
}
printf("Got packet\n");
printf("Origin: %s port %d\n",inet_ntoa(sin_recv.sin_addr),sin_recv.sin_port);
printf("Message: %s\n",mes);
}
}

WSAConnect returns WSAEINVAL on WindowsXP

I use sockets in non-blocking mode, and sometimes WSAConnect function returns WSAEINVAL error.
I investigate a problem and found, that it occurs if there is no pause (or it is very small ) between
WSAConnect function calls.
Does anyone know how to avoid this situation?
Below you can found source code, that reproduce the problem. If I increase value of parameter in Sleep function to 50 or great - problem dissapear.
P.S. This problem reproduces only on Windows XP, on Win7 it works well.
#undef UNICODE
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <iostream>
#include <windows.h>
#pragma comment(lib, "Ws2_32.lib")
static int getError(SOCKET sock)
{
DWORD error = WSAGetLastError();
return error;
}
void main()
{
SOCKET sock;
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
fprintf(stderr, "Socket Initialization Error. Program aborted\n");
return;
}
for (int i = 0; i < 1000; ++i) {
struct addrinfo hints;
struct addrinfo *res = NULL;
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_PASSIVE;
hints.ai_socktype = SOCK_STREAM;
hints.ai_family = AF_INET;
hints.ai_protocol = IPPROTO_TCP;
if (0 != getaddrinfo("172.20.1.59", "8091", &hints, &res)) {
fprintf(stderr, "GetAddrInfo Error. Program aborted\n");
closesocket(sock);
WSACleanup();
return;
}
struct addrinfo *ptr = 0;
for (ptr=res; ptr != NULL ;ptr=ptr->ai_next) {
sock = WSASocket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol, NULL, 0, NULL); //
if (sock == INVALID_SOCKET)
int err = getError(sock);
else {
u_long noblock = 1;
if (ioctlsocket(sock, FIONBIO, &noblock) == SOCKET_ERROR) {
int err = getError(sock);
closesocket(sock);
sock = INVALID_SOCKET;
}
break;
}
}
int ret;
do {
ret = WSAConnect(sock, ptr->ai_addr, (int)ptr->ai_addrlen, NULL, NULL, NULL, NULL);
if (ret == SOCKET_ERROR) {
int error = getError(sock);
if (error == WSAEWOULDBLOCK) {
Sleep(5);
continue;
}
else if (error == WSAEISCONN) {
fprintf(stderr, "+");
closesocket(sock);
sock = SOCKET_ERROR;
break;
}
else if (error == 10037) {
fprintf(stderr, "-");
closesocket(sock);
sock = SOCKET_ERROR;
break;
}
else {
fprintf(stderr, "Connect Error. [%d]\n", error);
closesocket(sock);
sock = SOCKET_ERROR;
break;
}
}
else {
int one = 1;
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof(one));
fprintf(stderr, "OK\n");
break;
}
}
while (1);
}
std::cout<<"end";
char ch;
std::cin >> ch;
}
You've got a whole basketful of errors and questionable design and coding decisions here. I'm going to have to break them up into two groups:
Outright Errors
I expect if you fix all of the items in this section, your symptom will disappear, but I wouldn't want to speculate about which one is the critical fix:
Calling connect() in a loop on a single socket is simply wrong.
If you mean to establish a connection, drop it, and reestablish it 1000 times, you need to call closesocket() at the end of each loop, then call socket() again to get a fresh socket. You can't keep re-connecting the same socket. Think of it like a power plug: if you want to plug it in twice, you have to unplug (closesocket()) between times.
If instead you mean to establish 1000 simultaneous connections, you need to allocate a new socket with socket() on each iteration, connect() it, then go back around again to get another socket. It's basically the same loop as for the previous case, except without the closesocket() call.
Beware that since XP is a client version of Windows, it's not optimized for handling thousands of simultaneous sockets.
Calling connect() again is not the correct response to WSAEWOULDBLOCK:
if (error == WSAEWOULDBLOCK) {
Sleep(5);
continue; /// WRONG!
}
That continue code effectively commits the same error as above, but worse, if you only fix the previous error and leave this, this usage will then make your code start leaking sockets.
WSAEWOULDBLOCK is not an error. All it means after a connect() on a nonblcoking socket is that the connection didn't get established immediately. The stack will notify your program when it does.
You get that notification by calling one of select(), WSAEventSelect(), or WSAAsyncSelect(). If you use select(), the socket will be marked writable when the connection gets established. With the other two, you will get an FD_CONNECT event when the connection gets established.
Which of these three APIs to call depends on why you want nonblocking sockets in the first place, and what the rest of the program will look like. What I see so far doesn't need nonblocking sockets at all, but I suppose you have some future plan that will inform your decision. I've written an article, Which I/O Strategy Should I Use (part of the Winsock Programmers' FAQ) which will help you decide which of these options to use; it may instead guide you to another option entirely.
You shouldn't use AI_PASSIVE and connect() on the same socket. Your use of AI_PASSIVE with getaddrinfo() tells the stack you intend to use this socket to accept incoming connections. Then you go and use that socket to make an outgoing connection.
You've basically lied to the stack here. Computers find ways to get revenge when you lie to them.
Sleep() is never the right way to fix problems with Winsock. There are built-in delays within the stack that your program can see, such as TIME_WAIT and the Nagle algorithm, but Sleep() is not the right way to cope with these, either.
Questionable Coding/Design Decisions
This section is for things I don't expect to make your symptom go away, but you should consider fixing them anyway:
The main reason to use getaddrinfo() — as opposed to older, simpler functions like inet_addr() — is if you have to support IPv6. That kind of conflicts with your wish to support XP, since XP's IPv6 stack wasn't nearly as heavily tested during the time XP was the current version of Windows as its IPv4 stack. I would expect XP's IPv6 stack to still have bugs as a result, even if you've got all the patches installed.
If you don't really need IPv6 support, doing it the old way might make your symptoms disappear. You might end up needing an IPv4-only build for XP.
This code:
for (int i = 0; i < 1000; ++i) {
// ...
if (0 != getaddrinfo("172.20.1.59", "8091", &hints, &res)) {
...is inefficient. There is no reason you need to keep reinitializing res on each loop.
Even if there is some reason I'm not seeing, you're leaking memory by not calling freeaddrinfo() on res.
You should initialize this data structure once before you enter the loop, then reuse it on each iteration.
else if (error == 10037) {
Why aren't you using WSAEALREADY here?
You don't need to use WSAConnect() here. You're using the 3-argument subset that Winsock shares with BSD sockets. You might as well use connect() here instead.
There's no sense making your code any more complex than it has to be.
Why aren't you using a switch statement for this?
if (error == WSAEWOULDBLOCK) {
// ...
}
else if (error == WSAEISCONN) {
// ...
}
// etc.
You shouldn't disable the Nagle algorithm:
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, ...);

How to make a G-WAN servlet close its connection silently without sending any reply

How to have gwan send no reply to some requests, i.e. make a servlet closed silently without building and sending a reply?
It is useful to reduce the out-going bandwidth from the server side.
For collecting data only, there's no need to respond anything to the client.
You can also close the connection from the servlet by doing something like (untested):
#include <sys/socket.h>
char buf[1024];
int s = (int)get_env(argv, CLIENT_SOCKET);
shutdown(s, SHUT_WR);
while(read(s, buf, sizeof(buf)) > 0);
close(s);
return 500;
Then return something like 500 like above so you don't have to build a reply.
You can do that with a gwan connection handler.
I think this is the event that you need to catch on the handler. Since you want the servlet to run then close the connection after.
HDL_BEFORE_WRITE, // after a reply was built, but before it is sent
Here is a sample code for the connection handler. You still need to add your filter. This code will close all requests after the reply was built.
int init(int argc, char *argv[])
{
u32 *states = (u32*)get_env(argv, US_HANDLER_STATES);
*states = (1 << HDL_BEFORE_WRITE)
}
int main(int argc, char *argv[])
{
long state = (long)argv[0];
if(state == HDL_BEFORE_WRITE)
{
return 0; // Close connection
}
return(255); // continue G-WAN's default execution path
}