2
votes

I am trying to send a UDP-datagram to an IP camera from a computer running on Linux in order to discover it. All devices are connected via a switch.

There is a windows app that is compatible with this camera, that sends out a UDP datagram to a multicast group and gets an answer from the camera via the same group. I found out this via Wireshark and decided to try and send the same datagram from a C program on my Linux machine. I am able to get the correct response if my C program sends it directly to the camera's IP-address, but not if I send it to the multicast group.

I therefor made a listener program on my Linux computer and tried to send it to the multicast address. This succeeded, but I did not catch anything in Wireshark.

So it seems that my C-program is able to send the datagram correctly, just not out on to the network. Can this be some kind of Linux configuration?

EDIT: As requested, here is the code. FYI: As of now, I am only trying to send data to the camera and examine the response in Wireshark.

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

#include "udp_socket.h"



int main( void )
{

    //int s = udp_socket(50000);
    int s = socket(AF_INET,SOCK_DGRAM,0);
    printf("Socket: %d\r\n", s);


    char buffer[48] = {0x67,0x45,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x67,0x45,0x00,0x00,0x14,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0xea,0xc8,0xc8,0xc8,0xf4,0xe6,0x00,0x00};
    struct sockaddr_in serveraddr;
    memset( &serveraddr, 0, sizeof(serveraddr) );
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons( 59125 );              
    serveraddr.sin_addr.s_addr = inet_addr("234.200.200.200");

    udp_socket_tx(s, buffer, sizeof(buffer), &serveraddr );

    close(s);
}

udp_socket_tx() from udp_socket.h:

int udp_socket_tx(int socket_fd, char * tx_buffer, int tx_buffer_len, const struct sockaddr_in * to_addr) {

return sendto(
    socket_fd,
    tx_buffer,
    tx_buffer_len,
    0,
    (const struct sockaddr *)to_addr,
    sizeof(struct sockaddr_in)
);

}
2
This is of course very hard without your code, but did you join the multicast group first in your Linux program?unwind
Multicast must be allowed on network interface. Try the command ifconfig eth0 multicast (replace eth0 with your adapter id).Marian
Can you attach your code ?Parham Alvani
@unwind I thought you didn't need to join a group to send things to it. FYI: The group exist because the camera creates it when it boots.Cortex
This page may help you: tldp.org/HOWTO/Multicast-HOWTO-6.htmlMathieu

2 Answers

0
votes

The following proposed code:

  1. cleanly compiles.
  2. performs the desired operation (sending a UDP packet).
  3. properly checks the returned status of the call to sendto().
  4. properly checks the returned status of the call to socket().
  5. does not include header files those contents are not used.
  6. expects the multicast address to be in the system 'route' table.
  7. respects the width of the printed page
  8. adds the missing #include for the call to printf().
  9. adds the missing #include for the call to memset().
  10. properly outputs error messages to stderr

and now the proposed code:

#include <stdio.h>      // perror(), printf()
#include <stdlib.h>     // exit(), EXIT_FAILURE, EXIT_SUCCESS
#include <string.h>     // memset()
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>


int main( void )
{
    int s = socket(AF_INET,SOCK_DGRAM,0);
    if ( 0 > s )
    {
        perror( "socket failed" );
        exit( EXIT_FAILURE );
    }

    // implied else, socket successful

    printf("Socket: %d\r\n", s);

    unsigned char buffer[] =
    {
        0x67, 0x45,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x00,
        0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00, 0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x67,0x45,
        0x00, 0x00,0x14,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,
        0xea, 0xc8, 0xc8, 0xc8, 0xf4, 0xe6, 0x00, 0x00
    };

    struct sockaddr_in serveraddr;
    memset( &serveraddr, 0, sizeof(serveraddr) );
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons( 59125 );
    serveraddr.sin_addr.s_addr = inet_addr("234.200.200.200");

    ssize_t sendtoStatus = sendto
    (
        s,
        buffer,
        sizeof(buffer),
        0,
        (const struct sockaddr *)&serveraddr,
        sizeof(struct sockaddr_in)
    );

    if( -1 == sendtoStatus )
    {
        perror( "sendto failed" );
        close(s);
        exit( EXIT_FAILURE );
    }

    close(s);
    return EXIT_SUCCESS;
} // end function: main
0
votes

When sending multicast datagrams, they will normally be sent out on whichever network interface is considered the default interface.

If that's not the interface you want to send on, you need to configure the outgoing multicast interface. This is done with the IP_MULTICAST_IF option:

If for example you want to send multicast from the interface with IP 192.168.1.1, you set it up as follows:

struct in_addr multi_interface;
multi_interface.s_addr = inet_addr("192.168.1.1");
if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF,
               (char *)&multi_interface, sizeof(multi_interface)) == -1) {
    perror("Error setting outgoing interface");
    close(s);
    exit(1);
}