Switch to unified view

a/src/upmpd.cxx b/src/upmpd.cxx
...
...
49
#include "execmd.h"
49
#include "execmd.h"
50
50
51
using namespace std;
51
using namespace std;
52
using namespace std::placeholders;
52
using namespace std::placeholders;
53
using namespace UPnPP;
53
using namespace UPnPP;
54
55
static const string dfltFriendlyName("UpMpd");
56
string upmpdProtocolInfo;
57
58
// Is sc2mpd (songcast-to-HTTP command) installed ? We only create
59
// an OpenHome Receiver service if it is. This is checked when
60
// starting up
61
static bool has_sc2mpd(false);
62
63
static UpnpDevice *dev;
64
65
static void onsig(int)
66
{
67
    LOGDEB("Got sig" << endl);
68
    dev->shouldExit();
69
}
70
71
static const int catchedSigs[] = {SIGINT, SIGQUIT, SIGTERM};
72
73
static void setupsigs()
74
{
75
    struct sigaction action;
76
    action.sa_handler = onsig;
77
    action.sa_flags = 0;
78
    sigemptyset(&action.sa_mask);
79
    for (unsigned int i = 0; i < sizeof(catchedSigs) / sizeof(int); i++)
80
        if (signal(catchedSigs[i], SIG_IGN) != SIG_IGN) {
81
            if (sigaction(catchedSigs[i], &action, 0) < 0) {
82
                perror("Sigaction failed");
83
            }
84
        }
85
}
86
54
87
// Note: if we ever need this to work without cxx11, there is this:
55
// Note: if we ever need this to work without cxx11, there is this:
88
// http://www.tutok.sk/fastgl/callback.html
56
// http://www.tutok.sk/fastgl/callback.html
89
//
57
//
90
// Note that there is a problem in the order in which we do things
58
// Note that there is a problem in the order in which we do things
...
...
111
    UpMpdRenderCtl *rdctl = new UpMpdRenderCtl(this);
79
    UpMpdRenderCtl *rdctl = new UpMpdRenderCtl(this);
112
    m_services.push_back(rdctl);
80
    m_services.push_back(rdctl);
113
    UpMpdAVTransport* avt = new UpMpdAVTransport(this);
81
    UpMpdAVTransport* avt = new UpMpdAVTransport(this);
114
    m_services.push_back(avt);
82
    m_services.push_back(avt);
115
    m_services.push_back(new UpMpdConMan(this));
83
    m_services.push_back(new UpMpdConMan(this));
84
    bool ohReceiver = (m_options & upmpdOhReceiver) != 0; 
116
    if (m_options & upmpdDoOH) {
85
    if (m_options & upmpdDoOH) {
117
        m_services.push_back(new OHProduct(this, friendlyname, has_sc2mpd));
86
        m_services.push_back(new OHProduct(this, friendlyname, ohReceiver));
118
        m_services.push_back(new OHInfo(this));
87
        m_services.push_back(new OHInfo(this));
119
        m_services.push_back(new OHTime(this));
88
        m_services.push_back(new OHTime(this));
120
        m_services.push_back(new OHVolume(this, rdctl));
89
        m_services.push_back(new OHVolume(this, rdctl));
121
        OHPlaylist *ohp = new OHPlaylist(this, rdctl, opts.ohmetasleep);
90
        OHPlaylist *ohp = new OHPlaylist(this, rdctl, opts.ohmetasleep);
122
        m_services.push_back(ohp);
91
        m_services.push_back(ohp);
123
        if (avt)
92
        if (avt)
124
            avt->setOHP(ohp);
93
            avt->setOHP(ohp);
125
        if (has_sc2mpd) {
94
        if (ohReceiver) {
126
            m_services.push_back(new OHReceiver(this, ohp, opts.schttpport));
95
            m_services.push_back(new OHReceiver(this, ohp, opts.schttpport));
127
        }
96
        }
128
    }
97
    }
129
}
98
}
130
99
...
...
145
/////////////////////////////////////////////////////////////////////
114
/////////////////////////////////////////////////////////////////////
146
// Main program
115
// Main program
147
116
148
#include "conftree.hxx"
117
#include "conftree.hxx"
149
118
119
static char *thisprog;
120
121
static int op_flags;
122
#define OPT_MOINS 0x1
123
#define OPT_h     0x2
124
#define OPT_p     0x4
125
#define OPT_d     0x8
126
#define OPT_D     0x10
127
#define OPT_c     0x20
128
#define OPT_l     0x40
129
#define OPT_f     0x80
130
#define OPT_q     0x100
131
#define OPT_i     0x200
132
#define OPT_P     0x400
133
#define OPT_O     0x800
134
135
static const char usage[] = 
136
    "-c configfile \t configuration file to use\n"
137
    "-h host    \t specify host MPD is running on\n"
138
    "-p port     \t specify MPD port\n"
139
    "-d logfilename\t debug messages to\n"
140
    "-l loglevel\t  log level (0-6)\n"
141
    "-D    \t run as a daemon\n"
142
    "-f friendlyname\t define device displayed name\n"
143
    "-q 0|1\t if set, we own the mpd queue, else avoid clearing it whenever we feel like it\n"
144
    "-i iface    \t specify network interface name to be used for UPnP\n"
145
    "-P upport    \t specify port number to be used for UPnP\n"
146
    "-O 0|1\t decide if we run and export the OpenHome services\n"
147
    "\n"
148
    ;
149
150
static void
151
Usage(void)
152
{
153
    fprintf(stderr, "%s: usage:\n%s", thisprog, usage);
154
    exit(1);
155
}
156
157
// The description XML document is the first thing downloaded by
158
// clients and tells them what services we export, and where to find
159
// them.
150
static string ohDesc(
160
static string ohDesc(
151
    "<service>"
161
    "<service>"
152
    "  <serviceType>urn:av-openhome-org:service:Product:1</serviceType>"
162
    "  <serviceType>urn:av-openhome-org:service:Product:1</serviceType>"
153
    "  <serviceId>urn:av-openhome-org:serviceId:Product</serviceId>"
163
    "  <serviceId>urn:av-openhome-org:serviceId:Product</serviceId>"
154
    "  <SCPDURL>/OHProduct.xml</SCPDURL>"
164
    "  <SCPDURL>/OHProduct.xml</SCPDURL>"
...
...
182
    "  <SCPDURL>/OHPlaylist.xml</SCPDURL>"
192
    "  <SCPDURL>/OHPlaylist.xml</SCPDURL>"
183
    "  <controlURL>/ctl/OHPlaylist</controlURL>"
193
    "  <controlURL>/ctl/OHPlaylist</controlURL>"
184
    "  <eventSubURL>/evt/OHPlaylist</eventSubURL>"
194
    "  <eventSubURL>/evt/OHPlaylist</eventSubURL>"
185
    "</service>"
195
    "</service>"
186
    );
196
    );
197
198
// We only advertise the Openhome Receiver service if the sc2mpd
199
// songcast-to-mpd gateway command is available
187
static string ohDescReceive(
200
static string ohDescReceive(
188
    "<service>"
201
    "<service>"
189
    "  <serviceType>urn:av-openhome-org:service:Receiver:1</serviceType>"
202
    "  <serviceType>urn:av-openhome-org:service:Receiver:1</serviceType>"
190
    "  <serviceId>urn:av-openhome-org:serviceId:Receiver</serviceId>"
203
    "  <serviceId>urn:av-openhome-org:serviceId:Receiver</serviceId>"
191
    "  <SCPDURL>/OHReceiver.xml</SCPDURL>"
204
    "  <SCPDURL>/OHReceiver.xml</SCPDURL>"
...
...
204
    "    <url>/icon.png</url>"
217
    "    <url>/icon.png</url>"
205
    "  </icon>"
218
    "  </icon>"
206
    "</iconList>"
219
    "</iconList>"
207
    );
220
    );
208
221
209
static char *thisprog;
210
211
static int op_flags;
212
#define OPT_MOINS 0x1
213
#define OPT_h     0x2
214
#define OPT_p     0x4
215
#define OPT_d     0x8
216
#define OPT_D     0x10
217
#define OPT_c     0x20
218
#define OPT_l     0x40
219
#define OPT_f     0x80
220
#define OPT_q     0x100
221
#define OPT_i     0x200
222
#define OPT_P     0x400
223
#define OPT_O     0x800
224
225
static const char usage[] = 
226
    "-c configfile \t configuration file to use\n"
227
    "-h host    \t specify host MPD is running on\n"
228
    "-p port     \t specify MPD port\n"
229
    "-d logfilename\t debug messages to\n"
230
    "-l loglevel\t  log level (0-6)\n"
231
    "-D    \t run as a daemon\n"
232
    "-f friendlyname\t define device displayed name\n"
233
    "-q 0|1\t if set, we own the mpd queue, else avoid clearing it whenever we feel like it\n"
234
    "-i iface    \t specify network interface name to be used for UPnP\n"
235
    "-P upport    \t specify port number to be used for UPnP\n"
236
    "-O 0|1\t decide if we run and export the OpenHome services\n"
237
    "\n"
238
    ;
239
static void
240
Usage(void)
241
{
242
    fprintf(stderr, "%s: usage:\n%s", thisprog, usage);
243
    exit(1);
244
}
245
246
static string myDeviceUUID;
247
248
static string datadir(DATADIR "/");
249
static string configdir(CONFIGDIR "/");
250
251
// Our XML description data. !Keep description.xml first!
222
// Our XML description data. !Keep description.xml first!
252
static vector<const char *> xmlfilenames = 
223
static vector<const char *> xmlfilenames = 
253
{
224
{
254
    /* keep first */ "description.xml", /* keep first */
225
    /* keep first */ "description.xml", /* keep first */
255
    "RenderingControl.xml", "AVTransport.xml", "ConnectionManager.xml",
226
    "RenderingControl.xml", "AVTransport.xml", "ConnectionManager.xml",
...
...
258
{
229
{
259
    "OHProduct.xml", "OHInfo.xml", "OHTime.xml", "OHVolume.xml", 
230
    "OHProduct.xml", "OHInfo.xml", "OHTime.xml", "OHVolume.xml", 
260
    "OHPlaylist.xml",
231
    "OHPlaylist.xml",
261
};
232
};
262
233
234
static const string dfltFriendlyName("UpMpd");
235
236
// This is global
237
string upmpdProtocolInfo;
238
239
// Static for cleanup in sig handler.
240
static UpnpDevice *dev;
241
242
static string datadir(DATADIR "/");
243
244
// Global
245
string g_configfilename(CONFIGDIR "/upmpdcli.conf");
246
247
// Path for the sc2mpd command, or empty
248
string g_sc2mpd_path;
249
250
static void onsig(int)
251
{
252
    LOGDEB("Got sig" << endl);
253
    dev->shouldExit();
254
}
255
256
static const int catchedSigs[] = {SIGINT, SIGQUIT, SIGTERM};
257
static void setupsigs()
258
{
259
    struct sigaction action;
260
    action.sa_handler = onsig;
261
    action.sa_flags = 0;
262
    sigemptyset(&action.sa_mask);
263
    for (unsigned int i = 0; i < sizeof(catchedSigs) / sizeof(int); i++)
264
        if (signal(catchedSigs[i], SIG_IGN) != SIG_IGN) {
265
            if (sigaction(catchedSigs[i], &action, 0) < 0) {
266
                perror("Sigaction failed");
267
            }
268
        }
269
}
263
270
264
int main(int argc, char *argv[])
271
int main(int argc, char *argv[])
265
{
272
{
266
    string mpdhost("localhost");
273
    string mpdhost("localhost");
267
    int mpdport = 6600;
274
    int mpdport = 6600;
268
    string mpdpassword;
275
    string mpdpassword;
269
    string logfilename;
276
    string logfilename;
270
    int loglevel(Logger::LLINF);
277
    int loglevel(Logger::LLINF);
271
    string configfile;
272
    string friendlyname(dfltFriendlyName);
278
    string friendlyname(dfltFriendlyName);
273
    bool ownqueue = true;
279
    bool ownqueue = true;
274
    bool openhome = true;
280
    bool openhome = true;
275
    bool ohmetapersist = true;
281
    bool ohmetapersist = true;
276
    string upmpdcliuser("upmpdcli");
282
    string upmpdcliuser("upmpdcli");
...
...
285
    if ((cp = getenv("UPMPD_PORT")))
291
    if ((cp = getenv("UPMPD_PORT")))
286
        mpdport = atoi(cp);
292
        mpdport = atoi(cp);
287
    if ((cp = getenv("UPMPD_FRIENDLYNAME")))
293
    if ((cp = getenv("UPMPD_FRIENDLYNAME")))
288
        friendlyname = atoi(cp);
294
        friendlyname = atoi(cp);
289
    if ((cp = getenv("UPMPD_CONFIG")))
295
    if ((cp = getenv("UPMPD_CONFIG")))
290
        configfile = cp;
296
        g_configfilename = cp;
291
    if ((cp = getenv("UPMPD_UPNPIFACE")))
297
    if ((cp = getenv("UPMPD_UPNPIFACE")))
292
        iface = cp;
298
        iface = cp;
293
    if ((cp = getenv("UPMPD_UPNPPORT")))
299
    if ((cp = getenv("UPMPD_UPNPPORT")))
294
        upport = atoi(cp);
300
        upport = atoi(cp);
295
301
...
...
300
        if (!(**argv))
306
        if (!(**argv))
301
            Usage();
307
            Usage();
302
        while (**argv)
308
        while (**argv)
303
            switch (*(*argv)++) {
309
            switch (*(*argv)++) {
304
            case 'c':   op_flags |= OPT_c; if (argc < 2)  Usage();
310
            case 'c':   op_flags |= OPT_c; if (argc < 2)  Usage();
305
                configfile = *(++argv); argc--; goto b1;
311
                g_configfilename = *(++argv); argc--; goto b1;
306
            case 'D':   op_flags |= OPT_D; break;
312
            case 'D':   op_flags |= OPT_D; break;
307
            case 'd':   op_flags |= OPT_d; if (argc < 2)  Usage();
313
            case 'd':   op_flags |= OPT_d; if (argc < 2)  Usage();
308
                logfilename = *(++argv); argc--; goto b1;
314
                logfilename = *(++argv); argc--; goto b1;
309
            case 'f':   op_flags |= OPT_f; if (argc < 2)  Usage();
315
            case 'f':   op_flags |= OPT_f; if (argc < 2)  Usage();
310
                friendlyname = *(++argv); argc--; goto b1;
316
                friendlyname = *(++argv); argc--; goto b1;
...
...
338
        Usage();
344
        Usage();
339
345
340
    UpMpd::Options opts;
346
    UpMpd::Options opts;
341
347
342
    string iconpath;
348
    string iconpath;
343
    if (!configfile.empty()) {
349
    if (!g_configfilename.empty()) {
344
        ConfSimple config(configfile.c_str(), 1, true);
350
        ConfSimple config(g_configfilename.c_str(), 1, true);
345
        if (!config.ok()) {
351
        if (!config.ok()) {
346
            cerr << "Could not open config: " << configfile << endl;
352
            cerr << "Could not open config: " << g_configfilename << endl;
347
            return 1;
353
            return 1;
348
        }
354
        }
349
        string value;
355
        string value;
350
        if (!(op_flags & OPT_d))
356
        if (!(op_flags & OPT_d))
351
            config.get("logfilename", logfilename);
357
            config.get("logfilename", logfilename);
...
...
378
        if (!(op_flags & OPT_P) && config.get("upnpport", value)) {
384
        if (!(op_flags & OPT_P) && config.get("upnpport", value)) {
379
            upport = atoi(value.c_str());
385
            upport = atoi(value.c_str());
380
        }
386
        }
381
        if (config.get("schttpport", value))
387
        if (config.get("schttpport", value))
382
            opts.schttpport = atoi(value.c_str());
388
            opts.schttpport = atoi(value.c_str());
389
        config.get("sc2mpd", g_sc2mpd_path);
383
        if (config.get("ohmetasleep", value))
390
        if (config.get("ohmetasleep", value))
384
            opts.ohmetasleep = atoi(value.c_str());
391
            opts.ohmetasleep = atoi(value.c_str());
385
    }
392
    }
386
387
    if (Logger::getTheLog(logfilename) == 0) {
393
    if (Logger::getTheLog(logfilename) == 0) {
388
        cerr << "Can't initialize log" << endl;
394
        cerr << "Can't initialize log" << endl;
389
        return 1;
395
        return 1;
390
    }
396
    }
391
    Logger::getTheLog("")->setLogLevel(Logger::LogLevel(loglevel));
397
    Logger::getTheLog("")->setLogLevel(Logger::LogLevel(loglevel));
398
399
    if (g_sc2mpd_path.empty()) {
400
        // Do we have an sc2mpd command installed (for songcast)?
401
        if (!ExecCmd::which("sc2mpd", g_sc2mpd_path))
402
            g_sc2mpd_path.clear();
403
    } else {
404
        if (access(g_sc2mpd_path.c_str(), X_OK|R_OK) != 0) {
405
            LOGERR("Specified path for sc2mpd: " << g_sc2mpd_path << 
406
                   " is not executable" << endl);
407
            g_sc2mpd_path.clear();
408
        }
409
    }
392
410
393
    Pidfile pidfile(pidfilename);
411
    Pidfile pidfile(pidfilename);
394
412
395
    string cachedir;
413
    string cachedir;
396
414
...
...
481
        } else {
499
        } else {
482
            break;
500
            break;
483
        }
501
        }
484
    }
502
    }
485
503
486
    // Do we have an sc2mpd command installed (for songcast)?
487
    string unused;
488
    has_sc2mpd = ExecCmd::which("sc2mpd", unused);
489
490
    // Initialize libupnpp, and check health
504
    // Initialize libupnpp, and check health
491
    LibUPnP *mylib = 0;
505
    LibUPnP *mylib = 0;
492
    string hwaddr;
506
    string hwaddr;
493
    int libretrysecs = 10;
507
    int libretrysecs = 10;
494
    for (;;) {
508
    for (;;) {
...
...
526
    // Create unique ID
540
    // Create unique ID
527
    string UUID = LibUPnP::makeDevUUID(friendlyname, hwaddr);
541
    string UUID = LibUPnP::makeDevUUID(friendlyname, hwaddr);
528
542
529
    // Read our XML data to make it available from the virtual directory
543
    // Read our XML data to make it available from the virtual directory
530
    if (openhome) {
544
    if (openhome) {
531
        if (has_sc2mpd) {
545
        if (!g_sc2mpd_path.empty()) {
532
            ohxmlfilenames.push_back("OHReceiver.xml");
546
            ohxmlfilenames.push_back("OHReceiver.xml");
533
        }
547
        }
534
        xmlfilenames.insert(xmlfilenames.end(), ohxmlfilenames.begin(),
548
        xmlfilenames.insert(xmlfilenames.end(), ohxmlfilenames.begin(),
535
                            ohxmlfilenames.end());
549
                            ohxmlfilenames.end());
536
    }
550
    }
...
...
563
        if (i == 0) {
577
        if (i == 0) {
564
            // Special for description: set UUID and friendlyname
578
            // Special for description: set UUID and friendlyname
565
            data = regsub1("@UUID@", data, UUID);
579
            data = regsub1("@UUID@", data, UUID);
566
            data = regsub1("@FRIENDLYNAME@", data, friendlyname);
580
            data = regsub1("@FRIENDLYNAME@", data, friendlyname);
567
            if (openhome) {
581
            if (openhome) {
568
                if (has_sc2mpd) {
582
                if (!g_sc2mpd_path.empty()) {
569
                    ohDesc += ohDescReceive;
583
                    ohDesc += ohDescReceive;
570
                }
584
                }
571
                data = regsub1("@OPENHOME@", data, ohDesc);
585
                data = regsub1("@OPENHOME@", data, ohDesc);
572
            } else {
586
            } else {
573
                data = regsub1("@OPENHOME@", data, "");
587
                data = regsub1("@OPENHOME@", data, "");
...
...
590
        opts.options |= UpMpd::upmpdOwnQueue;
604
        opts.options |= UpMpd::upmpdOwnQueue;
591
    if (openhome)
605
    if (openhome)
592
        opts.options |= UpMpd::upmpdDoOH;
606
        opts.options |= UpMpd::upmpdDoOH;
593
    if (ohmetapersist)
607
    if (ohmetapersist)
594
        opts.options |= UpMpd::upmpdOhMetaPersist;
608
        opts.options |= UpMpd::upmpdOhMetaPersist;
609
    if (!g_sc2mpd_path.empty())
610
        opts.options |= UpMpd::upmpdOhReceiver;
595
611
596
    // Initialize the UPnP device object.
612
    // Initialize the UPnP device object.
597
    UpMpd device(string("uuid:") + UUID, friendlyname, 
613
    UpMpd device(string("uuid:") + UUID, friendlyname, 
598
                 files, mpdclip, opts);
614
                 files, mpdclip, opts);
599
    dev = &device;
615
    dev = &device;