Recvfrom doesn't answer the right infos

Hello guys, We’re trying to communicate with a color bulb with C language.
We succeeded in discovering the bulb, we can also shutdown the bulb with Light :: SetPower but the response isn’t right : the answer we get is a stateService.

Could we have some help please ?

Do not hesitate to ask some questions :wink:

#include “in_DGRAM.h”

infoConnexion discover(int s, struct sockaddr_in svc);
void fct_shutdown(int s, struct sockaddr_in svc);

int main() 
{
    int s, l_svc, portBulb;
    int yes=1;
    infoConnexion infoBulb;
    
    struct sockaddr_in svc, moi;

    //creation socket
    CHECK(s=socket(AF_INET, SOCK_DGRAM,0), "Pb socket");
    //setsockopt(s, SOL_SOCKET, SO_BROADCAST, &yes, sizeof(int) );
    
    //preparation addr du serveur à contacter
    svc.sin_family = AF_INET;
    svc.sin_addr.s_addr=inet_addr("192.168.1.10");
    svc.sin_port = htons(PORT);
    bzero(&svc.sin_zero,8);
    
    //Recherche de la lampe et MAJ de son IP
    infoBulb = discover(s, svc);
    printf("Bulb's port : %d\n", infoBulb.port);
    printf("IP : %s\n", infoBulb.ip);
    svc.sin_addr.s_addr=inet_addr(infoBulb.ip);
    
    bind(s, (struct sockaddr *)&svc, sizeof(svc));
    
    fct_shutdown(s, svc);
    
    close(s);
    return 0;
}

infoConnexion discover(int s, struct sockaddr_in svc)
{
    //There's only one bulb in the system
      

    lx_protocol_header_t hd, hdResponse;
    int i = 0,j=0;
    int l_svc=sizeof(svc);
    struct sockaddr_in svcBulb;
    char str[INET_ADDRSTRLEN];
    infoConnexion infoBulb;
    
    
    //Setting the header
    //---frame--- 
    hd.protocol = 1024; 
    hd.addressable = 1;
    hd.tagged = 1;
    hd.origin = 0;
    hd.source = 1;
    
    //---frame address---
    for (i=0; i<8; i++)
    {
        hd.target[i] = 0; 
    }
    
    
    
    for (i=0; i<6; i++)
    {
        hd.reserved[i] = 0;
    }
    hd.res = 0;
    hd.ack_required = 0;
    hd.res_required = 0;
    hd.sequence = 2;
    
    //---protocol header---
    hd.resa = 0;
    hd.type = 2;
    hd.resb = 0;
    
    //---frame---
    hd.size = sizeof(hd);
    
    
    //Sending
    CHECK(sendto(s, &hd, sizeof(hd), 0, (struct sockaddr*) &svc, l_svc), "Sending problem (discover)");    
    
    printf("Request sent (discover)\n");

    //Answer receiving
    //recvfrom and display
    CHECK(recvfrom(s, &hdResponse, MAX_REP, 0, (struct sockaddr *) &svc, &l_svc), "Reception problem (discover)");
    
    if(hdResponse.port!=0 && hdResponse.service == 1 && hdResponse.type == 3)
    {
        svcBulb=(struct sockaddr_in)svc;
        printf("Communication OK (discover)\n");
        inet_ntop(AF_INET, &(svcBulb.sin_addr), str, INET_ADDRSTRLEN);
        
        infoBulb.port = hdResponse.port;
        
        strcpy(infoBulb.ip,str);
        
        printf("\n\n");
        for(j=0;j<=7;j++)
        {
            printf("\tByte n°%d MAC ADDRESS bulb %d\n", j, hdResponse.target[j]);        
        }
        printf("\n\n");
    }
    else
    {
        printf("communication problem \n");
    }
    
    return infoBulb;
}


void fct_shutdown(int s, struct sockaddr_in svc)
{
    lx_protocol_header_t hd, hdResponse;
    int i = 0;
    int l_svc=sizeof(svc);
    
    memset(&hd,0,sizeof(lx_protocol_header_t));
    memset(&hdResponse,0,sizeof(lx_protocol_header_t));
    //---frame---
    hd.protocol = 1024; 
    hd.addressable = 1;
    hd.tagged = 0;
    hd.origin = 0;
    hd.source = 1;
    
    //---frame address--- //d0:73:d5:01:c5:e1
    hd.target[0] = 208;
    hd.target[1] = 115;
    hd.target[2] = 213;
    hd.target[3] = 1;
    hd.target[4] = 197;
    hd.target[5] = 225;
    hd.target[6] = 0;
    hd.target[7] = 0;
    
    
    
    for (i=0; i<6; i++)
    {
        hd.reserved[i] = 0;
    }
    hd.res = 0;
    hd.ack_required = 0;
    hd.res_required = 1;
    hd.sequence = 117; 
    
    //---protocol header---
    hd.resa = 0;
    hd.type = 117;
    hd.resb = 0;
    
    //---others---
    hd.level = 0;
    hd.duration = 0;
    
    //---frame---
    hd.size = sizeof(hd);
   
    //Sending message
    CHECK(sendto(s, (char*)&hd, sizeof(hd), 0, (struct sockaddr*) &svc, l_svc), "Sending problem (fct_shutdown)");    
    
    printf("Request sent (fct_shutdown)\n");
    
    
    CHECK(recvfrom(s, (char*)&hdResponse, MAX_REP, 0, (struct sockaddr *) &svc, &l_svc), "Reception problem (fct_shutdown)");
    
    printf("\n\n\tsequence reponse : %d\n\n", hdResponse.sequence);
    
    if(hdResponse.port==PORT && hdResponse.type == 118)
    {
        printf("Communication OK (fct_shutdown)\n");
        printf("Power level %d\n", hdResponse.level);
    }
    else
    {
        printf("Communication proble\n");
        printf("\tPort : %d\n\tService : %d\n\tType : %d\n", hdResponse.port, hdResponse.service, hdResponse.type);
    }
}

And the content of my .h file :

#define CHECK(sts,msg) if((sts) == -1) {perror(msg);exit(-1);}

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>

#define SOCK_FILE "/tmp/ma_socket"
#define SOCK_CLIENT "/tmp/ma_socket2"
#define MAX_REP 736
#define PORT 56700

#pragma pack(push, 1)
    typedef struct {
      /* frame */
      uint16_t size;
      uint16_t protocol:12;
      uint8_t  addressable:1;
      uint8_t  tagged:1;
      uint8_t  origin:2;
      uint32_t source;
      /* frame address */
      uint8_t  target[8];
      uint8_t  reserved[6];
      uint8_t  res:6;
      uint8_t  ack_required:1;
      uint8_t  res_required:1;
      uint8_t  sequence;
      /* protocol header */
      uint64_t resa:64;
      uint16_t type;
      uint16_t resb:16;
      /* variable length payload follows */
      uint8_t service;
      uint32_t port;
      uint16_t level;
      uint32_t duration;
    } lx_protocol_header_t;
    #pragma pack(pop)
    
    
typedef struct {
    char ip[INET_ADDRSTRLEN];
    int port;
} infoConnexion;

Thanks in advance

Rather than listening on port 56700 I recommend that you listen on an ephemeral port, then send the ports from the same socket. The reason for this is that the bulb broadcasts replies to port 56700 when the source is not set. So messages that you get may be intended for other clients. When you have a socket listening on an ephemeral port and you send packets through that, as long as the source is non-zero, it will reply directly to the port the socket is listening on. This also means the bulb does not use broadcasts which are more reliable over WiFi and don’t clog up your network.

The other thing you might not be aware of is that the bulb might return several packets in answer to the Device::GetService message, because the bulbs host several services. Currently only one of these is documented for public use, so you’ll need to ignore the other responses.

1 Like