How to get the global variable address of the executable program through pin and libelf.h - global-variables

I want to develop a pintool to find out the address of global variable of my C program.Suppose I have a C program in which I had some Global pointer variables. When I run the same program with pintool then I wish to find the address of those global variable through pintool.
I am trying to get the address of a global variable via pin,but we
all know that Pin doesn't seem to provide such a funcionality. As per the documentation: "Symbol objects only provide information about the function symbols in the application. Information about other types of symbols (e.g. data symbols), must be obtained independently by the tool,libelf.h seems can get the address of global variable,please help me and suggest me how can I be able to do this?

I would have liked to do just a comment but it's a bit too long...
Per definition global variables resides in the executable (more precisely in the .data or .bss section depending if they are initialized or not). The other variables are allocated (either on stack or heap).
You don't even need symbols to check if a variable (given its address) is in one of the executable sections or not: use the image instrumentation functions (IMG_xxx), loop around the sections (SEC_xxx) get the base and end of the sections, check which one it is (.data or the .bss). You can get the type of the section with PIN using SEC_Type; once you have an address, if it lies inside .bss or .data, then you have a global variable.
Now, if you want the name of the variable that lies at a given address, it's more complicated and as the PIN documentation states, you'll need symbolic information. I don't know if libelf can do that easily, but libdwarf can. You can also check at the llvm-dwarfdump code which is open source and able to do that also.
note: I did the experimentation on Windows (.data section) but the output should be somewhat similar on Linux.
Here's a small dummy example with one known global variable; compiled without optimization:
#include <iostream>
int global_counter; // global
void count(const int i)
{
int local_counter = 0; // local
for(int j = 0; j < i; j++)
{
global_counter += 1;
if(j % 2 == 0) {
local_counter += 1;
}
}
std::cout << "local counter: " << local_counter << std::endl;
}
int main(int argc, char** argv)
{
if(argc < 2) {
return -1;
}
const auto i = std::atoi(argv[1]);
if (i >= 0) {
count(i);
std::cout << "global counter: " << global_counter << std::endl;
}
return 0;
}
Here's the disassembly of the part the count function where the global variable is used:
00007FF7077B10BE | 8B | mov eax,dword ptr ds:[<global_counter>] | PinTestSimpleTarget.cpp:14
00007FF7077B10C4 | FF | inc eax |
00007FF7077B10C6 | 89 | mov dword ptr ds:[<global_counter>],eax |
00007FF7077B10CC | 8B | mov eax,dword ptr ss:[rsp+20] | PinTestSimpleTarget.cpp:15
00007FF7077B10D0 | 99 | cdq |
00007FF7077B10D1 | 83 | and eax,1 |
00007FF7077B10D4 | 33 | xor eax,edx |
00007FF7077B10D6 | 2B | sub eax,edx |
00007FF7077B10D8 | 85 | test eax,eax |
00007FF7077B10DA | 75 | jne pintestsimpletarget.7FF7077B10E6 |
Disassembly of the std::cout on the global variable:
00007FF7077B117A | 8B | mov edx,dword ptr ds:[<global_counter>] |
00007FF7077B1180 | 48 | mov rcx,rax | rax:$LN23
00007FF7077B1183 | FF | call qword ptr ds:[<&??6?$basic_ostream#DU?$char_traits#D#std |
Notice the 3 addresses:
00007FF7077B10BE (read)
00007FF7077B10C6 (write)
00007FF7077B117A (std::cout)
The global variable itself is at:
00007FF7077B5628
Here's the pintool source (note: for an unknown reason I couldn't get the CRT to correctly initialize when using std::cout so I resorted to use printf instead).
#include "pin.H"
typedef struct _BOUNDARIES
{
ADDRINT lowest_address;
ADDRINT highest_address;
std::string to_str() const
{
std::stringstream stream;
stream << "Low Addr: " << std::hex << lowest_address <<
"; High Addr: " << highest_address;
return std::string(stream.str());
}
bool is_in_bounds(const ADDRINT addr) const
{
return addr >= lowest_address && addr < highest_address;
}
} BOUNDARIES;
/* ================================================================== */
// Global variables
/* ================================================================== */
BOUNDARIES main_executable_boundaries;
BOUNDARIES data_section_boundaries;
/* ===================================================================== */
// Utilities
/* ===================================================================== */
/*!
* Print out help message.
*/
INT32 Usage()
{
//std::cout << "[PINTOOL] This tool display the addresses of global variables in the .data section " << std::endl;
printf("[PINTOOL] This tool display the addresses of global variables in the .data section\n");
return -1;
}
/* ===================================================================== */
// Analysis routines
/* ===================================================================== */
// analysis for memory read
VOID record_mem_read(ADDRINT ip, ADDRINT addr)
{
if(data_section_boundaries.is_in_bounds(addr))
{
printf("[PINTOOL] Read on a global variable (.data); Instruction addr: %p; Read addr: %p\n", ip, addr);
}
}
// analysis for memory write
VOID record_mem_write(VOID* ip, ADDRINT addr)
{
if (data_section_boundaries.is_in_bounds(addr))
{
printf("[PINTOOL] Write on a global variable (.data); Instruction addr: %p; Write addr: %p\n", ip, addr);
}
}
/* ===================================================================== */
// Instrumentation callbacks
/* ===================================================================== */
VOID instrument_instruction(INS ins, VOID *v)
{
// must be valid and within bounds of the main executable.
if(!INS_Valid(ins) || !main_executable_boundaries.is_in_bounds(INS_Address(ins))) {
return;
}
const UINT32 mem_operands = INS_MemoryOperandCount(ins);
// Iterate over each memory operand of the instruction.
for (UINT32 memOp = 0; memOp < mem_operands; memOp++)
{
if (INS_MemoryOperandIsRead(ins, memOp))
{
INS_InsertPredicatedCall(
ins, IPOINT_BEFORE, reinterpret_cast<AFUNPTR>(record_mem_read),
IARG_INST_PTR,
IARG_MEMORYOP_EA, memOp,
IARG_END);
}
if (INS_MemoryOperandIsWritten(ins, memOp))
{
INS_InsertPredicatedCall(
ins, IPOINT_BEFORE, reinterpret_cast<AFUNPTR>(record_mem_write),
IARG_INST_PTR,
IARG_MEMORYOP_EA, memOp,
IARG_END);
}
}
}
VOID image_load(IMG img, VOID* v)
{
printf("[PINTOOL] Loading image: %s; Image ID: %i\n",IMG_Name(img).c_str(), IMG_Id(img));
if(IMG_IsMainExecutable(img)) {
// register lowest and highest addresses to restrict the trace between those addresses.
main_executable_boundaries.lowest_address = IMG_LowAddress(img);
main_executable_boundaries.highest_address = IMG_HighAddress(img);
printf("Main executable boundaries: %s\n", main_executable_boundaries.to_str().c_str());
// cycle through all sections of the main executable.
for (SEC sec = IMG_SecHead(img); SEC_Valid(sec); sec = SEC_Next(sec))
{
// get boundaries of the '.data' section
if(SEC_Name(sec) == ".data") {
const auto sec_address = SEC_Address(sec);
data_section_boundaries.lowest_address = sec_address;
data_section_boundaries.highest_address = sec_address + SEC_Size(sec);
printf("Data section boundaries: %s\n", data_section_boundaries.to_str().c_str());
}
}
}
}
VOID image_unload(IMG img, VOID* v)
{
printf("[PINTOOL] Unloading image: %s\n", IMG_Name(img).c_str());
}
VOID fini(INT32 code, VOID *v)
{
printf("[PINTOOL] Instrumentation tear down.\n");
}
/* ===================================================================== */
// Main
/* ===================================================================== */
int main(int argc, char *argv[])
{
//std::cerr << "[PINTOOL] Loading." << std::endl;
// Initialize PIN library. Print help message if -h(elp) is specified
// in the command line or the command line is invalid
if( PIN_Init(argc,argv) )
{
return Usage();
}
// Register Instruction to be called to instrument instructions
INS_AddInstrumentFunction(instrument_instruction, nullptr);
// Register ImageLoad to be called when an image is loaded
IMG_AddInstrumentFunction(image_load, nullptr);
// Register ImageUnload to be called when an image is unloaded
IMG_AddUnloadFunction(image_unload, nullptr);
// Register function to be called when the application exits
PIN_AddFiniFunction(fini, nullptr);
//std::cerr << "[PINTOOL] Starting instrumentation." << std::endl;
// Start the program, never returns
PIN_StartProgram();
return 0;
}
.\pin.exe -t MyPinTool.dll -- PinTestSimpleTarget.exe 6
output:
[PINTOOL] Loading image: G:\Appdata\CPP\PinTestSimpleTarget\x64\Release\PinTestSimpleTarget.exe; Image ID: 1
Main executable boundaries: Low Addr: 7ff7077b0000; High Addr: 7ff7077b8fff
Data section boundaries: Low Addr: 7ff7077b5000; High Addr: 7ff7077b5640
[PINTOOL] Loading image: C:\WINDOWS\System32\KERNELBASE.dll; Image ID: 2
[PINTOOL] Loading image: C:\WINDOWS\System32\KERNEL32.DLL; Image ID: 3
[PINTOOL] Loading image: C:\WINDOWS\SYSTEM32\ntdll.dll; Image ID: 4
[PINTOOL] Loading image: C:\WINDOWS\System32\ucrtbase.dll; Image ID: 5
[PINTOOL] Loading image: C:\WINDOWS\SYSTEM32\VCRUNTIME140.dll; Image ID: 6
[PINTOOL] Loading image: C:\WINDOWS\SYSTEM32\MSVCP140.dll; Image ID: 7
[PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b1ed1; Read addr: 0x7ff7077b5008
[PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b1f63; Write addr: 0x7ff7077b5000
[PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b1cb6; Read addr: 0x7ff7077b55c0
[PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b1cc7; Write addr: 0x7ff7077b55c0
[PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b2265; Write addr: 0x7ff7077b501c
[PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b2271; Write addr: 0x7ff7077b5018
[PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b22c0; Read addr: 0x7ff7077b5020
[PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b22c0; Write addr: 0x7ff7077b5020
[PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b2310; Read addr: 0x7ff7077b5624
[PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b233f; Write addr: 0x7ff7077b5624
[PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b234d; Write addr: 0x7ff7077b5018
[PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b2357; Write addr: 0x7ff7077b501c
[PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b238b; Read addr: 0x7ff7077b501c
[PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b2394; Write addr: 0x7ff7077b5018
[PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b239e; Write addr: 0x7ff7077b501c
[PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b23ad; Write addr: 0x7ff7077b5018
[PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b23b7; Write addr: 0x7ff7077b501c
[PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b23d2; Read addr: 0x7ff7077b5030
[PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b1c97; Read addr: 0x7ff7077b55b8
[PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b1c97; Write addr: 0x7ff7077b55b8
[PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b1998; Read addr: 0x7ff7077b55b0
[PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b19ab; Write addr: 0x7ff7077b55b0
[PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b1d02; Read addr: 0x7ff7077b55c1
[PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b23d2; Read addr: 0x7ff7077b5030
[PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b1d4f; Write addr: 0x7ff7077b55c8
[PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b1d57; Write addr: 0x7ff7077b55d8
[PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b1d5e; Write addr: 0x7ff7077b55e0
[PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b1d66; Write addr: 0x7ff7077b55f0
[PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b1d6d; Write addr: 0x7ff7077b55c1
[PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b1e76; Read addr: 0x7ff7077b55c8
[PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b1fca; Read addr: 0x7ff7077b5014
[PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b1fb5; Read addr: 0x7ff7077b5610
[PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b1fb5; Write addr: 0x7ff7077b5610
[PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b1fbe; Read addr: 0x7ff7077b5618
[PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b1fbe; Write addr: 0x7ff7077b5618
[PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b19e9; Write addr: 0x7ff7077b55b0
[PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b23d2; Read addr: 0x7ff7077b5030
[PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b1e37; Read addr: 0x7ff7077b55b8
[PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b1e37; Write addr: 0x7ff7077b55b8
[PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b1a0c; Read addr: 0x7ff7077b5638
[PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b1a38; Read addr: 0x7ff7077b5630
[PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b10be; Read addr: 0x7ff7077b5628
[PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b10c6; Write addr: 0x7ff7077b5628
[PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b10be; Read addr: 0x7ff7077b5628
[PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b10c6; Write addr: 0x7ff7077b5628
[PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b10be; Read addr: 0x7ff7077b5628
[PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b10c6; Write addr: 0x7ff7077b5628
[PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b10be; Read addr: 0x7ff7077b5628
[PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b10c6; Write addr: 0x7ff7077b5628
[PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b10be; Read addr: 0x7ff7077b5628
[PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b10c6; Write addr: 0x7ff7077b5628
[PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b10be; Read addr: 0x7ff7077b5628
[PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b10c6; Write addr: 0x7ff7077b5628
[PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b143d; Read addr: 0x7ff7077b5008
[PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b1860; Read addr: 0x7ff7077b5008
local counter: 3
[PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b143d; Read addr: 0x7ff7077b5008
global counter: [PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b1860; Read addr: 0x7ff7077b5008
[PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b117a; Read addr: 0x7ff7077b5628
6
[PINTOOL] Loading image: C:\WINDOWS\System32\kernel.appcore.dll; Image ID: 8
[PINTOOL] Loading image: C:\WINDOWS\System32\msvcrt.dll; Image ID: 9
[PINTOOL] Loading image: C:\WINDOWS\System32\RPCRT4.dll; Image ID: 10
[PINTOOL] Unloading image: G:\Appdata\CPP\PinTestSimpleTarget\x64\Release\PinTestSimpleTarget.exe
[PINTOOL] Unloading image: C:\WINDOWS\System32\KERNELBASE.dll
[PINTOOL] Unloading image: C:\WINDOWS\System32\KERNEL32.DLL
[PINTOOL] Unloading image: C:\WINDOWS\SYSTEM32\ntdll.dll
[PINTOOL] Unloading image: C:\WINDOWS\System32\ucrtbase.dll
[PINTOOL] Unloading image: C:\WINDOWS\SYSTEM32\VCRUNTIME140.dll
[PINTOOL] Unloading image: C:\WINDOWS\SYSTEM32\MSVCP140.dll
[PINTOOL] Unloading image: C:\WINDOWS\System32\kernel.appcore.dll
[PINTOOL] Unloading image: C:\WINDOWS\System32\msvcrt.dll
[PINTOOL] Unloading image: C:\WINDOWS\System32\RPCRT4.dll
[PINTOOL] Instrumentation tear down.
Obviously there are some other global variables used internally by the program which are displayed; but at least it should give you a good idea on how to track global variables in your program.

Related

Unable to connect to Thingsboard running on localhost server using mosquitto/mqtt

I am unable to connect to thingsboard running on localhost through MQTT. My arduino code worked well with Thingsboard's demo server. It connected succesfully and was able to see values under Latest Telemetry. While running locally, I am getting
"Connecting to ThingsBoard node ...[FAILED] [ rc = -2 : retrying in 5 seconds]"
error in arduino serial monitor.
I have installed tb-gateway and mosquitto broker. Following are the changes done:
tb-gateway.yml
path: storage
bufferSize: 1000
connection:
host: "127.0.0.1"
port: 1882
retryInterval: 3000
mqtt-config.json
{
"host": "127.0.0.1",
"port": 1883,
"ssl": false,
"retryInterval": 3000,
}
thingsboard.yml
mqtt:
# Enable/disable mqtt transport protocol.
enabled: "${MQTT_ENABLED:true}"
bind_address: "${MQTT_BIND_ADDRESS:0.0.0.0}"
bind_port: "${MQTT_BIND_PORT:1882}"
timeout: "${MQTT_TIMEOUT:10000}"
netty:
Here is my arduino code :
#include <Wire.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
#include <WiFi.h>
#include <WiFiClient.h>
// MPU6050 Slave Device Address
const uint8_t MPU6050SlaveAddress = 0x68;
// Select SDA and SCL pins for I2C communication
const uint8_t scl = 22;
const uint8_t sda = 21;
#define TOKEN "oPfC3R8p3LLKJ4lBU9u2"
#define WIFI_AP ""
#define WIFI_PASSWORD ""
char thingsboardServer[] = "127.0.0.1";
unsigned long lastSend;
int status = WL_IDLE_STATUS;
WiFiClient wifiClient;
PubSubClient client(wifiClient);
// sensitivity scale factor respective to full scale setting provided in
datasheet
const uint16_t AccelScaleFactor = 16384;
const uint16_t GyroScaleFactor = 131;
int16_t AccelX, AccelY, AccelZ, Temperature;
void setup() {
Serial.begin(115200);
InitWiFi();
client.setServer( thingsboardServer, 1883 );
Wire.begin(sda, scl);
MPU6050_Init();
lastSend = 0;
}
void loop() {
if ( !client.connected() ) {
reconnect();
}
if ( millis() - lastSend > 1000 ) { // Update and send only after 1 seconds
getAndSendData();
lastSend = millis();
}
delay(10);
client.loop();
}
void getAndSendData(){
double Ax, Ay, Az, T, Gx, Gy, Gz;
Read_RawValue(MPU6050SlaveAddress, MPU6050_REGISTER_ACCEL_XOUT_H);
//divide each with their sensitivity scale factor
Ax = (double)AccelX/AccelScaleFactor;
Ay = (double)AccelY/AccelScaleFactor;
Az = (double)AccelZ/AccelScaleFactor;
T = (double)Temperature/340+36.53; //temperature formula
Serial.println("Collecting Data ");
Serial.print("Ax: "); Serial.print(Ax);
Serial.print(" Ay: "); Serial.print(Ay);
Serial.print(" Az: "); Serial.print(Az);
Serial.print(" T: "); Serial.print(T);
// Prepare a JSON payload string
String payload = "{";
payload += "\"Ax\":"; payload += String(Ax); payload += ",";
payload += "\"Ay\":"; payload += String(Ay); payload += ",";
payload += "\"Az\":"; payload += String(Az); payload += ",";
payload += "\"temperature\":"; payload += String(T);
payload += "}";
// Send payload
char attributes[100];
payload.toCharArray( attributes, 100 );
client.publish( "v1/devices/me/telemetry", attributes );
Serial.println( attributes );
Serial.println("%. Sent to Thingsboard.");
}
void I2C_Write(uint8_t deviceAddress, uint8_t regAddress, uint8_t data){
Wire.beginTransmission(deviceAddress);
Wire.write(regAddress);
Wire.write(data);
Wire.endTransmission();
}
// read all 14 register
void Read_RawValue(uint8_t deviceAddress, uint8_t regAddress){
Wire.beginTransmission(deviceAddress);
Wire.write(regAddress);
Wire.endTransmission();
Wire.requestFrom(deviceAddress, (uint8_t)14);
AccelX = (((int16_t)Wire.read()<<8) | Wire.read());
AccelY = (((int16_t)Wire.read()<<8) | Wire.read());
AccelZ = (((int16_t)Wire.read()<<8) | Wire.read());
Temperature = (((int16_t)Wire.read()<<8) | Wire.read());
}
//configure MPU6050
void MPU6050_Init(){
delay(150);
.......
}
void InitWiFi()
{
Serial.println("Connecting to AP ...");
WiFi.begin(WIFI_AP, WIFI_PASSWORD);
.......
}
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
status = WiFi.status();
if ( status != WL_CONNECTED) {
WiFi.begin(WIFI_AP, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("Connected to AP");
}
Serial.print("Connecting to ThingsBoard node ...");
// Attempt to connect (clientId, username, password)
if ( client.connect("fa5c6fe0-05cc-11e9-bfc6-27e4379bb947", TOKEN,
NULL,NULL,NULL,NULL,NULL,NULL) ) {
Serial.println( "[DONE]" );
} else {
Serial.print( "[FAILED] [ rc = " );
Serial.print( client.state() );
Serial.println( " : retrying in 5 seconds]" );
// Wait 5 seconds before retrying
delay( 5000 );
}
}
}
Please let me know in case I am missing any configuration or doing something wrong.
Your ESP8266 code has set the IP address thingsboardServer to 127.0.0.1 - that will never work for the ESP8266.
127.0.0.1 is a special IP address - it's localhost - it always refers to "self". Used on the computer running ThingsBoard, it will refer to that computer, but used on another computer it refers to the other computer. No other computer or device will be able to connect to the ThingsBoard server using 127.0.0.1.
It's like if you say "I like cake" and then your friend says "I like pie". 127.0.0.1 is "I" - your friend saying "I like pie" doesn't mean you like pie.
You need to find out the correct IP address of the server you're trying to connect to. If you're running it on a Linux computer you can use /sbin/ifconfig to list your network interfaces. Ignore lo - that's loopback, which is localhost and 127.0.0.1. If the server has a wired (ethernet) connection, look for en0 or enp0s## or something like that, with an inet addr. If it's connected to wifi, look for something like wlan0 or wlp5s0. The names vary depending on the OS and the hardware, so you'll have to figure that out for yourself.
For instance, on one of my Linux computers:
enp0s25 Link encap:Ethernet HWaddr 70:85:c2:00:12:76
inet addr:10.0.1.104 Bcast:10.0.1.255 Mask:255.255.255.0
inet6 addr: fe80::7886:c2fe:fd00:1872/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:846697237 errors:0 dropped:0 overruns:0 frame:0
TX packets:96279263 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:167800766971 (167.8 GB) TX bytes:34595177085 (34.5 GB)
Interrupt:20 Memory:fb400000-fb420000
That computer's IP address is 10.0.1.104.
This will work on a Macintosh as well.
If you're running on Windows, this article will help you find your IP address. Do not use a web service like https://www.whatismyip.com/ - that will tell you the IP address of your router, not the IP address of your computer.
Once you have the correct IP address, use it in your ESP8266 code instead of 127.0.0.1.
In your tb-gateway.yml and mqtt-config.json files, you're telling the server to only listen on 127.0.0.1. You should double check the documentation, but you almost certainly need to change this to 0.0.0.0 in both files. That should tell the server to listen on all network devices. Without that change it won't be able to communicate with anything that's not running on the same computer.
Once you do that, be aware that anything on your network will be able to talk to your MQTT server; you should configure it with proper access controls if that's a problem for you.

Serial communication on STM32F303 using HAL - Rx not working

I am using an STM32F303RE Nucleo board connected to my own PCB to do RS-232 serial communications, and I can't figure out why this code doesn't work in certain circumstances.
I'm using HAL functions (HAL_UART_Transmit and HAL_UART_Receive) for my communications, using the USB connector on the Nucleo for usart2 and a 9-pin RS-232 serial port on my own PCB for usart1. Both usart configurations have been set up by HAL.
When I communicate (using a Putty terminal) using only the USB connection (usart2), the code works perfectly. When I use usart1 for Tx and usart2 for Rx, still no problems. When I use usart2 for Tx and usart1 for Rx, it also works fine.
The problem is when I try to use usart1 (which is my RS-232 cable) for both Tx and Rx. My processor transmits the initial data fine, but when it's time to receive the data, nothing makes it into the received data register. I have some code to simply echo back any received data on the transmit line, and nothing comes through in this configuration. Once again - the code works fine in every other configuration of usart1 and usart2 for both sending and receiving, but no Rx when I try to do it all on usart1 (RS-232)
Here is the relevant section of code I'm using. COMTYPE is set to either &huart1 or &huart2 (in the problem case, it's set to &huart1)
Main loop (received data used for switch statement in menu system):
HAL_UART_Transmit(COMTYPE, prompt, sizeof(prompt), TIMEOUT);
cmd_size = UART_getstr(command);
cmd_num = parse_menu_input(command, cmd_size);
converted = (uint8_t)cmd_num + '0';
// error parsing command for menu selection
if(cmd_num == -1){
HAL_UART_Transmit(COMTYPE, parse_error, sizeof(parse_error), TIMEOUT);
}
else{
menu_switch(cmd_num);
}
}
Function containing Rx function and echo back (Tx) function:
int UART_getstr(uint8_t* command){
int x = 0; // tracker for buffer pointer
int chars = 0;
uint8_t buffer; // single char storage for UART receive
while(1){
// get single char from UART_Receive
HAL_UART_Receive(COMTYPE, &buffer, 1, HAL_MAX_DELAY);
// echo back function
HAL_UART_Transmit(COMTYPE, &buffer, sizeof(char), TIMEOUT);
// write value of received char to "command" array
command[x] = buffer;
// increment the number of valid chars
chars++;
// stop adding chars to command after [Enter] pressed
if(command[x] == '\r'){
chars--;
break;
}
// correct for storing DELETE as char in buffer
if(command[x] == 0x7F){
command -= 1;
chars -= 2;
}
else{
x++;
}
}
command[x] = '\0';
// return length of command buffer
return chars; }
I don't understand why the exact same code would work in 3 out of 4 circumstances, but not the 4th. I've checked the serial cable, and the rest of the RS-232 hardware functions fine when being used ONLY for Tx or ONLY for Rx. But the Rx seems blocked by something when trying to use RS-232 for both.
EDIT: Adding UART initialization code (generated by HAL):
/* USART1 init function */
static void MX_USART1_UART_Init(void)
{
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}
/* USART2 init function */
static void MX_USART2_UART_Init(void)
{
huart2.Instance = USART2;
huart2.Init.BaudRate = 115200;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart2) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}

Adding nftables nat rules with libnftnl APIs

I want to add following snat and dnat rules using nftables:
nft add rule nat post udp sport 29000 ip saddr 192.168.101.102 udp dport 40000 ip daddr 192.168.101.102 snat 192.168.101.55:35000
nft add rule nat pre udp sport 29000 ip saddr 192.168.101.103 udp dport 32000 ip daddr 192.168.101.55 dnat 192.168.101.102:40000
Here, pre and post is name of the chains in the nat table and I have added those with the following commands:
nft add table nat
nft add chain nat pre { type nat hook prerouting priority 0 \; }
nft add chain nat post { type nat hook postrouting priority 100 \; }
I have already checked it with the nft command and it is working perfectly.
I want to achieve the same with API approach from my application. There are some examples and test program provided in the libnftnl library. From the reference of nft-rule-add.c and nft-expr_nat-test.c I have made a test application for the same as follows:
/* Packets coming from */
#define SADDR "192.168.1.103"
#define SPORT 29000
/* Packets coming to (the machine on which nat happen) */
#define DADDR "192.168.101.55"
#define DPORT 32000
/* Packets should go from (the machine on which nat happen) */
#define SNATADDR DADDR
#define SNATPORT 35000
/* Packets should go to */
#define DNATADDR SADDR
#define DNATPORT 38000
static void add_payload(struct nftnl_rule *rRule, uint32_t base, uint32_t dreg,
uint32_t offset, uint32_t len)
{
struct nftnl_expr *tExpression = nftnl_expr_alloc("payload");
if (tExpression == NULL) {
perror("expr payload oom");
exit(EXIT_FAILURE);
}
nftnl_expr_set_u32(tExpression, NFTNL_EXPR_PAYLOAD_BASE, base);
nftnl_expr_set_u32(tExpression, NFTNL_EXPR_PAYLOAD_DREG, dreg);
nftnl_expr_set_u32(tExpression, NFTNL_EXPR_PAYLOAD_OFFSET, offset);
nftnl_expr_set_u32(tExpression, NFTNL_EXPR_PAYLOAD_LEN, len);
nftnl_rule_add_expr(rRule, tExpression);
}
static void add_cmp(struct nftnl_rule *rRule, uint32_t sreg, uint32_t op,
const void *data, uint32_t data_len)
{
struct nftnl_expr *tExpression = nftnl_expr_alloc("cmp");
if (tExpression == NULL) {
perror("expr cmp oom");
exit(EXIT_FAILURE);
}
nftnl_expr_set_u32(tExpression, NFTNL_EXPR_CMP_SREG, sreg);
nftnl_expr_set_u32(tExpression, NFTNL_EXPR_CMP_OP, op);
nftnl_expr_set(tExpression, NFTNL_EXPR_CMP_DATA, data, data_len);
nftnl_rule_add_expr(rRule, tExpression);
}
static void add_nat(struct nftnl_rule *rRule, uint32_t sreg,
const void *ip, uint32_t ip_len,
const void *port, uint32_t port_len)
{
struct nftnl_expr *tExpression = nftnl_expr_alloc("nat");
if (tExpression == NULL) {
perror("expr cmp oom");
exit(EXIT_FAILURE);
}
/* Performing snat */
nftnl_expr_set_u32(tExpression, NFTNL_EXPR_NAT_TYPE, NFT_NAT_SNAT);
/* Nat family IPv4 */
nftnl_expr_set_u32(tExpression, NFTNL_EXPR_NAT_FAMILY, NFPROTO_IPV4);
/* Don't know what to do with these four calls */
/* How to add IP address and port that should be used in snat */
// nftnl_expr_set_u32(tExpression, NFTNL_EXPR_NAT_REG_ADDR_MIN, NFT_REG_1);
// nftnl_expr_set_u32(tExpression, NFTNL_EXPR_NAT_REG_ADDR_MAX, NFT_REG_3);
// nftnl_expr_set_u32(tExpression, NFTNL_EXPR_NAT_REG_PROTO_MIN, 0x6124385);
// nftnl_expr_set_u32(tExpression, NFTNL_EXPR_NAT_REG_PROTO_MAX, 0x2153846);
nftnl_rule_add_expr(rRule, tExpression);
}
static struct nftnl_rule *setup_rule(uint8_t family, const char *table,
const char *chain, const char *handle)
{
struct nftnl_rule *rule = NULL;
uint8_t proto = 0;
uint16_t dport = 0, sport = 0, sNatPort = 0, dNatPort = 0;
uint8_t saddr[sizeof(struct in6_addr)]; /* Packets coming from */
uint8_t daddr[sizeof(struct in6_addr)]; /* Packets coming to (the machine on which nat happens) */
uint8_t snataddr[sizeof(struct in6_addr)]; /* Packets should go from (the machine on which nat happens) */
uint8_t dnataddr[sizeof(struct in6_addr)]; /* Packets should go to */
uint64_t handle_num;
rule = nftnl_rule_alloc();
if (rule == NULL) {
perror("OOM");
exit(EXIT_FAILURE);
}
nftnl_rule_set(rule, NFTNL_RULE_TABLE, table);
nftnl_rule_set(rule, NFTNL_RULE_CHAIN, chain);
nftnl_rule_set_u32(rule, NFTNL_RULE_FAMILY, family);
if (handle != NULL) {
handle_num = atoll(handle);
nftnl_rule_set_u64(rule, NFTNL_RULE_POSITION, handle_num);
}
/* Declaring tcp port or udp port */
proto = IPPROTO_UDP;
add_payload(rule, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1,
offsetof(struct iphdr, protocol), sizeof(uint8_t));
add_cmp(rule, NFT_REG_1, NFT_CMP_EQ, &proto, sizeof(uint8_t));
/* Declaring dport */
dport = htons(DPORT);
add_payload(rule, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG_1,
offsetof(struct udphdr, dest), sizeof(uint16_t));
add_cmp(rule, NFT_REG_1, NFT_CMP_EQ, &dport, sizeof(uint16_t));
/* Declaring dest ip */
add_payload(rule, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1,
offsetof(struct iphdr, daddr), sizeof(daddr));
inet_pton(AF_INET, DADDR, daddr);
add_cmp(rule, NFT_REG_1, NFT_CMP_EQ, daddr, sizeof(daddr));
/* Declaring sport */
sport = htons(SPORT);
add_payload(rule, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG_1,
offsetof(struct udphdr, source), sizeof(uint16_t));
add_cmp(rule, NFT_REG_1, NFT_CMP_EQ, &sport, sizeof(uint16_t));
/* Declaring src ip */
add_payload(rule, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1,
offsetof(struct iphdr, saddr), sizeof(saddr));
inet_pton(AF_INET, SADDR, saddr);
add_cmp(rule, NFT_REG_1, NFT_CMP_EQ, saddr, sizeof(saddr));
/* Addding snat params */
inet_pton(AF_INET, SNATADDR, snataddr);
sNatPort = htons(SNATPORT);
add_nat(rule, NFT_REG_1, snataddr, sizeof(snataddr), &sNatPort, sizeof(uint16_t));
return rule;
}
int main(int argc, char *argv[])
{
struct mnl_socket *nl;
struct nftnl_rule *r;
struct nlmsghdr *nlh;
struct mnl_nlmsg_batch *batch;
uint8_t family;
char buf[MNL_SOCKET_BUFFER_SIZE];
uint32_t seq = time(NULL);
int ret, batching;
if (argc < 4 || argc > 5) {
fprintf(stderr, "Usage: %s <family> <table> <chain>\n", argv[0]);
exit(EXIT_FAILURE);
}
if (strcmp(argv[1], "ip") == 0)
family = NFPROTO_IPV4;
else if (strcmp(argv[1], "ip6") == 0)
family = NFPROTO_IPV6;
else {
fprintf(stderr, "Unknown family: ip, ip6\n");
exit(EXIT_FAILURE);
}
// Now creating rule
if (argc != 5)
r = setup_rule(family, argv[2], argv[3], NULL);
else
r = setup_rule(family, argv[2], argv[3], argv[4]);
// Now adding rule through mnl socket
nl = mnl_socket_open(NETLINK_NETFILTER);
if (nl == NULL) {
perror("mnl_socket_open");
exit(EXIT_FAILURE);
}
if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
perror("mnl_socket_bind");
exit(EXIT_FAILURE);
}
batching = nftnl_batch_is_supported();
if (batching < 0) {
perror("cannot talk to nfnetlink");
exit(EXIT_FAILURE);
}
batch = mnl_nlmsg_batch_start(buf, sizeof(buf));
if (batching) {
nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
mnl_nlmsg_batch_next(batch);
}
nlh = nftnl_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
NFT_MSG_NEWRULE,
nftnl_rule_get_u32(r, NFTNL_RULE_FAMILY),
NLM_F_APPEND|NLM_F_CREATE|NLM_F_ACK, seq++);
nftnl_rule_nlmsg_build_payload(nlh, r);
nftnl_rule_free(r);
mnl_nlmsg_batch_next(batch);
if (batching) {
nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++);
mnl_nlmsg_batch_next(batch);
}
ret = mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch),
mnl_nlmsg_batch_size(batch));
if (ret == -1) {
perror("mnl_socket_sendto");
exit(EXIT_FAILURE);
}
mnl_nlmsg_batch_stop(batch);
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
if (ret == -1) {
perror("mnl_socket_recvfrom");
exit(EXIT_FAILURE);
}
ret = mnl_cb_run(buf, ret, 0, mnl_socket_get_portid(nl), NULL, NULL);
if (ret < 0) {
perror("mnl_cb_run");
exit(EXIT_FAILURE);
}
mnl_socket_close(nl);
return EXIT_SUCCESS;
}
Here, main() function calls setup_rule() where whole rule is built. setup_rule() calls add_nat() where expression for snat is built. The IP and Port that should be used for snat or dnat are passed as args to add_nat().
As I understand, the phylosophy of building a rule is that a rule is built with various expressions. In add_nat() an expression is built for doing snat and that's where I start to fumble. Don't know what to do with NFTNL_EXPR_NAT_REG_ADDR_MIN and NFTNL_EXPR_NAT_REG_PROTO_MIN kind of macros. How to pass IP Address and Port Address which will be used in snat or dnat.
I run the above test application as follows:
./application ip nat pre
And with the following command
nft list table nat -a
got the output as follows:
table ip nat {
chain pre {
type nat hook prerouting priority 0; policy accept;
udp dport 32000 ip daddr 192.168.101.55 #nh,160,96 541307071 udp sport 29000 ip saddr 192.168.1.103 ip daddr 0.0.0.0 #nh,160,64 3293205175 snat to # handle 250
} # handle 33
chain post {
type nat hook postrouting priority 100; policy accept;
} # handle 34
} # handle 0
May be the approach is wrong, but, as shown above, it displayed snat to in the end. And that gives me the hope that this is the way forward. I also digged in the nftables utility code but to no avail.
So to list all queries:
How to add snat or dnat rules with nftable apis?
What is with NFT_REG_1? How these registers should be used and where it should be used?
What is written after # in the output of the nft list table nat -a command? When I apply rules with nft command than it does not show info after # in the output of nft list table
Also, there is an extra ip addr 0.0.0.0 displayed in the output of nft list table nat -a command. Where does that get added?

MODBUS TCP between PLC and Arduino

I am trying to exchange data between an PLC(WAGO 750-8101) and an Arduino(UNO) with PLC as master, and the Arduino as Slave, but cant seem to get a connection.
For the Arduino I have a MINI ENC28J60 as the networkmodule, and is connected to the arduino like this:
SCK - Pin 13, SO - Pin 12, SI - Pin 11, CS - Pin 10
VCC: 3.3V
For the arduino I am using these libraries:
EtherCard
Modbus-Arduino
Master Setup
SendRequest : WagoAppPlcModbus.FbMbMasterTcp := ( xConnect := TRUE,
sHost:= '192.168.1.88',
wPort:=502,
utKeepAlive:= ( xEnable :=TRUE,
tMaxIdleTime := T#5S,
tInterval:= T#2S,
udiProbes:=5),
eFrameType := eMbFrameType.ETHERNET,
tTimeOut:= T#30S);
utQuery: typMbQuery := ( bUnitId := 88, // slave ID,
bFunctionCode:=16#4, // analog input registers
uiReadAddress:= 0,
uiReadQuantity:=2,
uiWriteAddress:=0,
uiWriteQuantity:=0,
awWriteData:= [124(0)]);
xTxTrigger : BOOL;
utResponse : typMbResponse;
TimerForRequest : TON := (PT := T#5S);
HeartRate: WORD;
AirQuality : WORD;
HentSensorData : BOOL;
and code in main:
//TimerForRequest(IN:=HentSensorData);
//xTxTrigger S= TimerForRequest.Q;
SendRequest( utQuery := utQuery,
xTrigger := HentSensorData, //a toggle switch on HMI
utResponse := utResponse);
HeartRate := utResponse.awData[0];
AirQuality := utResponse.awData[1];
Slave setup (arduino):
#include <EtherCard.h>
#include <ModbusIP_ENC28J60.h>
#include <Modbus.h>
const int HeartBeat = 0;
const int Oxygen = 1;
ModbusIP mb;
void setup() {
// The media access control (ethernet hardware) address for the shield
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
// The IP address for the shield
byte ip[] = { 192, 168, 1, 88 };
byte dns[] = { 192, 168, 1, 1 };
byte gw[] = { 192, 168, 1, 1 };
byte subnet[] = { 255, 255, 255, 0 };
Serial.begin(9600);
Serial.println("DEBUG");
Serial.println();
//Config Modbus IP
mb.config(mac, ip, dns, gw, subnet);
Serial.println("Modbus com. setup done");
Serial.println();
Serial.println("SLAVE SETTINGS");
ether.printIp("IP: ",ether.myip);
ether.printIp("DNS: ", ether.dnsip);
//ether.printIp("GW: ",ether.gwip); ether.printIp("Mask: ",
ether.mymask);
Serial.println();
// Add SENSOR_IREG register - Use addIreg() for analog Inputs
mb.addIreg(HeartBeat);
Serial.print("HeartBeatSensor added at address: ");
Serial.println(HeartBeat);
mb.addIreg(Oxygen);
Serial.print("OxygenSensor added at address: ");
Serial.println(Oxygen);
}
void loop() {
//Call once inside loop() - all magic here
mb.task();
//Testcode
for(int i=0;i<400; i++)
{
mb.Ireg(HeartBeat, i);
mb.Ireg(Oxygen,i+2000);
Serial.println(i);
delay(2000);
}
}
Output (debug) slave:
Arduino debug
I am able to get connection between the PLC and a Modbus Slave simulator (and exchange data), but when I try to connect the arduino I can't seem to get a connection.
This is the error i get in the PLC:
Error in the functionblock (master)
Any suggestions? Is it possible that the problem is that I'm using a crossover-cable (even though WAGO is set to switch mode in Ethernet settings?)
Solved
The problem was sending and receiving on the Arduino-side. I connected the Arduino and the PLC to a switch. I was then able to exchange data.
My setup that didn't work:
Ardunio <-------> PLC (WAGO)
My setup that did work:
Arduino <------> switch <-----> PLC.
Ethernet TCP/IP Switch and Modbus/TCP switch can co-exist on the same network.
But if you want to communicate between Ethernet TCP/IP protocol & Modbus TCP protocol, you need a converter.
So i believe than your PLC and Arduino is already communicating in Modbus TCP.
It will be great to precise if the switch is a Modbus TCP switch or an ordinary Ethernet Switch.
I presume it's an ordinary switch since thoses protocol can co-exist on the same network.

Problem in listening to multicast in C++ with multiple NICs

I am trying to write a multicast client on a machine with two NICs, and I can't make it work. I can see with a sniffer that once I start the program the NIC (eth4) start receiving the multicast datagrams, However, I can't recieve() any in my program.
When running "tshark -i eth4 -R udp.port==xxx (multicast port)"
I get:
1059.435483 y.y.y.y. (some ip) -> z.z.z.z (multicast ip, not my eth4 NIC IP) UDP Source port: kkk (some other port) Destination port: xxx (multicast port)
Searched the web for some examples/explanations, but it seems like I do what everybody else does. Any help will be appreciated. (anything to do with route/iptables/code?)
bool connectionManager::sendMulticastJoinRequest()
{
struct sockaddr_in localSock;
struct ip_mreqn group;
char* mc_addr_str = SystemManager::Instance()->getTCP_IP_CHT();
char* local_addr_str = SystemManager::Instance()->getlocal_IP_TOLA();
int port = SystemManager::Instance()->getTCP_Port_CHT();
/* Create a datagram socket on which to receive. */
CHT_UDP_Feed_sock = socket(AF_INET, SOCK_DGRAM, 0);
if(CHT_UDP_Feed_sock < 0)
{
perror("Opening datagram socket error");
return false;
}
/* application to receive copies of the multicast datagrams. */
{
int reuse = 1;
if(setsockopt(CHT_UDP_Feed_sock, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0)
{
perror("Setting SO_REUSEADDR error");
close(CHT_UDP_Feed_sock);
return false;
}
}
/* Bind to the proper port number with the IP address */
/* specified as INADDR_ANY. */
memset((char *) &localSock, 0, sizeof(localSock));
localSock.sin_family = AF_INET;
localSock.sin_port = htons(port);
localSock.sin_addr.s_addr =inet_addr(local_addr_str); // htonl(INADDR_ANY); //
if(bind(CHT_UDP_Feed_sock, (struct sockaddr*)&localSock, sizeof(localSock)))
{
perror("Binding datagram socket error");
close(CHT_UDP_Feed_sock);
return false;
}
/* Join the multicast group mc_addr_str on the local local_addr_str */
/* interface. Note that this IP_ADD_MEMBERSHIP option must be */
/* called for each local interface over which the multicast */
/* datagrams are to be received. */
group.imr_ifindex = if_nametoindex("eth4");
if (setsockopt(CHT_UDP_Feed_sock, SOL_SOCKET, SO_BINDTODEVICE, "eth4", 5) < 0)
return false;
group.imr_multiaddr.s_addr = inet_addr(mc_addr_str);
group.imr_address.s_addr = htonl(INADDR_ANY); //also tried inet_addr(local_addr_str); instead
if(setsockopt(CHT_UDP_Feed_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&group, sizeof(group)) < 0)
{
perror("Adding multicast group error");
close(CHT_UDP_Feed_sock);
return false;
}
// Read from the socket.
char databuf[1024];
int datalen = sizeof(databuf);
if(read(CHT_UDP_Feed_sock, databuf, datalen) < 0)
{
perror("Reading datagram message error");
close(CHT_UDP_Feed_sock);
return false;
}
else
{
printf("Reading datagram message...OK.\n");
printf("The message from multicast server is: \"%s\"\n", databuf);
}
return true;
}
Just a thought, (I've not done much work with multicast), but could it be because you're binding to a specific IP address? The socket could be only accepting packets destined for it's bound IP address and rejecting the multicast ones?
Well, there is some time ago since I didn't play with multicast. Don't you need root/admin rights to use it? did you enable them when launching your program?

Resources