Switch to unified view

a/scctl_src/scctl.cpp b/scctl_src/scctl.cpp
...
...
24
 * will just keep playing the same URI), or tell a Receiver to return
24
 * will just keep playing the same URI), or tell a Receiver to return
25
 * to Playlist operation.
25
 * to Playlist operation.
26
 * 
26
 * 
27
 * To avoid encurring a discovery timeout for each op, there is a
27
 * To avoid encurring a discovery timeout for each op, there is a
28
 * server mode, in which a permanent process executes the above
28
 * server mode, in which a permanent process executes the above
29
 * commands, received on Unix socket, and returns the results.
29
 * commands, received on Unix socket, and returns the results. The
30
 * Unix socket name is based on the uid, so there is one per active
31
 * user.
30
 *
32
 *
31
 * When executing any of the ops from the command line, the program
33
 * When executing any of the ops from the command line, the program
32
 * first tries to contact the server, and does things itself if no
34
 * first tries to contact the server, and does things itself if no
33
 * server is found (encurring 2-3 S of timeout in the latter case).
35
 * server is found (encurring 2-3 S of timeout in the latter case).
34
 */
36
 */
...
...
57
59
58
using namespace UPnPClient;
60
using namespace UPnPClient;
59
using namespace UPnPP;
61
using namespace UPnPP;
60
using namespace std;
62
using namespace std;
61
using namespace Songcast;
63
using namespace Songcast;
64
65
#ifdef LIBUPNPP_VERSION_MAJOR
66
#if LIBUPNPP_AT_LEAST(0,16,0)
67
#define HAVE_SETSOURCEINDEX_IN_LINN
68
#endif
69
#endif
62
70
63
#define OPT_L 0x1
71
#define OPT_L 0x1
64
#define OPT_S 0x2
72
#define OPT_S 0x2
65
#define OPT_f 0x4
73
#define OPT_f 0x4
66
#define OPT_h 0x8
74
#define OPT_h 0x8
...
...
117
        out << endl;
125
        out << endl;
118
    }
126
    }
119
    return out.str();
127
    return out.str();
120
}
128
}
121
129
130
int dosomething(int opflags, const vector<string>& args, string& out)
131
{
132
    if (opflags & OPT_l) {
133
        out = showReceivers(opflags);
134
    } else if (opflags & OPT_L) {
135
        out = showSenders(opflags);
136
    } else if (opflags & OPT_r) {
137
        if (args.size() < 2)
138
            return 1;
139
        setReceiversFromSender(args[0], vector<string>(args.begin() + 1,
140
                                                       args.end()));
141
    } else if (opflags & OPT_s) {
142
        if (args.size() < 2)
143
            return 1;
144
        setReceiversFromSender(args[0], vector<string>(args.begin() + 1,
145
                                                       args.end()));
146
    } else if (opflags & OPT_x) {
147
        if (args.size() < 1)
148
            return 1;
149
        stopReceivers(args);
150
#ifdef HAVE_SETSOURCEINDEX_IN_LINN
151
    } else if ((opflags & OPT_i)) {
152
        if (args.size() < 2)
153
            return 1;
154
        setSourceIndex(args[0], std::stoi(args[1]));
155
    } else if ((opflags & OPT_I)) {
156
        if (args.size() < 2)
157
            return 1;
158
        setSourceIndexByName(args[0], args[1]);
159
#endif
160
    }
161
    return 0;
162
}
163
122
static char *thisprog;
164
static char *thisprog;
123
static char usage [] =
165
static char usage [] =
124
" -l List renderers with Songcast Receiver capability\n"
166
" -l List renderers with Songcast Receiver capability\n"
125
" -L List Songcast Senders\n"
167
" -L List Songcast Senders\n"
126
"   -m : for above modes: use parseable format\n"
168
"   -m : for above modes: use parseable format\n"
127
"For the following options the renderers can be designated by their \n"
169
"For the following options the renderers can be designated by their \n"
128
"uid (safer) or friendly name\n"
170
"uid (safer) or friendly name\n"
171
#ifdef HAVE_SETSOURCEINDEX_IN_LINN
129
" -i <renderer> i : set source index\n"
172
" -i <renderer> i : set source index\n"
130
" -I <renderer> name : set source index by name\n"
173
" -I <renderer> name : set source index by name\n"
174
#endif
131
" -s <master> <slave> [slave ...] : Set up the slaves renderers as Songcast\n"
175
" -s <master> <slave> [slave ...] : Set up the slaves renderers as Songcast\n"
132
"    Receivers and make them play from the same uri as the master receiver\n"
176
"    Receivers and make them play from the same uri as the master receiver\n"
133
" -x <renderer> [renderer ...] Reset renderers from Songcast to Playlist\n"
177
" -x <renderer> [renderer ...] Reset renderers from Songcast to Playlist\n"
134
" -r <sender> <renderer> <renderer> : set up the renderers in Receiver mode\n"
178
" -r <sender> <renderer> <renderer> : set up the renderers in Receiver mode\n"
135
"    playing data from the sender. This is like -s but we get the uri from \n"
179
"    playing data from the sender. This is like -s but we get the uri from \n"
...
...
163
    int ret;
207
    int ret;
164
    while ((ret = getopt(argc, argv, "fhmLlrsSxiI")) != -1) {
208
    while ((ret = getopt(argc, argv, "fhmLlrsSxiI")) != -1) {
165
        switch (ret) {
209
        switch (ret) {
166
        case 'f': op_flags |= OPT_f; break;
210
        case 'f': op_flags |= OPT_f; break;
167
        case 'h': Usage(stdout); break;
211
        case 'h': Usage(stdout); break;
168
        case 'l':
212
        case 'l': op_flags |= OPT_l; break;
169
            op_flags |= OPT_l;
213
        case 'L': op_flags |= OPT_L; break;
170
            break;
214
        case 'm': op_flags |= OPT_m; break;
171
        case 'L':
215
        case 'r': op_flags |= OPT_r; break;
172
            op_flags |= OPT_L;
216
        case 's': op_flags |= OPT_s; break;
173
            break;
217
        case 'S': op_flags |= OPT_S; break;
174
        case 'm':
218
        case 'x': op_flags |= OPT_x; break;
175
            op_flags |= OPT_m;
219
        case 'i': op_flags |= OPT_i; break;
176
            break;
220
        case 'I': op_flags |= OPT_I; break;
177
        case 'r':
178
            op_flags |= OPT_r;
179
            break;
180
        case 's':
181
            op_flags |= OPT_s;
182
            break;
183
        case 'S':
184
            op_flags |= OPT_S;
185
            break;
186
        case 'x':
187
            op_flags |= OPT_x;
188
            break;
189
        case 'i':
190
            op_flags |= OPT_i;
191
            break;
192
        case 'I':
193
            op_flags |= OPT_I;
194
            break;
195
        default: Usage();
221
        default: Usage();
196
        }
222
        }
197
    }
223
    }
198
    //fprintf(stderr, "argc %d optind %d flgs: 0x%x\n", argc, optind, op_flags);
199
224
200
    // If we're not a server, try to contact one to avoid the
225
    // If we're not to become a server, try to contact one to avoid
201
    // discovery timeout
226
    // the discovery timeout
202
    if (!(op_flags & OPT_S) && tryserver(op_flags, argc -optind, 
227
    if (!(op_flags & OPT_S) && tryserver(op_flags, argc - optind, 
203
                                         &argv[optind])) {
228
                                         &argv[optind])) {
204
        exit(0);
229
        exit(0);
205
    }
230
    }
206
231
207
    // At least one action needed. 
232
    // At least one action needed. 
208
    if ((op_flags & ~(OPT_f|OPT_m)) == 0)
233
    if ((op_flags & ~(OPT_f|OPT_m)) == 0)
209
        Usage();
234
        Usage();
210
235
236
    // Logger::getTheLog("stderr")->setLogLevel(Logger::LLDEB0);
237
211
    LibUPnP *mylib = LibUPnP::getLibUPnP();
238
    LibUPnP *mylib = LibUPnP::getLibUPnP();
212
    if (!mylib) {
239
    if (!mylib) {
213
        cerr << "Can't get LibUPnP" << endl;
240
        cerr << "Can't get LibUPnP" << endl;
214
        return 1;
241
        return 1;
215
    }
242
    }
...
...
222
249
223
    vector<string> args;
250
    vector<string> args;
224
    while (optind < argc) {
251
    while (optind < argc) {
225
        args.push_back(argv[optind++]);
252
        args.push_back(argv[optind++]);
226
    }
253
    }
227
    
254
228
    if ((op_flags & OPT_l)) {
255
    if ((op_flags & OPT_S)) {
229
        if (args.size())
230
            Usage();
231
        string out = showReceivers(op_flags);
232
        cout << out;
233
    } else if ((op_flags & OPT_L)) {
234
        if (args.size())
235
            Usage();
236
        string out = showSenders(op_flags);
237
        cout << out;
238
    } else if ((op_flags & OPT_r)) {
239
        if (args.size() < 2)
240
            Usage();
241
        setReceiversFromSender(args[0], vector<string>(args.begin() + 1,
242
                                                       args.end()));
243
    } else if ((op_flags & OPT_s)) {
244
        if (args.size() < 2)
245
            Usage();
246
        setReceiversFromReceiver(args[0], vector<string>(args.begin()+1,
247
                                                         args.end()));
248
    } else if ((op_flags & OPT_x)) {
249
        if (args.size() < 1)
250
            Usage();
251
        stopReceivers(args);
252
    } else if ((op_flags & OPT_i)) {
253
        if (args.size() < 2)
254
            Usage();
255
        setSourceIndex(args[0], std::stoi(args[1]));
256
    } else if ((op_flags & OPT_I)) {
257
        if (args.size() < 2)
258
            Usage();
259
        setSourceIndexByName(args[0], args[1]);
260
    } else if ((op_flags & OPT_S)) {
261
        exit(runserver());
256
        exit(runserver());
262
    } else {
257
    } else {
258
        string out;
259
        if (dosomething(op_flags, args, out)) {
263
        Usage();
260
            Usage();
261
        }
262
        cout << out;
264
    }
263
    }
265
264
266
    // If we get here, we have executed a local command. If -f is set,
265
    // If we get here, we have executed a local command. If -f is set,
267
    // fork and run the server code so that a next execution will use
266
    // fork and run the server code so that a next execution will use
268
    // this instead (and not incur the discovery timeout)
267
    // this instead (and not incur the discovery timeout)
...
...
272
            runserver();
271
            runserver();
273
    } 
272
    } 
274
    return 0;
273
    return 0;
275
}
274
}
276
275
276
277
// The Unix socket path which we use for client-server operation
277
// The Unix socket path which we use for client-server operation
278
bool sockname(string& nm)
278
bool sockname(string& nm)
279
{
279
{
280
    char buf[80];
280
    char buf[80];
281
    sprintf(buf, "/tmp/scctl%d", int(getuid()));
281
    sprintf(buf, "/tmp/scctl%d", int(getuid()));
...
...
333
        }
333
        }
334
    }
334
    }
335
    return true;
335
    return true;
336
}
336
}
337
337
338
static vector<string> argvtov(char *argv[])
339
{
340
    vector<string> out;
341
    while (argv && *argv) {
342
        out.push_back(*argv++);
343
    }
344
    return out;
345
}
346
338
bool tryserver(int opflags, int argc, char **argv)
347
bool tryserver(int opflags, int argc, char *argv[])
339
{
348
{
340
    char opts[30];
349
    char opts[30];
341
    sprintf(opts, "0x%x", opflags);
350
    sprintf(opts, "0x%x", opflags);
342
    string cmd(opts);
351
    string cmd(opts);
343
    cmd += " ";
352
    cmd += " ";
344
        
353
    vector<string> va = argvtov(argv);
345
    for (int i = 0; i < argc; i++) {
354
    cmd += stringsToString(va);
346
        // May need quoting here ? 
347
        cmd  += argv[i]; 
348
        cmd += " ";
349
    }
350
    cmd += "\n";
355
    cmd += "\n";
351
    return tryserver(cmd);
356
    return tryserver(cmd);
352
}
357
}
353
358
354
359
...
...
372
    std::unique_ptr<Netcon> conhold(con);
377
    std::unique_ptr<Netcon> conhold(con);
373
378
374
    // Get command
379
    // Get command
375
    string line;
380
    string line;
376
    {
381
    {
382
        const int LL(10240);
377
        char buf[2048];
383
        char buf[LL];
378
        if  (con->getline(buf, 2048, 2) <= 0) {
384
        if  (con->getline(buf, LL, 2) <= 0) {
379
            LOGERR("scctl: server: getline() failed\n");
385
            LOGERR("scctl: server: getline() failed\n");
380
            return 1;
386
            return 1;
381
        }
387
        }
382
        line = buf;
388
        line = buf;
383
    }
389
    }
384
385
    trimstring(line, " \n");
390
    trimstring(line, " \n");
386
387
    LOGDEB1("scctl: server: got cmd: " << line << endl);
391
    LOGDEB1("scctl: server: got cmd: " << line << endl);
388
392
389
    vector<string> toks;
393
    vector<string> args;
390
    stringToTokens(line, toks);
394
    stringToStrings(line, args);
391
    if (toks.empty()) {
395
    if (args.empty()) {
392
        return 1;
396
        return 1;
393
    }
397
    }
394
398
395
    int opflags = strtoul(toks[0].c_str(), 0, 0);
399
    int opflags = strtoul(args[0].c_str(), 0, 0);
396
400
    args.erase(args.begin());
397
    string out;
401
    string out;
398
    if (opflags & OPT_p) {
402
    if (opflags & OPT_p) {
399
        // ping
403
        // ping
400
        out = "Ok\n";
404
        out = "Ok\n";
401
    } else if (opflags & OPT_l) {
402
        out = showReceivers(opflags);
403
    } else if (opflags & OPT_L) {
404
        out = showSenders(opflags);
405
    } else if (opflags & OPT_s) {
406
        if (toks.size() < 3)
407
            return 1;
408
        vector<string>::iterator beg = toks.begin();
409
        beg++;
410
        string master = *beg;
411
        beg++;
412
        vector<string> slaves(beg, toks.end());
413
        ReceiverState mst;
414
        getReceiverState(master, mst);
415
        for (auto it = slaves.begin(); it != slaves.end(); it++) {
416
            ReceiverState st;
417
            getReceiverState(*it, st);
418
            setReceiverPlaying(st, mst.uri, mst.meta);
419
        }
420
    } else if (opflags & OPT_x) {
421
        if (toks.size() < 2)
422
            return 1;
423
        vector<string>::iterator beg = toks.begin();
424
        beg++;
425
        vector<string> slaves(beg, toks.end());
426
        stopReceivers(slaves);
427
    } else if (opflags & OPT_r) {
428
        if (toks.size() < 3)
429
            return 1;
430
        vector<string>::iterator beg = toks.begin();
431
        beg++;
432
        string sender = *beg;
433
        beg++;
434
        vector<string> receivers(beg, toks.end());
435
        setReceiversFromSender(sender, receivers);
436
    } else {
405
    } else {
437
        LOGERR("scctl: server: bad cmd:" << toks[0] << endl);
406
        dosomething(opflags, args, out);
438
        return 1;
439
    }
407
    }
440
408
441
    if (con->send(out.c_str(), out.size(), 0) < 0) {
409
    if (con->send(out.c_str(), out.size(), 0) < 0) {
442
        LOGERR("scctl: server: send() failed\n");
410
        LOGERR("scctl: server: send() failed\n");
443
        return 1;
411
        return 1;