discuss-gnustep
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Sending UDP packets


From: Saso Kiselkov
Subject: Re: Sending UDP packets
Date: Thu, 26 Nov 2009 11:01:55 +0100
User-agent: Thunderbird 2.0.0.23 (X11/20090817)

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi,

My name is "SasO", not "Sasa". :-)

Andreas Höschler wrote:
> Hello Sasa,
> 
>> Try replacing the "NSLog (@"sendto() failed");" with "perror ("sendto()
>> failed") - that will tell you exactly what went wrong.
> 
> Sending packet 9
> sendto() failed: Permission denied
> 
> Wow? Why that? I tried it as root, but that leads to the same error!?

Try tcpdump-ing on the network and checking that you don't get an "ICMP
connection refused" packet in response from the destination machines -
it could happen if you send a UDP packet to a port with no listening
socket bound to it (e.g. port mismatch between sender and receiver).

> 
>> Also, as Lars suggested, your application might be an ideal example of
>> when to use IP
>> multicast
> 
> I will look into the links Lars gave ...
> 
>> (if you need, I can rewrite this code to work over multicast).
> 
> If that weren't too much work for you, ... I would pretty much
> appreciate a working code snippet.
> 
> Thanks a lot for your help!
> 
> Regards,
> 
>  Andreas
> 

Modified code snipped below:

Btw: in case you were wondering, perror is equivalent to:

void perror (const char *msg)
{
  fprintf (stderr, "%s: %s\n", msg, strerror (errno));
}

**********************************
UDP sender
**********************************
#define BUFLEN 512
#define NPACK 10
#define PORT 9930
//#define SRV_IP "127.0.0.1"

// 224.0.0.0 - 239.255.255.255
#define GROUP_IP "224.1.2.3"

{
  struct sockaddr_in si_other;
  int s, i, slen=sizeof(si_other);
  char buf[BUFLEN];
  if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
     NSLog(@"socket could not be opened");

  // shouldn't be necessary
  // 2nd note: cast to (char *) isn't needed, since an implicit cast to
  // (void *) is allowed in C
//  memset((char *) &si_other, 0, sizeof(si_other));
  si_other.sin_family = AF_INET;
  si_other.sin_port = htons(PORT);
  if (inet_aton(GROUP_IP, &si_other.sin_addr)==0)
    {
      fprintf(stderr, "inet_aton() failed\n");
      exit(1);
    }

  // we can do a connect() here, since we'll be multicasting
  // to a single group address
  if (connect (s, (struct sockaddr *) &si_other, sizeof (si_other)) < 0)
    {
      perror ("connect()");
      exit (EXIT_FAILURE);
    }

  // By default, multicast packets have a ttl = 1, meaning they won't
  // leave your local broadcast segment across a router with multicast
  // routing support. If you do want to be able to route your multicast
  // packets, uncomment the following code:
  /*
  unsigned char ttl = 255;
  if (setsockopt (s, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0)
    {
      perror ("Increasing send TTL failed");
      exit (EXIT_FAILURE);
    }
  */

  for (i=0; i<NPACK; i++)
    {
      printf("Sending packet %d\n", i);
      sprintf(buf, "This is packet %d\n", i);
      if (write (s, buf, BUFLEN) == -1)
        perror ("sendto() failed");
    }
  close(s);
}

**********************************
UDP receiver
**********************************
{
  struct sockaddr_in si_me, si_other;
  int s, i, slen=sizeof(si_other);
  char buf[BUFLEN];
  if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
    perror ("socket() failed");

  // not necessary
//  memset((char *) &si_me, 0, sizeof(si_me));

  si_me.sin_family = AF_INET;
  si_me.sin_port = htons(PORT);
  si_me.sin_addr.s_addr = htonl(INADDR_ANY);

  if (bind(s, &si_me, sizeof(si_me))==-1)
    NSLog(@"bind failed");

  // join the multicast group using IGMP
  struct ip_mreq req;

  req.imr_multiaddr = GROUP_IP;
  req.imr_interface.s_addr = INADDR_ANY;

// Linux uses SOL_IP, Solaris uses IPPROTO_IP - not sure which one
// BSD/Darwin use, but I assume it's going to be the same as Linux
#ifdef SOL_IP
# define SOCKOPT_LEVEL SOL_IP
#else
# define SOCKOPT_LEVEL IPPROTO_IP
#endif

  setsockopt (s, SOCKOPT_LEVEL, IP_ADD_MEMBERSHIP, &req, sizeof (req));

  for (i=0; i<NPACK; i++)
    {
      if (recvfrom(s, buf, BUFLEN, 0, &si_other,
&slen)==-1)NSLog(@"recvfrom()");
      printf("Received packet from %s:%d\nData: %s\n\n",
inet_ntoa(si_other.sin_addr), ntohs(si_other.sin_port), buf);
    }
}


********

The beauty of using multicast is that on a LAN with L2+ switches with
IGMP snooping enabled, the network itself is capable of "steering" the
packets to the appropriate listener ports. In case you don't have a
multicast router with IGMP enabled connected to the LAN, make sure you
have one switch configured as an active IGMP querier (sends periodic
"query" messages to determine group membership). If your LAN doesn't
support IGMP snooping (i.e. it's disabled, or your switches don't
support it), it falls back to behaving like broadcast, so everything
will still work, only a bit less efficiently (with none of the drawbacks
of broadcast at the endpoints, like delivery of packets to unrelated
services which happen to listen on the same UDP port on other machines -
the OS knows that multicast != broadcast and will ignore it).

- --
Saso
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iEYEARECAAYFAksOUhMACgkQRO8UcfzpOHDNnwCaAwo4YfFtHJXHz8SYExiqn8Rx
j8kAn3GjBoQpxkV9a1PWV9VgMDFnvMaI
=cZj4
-----END PGP SIGNATURE-----




reply via email to

[Prev in Thread] Current Thread [Next in Thread]