mirror of
https://github.com/owntone/owntone-server.git
synced 2024-12-24 22:25:56 -05:00
forgot upnp files
This commit is contained in:
parent
1f640234f5
commit
5e9d9a3f20
228
src/upnp.c
Executable file
228
src/upnp.c
Executable 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
40
src/upnp.h
Executable 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_ */
|
Loading…
Reference in New Issue
Block a user