forgot upnp files

This commit is contained in:
Ron Pedde 2007-04-13 21:38:05 +00:00
parent 1f640234f5
commit 5e9d9a3f20
2 changed files with 268 additions and 0 deletions

228
src/upnp.c Executable file
View File

@ -0,0 +1,228 @@
/*
* $Id: $
*
* Implementation of functions for UPnP discovery
*
* Copyright (C) 2007 Ron Pedde (ron@pedde.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdio.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "conf.h"
#include "daapd.h"
#include "err.h"
#include "os.h"
#include "util.h"
#define UPNP_MAX_PACKET 1500
#define UPNP_UUID "12345678-1234-1234-1234-123456789012"
typedef struct upnp_packetinfo_t {
char *group_id;
char *base_packet;
char *location;
char *usn;
char *nt;
char *body;
struct upnp_packetinfo_t *next;
} UPNP_PACKETINFO;
/* Globals */
UPNP_PACKETINFO upnp_packetlist;
OS_SOCKETTYPE upnp_socket;
/* Forwards */
int upnp_strcat(char *what, char *where, int bytes_left);
void upnp_build_packet(char *packet, int len, UPNP_PACKETINFO *pi);
void upnp_broadcast(void);
/**
* add a upnp packet too the root list.
*/
void upnp_add_packet(char *group_id, char *location,
char *usn, char *nt, char *body) {
UPNP_PACKETINFO *pnew;
pnew = (UPNP_PACKETINFO *)malloc(sizeof(UPNP_PACKETINFO));
if(!pnew)
DPRINTF(E_FATAL,L_MISC,"Malloc error\n");
memset(pnew,0,sizeof(UPNP_PACKETINFO));
if(group_id)
pnew->group_id = strdup(group_id);
if(location)
pnew->location = strdup(location);
if(usn)
pnew->usn = strdup(usn);
if(nt)
pnew->nt = strdup(nt);
if(body)
pnew->body = strdup(body);
util_mutex_lock(l_upnp);
pnew->next = upnp_packetlist.next;
upnp_packetlist.next = pnew;
util_mutex_unlock(l_upnp);
}
int upnp_strcat(char *what, char *where, int bytes_left) {
if(!what)
return bytes_left;
if(strlen(what) < bytes_left) {
strcat(where,what);
return bytes_left - strlen(what);
}
return bytes_left;
}
void upnp_build_packet(char *packet, int len, UPNP_PACKETINFO *pi) {
char buffer[256];
char hostname[256];
*packet = '\0';
int port;
port = conf_get_int("general","port",0);
len = upnp_strcat("NOTIFY * HTTP/1.0\r\n",packet,len);
if(pi->location) {
gethostname(hostname,sizeof(hostname));
snprintf(buffer,sizeof(buffer),"LOCATION: http://%s:%d%s\r\n",
hostname,port,pi->location);
len=upnp_strcat(buffer,packet,len);
}
len=upnp_strcat("HOST: 239.255.255.250:1900\r\n",packet,len);
len=upnp_strcat("SERVER: POSIX, UPnP/1.0, Firefly/" VERSION "\r\n",
packet,len);
len=upnp_strcat("NTS: ssdp:alive\r\n",packet,len);
/* USN */
len=upnp_strcat("USN: uuid:",packet,len);
len=upnp_strcat(UPNP_UUID,packet,len);
if(pi->usn) {
snprintf(buffer,sizeof(buffer),"::%s",pi->usn);
len=upnp_strcat(buffer,packet,len);
}
len=upnp_strcat("\r\n",packet,len);
len=upnp_strcat("CACHE-CONTROL: max-age=1800\r\n",packet,len);
if(pi->nt) {
snprintf(buffer,sizeof(buffer),"NT: %s\r\n",pi->nt);
} else {
snprintf(buffer,sizeof(buffer),"NT: uuid:%s\r\n", UPNP_UUID);
}
len=upnp_strcat(buffer,packet,len);
if(pi->body) {
snprintf(buffer,sizeof(buffer),"Content-Length: %d\r\n\r\n",
strlen(pi->body));
len=upnp_strcat(buffer,packet,len);
len=upnp_strcat(pi->body,packet,len);
} else {
len=upnp_strcat("Content-Length: 0\r\n\r\n",packet,len);
}
}
/**
* broadcast out the upnp packets
*/
void upnp_broadcast(void) {
UPNP_PACKETINFO *pi;
struct sockaddr_in sin;
char packet[UPNP_MAX_PACKET];
int pass;
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");
util_mutex_lock(l_upnp);
for(pass=0; pass < 2; pass++) {
pi=upnp_packetlist.next;
while(pi) {
upnp_build_packet(packet, UPNP_MAX_PACKET, pi);
sendto(upnp_socket,packet,strlen(packet),0,
(struct sockaddr *)&sin, sizeof(sin));
pi = pi->next;
}
}
util_mutex_unlock(l_upnp);
}
int upnp_tick(void) {
static time_t last_broadcast = 0;
if((time(NULL) - last_broadcast) > 60) {
upnp_broadcast();
last_broadcast = time(NULL);
}
return TRUE;
}
/**
* start UPnP broadcaster. We'll want to send at least a rootdevice
* announcement with a location pointer to the admin page
*/
int upnp_init(void) {
int ttl = 3;
int result;
memset(&upnp_packetlist,0,sizeof(upnp_packetlist));
upnp_add_packet("base","/",NULL,NULL,NULL);
upnp_add_packet("base","/",
"urn:schemas-upnp-org:device:Basic:1.0",
"urn:schemas-upnp-org:device:Basic:1.0",NULL);
upnp_add_packet("base","/","upnp:rootdevice","upnp:rootdevice",NULL);
upnp_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
result = setsockopt(upnp_socket, IPPROTO_IP, IP_MULTICAST_TTL,
&ttl, sizeof(ttl));
if(result == -1) {
close(upnp_socket);
return FALSE;
}
return TRUE;
}
/**
* turn off any upnp services. Should really de-register
* all registered devices, etc.
*/
int upnp_deinit(void) {
close(upnp_socket);
return TRUE;
}

40
src/upnp.h Executable file
View File

@ -0,0 +1,40 @@
/*
* $Id: $
*
* Header functions for UPnP discovery
*
* Copyright (C) 2007 Ron Pedde (ron@pedde.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/**
* This could probably be as easily (or better?) done via some
* UPnP library, but I don't see any that are cross-platform to
* the variety of platforms I want to port to, not to mention that
* it's just some simple UDP broadcasts.
*/
#ifndef _UPNP_H_
#define _UPNP_H_
extern int upnp_init(void);
extern int upnp_tick(void);
extern int upnp_deinit(void);
extern void upnp_add_packet(char *group_id, char *location,
char *usn, char *nt, char *body);
#endif /* _UPNP_H_ */