CocoaDev

Edit AllPages

I am trying to write General/UPnP support for my app, and I seem to be running into some trouble. The code I have broadcasts, but the General/UPnP device I am using will not respond. I know the message is correct, as I have copied the message from a working General/UPnPMediaServer app. Below is the code for the broadcast of Notification. This is to show the device that my app is a Media Server. It broadcasts, but it will not make a TCP request for the file path included. I think it may be that I need to set some additional socket flags, but I do not know what they may be. Thanks for any help.

variable a through e are char **s with the messages. Here is an example of one.

char *a = “NOTIFY * HTTP/1.1\r\n” “LOCATION: http://192.168.50.108:10002/\r\n” “HOST: 239.255.255.250:1900\r\n” “SERVER: POSIX, General/UPnP/1.0, General/MyProgram/1.1.7\r\n” “NTS: ssdp:alive\r\n” “USN: uuid:12345678-1234-1234-1234-123456789012::upnp:rootdevice\r\n” “CACHE-CONTROL: max-age=1800\r\n” “NT: upnp:rootdevice\r\n” “Content-Length: 0\r\n\r\n”;

void udpBroadcast() { char *theMessage[5]; theMessage[0] = a; theMessage[1] = b; theMessage[2] = c; theMessage[3] = d; theMessage[4] = e; for (int message = 0;message<5;message++) { unsigned int ss = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (ss == INVALID_SOCKET) { printf(“socket: error”); return; }

	for (int repeat = 0; repeat < 2;repeat++) {			
		int on = 1; 
		int ret = setsockopt(ss, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
		
		if (ret == -1) {
			printf("setsockopt: error");
			return;
		}
		struct sockaddr_in sin;
		memset(&sin, 0, sizeof(sin));
		sin.sin_family = AF_INET;
		sin.sin_port = htons(1900);
		sin.sin_addr.s_addr = inet_addr("239.255.255.250"); 
		int n = sendto(ss, theMessage[message], strlen(theMessage[message]), 0, (struct sockaddr *) &sin, sizeof(sin));
		printf("Message sent, return value: %d\n",n);
		shutdown(ss, 2);
		close(ss);
	}
} }

This runs perfectly, and sends messages correctly, but the General/UPnP device will not respond.

Thanks, Mike

p.s. I know it’s not Cocoa, but it’s for a Cocoa app, and it must be socket code because it will be used cross-platform.


Why don’t you use available General/UPnP librairies?

*General/CyberLink for C++ (Open Source) - http://sourceforge.net/projects/clinkcc/ *General/CyberLink for Java (Open Source) - http://sourceforge.net/projects/cgupnpjava/ *General/UPNPLib (Open Source Java) - http://www.sbbi.net/site/upnp/

Might not suitable for your project, but still interresting:

*libupnp (Open Source) the most used ,but not sure about OS X availability - http://upnp.sourceforge.net/ *General/UPnP AV SDK by General/TwonkyVision (Commercial) - http://www.twonkyvision.de/General/UPnP/avsdk.html *Pure Perl General/UPnP (Open Source) - http://sourceforge.net/projects/perlupnp

General/StephaneBoisson


General/UPnP uses multicasts rather then broadcasts (although your code would probably still work). Also, you close your socket after sending your first NOTIFY for your root device. So I doubt you sent out anything beyond that first NOTIFY broadcast. I don’t know what device you have, but the root device is usually uninteresting, so it could be that the device just didn’t see anything that it wanted to respond/connect to. Lastly, you don’t need to be creating a new socket for every message, you can reuse them. You should probably try something like this:

void udpBroadcast() { char *theMessage[5]; theMessage[0] = a; theMessage[1] = b; theMessage[2] = c; theMessage[3] = d; theMessage[4] = e;

// create socket
unsigned int ss = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (ss == INVALID_SOCKET)
{
	printf("socket: error");
	return;
}   
// set multicast, with a time to live of 4 hops, as recommended by the General/UPnP Spec
int ttl = 4;
int ret = setsockopt(ss,IPPROTO_IP,IP_MULTICAST_TTL,&ttl,sizeof(ttl));
if (ret == -1) 
{
	printf("setsockopt: error");
	close(ss); // don't leak sockets...
	return;
}
// Setup the General/UPnP broadcast address
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(1900);
sin.sin_addr.s_addr = inet_addr("239.255.255.250"); 

// send each message 2 times
for (int message = 0; message < 5; message++)
{
	for (int repeat = 0; repeat < 2; repeat++)
	{		
		int n = sendto(ss, theMessage[message], strlen(theMessage[message]),
					   0, (struct sockaddr *) &sin, sizeof(sin));
		printf("Message sent, return value: %d\n",n);
	}
}
// close the socket after we have sent all the multicasts
close(ss); }

Michael

P.S. Use Ethereal (http://www.ethereal.com/) to verify what is going out on the wire, is what you wanted to send.