X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/blobdiff_plain/b60ceb3caecce2c86c484e6173fb1428b71d456a..34fb8c61ac9d00d64a82facbfc16113cc5b6cfd1:/server/server.c diff --git a/server/server.c b/server/server.c index c93701a..844e091 100644 --- a/server/server.c +++ b/server/server.c @@ -1,6 +1,6 @@ /* * This file is part of DisOrder. - * Copyright (C) 2004-2009 Richard Kettlewell + * Copyright (C) 2004-2012 Richard Kettlewell * * 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 @@ -42,6 +42,7 @@ int wideopen; struct listener { const char *name; int pf; + int privileged; }; struct conn; @@ -117,6 +118,12 @@ struct conn { void *body_u; /** @brief Accumulating body */ struct vector body[1]; + + /** @brief Nonzero if an active RTP request exists */ + int rtp_requested; + + /** @brief RTP destination (if @ref rtp_requested is nonzero) */ + struct sockaddr_storage rtp_destination; }; /** @brief Linked list of connections */ @@ -140,10 +147,18 @@ static int command(struct conn *c, char *line); static const char *noyes[] = { "no", "yes" }; -/** @brief Remove a connection from the connection list */ +/** @brief Remove a connection from the connection list + * + * This is a good place for cleaning things up when connections are closed for + * any reason. + */ static void remove_connection(struct conn *c) { struct conn **cc; + if(c->rtp_requested) { + rtp_request_cancel(&c->rtp_destination); + c->rtp_requested = 0; + } for(cc = &connections; *cc && *cc != c; cc = &(*cc)->next) ; if(*cc) @@ -589,7 +604,7 @@ static int c_user(struct conn *c, /* check whether the response is right */ res = authhash(c->nonce, sizeof c->nonce, password, config->authorization_algorithm); - if(wideopen || (res && !strcmp(res, vec[1]))) { + if(wideopen || c->l->privileged || (res && !strcmp(res, vec[1]))) { c->who = vec[0]; c->rights = rights; /* currently we only bother logging remote connections */ @@ -669,9 +684,10 @@ static int files_dirs(struct conn *c, char **vec, int nvec, enum trackdb_listable what) { - const char *dir, *re, *errstr; - int erroffset; - pcre *rec; + const char *dir, *re; + char errstr[RXCERR_LEN]; + size_t erroffset; + regexp *rec; char **fvec, *key; switch(nvec) { @@ -702,8 +718,8 @@ static int files_dirs(struct conn *c, } else { /* Cache miss, we'll do the lookup and key != 0 so we'll store the answer * in the cache. */ - if(!(rec = pcre_compile(re, PCRE_CASELESS|PCRE_UTF8, - &errstr, &erroffset, 0))) { + if(!(rec = regexp_compile(re, RXF_CASELESS, + errstr, sizeof(errstr), &erroffset))) { sink_printf(ev_writer_sink(c->w), "550 Error compiling regexp: %s\n", errstr); return 1; @@ -1215,15 +1231,65 @@ static int c_rtp_address(struct conn *c, if(api == &uaudio_rtp) { char **addr; - netaddress_format(&config->broadcast, NULL, &addr); - sink_printf(ev_writer_sink(c->w), "252 %s %s\n", - quoteutf8(addr[1]), - quoteutf8(addr[2])); + if(!strcmp(config->rtp_mode, "request")) + sink_printf(ev_writer_sink(c->w), "252 - -\n"); + else { + netaddress_format(&config->broadcast, NULL, &addr); + sink_printf(ev_writer_sink(c->w), "252 %s %s\n", + quoteutf8(addr[1]), + quoteutf8(addr[2])); + } } else sink_writes(ev_writer_sink(c->w), "550 No RTP\n"); return 1; } +static int c_rtp_cancel(struct conn *c, + char attribute((unused)) **vec, + int attribute((unused)) nvec) { + if(!c->rtp_requested) { + sink_writes(ev_writer_sink(c->w), "550 No active RTP stream\n"); + return 1; + } + rtp_request_cancel(&c->rtp_destination); + c->rtp_requested = 0; + sink_writes(ev_writer_sink(c->w), "250 Cancelled RTP stream\n"); + return 1; +} + +static int c_rtp_request(struct conn *c, + char **vec, + int attribute((unused)) nvec) { + static const struct addrinfo hints = { + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_DGRAM, + .ai_protocol = IPPROTO_UDP, + .ai_flags = AI_NUMERICHOST|AI_NUMERICSERV, + }; + struct addrinfo *res; + int rc = getaddrinfo(vec[0], vec[1], &hints, &res); + if(rc) { + disorder_error(0, "%s port %s: %s", + vec[0], vec[1], gai_strerror(rc)); + sink_writes(ev_writer_sink(c->w), "550 Invalid address\n"); + return 1; + } + disorder_info("%s requested RTP stream to %s %s", c->who, vec[0], vec[1]); + /* TODO might be useful to tighten this up to restrict clients to targetting + * themselves only */ + if(c->rtp_requested) { + rtp_request_cancel(&c->rtp_destination); + c->rtp_requested = 0; + } + memcpy(&c->rtp_destination, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); + rtp_request(&c->rtp_destination); + c->rtp_requested = 1; + sink_writes(ev_writer_sink(c->w), "250 Initiated RTP stream\n"); + // TODO teardown on connection close + return 1; +} + static int c_cookie(struct conn *c, char **vec, int attribute((unused)) nvec) { @@ -1916,6 +1982,8 @@ static const struct server_command { { "resume", 0, 0, c_resume, RIGHT_PAUSE }, { "revoke", 0, 0, c_revoke, RIGHT_READ }, { "rtp-address", 0, 0, c_rtp_address, 0 }, + { "rtp-cancel", 0, 0, c_rtp_cancel, 0 }, + { "rtp-request", 2, 2, c_rtp_request, RIGHT_READ }, { "schedule-add", 3, INT_MAX, c_schedule_add, RIGHT_READ }, { "schedule-del", 1, 1, c_schedule_del, RIGHT_READ }, { "schedule-get", 1, 1, c_schedule_get, RIGHT_READ }, @@ -2136,12 +2204,16 @@ static int listen_callback(ev_source *ev, int server_start(ev_source *ev, int pf, size_t socklen, const struct sockaddr *sa, - const char *name) { + const char *name, + int privileged) { int fd; struct listener *l = xmalloc(sizeof *l); static const int one = 1; - D(("server_init socket %s", name)); + D(("server_init socket %s privileged=%d", name, privileged)); + /* Sanity check */ + if(privileged && pf != AF_UNIX) + disorder_fatal(0, "cannot create a privileged listener on a non-local port"); fd = xsocket(pf, SOCK_STREAM, 0); xsetsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one); if(bind(fd, sa, socklen) < 0) { @@ -2153,6 +2225,7 @@ int server_start(ev_source *ev, int pf, cloexec(fd); l->name = name; l->pf = pf; + l->privileged = privileged; if(ev_listen(ev, fd, listen_callback, l, "server listener")) exit(EXIT_FAILURE); disorder_info("listening on %s", name);