Page 1 of 1

E1.31 Multicast - receive on transmitting host

Posted: Sat Aug 03, 2019 4:08 pm
by labrat
Good afternoon,

I'm looking for some help to try and run an e1.31 receiving process on the same box as the QLC+ application.

I am trying to integrate a custom USB device (DMX output) into a QLC+ installation. Options are to write a custom plugin, or to try and use an existing application that can receive E1.31 and talk to the USB device to create an E1.31 to DMX bridge. I am running QLC+ version 4.12.2 GIT atop of an UBUNTU 16.04 stock image, configuring the first Universe to output E1.31 as a MULTICAST target. On the same host that is running QLC+, I am trying to also run the multicast receiver, that would then convert the output to data sent to the USB device.

The problem:
If I run this application on a second device on the network, everything works fine. If I run this application on the same host as the QLC+ instance, the packets are never seen by the application. Executing tcpdump -i eth0 port 5568 sees the outgoing packets from QLC+ as expected.

I have tried updating the QAbstractSocket::MulticastLoopbackOption to 'true' in plugins/E1.31/e131controller.cpp, but still I am unable to receive the udp packets in my demo sniffer application.

Any pointers/assistance greatly appreciated..

LabRat
---
Sample code for the Multicast listener...

Code: Select all

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>  // memset
#include <strings.h>
#include "sacn.h"
#include <unistd.h> // sleep/usleep
// Retrieve MAC address
#include <sys/ioctl.h>
#include <linux/if.h>

#define EXAMPLE_PORT 5568
#define EXAMPLE_GROUP "239.255.0.1"

void sacn_dump ( tSACN_PACKET *buf ) {
   int i;
 // ROOT
   printf("ROOT\n");
   printf("\tpreamble_size:\t0x%4.4x\n",ntohs(buf->preamble_size));
   printf("\tpostable_size:\t0x%4.4x\n",ntohs(buf->postamble_size));
   printf("\tacn_id:\t\t%s\n",buf->acn_id);
   printf("\tflag_n_length:\t0x%2.2x [%d]\n",ntohs(buf->root_flag_n_length), (uint16_t)(ntohs(buf->root_flag_n_length))&0x0FFF);
   printf("\troot_vector:\t%8.8x\n",ntohs(buf->root_vector));
   // pulling the MAC address to populate the CID field
   printf("\tcid:\t\t");
     for (i=0;i<16;i++) { printf("%2.2x",buf->cid[i]); }
     printf("\n");

 // FRAME
   printf("FRAME\n");
   printf("\tflag_n_length:\t0x%2.2x [%d]\n",ntohs(buf->frame_flag_n_length), ntohs(buf->frame_flag_n_length) & 0x0FFF);
   printf("\tframe_vector:\t0x%8.8x\n",ntohl(buf->frame_vector));
   printf("\tsource_name:\t%s\n",buf->source_name);
   printf("\tpriority:\t0x%2.2x\n",buf->priority);
   printf("\treserved:\t0x%4.4x\n",buf->reserved);
   printf("\tsequence:\t0x%2.2x\n",buf->sequence);
   printf("\toptions:\t0x%2.2x\n",buf->options);
   printf("\tuniverse:\t0x%2.2x\n",ntohs(buf->universe));
// DMP
   printf("DMP\n");
   printf("\tflag_n_length:\t0x%2.2x [%d]\n",ntohs(buf->dmp_flag_n_length), ntohs(buf->dmp_flag_n_length)& 0x0FFF);
   printf("\tdmp_vector:\t\t0x%2.2x\n",buf->dmp_vector);
   printf("\taddress_type:\t\t0x%2.2x\n",buf->address_type);
   printf("\tfirst_property_addr:\t0x%4.4x\n",ntohs(buf->first_property_addr));
   printf("\taddress_increment:\t0x%4.4x\n",ntohs(buf->address_increment));
   printf("\tproperty_value_count:\t0x%4.4x\n",ntohs(buf->property_value_count));
   printf("\tproperty_start:\t\t0x%2.2x",buf->property_start);
   printf("\tproperty_values\t\t");
   {
       for (i=0; i<9; i++) {
           printf("%2.2x ",buf->property_values[i]);
       }
       printf("\n");
    }
  if (buf->property_start != 00) exit(0);
}

int main(int argc)
{
   struct sockaddr_in addr;
   int addrlen, sock, cnt;
   struct ip_mreq mreq;
   char message[50];
   tSACN_PACKET sacn_buffer;

   /* set up socket */
   sock = socket(AF_INET, SOCK_DGRAM, 0);
   if (sock < 0) {
     perror("socket");
     exit(1);
   }
   bzero((char *)&addr, sizeof(addr));
   addr.sin_family = AF_INET;
   addr.sin_addr.s_addr = htonl(INADDR_ANY);
   addr.sin_port = htons(EXAMPLE_PORT);
   addrlen = sizeof(addr);

      { // Allow for re-use
         int trueValue = 1;
         setsockopt(sock, SOL_SOCKET, SO_REUSEADDR|SO_REUSEPORT, &trueValue, sizeof(trueValue));
      }
      /* receive */
      if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
         perror("bind");
         exit(1);
      }
      mreq.imr_multiaddr.s_addr = inet_addr(EXAMPLE_GROUP);
      mreq.imr_interface.s_addr = htonl(INADDR_ANY);      if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
                     &mreq, sizeof(mreq)) < 0) {
         perror("setsockopt mreq");
         exit(1);
      }

      while (1) {
         cnt = recvfrom(sock, &sacn_buffer, sizeof(sacn_buffer), 0,
                        (struct sockaddr *) &addr, &addrlen);
         if (cnt < 0) {
            perror("recvfrom");
            exit(1);
         } else if (cnt == 0) {
            break;
         }
         printf("%s: %d bytes\n", inet_ntoa(addr.sin_addr),cnt);
         sacn_dump(&sacn_buffer);
      }
}