|
a/src/upmpd.cxx |
|
b/src/upmpd.cxx |
|
... |
|
... |
45 |
#include "ohtime.hxx" // for OHTime
|
45 |
#include "ohtime.hxx" // for OHTime
|
46 |
#include "ohvolume.hxx" // for OHVolume
|
46 |
#include "ohvolume.hxx" // for OHVolume
|
47 |
#include "renderctl.hxx" // for UpMpdRenderCtl
|
47 |
#include "renderctl.hxx" // for UpMpdRenderCtl
|
48 |
#include "upmpdutils.hxx" // for path_cat, Pidfile, regsub1, etc
|
48 |
#include "upmpdutils.hxx" // for path_cat, Pidfile, regsub1, etc
|
49 |
#include "execmd.h"
|
49 |
#include "execmd.h"
|
|
|
50 |
#include "httpfs.hxx"
|
50 |
|
51 |
|
51 |
using namespace std;
|
52 |
using namespace std;
|
52 |
using namespace std::placeholders;
|
53 |
using namespace std::placeholders;
|
53 |
using namespace UPnPP;
|
54 |
using namespace UPnPP;
|
54 |
|
55 |
|
|
... |
|
... |
142 |
{
|
143 |
{
|
143 |
fprintf(stderr, "%s: usage:\n%s", thisprog, usage);
|
144 |
fprintf(stderr, "%s: usage:\n%s", thisprog, usage);
|
144 |
exit(1);
|
145 |
exit(1);
|
145 |
}
|
146 |
}
|
146 |
|
147 |
|
147 |
// The description XML document is the first thing downloaded by
|
|
|
148 |
// clients and tells them what services we export, and where to find
|
|
|
149 |
// them.
|
|
|
150 |
static string ohDesc(
|
|
|
151 |
"<service>"
|
|
|
152 |
" <serviceType>urn:av-openhome-org:service:Product:1</serviceType>"
|
|
|
153 |
" <serviceId>urn:av-openhome-org:serviceId:Product</serviceId>"
|
|
|
154 |
" <SCPDURL>/upmpd/OHProduct.xml</SCPDURL>"
|
|
|
155 |
" <controlURL>/ctl/OHProduct</controlURL>"
|
|
|
156 |
" <eventSubURL>/evt/OHProduct</eventSubURL>"
|
|
|
157 |
"</service>"
|
|
|
158 |
"<service>"
|
|
|
159 |
" <serviceType>urn:av-openhome-org:service:Info:1</serviceType>"
|
|
|
160 |
" <serviceId>urn:av-openhome-org:serviceId:Info</serviceId>"
|
|
|
161 |
" <SCPDURL>/upmpd/OHInfo.xml</SCPDURL>"
|
|
|
162 |
" <controlURL>/ctl/OHInfo</controlURL>"
|
|
|
163 |
" <eventSubURL>/evt/OHInfo</eventSubURL>"
|
|
|
164 |
"</service>"
|
|
|
165 |
"<service>"
|
|
|
166 |
" <serviceType>urn:av-openhome-org:service:Time:1</serviceType>"
|
|
|
167 |
" <serviceId>urn:av-openhome-org:serviceId:Time</serviceId>"
|
|
|
168 |
" <SCPDURL>/upmpd/OHTime.xml</SCPDURL>"
|
|
|
169 |
" <controlURL>/ctl/OHTime</controlURL>"
|
|
|
170 |
" <eventSubURL>/evt/OHTime</eventSubURL>"
|
|
|
171 |
"</service>"
|
|
|
172 |
"<service>"
|
|
|
173 |
" <serviceType>urn:av-openhome-org:service:Volume:1</serviceType>"
|
|
|
174 |
" <serviceId>urn:av-openhome-org:serviceId:Volume</serviceId>"
|
|
|
175 |
" <SCPDURL>/upmpd/OHVolume.xml</SCPDURL>"
|
|
|
176 |
" <controlURL>/ctl/OHVolume</controlURL>"
|
|
|
177 |
" <eventSubURL>/evt/OHVolume</eventSubURL>"
|
|
|
178 |
"</service>"
|
|
|
179 |
"<service>"
|
|
|
180 |
" <serviceType>urn:av-openhome-org:service:Playlist:1</serviceType>"
|
|
|
181 |
" <serviceId>urn:av-openhome-org:serviceId:Playlist</serviceId>"
|
|
|
182 |
" <SCPDURL>/upmpd/OHPlaylist.xml</SCPDURL>"
|
|
|
183 |
" <controlURL>/ctl/OHPlaylist</controlURL>"
|
|
|
184 |
" <eventSubURL>/evt/OHPlaylist</eventSubURL>"
|
|
|
185 |
"</service>"
|
|
|
186 |
);
|
|
|
187 |
|
|
|
188 |
// We only advertise the Openhome Receiver service if the sc2mpd
|
|
|
189 |
// songcast-to-mpd gateway command is available
|
|
|
190 |
static string ohDescReceive(
|
|
|
191 |
"<service>"
|
|
|
192 |
" <serviceType>urn:av-openhome-org:service:Receiver:1</serviceType>"
|
|
|
193 |
" <serviceId>urn:av-openhome-org:serviceId:Receiver</serviceId>"
|
|
|
194 |
" <SCPDURL>/upmpd/OHReceiver.xml</SCPDURL>"
|
|
|
195 |
" <controlURL>/ctl/OHReceiver</controlURL>"
|
|
|
196 |
" <eventSubURL>/evt/OHReceiver</eventSubURL>"
|
|
|
197 |
"</service>"
|
|
|
198 |
);
|
|
|
199 |
|
|
|
200 |
static const string iconDesc(
|
|
|
201 |
"<iconList>"
|
|
|
202 |
" <icon>"
|
|
|
203 |
" <mimetype>image/png</mimetype>"
|
|
|
204 |
" <width>64</width>"
|
|
|
205 |
" <height>64</height>"
|
|
|
206 |
" <depth>32</depth>"
|
|
|
207 |
" <url>/upmpd/icon.png</url>"
|
|
|
208 |
" </icon>"
|
|
|
209 |
"</iconList>"
|
|
|
210 |
);
|
|
|
211 |
|
|
|
212 |
// Our XML description data. !Keep description.xml first!
|
|
|
213 |
static vector<const char *> xmlfilenames =
|
|
|
214 |
{
|
|
|
215 |
/* keep first */ "description.xml", /* keep first */
|
|
|
216 |
"RenderingControl.xml", "AVTransport.xml", "ConnectionManager.xml",
|
|
|
217 |
};
|
|
|
218 |
static vector<const char *> ohxmlfilenames =
|
|
|
219 |
{
|
|
|
220 |
"OHProduct.xml", "OHInfo.xml", "OHTime.xml", "OHVolume.xml",
|
|
|
221 |
"OHPlaylist.xml",
|
|
|
222 |
};
|
|
|
223 |
|
|
|
224 |
static const string dfltFriendlyName("UpMpd");
|
148 |
static const string dfltFriendlyName("UpMpd");
|
225 |
|
149 |
|
226 |
// This is global
|
150 |
// This is global
|
227 |
string upmpdProtocolInfo;
|
151 |
string g_protocolInfo;
|
228 |
|
152 |
|
229 |
// Static for cleanup in sig handler.
|
153 |
// Static for cleanup in sig handler.
|
230 |
static UpnpDevice *dev;
|
154 |
static UpnpDevice *dev;
|
231 |
|
155 |
|
232 |
static string datadir(DATADIR "/");
|
156 |
static string datadir(DATADIR "/");
|
|
... |
|
... |
269 |
bool ownqueue = true;
|
193 |
bool ownqueue = true;
|
270 |
bool openhome = true;
|
194 |
bool openhome = true;
|
271 |
bool ohmetapersist = true;
|
195 |
bool ohmetapersist = true;
|
272 |
string upmpdcliuser("upmpdcli");
|
196 |
string upmpdcliuser("upmpdcli");
|
273 |
string pidfilename("/var/run/upmpdcli.pid");
|
197 |
string pidfilename("/var/run/upmpdcli.pid");
|
|
|
198 |
string presentationhtml(DATADIR "/presentation.html");
|
274 |
string iface;
|
199 |
string iface;
|
275 |
unsigned short upport = 0;
|
200 |
unsigned short upport = 0;
|
276 |
string upnpip;
|
201 |
string upnpip;
|
277 |
|
202 |
|
278 |
const char *cp;
|
203 |
const char *cp;
|
|
... |
|
... |
364 |
}
|
289 |
}
|
365 |
if (config.get("ohmetapersist", value)) {
|
290 |
if (config.get("ohmetapersist", value)) {
|
366 |
ohmetapersist = atoi(value.c_str()) != 0;
|
291 |
ohmetapersist = atoi(value.c_str()) != 0;
|
367 |
}
|
292 |
}
|
368 |
config.get("iconpath", iconpath);
|
293 |
config.get("iconpath", iconpath);
|
|
|
294 |
config.get("presentationhtml", presentationhtml);
|
369 |
config.get("cachedir", cachedir);
|
295 |
config.get("cachedir", cachedir);
|
370 |
if (!(op_flags & OPT_i)) {
|
296 |
if (!(op_flags & OPT_i)) {
|
371 |
config.get("upnpiface", iface);
|
297 |
config.get("upnpiface", iface);
|
372 |
if (iface.empty()) {
|
298 |
if (iface.empty()) {
|
373 |
config.get("upnpip", upnpip);
|
299 |
config.get("upnpip", upnpip);
|
|
... |
|
... |
534 |
}
|
460 |
}
|
535 |
|
461 |
|
536 |
// Create unique ID
|
462 |
// Create unique ID
|
537 |
string UUID = LibUPnP::makeDevUUID(friendlyname, hwaddr);
|
463 |
string UUID = LibUPnP::makeDevUUID(friendlyname, hwaddr);
|
538 |
|
464 |
|
539 |
// Read our XML data to make it available from the virtual directory
|
465 |
// Initialize the data we serve through HTTP (device and service
|
540 |
if (openhome) {
|
466 |
// descriptions, icons, presentation page, etc.)
|
541 |
if (!g_sc2mpd_path.empty()) {
|
|
|
542 |
ohxmlfilenames.push_back("OHReceiver.xml");
|
|
|
543 |
}
|
|
|
544 |
xmlfilenames.insert(xmlfilenames.end(), ohxmlfilenames.begin(),
|
|
|
545 |
ohxmlfilenames.end());
|
|
|
546 |
}
|
|
|
547 |
|
|
|
548 |
{
|
|
|
549 |
string protofile = path_cat(datadir, "protocolinfo.txt");
|
|
|
550 |
if (!read_protocolinfo(protofile, upmpdProtocolInfo)) {
|
|
|
551 |
LOGFAT("Failed reading protocol info from " << protofile << endl);
|
|
|
552 |
return 1;
|
|
|
553 |
}
|
|
|
554 |
}
|
|
|
555 |
|
|
|
556 |
string reason;
|
|
|
557 |
|
|
|
558 |
string icondata;
|
|
|
559 |
if (!iconpath.empty()) {
|
|
|
560 |
if (!file_to_string(iconpath, icondata, &reason)) {
|
|
|
561 |
LOGERR("Failed reading " << iconpath << " : " << reason << endl);
|
|
|
562 |
}
|
|
|
563 |
}
|
|
|
564 |
|
|
|
565 |
unordered_map<string, VDirContent> files;
|
467 |
unordered_map<string, VDirContent> files;
|
566 |
string dir("/upmpd/");
|
468 |
if (!initHttpFs(files, datadir, UUID, friendlyname, openhome, iconpath,
|
567 |
for (unsigned int i = 0; i < xmlfilenames.size(); i++) {
|
469 |
presentationhtml)) {
|
568 |
string filename = path_cat(datadir, xmlfilenames[i]);
|
470 |
exit(1);
|
569 |
string data;
|
|
|
570 |
if (!file_to_string(filename, data, &reason)) {
|
|
|
571 |
LOGFAT("Failed reading " << filename << " : " << reason << endl);
|
|
|
572 |
return 1;
|
|
|
573 |
}
|
|
|
574 |
if (i == 0) {
|
|
|
575 |
// Special for description: set UUID and friendlyname
|
|
|
576 |
data = regsub1("@UUID@", data, UUID);
|
|
|
577 |
data = regsub1("@FRIENDLYNAME@", data, friendlyname);
|
|
|
578 |
if (openhome) {
|
|
|
579 |
if (!g_sc2mpd_path.empty()) {
|
|
|
580 |
ohDesc += ohDescReceive;
|
|
|
581 |
}
|
|
|
582 |
data = regsub1("@OPENHOME@", data, ohDesc);
|
|
|
583 |
} else {
|
|
|
584 |
data = regsub1("@OPENHOME@", data, "");
|
|
|
585 |
}
|
|
|
586 |
if (!icondata.empty())
|
|
|
587 |
data = regsub1("@ICONLIST@", data, iconDesc);
|
|
|
588 |
else
|
|
|
589 |
data = regsub1("@ICONLIST@", data, "");
|
|
|
590 |
}
|
|
|
591 |
files.insert(pair<string, VDirContent>
|
|
|
592 |
(dir + xmlfilenames[i],
|
|
|
593 |
VDirContent(data, "application/xml")));
|
|
|
594 |
}
|
|
|
595 |
|
|
|
596 |
if (!icondata.empty()) {
|
|
|
597 |
files.insert(pair<string, VDirContent>
|
|
|
598 |
(dir + "icon.png", VDirContent(icondata, "image/png")));
|
|
|
599 |
}
|
471 |
}
|
600 |
|
472 |
|
601 |
if (ownqueue)
|
473 |
if (ownqueue)
|
602 |
opts.options |= UpMpd::upmpdOwnQueue;
|
474 |
opts.options |= UpMpd::upmpdOwnQueue;
|
603 |
if (openhome)
|
475 |
if (openhome)
|