ZeroMQ: Using EPGM transport - c++

I am trying to use the epgm transport in my simple publisher-subscriber program, but I am unable to do so. From what I understand, I am unable to supply a correct address string in bind and connect statements.
The publisher and subscriber can be running on same or different machines.
Below is the required code which usees tcp transport and works correctly. It uses cppzmq: https://github.com/zeromq/cppzmq.
Publisher code:
#include <zmq.hpp>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
int main () {
zmq::context_t context (1);
zmq::socket_t publisher (context, ZMQ_PUB);
publisher.bind("tcp://10.1.1.8:5000");
int i = 0;
while (1) {
int topic = 101;
zmq::message_t message(50);
snprintf ((char *) message.data(), 50, "%03d %10d %10d", topic, i, i);
//fprintf(stderr, "message: %s\n", (char *) message.data());
publisher.send(message);
++i;
}
return 0;
}
Subscriber code:
#include <zmq.hpp>
#include <iostream>
#include <sstream>
#include <unistd.h>
#include <cassert>
int main (int argc, char *argv[]) {
zmq::context_t context (1);
zmq::socket_t subscriber (context, ZMQ_SUB);
subscriber.connect("tcp://10.1.1.8:5000");
const char *filter = "101 ";
subscriber.setsockopt(ZMQ_SUBSCRIBE, filter, strlen (filter));
zmq::message_t tp;
int maxx = 0;
for (int i = 0; i < 1000; ++i) {
zmq::message_t update;
int topic, a, b;
if(subscriber.krecv(&update, ZMQ_DONTWAIT)) {
//fprintf(stderr, "size of data received: %zd\n", sizeof(update.data()));
std::istringstream iss(static_cast<char*>(update.data()));
iss >> topic >> a >> b;
assert(a == b);
}
else {
--i;
}
maxx = a > maxx ? a : maxx;
}
fprintf(stderr, "maxx = %d\n", maxx);
return 0;
}
krecv method that is used in subscriber:
inline bool krecv (message_t *msg_, int flags_ = 0) {
int nbytes = zmq_msg_recv (&(msg_->msg), ptr, flags_);
if (nbytes >= 0)
return true;
if (zmq_errno () == EAGAIN)
return false;
return false;
}
I tried changing the bind statement in publisher to following:
publisher.bind("epgm://10.1.1.8:5000");
publisher.bind("epgm://224.1.1.1:5000");
publisher.bind("epgm://eth0;224.1.1.1:5000");
publisher.bind("epgm://10.1.1.8;224.1.1.1:5000");
publisher.bind("epgm://localhost:5000");
For all 5 cases, the program crashes with Assertion failed: false (src/pgm_socket.cpp:165). For the 5th case (epgm://localhost:5000), I also receive following warnings along with the crash:
Warn: Interface lo reports as a loopback device.
Warn: Interface lo reports as a non-multicast capable device.
How can I resolve this issue? I am guessing that the address change will be same in both publisher and subscriber?
I am using libpgm 5.2.122 with zeromq-4.1.3.
Note that the machine has following interfaces:
eth0 (Ethernet) -- inet addr:10.1.1.8
ib0 (InfiniBand) -- inet addr:10.1.3.8
lo (Local Loopback) -- inet addr:127.0.0.1

Try a 239.0.0.0/8 IP in your bind:
publisher.bind("epgm://;239.0.0.1:5000");
Wikipedia:
The 239.0.0.0/8 range is assigned by RFC 2365 for private use within an organization. From the RFC, packets destined to administratively scoped IPv4 multicast addresses do not cross administratively defined organizational boundaries, and administratively scoped IPv4 multicast addresses are locally assigned and do not have to be globally unique.

I have used epgm with zeromq on linux and it's tricky to configure correctly
Assuming you are using linux the read below, if not I have no experience with windows so disregard:
epgm does not work with the loopback adapter on linux so forget that.
Your eth0 should work. Is MCAST definitely enabled (check ifconfg)?
Port usage, is the port already in use?
I link zeromq with openpgm and there are some rather special differences in the way port reuse works between different linux kernels.
I added some code to the openpgm repo to fix my issues with rhel7
https://github.com/steve-o/openpgm/pull/52
James

Related

How do I handle socket requests in separate threads, thread seems to be blocking main process

I am trying to create a simple HTTP server in C++. I want each request to be handled simultaneously in separate threads, but when I create a thread and put a simple sleep(10) at the start to cause some delay, another request to the server cannot be made until the first thread finishes. What am I doing wrong?
Here is my code so far:
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string>
#include <ostream>
#include <iostream>
#include <thread>
using namespace std;
void send_response (int socket)
{
sleep (10);
char buffer[2048] = {0};
int request = recv (socket, buffer, 2048, 0);
if (request == -1) {
perror ("error");
}
string message = "Hello from server";
string length = to_string (message.length ());
string hello = "HTTP/1.1 200 OK\nContent-Type: text/plain\nContent-Length: " + length + "\n\n" + message;
send (socket, hello.c_str (), hello.length (), 0);
close (socket);
}
int main(int argc, char const *argv[])
{
struct sockaddr_in address;
int opt = 1;
socklen_t addrlen = sizeof (address);
int server_fd = socket (AF_INET, SOCK_STREAM, 0);
if (server_fd == 0) {
perror ("socket failed");
exit (EXIT_FAILURE);
}
if (setsockopt (server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof (opt))) {
perror ("setsockopt");
exit (EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons (8080);
if (bind (server_fd, (struct sockaddr *)(&address), sizeof (address)) < 0) {
perror ("bind failed");
exit (EXIT_FAILURE);
}
if (listen (server_fd, 3) < 0) {
perror ("listen");
exit (EXIT_FAILURE);
}
while (true) {
int new_socket = accept (server_fd, (struct sockaddr *)(&address), &addrlen);
if (new_socket < 0) {
perror ("accept");
exit (EXIT_FAILURE);
}
thread response (&send_response, new_socket);
response.detach ();
cout << "request handled" << endl;
}
return 0;
}
I don't need to wait for the thread to finish or get any data back from the thread, I just want it to start, do some work, and send something back to the client. I expect each thread will be doing a decent amount of work, that's why I used sleep.
Edit: It seems the loop is ready and waiting for a second connection and will successfully accept a new connection and create a new thread to handle it, but only if the second connection is from a different IP address. So if I visit the server at 127.0.0.1:8080 and from a different local IP address like 192.168.1.91, both connections will go through with two threads running simultaneously. However, if I simply open two tabs, both at 127.0.0.1:8080, only one connection will be accepted at a time, the other will stall. It seems I need the code to handle multiple connections from the same IP address, but a search for that kind of problem on Google hasn't given me any good results.
Ok, my bad, everything is working as expected. Using wget to send multiple requests from the same IP causes multiple threads to be created and for the requests to be processed simultaneously. In Chrome, for some reason opening multiple tabs from the same IP causes them to be sent in serial, but in Firefox they are sent in parallel and arrive and are processed at the same time. That is weird, but I'll chock it up to an oddity of Chrome.

ZMQ_HEARTBEAT_TTL does not discard outgoing queue even if ZMQ_LINGER is set

I have a server which uses a ZMQ_ROUTER to communicate with ZMQ_DEALER clients. I set the ZMQ_HEARTBEAT_IVL and ZMQ_HEARTBEAT_TTL options on the client socket to make the client and server ping pong each other. Beside, because of the ZMQ_HEARTBEAT_TTL option, the server will timeout the connection if it does not receive any pings from the client in a time period, according to zmq man page:
The ZMQ_HEARTBEAT_TTL option shall set the timeout on the remote peer for ZMTP heartbeats. If
this option is greater than 0, the remote side shall time out the connection if it does not
receive any more traffic within the TTL period. This option does not have any effect if
ZMQ_HEARTBEAT_IVL is not set or is 0. Internally, this value is rounded down to the nearest
decisecond, any value less than 100 will have no effect.
Therefore, what I expect the server to behave is that, when it does not receive any traffic from a client in a time period, it will close the connection to that client and discard all the messages in the outgoing queue after the linger time expires. I create a toy example to check if my hypothesis is correct and it turns out that it is not. The chain of events is as followed:
The server sends a bunch of data to the client.
The client receives and processes the data, which is slow.
All send commands return successfully.
While the client is still receiving the data, I unplug the internet cable.
After a few seconds (set by the ZMQ_HEARTBEAT_TTL option), the server starts sending FIN signals to the client, which are not being ACKed back.
The outgoing messages are not discarded (I check the memory consumption) even after a while. They are discarded only if I call zmq_close on the router socket.
So my question is, is this suppose to be how one should use the ZMQ heartbeat mechanism? If it is not then is there any solution for what I want to achieve? I figure that I can do heartbeat myself instead of using ZMQ's built in. However, even if I do, it seems that ZMQ does not provide a way to close a connection between a ZMQ_ROUTER and a ZMQ_DEALER, although that another version of ZMQ_ROUTER - ZMQ_STREAM provides a way to do this by sending an identity frame followed by an empty frame.
The toy example is below, any help would be thankful.
Server's side:
#include <zmq.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char **argv)
{
void *context = zmq_ctx_new();
void *router = zmq_socket(context, ZMQ_ROUTER);
int router_mandatory = 1;
zmq_setsockopt(router, ZMQ_ROUTER_MANDATORY, &router_mandatory, sizeof(router_mandatory));
int hwm = 0;
zmq_setsockopt(router, ZMQ_SNDHWM, &hwm, sizeof(hwm));
int linger = 3000;
zmq_setsockopt(router, ZMQ_LINGER, &linger, sizeof(linger));
char bind_addr[1024];
sprintf(bind_addr, "tcp://%s:%s", argv[1], argv[2]);
if (zmq_bind(router, bind_addr) == -1) {
perror("ERROR");
exit(1);
}
// Receive client identity (only 1)
zmq_msg_t identity;
zmq_msg_init(&identity);
zmq_msg_recv(&identity, router, 0);
zmq_msg_t dump;
zmq_msg_init(&dump);
zmq_msg_recv(&dump, router, 0);
printf("%s\n", (char *) zmq_msg_data(&dump)); // hello
zmq_msg_close(&dump);
char buff[1 << 16];
for (int i = 0; i < 50000; ++i) {
if (zmq_send(router, zmq_msg_data(&identity),
zmq_msg_size(&identity),
ZMQ_SNDMORE) == -1) {
perror("ERROR");
exit(1);
}
if (zmq_send(router, buff, 1 << 16, 0) == -1) {
perror("ERROR");
exit(1);
}
}
printf("OK IM DONE SENDING\n");
// All send commands have returned successfully
// While the client is still receiving data, I unplug the intenet cable on the client machine
// After a while, the server starts sending FIN signals
printf("SLEEP before closing\n"); // At this point, the messages are not discarded (memory usage is high).
getchar();
zmq_close(router);
zmq_ctx_destroy(context);
}
Client's side:
#include <zmq.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv)
{
void *context = zmq_ctx_new();
void *dealer = zmq_socket(context, ZMQ_DEALER);
int heartbeat_ivl = 3000;
int heartbeat_timeout = 6000;
zmq_setsockopt(dealer, ZMQ_HEARTBEAT_IVL, &heartbeat_ivl, sizeof(heartbeat_ivl));
zmq_setsockopt(dealer, ZMQ_HEARTBEAT_TIMEOUT, &heartbeat_timeout, sizeof(heartbeat_timeout));
zmq_setsockopt(dealer, ZMQ_HEARTBEAT_TTL, &heartbeat_timeout, sizeof(heartbeat_timeout));
int hwm = 0;
zmq_setsockopt(dealer, ZMQ_RCVHWM, &hwm, sizeof(hwm));
char connect_addr[1024];
sprintf(connect_addr, "tcp://%s:%s", argv[1], argv[2]);
zmq_connect(dealer, connect_addr);
zmq_send(dealer, "hello", 6, 0);
size_t size = 0;
int i = 0;
while (size < (1ll << 16) * 50000) {
zmq_msg_t msg;
zmq_msg_init(&msg);
if (zmq_msg_recv(&msg, dealer, 0) == -1) {
perror("ERROR");
exit(1);
}
size += zmq_msg_size(&msg);
printf("i = %d, size = %ld, total = %ld\n", i, zmq_msg_size(&msg), size); // This causes the cliet to be slow
// Somewhere in this loop I unplug the internet cable.
// The client starts sending FIN signals as well as trying to reconnect. The recv command hangs forever.
zmq_msg_close(&msg);
++i;
}
zmq_close(dealer);
zmq_ctx_destroy(context);
}
PS: I know that setting the highwater mark to unlimited is bad practice, however I figure that the problem will be the same even if the highwater mark is low so let's ignore it for now.

recvfrom works with INADDR_ANY, but specifying certain interface doesn't work

I wrote a program that join source specific multicast group and receive udp multicast packets:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <net/if.h>
typedef unsigned int UINT32;
int join_ssm_group(int s, UINT32 group, UINT32 source, UINT32 inter) {
struct ip_mreq_source imr;
imr.imr_multiaddr.s_addr = group;
imr.imr_sourceaddr.s_addr = source;
imr.imr_interface.s_addr = inter;
return setsockopt(s, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP, (char *) &imr, sizeof(imr));
}
UINT32 LISTEN_INTERFACE = inet_addr("10.10.1.2");
int main(int argc, char *argv[]) {
if (argc<3) {
printf(" Use: %s <group> <source> <port>", argv[0]);
return 1;
}
// Make socket
int sd = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
struct sockaddr_in Sender;
socklen_t SenderAddrSize = sizeof( Sender );
struct sockaddr_in binda;
// Bind it to listen appropriate UDP port
binda.sin_family = AF_INET;
binda.sin_port = htons( atoi(argv[3]));
= INADDR_ANY;
// binda.sin_addr.s_addr = LISTEN_INTERFACE;
bind(sd,(struct sockaddr*)&binda, sizeof(binda));
// Join to group
join_ssm_group( sd, inet_addr(argv[1]),
inet_addr(argv[2]),
INADDR_ANY );
char buf[65536];
UINT32 seq;
while(1) {
printf("try receive\n");
int res=recvfrom(sd,(char*)buf,sizeof(buf),0, (struct sockaddr *)& Sender, &SenderAddrSize);
printf("received\n");
seq = *(UINT32*)buf;
printf("scr=:%12s;\tseq=%6d;\tlen=%4d\n", inet_ntoa(Sender.sin_addr), seq, res);
}
return 0;
}
It works fine but note that I'm using binda.sin_addr.s_addr = INADDR_ANY;. netstat shows this:
netstat -a | grep 16002
udp 0 0 0.0.0.0:16002 0.0.0.0:*
When I change it to binda.sin_addr.s_addr = LISTEN_INTERFACE; program stops working - it can not recieve packets, it hangs in recvfrom. netstat shows this:
netstat -a | grep 16002
udp 0 0 localhost.localdo:16002 0.0.0.0:*
In both cases tcpdump shows that data is online, so the problem is that I can not receive data on the specific interface, only on ALL interfaces. I'm using RHEL 7, teaming, and LISTEN_INTERFACE is the IP of the corresponding VLAN. Why my code doesn't work and how to troubleshoot it? I do not want to use INADDR_ANY for performance reasons - listening ALL interfaces would be more expensive than listeining certain interface.
upd passing LISTEN_INTERFACE to both join_ssm_group and and binda.sin_addr.s_addr doesn't work too. BTW similar Windows version of such code works on the same PC under Windows Server 2008 R2, but it doesn't work in RHEL 7. I guess I should check these:
if RHEL 7 receives data on the requreid interface on the required port (answer is Yes, proved by tcpdump)
if socket is listening on the required interface on the required port (answer is Yes, proved by netstat?)
if both answers above are Yes then how is it possible that call to recvfrom doesn't receive data?
Well probably this question more about RHEL 7 now, than about c++.
When you join the multicast group you need to specify the same interface that you are listening on, or join it via all interfaces in a loop.
However listening on all interfaces is the norm. It is not 'slow', and it is a 'good idea', unless you have a specific reason to restrict who can connect.

ZeroMQ is not working over unicast IPv6

I'm in a trouble with ZeroMQ and IPv6. When I use a connection through IPv4 or if I use "tcp://[::1]:5558", it connects like a charm. However, if I use the server full IPv6 address (on my local host or remote host) it connects, but don't get data on the other endpoint.
Here is my code sample:
client.cpp
#include <stdio.h>
#include <zmq.h>
int main(int argc, char** argv)
{
void* context = zmq_ctx_new();
void* socket = zmq_socket(context, ZMQ_SUB);
int ipv6 = 1;
zmq_setsockopt(socket, ZMQ_IPV6, &ipv6, 4);
zmq_connect(socket, "tcp://[fe80::52e5:49ff:fef8:dbc6]:5558");
//zmq_connect(socket, "tcp://[::1]:5558");
zmq_setsockopt(socket, ZMQ_SUBSCRIBE, "pub", 3);
zmq_msg_t message;
do {
zmq_msg_init (&message);
zmq_msg_recv (&message, socket, 0);
printf("%s\n", (char*)zmq_msg_data(&message));
zmq_msg_close(&message);
} while (zmq_msg_more(&message));
}
And server.cpp
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <zmq.h>
int main(int argc, char**argv)
{
void* context = zmq_ctx_new();
void* publisher = zmq_socket(context, ZMQ_PUB);
int ipv6 = 1;
zmq_setsockopt(publisher, ZMQ_IPV6, &ipv6, sizeof(int));
zmq_bind(publisher, "tcp://*:5558");
char buffer[4] = "pub";
unsigned tries = 0;
while(tries < 10) {
zmq_send(publisher, &buffer, strlen(buffer), 0);
tries++;
sleep(1);
}
return 0;
}
I'm using ZeroMQ 4.0.0 RC, but it is also happening on 3.2. I'm on linux (slackware) and installed it from sources. I also tested using a java server using jeroMQ and the problem is the same. I did another test using a REQ-REP connection and the problem is the same.
Thanks in advance for any help.
fe80* addresses are link local, you must specify the local hosts link name: e.g. fe80...:1%eth1
fe80::/10 — Addresses in the link-local prefix are only valid and
unique on a single link. Within this prefix only one subnet is
allocated (54 zero bits), yielding an effective format of fe80::/64.
The least significant 64 bits are usually chosen as the interface
hardware address constructed in modified EUI-64 format. A link-local
address is required on every IPv6-enabled interface—in other words,
applications may rely on the existence of a link-local address even
when there is no IPv6 routing. These addresses are comparable to the
auto-configuration addresses 169.254.0.0/16 of IPv4.
http://en.wikipedia.org/wiki/IPv6_address#Local_addresses

how to scan wireless network and display the list of all computers and devices connected

I need to build a tool (c++) very much like "Wireless Network Watcher" which is a small utility that scans your wireless network and displays the list of all computers and devices that are currently connected to your network.
here's the existing tool http://www.nirsoft.net/utils/wireless_network_watcher.html
I need to know what are the win32 sdk functions to use to build this kind of functionality: scan the wireless network I am connected to and display all computers and devices connected to it.
ok, it seems is done this way: first sent an ARP request packet to each possible IP address in the network (you calculate them based on the net mask and the interface ip), for this step you can use SendARP functions. Then you have to call getnameinfo for each IP that responded previously, or you can send an NetBios request packet (port 137) to retreive the name of the device, if it has one, or know how to respond to that request.
for some networks this can take awhile (very long time).
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <netinet/ip_icmp.h>
#include <time.h>
#include <fcntl.h>
#include <signal.h>
#include <time.h>
// Define the Packet Constants
// ping packet size
#define PING_PKT_S 64
// Automatic port number
#define PORT_NO 0
// Automatic port number
#define PING_SLEEP_RATE 1000000
// Gives the timeout delay for receiving packets
// in seconds
#define RECV_TIMEOUT 1
// Performs a DNS lookup
char* dns_lookup(char* addr_host, struct sockaddr_in* addr_con) {
// printf("\nResolving DNS..\n");
struct hostent* host_entity;
char* ip = (char*)malloc(NI_MAXHOST * sizeof(char));
int i;
if ((host_entity = gethostbyname(addr_host)) == NULL) {
// No ip found for hostname
return NULL;
}
// filling up address structure
strcpy(ip, inet_ntoa(*(struct in_addr*)host_entity->h_addr));
(*addr_con).sin_family = host_entity->h_addrtype;
(*addr_con).sin_port = htons(PORT_NO);
(*addr_con).sin_addr.s_addr = *(long*)host_entity->h_addr;
return ip;
}
// Resolves the reverse lookup of the hostname
char* reverse_dns_lookup(char* ip_addr) {
struct sockaddr_in temp_addr;
socklen_t len;
char buf[NI_MAXHOST], *ret_buf;
temp_addr.sin_family = AF_INET;
temp_addr.sin_addr.s_addr = inet_addr(ip_addr);
len = sizeof(struct sockaddr_in);
if (getnameinfo((struct sockaddr*)&temp_addr, len, buf, sizeof(buf), NULL, 0,
NI_NAMEREQD)) {
// printf("Could not resolve reverse lookup of hostname\n");
return NULL;
}
ret_buf = (char*)malloc((strlen(buf) + 1) * sizeof(char));
strcpy(ret_buf, buf);
return ret_buf;
}
// Driver Code
int main(int argc, char* argv[]) {
int sockfd;
char *ip_addr, *reverse_hostname;
struct sockaddr_in addr_con;
int addrlen = sizeof(addr_con);
char net_buf[NI_MAXHOST];
int i = 0;
for (int i = 1; i < 255; ++i) {
char ip[80];
sprintf(ip, "192.168.2.%d", i);
ip_addr = dns_lookup(ip, &addr_con);
if (ip_addr == NULL) {
// printf("\nDNS lookup failed! Could not resolve hostname!\n");
continue;
}
reverse_hostname = reverse_dns_lookup(ip_addr);
if (reverse_hostname == NULL) {
// printf("\nDNS lookup failed! Could not resolve hostname!\n");
continue;
}
// printf("\nTrying to connect to '%s' IP: %s\n",ip, ip_addr);
printf("\nReverse Lookup domain: %s", reverse_hostname);
printf("\n %s \n", ip);
}
return 0;
}
result:
Reverse Lookup domain: router.asus.com
192.168.2.1
Reverse Lookup domain: DESKTOP-CMK0J2S
192.168.2.10
Reverse Lookup domain: User255
192.168.2.14
Very vague question, there is no single "find all devices" feature to Windows, wireless or even networking in general. You need to scan fer certain services like netbios (139), UPNP, etc. Also, none of this is specific to wireless conenctions.