1 // Copyright 2005-2019 The Mumble Developers. All rights reserved.
2 // Use of this source code is governed by a BSD-style license
3 // that can be found in the LICENSE file at the root of the
4 // Mumble source tree or at <https://www.mumble.info/LICENSE>.
5
6 #ifndef Q_MOC_RUN
7 # include <boost/function.hpp>
8 #endif
9
10 #include "murmur_pch.h"
11
12 #include "Mumble.pb.h"
13
14 #include "../Message.h"
15 #include "../Group.h"
16 #include "MurmurGRPCImpl.h"
17 #include "ServerDB.h"
18 #include "ServerUser.h"
19 #include "Server.h"
20 #include "Channel.h"
21 #include "Utils.h"
22
23 #include <chrono>
24
25 #include <QtCore/QStack>
26
27 #include "MurmurRPC.proto.Wrapper.cpp"
28
29 // GRPC system overview
30 // ====================
31 //
32 // Definitions:
33 //
34 // - Completion queue: a mechanism used for handling asynchronous grpc
35 // requests. Whenever you want to do something with grpc (e.g. accept a
36 // remote call, read/write a message), the completion queue manages that
37 // request for you.
38 //
39 // When you wish to perform an asynchronous action, you provide the
40 // completion queue with a unique "tag". This tag used to identify the
41 // request after it has finished.
42 //
43 // To check the status of asynchronous actions that have been added to the
44 // completion queue, you call its "Next" method. Next returns when there is
45 // a finished action in the completion queue. Next provides two output
46 // variables: the completed action's tag, and a boolean, which indicates if
47 // the action was successful. All tags in this project are are
48 // heap-allocated pointers to "boost::function"s that accept a boolean.
49 // After Next returns, the tag pointer is dereferenced, executed with the
50 // success variable, and then freed.
51 //
52 // - Wrapper class: each RPC method that is defined in the .proto has had a
53 // class generated for it (the generator program is located in scripts/).
54 // Each class provides storage for the incoming and outgoing protocol buffer
55 // message, as well as helper methods for registering events with the
56 // completion queue. Each wrapper class also has an "impl(bool)" method;
57 // each one is implemented in this file. This impl method gets executed when
58 // the particular RPC method gets invoked by an RPC client.
59 //
60 // Each wrapper class extends RPCCall. Among other things, RPCCall provides
61 // reference counting for the object. This is needed for memory management,
62 // as the wrapper objects can be used and stored in several locations (this
63 // is only really true for streaming grpc calls).
64 //
65 // The flow of the grpc system is as follows:
66 //
67 // - GRPCStart() is called from murmur's main().
68 // - If an address for the grpc has been set in murmur.ini, the grpc service
69 // begins listening on that address for grpc client connections.
70 // - A new thread is created which handles the grpc completion queue (defined
71 // above). This thread continuously calls the completion queue's Next method
72 // to process the next completed event.
73 // - The wrapper classes' "create" methods are executed, which makes them
74 // invokable by grpc clients.
75 // - With the completion queue now running in the background, murmur
76 // continues starting up.
77 //
78 // - When a grpc client invokes an RPC method, the previously mentioned thread
79 // is notified of this and executes the "tag" (recall, tags are pointers to
80 // functions). The wrapper method "impl(bool)" for the corresponding RPC
81 // method ends up being called. It is important to note that this impl
82 // method gets executed in the main thread. This prevents data corruption
83 // of murmur's data structures without the need of locks.
84 //
85 // Additionally, the execution of tags are wrapped with a try-catch. This
86 // try-catch catches any grpc::Status that is thrown. If one is caught, the
87 // status is automatically sent to the grpc client and the invocation of the
88 // current method is stopped.
89
90 static MurmurRPCImpl *service;
91
GRPCStart()92 void GRPCStart() {
93 const auto &address = meta->mp.qsGRPCAddress;
94 if (address.isEmpty()) {
95 return;
96 }
97 const auto &cert = meta->mp.qsGRPCCert;
98 const auto &key = meta->mp.qsGRPCKey;
99 std::shared_ptr<::grpc::ServerCredentials> credentials;
100 if (cert.isEmpty() || key.isEmpty()) {
101 credentials = ::grpc::InsecureServerCredentials();
102 } else {
103 ::grpc::SslServerCredentialsOptions options;
104 ::grpc::SslServerCredentialsOptions::PemKeyCertPair pair;
105 {
106 QFile file(cert);
107 if (!file.open(QIODevice::ReadOnly)) {
108 qFatal("could not open gRPC certificate file: %s", cert.toStdString().c_str());
109 return;
110 }
111 QTextStream stream(&file);
112 auto contents = stream.readAll();
113 pair.cert_chain = contents.toStdString();
114 }
115 {
116 QFile file(key);
117 if (!file.open(QIODevice::ReadOnly)) {
118 qFatal("could not open gRPC key file: %s", key.toStdString().c_str());
119 return;
120 }
121 QTextStream stream(&file);
122 auto contents = stream.readAll();
123 pair.private_key = contents.toStdString();
124 }
125 options.pem_key_cert_pairs.push_back(pair);
126 credentials = ::grpc::SslServerCredentials(options);
127 }
128
129 service = new MurmurRPCImpl(address, credentials);
130
131 qWarning("GRPC: listening on '%s'", qPrintable(address));
132 }
133
GRPCStop()134 void GRPCStop() {
135 if (service) {
136 delete service;
137 }
138 }
139
MurmurRPCImpl(const QString & address,std::shared_ptr<::grpc::ServerCredentials> credentials)140 MurmurRPCImpl::MurmurRPCImpl(const QString &address, std::shared_ptr<::grpc::ServerCredentials> credentials) {
141 ::grpc::ServerBuilder builder;
142 builder.AddListeningPort(u8(address), credentials);
143 builder.RegisterService(&m_V1Service);
144 m_completionQueue = builder.AddCompletionQueue();
145 m_server = builder.BuildAndStart();
146 meta->connectListener(this);
147 m_isRunning = true;
148 start();
149 }
150
~MurmurRPCImpl()151 MurmurRPCImpl::~MurmurRPCImpl() {
152 void *ignored_tag;
153 bool ignored_ok;
154 m_isRunning = false;
155 m_server->Shutdown(std::chrono::system_clock::now());
156 m_completionQueue->Shutdown();
157 while (m_completionQueue->Next(&ignored_tag, &ignored_ok)) {
158 if (ignored_tag) {
159 auto op = static_cast<boost::function<void(bool)> *>(ignored_tag);
160 delete op;
161 }
162 }
163 }
164
165 // ToRPC/FromRPC methods convert data to/from grpc protocol buffer messages.
ToRPC(const::Server * srv,const::Channel * c,::MurmurRPC::Channel * rc)166 void ToRPC(const ::Server *srv, const ::Channel *c, ::MurmurRPC::Channel *rc) {
167 rc->mutable_server()->set_id(srv->iServerNum);
168
169 rc->set_id(c->iId);
170 rc->set_name(u8(c->qsName));
171 if (c->cParent) {
172 rc->mutable_parent()->mutable_server()->set_id(srv->iServerNum);
173 rc->mutable_parent()->set_id(c->cParent->iId);
174 }
175 rc->set_description(u8(c->qsDesc));
176 rc->set_position(c->iPosition);
177 foreach(::Channel *chn, c->qsPermLinks) {
178 ::MurmurRPC::Channel *linked = rc->add_links();
179 linked->mutable_server()->set_id(srv->iServerNum);
180 linked->set_id(chn->iId);
181 }
182 rc->set_temporary(c->bTemporary);
183 }
184
ToRPC(const::Server * srv,const::User * u,::MurmurRPC::User * ru)185 void ToRPC(const ::Server *srv, const ::User *u, ::MurmurRPC::User *ru) {
186 ru->mutable_server()->set_id(srv->iServerNum);
187
188 ru->set_session(u->uiSession);
189 if (u->iId >= 0) {
190 ru->set_id(u->iId);
191 }
192 ru->set_name(u8(u->qsName));
193 ru->set_mute(u->bMute);
194 ru->set_deaf(u->bDeaf);
195 ru->set_suppress(u->bSuppress);
196 ru->set_recording(u->bRecording);
197 ru->set_priority_speaker(u->bPrioritySpeaker);
198 ru->set_self_mute(u->bSelfMute);
199 ru->set_self_deaf(u->bSelfDeaf);
200 ru->mutable_channel()->mutable_server()->set_id(srv->iServerNum);
201 ru->mutable_channel()->set_id(u->cChannel->iId);
202 ru->set_comment(u8(u->qsComment));
203
204 const auto su = static_cast<const ServerUser *>(u);
205 ru->set_online_secs(su->bwr.onlineSeconds());
206 ru->set_bytes_per_sec(su->bwr.bandwidth());
207 ru->mutable_version()->set_version(su->uiVersion);
208 ru->mutable_version()->set_release(u8(su->qsRelease));
209 ru->mutable_version()->set_os(u8(su->qsOS));
210 ru->mutable_version()->set_os_version(u8(su->qsOSVersion));
211 ru->set_plugin_identity(u8(su->qsIdentity));
212 ru->set_plugin_context(su->ssContext);
213 ru->set_idle_secs(su->bwr.idleSeconds());
214 ru->set_udp_ping_msecs(su->dUDPPingAvg);
215 ru->set_tcp_ping_msecs(su->dTCPPingAvg);
216
217 ru->set_tcp_only(QAtomicIntLoad(su->aiUdpFlag) == 0);
218
219 ru->set_address(su->haAddress.toStdString());
220 }
221
ToRPC(const::Server * srv,const QMap<int,QString> & info,const QByteArray & texture,::MurmurRPC::DatabaseUser * du)222 void ToRPC(const ::Server *srv, const QMap<int, QString> &info, const QByteArray &texture, ::MurmurRPC::DatabaseUser *du) {
223 du->mutable_server()->set_id(srv->iServerNum);
224
225 if (info.contains(::ServerDB::User_Name)) {
226 du->set_name(u8(info[::ServerDB::User_Name]));
227 }
228 if (info.contains(::ServerDB::User_Email)) {
229 du->set_email(u8(info[::ServerDB::User_Email]));
230 }
231 if (info.contains(::ServerDB::User_Comment)) {
232 du->set_comment(u8(info[::ServerDB::User_Comment]));
233 }
234 if (info.contains(::ServerDB::User_Hash)) {
235 du->set_hash(u8(info[::ServerDB::User_Hash]));
236 }
237 if (info.contains(::ServerDB::User_Password)) {
238 du->set_password(u8(info[::ServerDB::User_Password]));
239 }
240 if (info.contains(::ServerDB::User_LastActive)) {
241 du->set_last_active(u8(info[::ServerDB::User_LastActive]));
242 }
243 if (!texture.isNull()) {
244 du->set_texture(texture.constData(), texture.size());
245 }
246 }
247
FromRPC(const::MurmurRPC::DatabaseUser & du,QMap<int,QString> & info)248 void FromRPC(const ::MurmurRPC::DatabaseUser &du, QMap<int, QString> &info) {
249 if (du.has_name()) {
250 info.insert(::ServerDB::User_Name, u8(du.name()));
251 }
252 if (du.has_email()) {
253 info.insert(::ServerDB::User_Email, u8(du.email()));
254 }
255 if (du.has_comment()) {
256 info.insert(::ServerDB::User_Comment, u8(du.comment()));
257 }
258 if (du.has_hash()) {
259 info.insert(::ServerDB::User_Hash, u8(du.hash()));
260 }
261 if (du.has_password()) {
262 info.insert(::ServerDB::User_Password, u8(du.password()));
263 }
264 if (du.has_last_active()) {
265 info.insert(::ServerDB::User_LastActive, u8(du.last_active()));
266 }
267 }
268
ToRPC(const::Server * srv,const::ChanACL * acl,::MurmurRPC::ACL * ra)269 void ToRPC(const ::Server *srv, const ::ChanACL *acl, ::MurmurRPC::ACL *ra) {
270 ra->set_apply_here(acl->bApplyHere);
271 ra->set_apply_subs(acl->bApplySubs);
272 ra->set_inherited(false);
273
274 if (acl->iUserId >= 0) {
275 ra->mutable_user()->mutable_server()->set_id(srv->iServerNum);
276 ra->mutable_user()->set_id(acl->iUserId);
277 }
278 if (!acl->qsGroup.isEmpty()) {
279 ra->mutable_group()->set_name(u8(acl->qsGroup));
280 }
281
282 ra->set_allow(MurmurRPC::ACL_Permission(int(acl->pAllow)));
283 ra->set_deny(MurmurRPC::ACL_Permission(int(acl->pDeny)));
284 }
285
ToRPC(const::Server *,const::Group * g,::MurmurRPC::ACL_Group * rg)286 void ToRPC(const ::Server *, const ::Group *g, ::MurmurRPC::ACL_Group *rg) {
287 rg->set_name(u8(g->qsName));
288 rg->set_inherit(g->bInherit);
289 rg->set_inheritable(g->bInheritable);
290 }
291
ToRPC(const::Server * srv,const::Ban & ban,::MurmurRPC::Ban * rb)292 void ToRPC(const ::Server *srv, const ::Ban &ban, ::MurmurRPC::Ban *rb) {
293 rb->mutable_server()->set_id(srv->iServerNum);
294
295 rb->set_address(ban.haAddress.toStdString());
296 rb->set_bits(ban.iMask);
297 rb->set_name(u8(ban.qsUsername));
298 rb->set_hash(u8(ban.qsHash));
299 rb->set_reason(u8(ban.qsReason));
300 rb->set_start(ban.qdtStart.toLocalTime().toTime_t());
301 rb->set_duration_secs(ban.iDuration);
302 }
303
FromRPC(const::Server *,const::MurmurRPC::Ban & rb,::Ban & ban)304 void FromRPC(const ::Server *, const ::MurmurRPC::Ban &rb, ::Ban &ban) {
305 ban.haAddress = HostAddress(rb.address());
306 ban.iMask = rb.bits();
307 ban.qsUsername = u8(rb.name());
308 ban.qsHash = u8(rb.hash());
309 ban.qsReason = u8(rb.reason());
310 ban.qdtStart = QDateTime::fromTime_t(static_cast<quint32>(rb.start())).toUTC();
311 ban.iDuration = rb.duration_secs();
312 }
313
ToRPC(int serverID,const::ServerDB::LogRecord & log,::MurmurRPC::Log * rl)314 void ToRPC(int serverID, const ::ServerDB::LogRecord &log, ::MurmurRPC::Log *rl) {
315 rl->mutable_server()->set_id(serverID);
316
317 rl->set_timestamp(log.first);
318 rl->set_text(u8(log.second));
319 }
320
ToRPC(const::Server * srv,const::User * user,const::TextMessage & message,::MurmurRPC::TextMessage * rtm)321 void ToRPC(const ::Server *srv, const ::User *user, const ::TextMessage &message, ::MurmurRPC::TextMessage *rtm) {
322 rtm->mutable_server()->set_id(srv->iServerNum);
323
324 rtm->mutable_actor()->mutable_server()->set_id(srv->iServerNum);
325 rtm->mutable_actor()->set_session(user->uiSession);
326
327 foreach(auto session, message.qlSessions) {
328 auto target = rtm->add_users();
329 target->mutable_server()->set_id(srv->iServerNum);
330 target->set_session(session);
331 }
332
333 foreach(auto id, message.qlChannels) {
334 auto target = rtm->add_channels();
335 target->mutable_server()->set_id(srv->iServerNum);
336 target->set_id(id);
337 }
338
339 foreach(auto id, message.qlTrees) {
340 auto target = rtm->add_trees();
341 target->mutable_server()->set_id(srv->iServerNum);
342 target->set_id(id);
343 }
344
345 rtm->set_text(u8(message.qsText));
346 }
347
348 // Sends a meta event to any subscribed listeners.
sendMetaEvent(const::MurmurRPC::Event & e)349 void MurmurRPCImpl::sendMetaEvent(const ::MurmurRPC::Event &e) {
350 auto listeners = m_metaServiceListeners;
351
352 for (auto i = listeners.constBegin(); i != listeners.constEnd(); ++i) {
353 auto listener = *i;
354 listener->ref();
355 auto cb = [this, listener] (::MurmurRPC::Wrapper::V1_Events *, bool ok) {
356 if (!ok && m_metaServiceListeners.remove(listener)) {
357 listener->deref();
358 }
359 listener->deref();
360 };
361 listener->write(e, listener->callback(cb));
362 }
363 }
364
365 // Called when a server starts.
started(::Server * server)366 void MurmurRPCImpl::started(::Server *server) {
367 server->connectListener(this);
368 server->connectAuthenticator(this);
369 connect(server, SIGNAL(contextAction(const User *, const QString &, unsigned int, int)), this, SLOT(contextAction(const User *, const QString &, unsigned int, int)));
370 connect(server, SIGNAL(textMessageFilterSig(int &, const User *, MumbleProto::TextMessage &)), this, SLOT(textMessageFilter(int &, const User *, MumbleProto::TextMessage &)));
371
372 ::MurmurRPC::Event rpcEvent;
373 rpcEvent.set_type(::MurmurRPC::Event_Type_ServerStarted);
374 rpcEvent.mutable_server()->set_id(server->iServerNum);
375 sendMetaEvent(rpcEvent);
376 }
377
378 // Called when a server stops.
stopped(::Server * server)379 void MurmurRPCImpl::stopped(::Server *server) {
380 removeActiveContextActions(server);
381
382 ::MurmurRPC::Event rpcEvent;
383 rpcEvent.set_type(::MurmurRPC::Event_Type_ServerStopped);
384 rpcEvent.mutable_server()->set_id(server->iServerNum);
385 sendMetaEvent(rpcEvent);
386 }
387
388 // Removes a connected text message filter.
removeTextMessageFilter(const::Server * s)389 void MurmurRPCImpl::removeTextMessageFilter(const ::Server *s) {
390 auto filter = m_textMessageFilters.value(s->iServerNum);
391 if (!filter) {
392 return;
393 }
394 filter->error(::grpc::Status(::grpc::CANCELLED, "filter detached"));
395 m_textMessageFilters.remove(s->iServerNum);
396 }
397
398 // Removes a connected authenticator.
removeAuthenticator(const::Server * s)399 void MurmurRPCImpl::removeAuthenticator(const ::Server *s) {
400 auto authenticator = m_authenticators.value(s->iServerNum);
401 if (!authenticator) {
402 return;
403 }
404 authenticator->error(::grpc::Status(::grpc::CANCELLED, "authenticator detached"));
405 m_authenticators.remove(s->iServerNum);
406 }
407
408 // Called when a connecting user needs to be authenticated.
authenticateSlot(int & res,QString & uname,int sessionId,const QList<QSslCertificate> & certlist,const QString & certhash,bool certstrong,const QString & pw)409 void MurmurRPCImpl::authenticateSlot(int &res, QString &uname, int sessionId, const QList<QSslCertificate> &certlist, const QString &certhash, bool certstrong, const QString &pw) {
410 ::Server *s = qobject_cast< ::Server *> (sender());
411 auto authenticator = RPCCall::Ref<::MurmurRPC::Wrapper::V1_AuthenticatorStream>(m_authenticators.value(s->iServerNum));
412 if (!authenticator) {
413 return;
414 }
415
416 auto &request = authenticator->response;
417 request.Clear();
418 request.mutable_authenticate()->set_name(u8(uname));
419 if (!pw.isEmpty()) {
420 request.mutable_authenticate()->set_password(u8(pw));
421 }
422 foreach(const auto &cert, certlist) {
423 auto data = cert.toDer();
424 request.mutable_authenticate()->add_certificates(data.constData(), data.size());
425 }
426 if (!certhash.isEmpty()) {
427 request.mutable_authenticate()->set_certificate_hash(u8(certhash));
428 request.mutable_authenticate()->set_strong_certificate(certstrong);
429 }
430
431 {
432 QMutexLocker l(&qmAuthenticatorsLock);
433 if (!authenticator->writeRead()) {
434 removeAuthenticator(s);
435 res = -1;
436 return;
437 }
438 }
439
440 auto &response = authenticator->request;
441 switch (response.authenticate().status()) {
442 case ::MurmurRPC::Authenticator_Response_Status_Success:
443 if (!response.authenticate().has_id()) {
444 res = -3;
445 break;
446 }
447 res = response.authenticate().id();
448 if (response.authenticate().has_name()) {
449 uname = u8(response.authenticate().name());
450 }
451 {
452 QStringList qsl;
453 for (int i = 0; i < response.authenticate().groups_size(); i++) {
454 auto &group = response.authenticate().groups(i);
455 if (group.has_name()) {
456 qsl << u8(group.name());
457 }
458 }
459 if (!qsl.isEmpty()) {
460 s->setTempGroups(res, sessionId, NULL, qsl);
461 }
462 }
463 break;
464 case ::MurmurRPC::Authenticator_Response_Status_TemporaryFailure:
465 res = -3;
466 break;
467 case ::MurmurRPC::Authenticator_Response_Status_Failure:
468 res = -1;
469 break;
470 default:
471 break;
472 }
473 }
474
475 // Called when a user is being registered on the server.
registerUserSlot(int & res,const QMap<int,QString> & info)476 void MurmurRPCImpl::registerUserSlot(int &res, const QMap<int, QString> &info) {
477 ::Server *s = qobject_cast< ::Server *> (sender());
478 auto authenticator = RPCCall::Ref<::MurmurRPC::Wrapper::V1_AuthenticatorStream>(m_authenticators.value(s->iServerNum));
479 if (!authenticator) {
480 return;
481 }
482
483 auto &request = authenticator->response;
484 request.Clear();
485 ToRPC(s, info, QByteArray(), request.mutable_register_()->mutable_user());
486
487 {
488 QMutexLocker l(&qmAuthenticatorsLock);
489 if (!authenticator->writeRead()) {
490 removeAuthenticator(s);
491 return;
492 }
493 }
494
495 auto &response = authenticator->request;
496 switch (response.register_().status()) {
497 case ::MurmurRPC::Authenticator_Response_Status_Success:
498 if (!response.register_().has_user() || !response.register_().user().has_id()) {
499 res = -1;
500 break;
501 }
502 res = response.register_().user().id();
503 break;
504 case ::MurmurRPC::Authenticator_Response_Status_Fallthrough:
505 break;
506 default:
507 res = -1;
508 break;
509 }
510 }
511
512 // Called when a user is being deregistered on the server.
unregisterUserSlot(int & res,int id)513 void MurmurRPCImpl::unregisterUserSlot(int &res, int id) {
514 ::Server *s = qobject_cast< ::Server *> (sender());
515 auto authenticator = RPCCall::Ref<::MurmurRPC::Wrapper::V1_AuthenticatorStream>(m_authenticators.value(s->iServerNum));
516 if (!authenticator) {
517 return;
518 }
519
520 auto &request = authenticator->response;
521 request.Clear();
522 request.mutable_deregister()->mutable_user()->mutable_server()->set_id(s->iServerNum);
523 request.mutable_deregister()->mutable_user()->set_id(id);
524
525 {
526 QMutexLocker l(&qmAuthenticatorsLock);
527 if (!authenticator->writeRead()) {
528 removeAuthenticator(s);
529 return;
530 }
531 }
532
533 auto &response = authenticator->request;
534
535 if (response.deregister().status() != ::MurmurRPC::Authenticator_Response_Status_Fallthrough) {
536 res = 0;
537 }
538 }
539
540 // Called when a list of registered users is requested.
getRegisteredUsersSlot(const QString & filter,QMap<int,QString> & res)541 void MurmurRPCImpl::getRegisteredUsersSlot(const QString &filter, QMap<int, QString> &res) {
542 ::Server *s = qobject_cast< ::Server *> (sender());
543 auto authenticator = RPCCall::Ref<::MurmurRPC::Wrapper::V1_AuthenticatorStream>(m_authenticators.value(s->iServerNum));
544 if (!authenticator) {
545 return;
546 }
547
548 auto &request = authenticator->response;
549 request.Clear();
550 if (!filter.isEmpty()) {
551 request.mutable_query()->set_filter(u8(filter));
552 }
553
554 {
555 QMutexLocker l(&qmAuthenticatorsLock);
556 if (!authenticator->writeRead()) {
557 removeAuthenticator(s);
558 return;
559 }
560 }
561
562 auto &response = authenticator->request;
563
564 for (int i = 0; i < response.query().users_size(); i++) {
565 const auto &user = response.query().users(i);
566 if (!user.has_id() || !user.has_name()) {
567 continue;
568 }
569 res.insert(user.id(), u8(user.name()));
570 }
571 }
572
573 // Called when information about a registered user is requested.
getRegistrationSlot(int & res,int id,QMap<int,QString> & info)574 void MurmurRPCImpl::getRegistrationSlot(int &res, int id, QMap<int, QString> &info) {
575 ::Server *s = qobject_cast< ::Server *> (sender());
576 auto authenticator = RPCCall::Ref<::MurmurRPC::Wrapper::V1_AuthenticatorStream>(m_authenticators.value(s->iServerNum));
577 if (!authenticator) {
578 return;
579 }
580
581 auto &request = authenticator->response;
582 request.Clear();
583 request.mutable_find()->set_id(id);
584
585 res = -1;
586
587 {
588 QMutexLocker l(&qmAuthenticatorsLock);
589 if (!authenticator->writeRead()) {
590 removeAuthenticator(s);
591 return;
592 }
593 }
594
595 auto &response = authenticator->request;
596 if (response.find().has_user()) {
597 FromRPC(response.find().user(), info);
598 res = 1;
599 }
600 }
601
602 // Called when information about a registered user is being updated.
setInfoSlot(int & res,int id,const QMap<int,QString> & info)603 void MurmurRPCImpl::setInfoSlot(int &res, int id, const QMap<int, QString> &info) {
604 ::Server *s = qobject_cast< ::Server *> (sender());
605 auto authenticator = RPCCall::Ref<::MurmurRPC::Wrapper::V1_AuthenticatorStream>(m_authenticators.value(s->iServerNum));
606 if (!authenticator) {
607 return;
608 }
609
610 auto &request = authenticator->response;
611 request.Clear();
612 request.mutable_update()->mutable_user()->set_id(id);
613 ToRPC(s, info, QByteArray(), request.mutable_update()->mutable_user());
614
615 res = 0;
616
617 {
618 QMutexLocker l(&qmAuthenticatorsLock);
619 if (!authenticator->writeRead()) {
620 removeAuthenticator(s);
621 return;
622 }
623 }
624
625 auto &response = authenticator->request;
626 switch (response.update().status()) {
627 case ::MurmurRPC::Authenticator_Response_Status_Success:
628 res = 1;
629 break;
630 case ::MurmurRPC::Authenticator_Response_Status_Fallthrough:
631 res = -1;
632 break;
633 default:
634 break;
635 }
636 }
637
638 // Called when a texture for a registered user is being updated.
setTextureSlot(int & res,int id,const QByteArray & texture)639 void MurmurRPCImpl::setTextureSlot(int &res, int id, const QByteArray &texture) {
640 ::Server *s = qobject_cast< ::Server *> (sender());
641 auto authenticator = RPCCall::Ref<::MurmurRPC::Wrapper::V1_AuthenticatorStream>(m_authenticators.value(s->iServerNum));
642 if (!authenticator) {
643 return;
644 }
645
646 auto &request = authenticator->response;
647 request.Clear();
648 request.mutable_update()->mutable_user()->set_id(id);
649 request.mutable_update()->mutable_user()->set_texture(texture.constData(), texture.size());
650
651 {
652 QMutexLocker l(&qmAuthenticatorsLock);
653 if (!authenticator->writeRead()) {
654 removeAuthenticator(s);
655 return;
656 }
657 }
658
659 auto &response = authenticator->request;
660 if (response.update().status() == ::MurmurRPC::Authenticator_Response_Status_Success) {
661 res = 1;
662 }
663 }
664
665 // Called when a user name needs to be converted to a user ID.
nameToIdSlot(int & res,const QString & name)666 void MurmurRPCImpl::nameToIdSlot(int &res, const QString &name) {
667 ::Server *s = qobject_cast< ::Server *> (sender());
668 auto authenticator = RPCCall::Ref<::MurmurRPC::Wrapper::V1_AuthenticatorStream>(m_authenticators.value(s->iServerNum));
669 if (!authenticator) {
670 return;
671 }
672
673 auto &request = authenticator->response;
674 request.Clear();
675 request.mutable_find()->set_name(u8(name));
676
677 {
678 QMutexLocker l(&qmAuthenticatorsLock);
679 if (!authenticator->writeRead()) {
680 removeAuthenticator(s);
681 return;
682 }
683 }
684
685 auto &response = authenticator->request;
686 if (response.find().has_user() && response.find().user().has_id()) {
687 res = response.find().user().id();
688 }
689 }
690
691 // Called when a user ID needs to be converted to a user name.
idToNameSlot(QString & res,int id)692 void MurmurRPCImpl::idToNameSlot(QString &res, int id) {
693 ::Server *s = qobject_cast< ::Server *> (sender());
694 auto authenticator = RPCCall::Ref<::MurmurRPC::Wrapper::V1_AuthenticatorStream>(m_authenticators.value(s->iServerNum));
695 if (!authenticator) {
696 return;
697 }
698
699 auto &request = authenticator->response;
700 request.Clear();
701 request.mutable_find()->set_id(id);
702
703 {
704 QMutexLocker l(&qmAuthenticatorsLock);
705 if (!authenticator->writeRead()) {
706 removeAuthenticator(s);
707 return;
708 }
709 }
710
711 auto &response = authenticator->request;
712 if (response.find().has_user() && response.find().user().has_name()) {
713 res = u8(response.find().user().name());
714 }
715 }
716
717 // Called when a texture for a given registered user is requested.
idToTextureSlot(QByteArray & res,int id)718 void MurmurRPCImpl::idToTextureSlot(QByteArray &res, int id) {
719 ::Server *s = qobject_cast< ::Server *> (sender());
720 auto authenticator = RPCCall::Ref<::MurmurRPC::Wrapper::V1_AuthenticatorStream>(m_authenticators.value(s->iServerNum));
721 if (!authenticator) {
722 return;
723 }
724
725 auto &request = authenticator->response;
726 request.Clear();
727 request.mutable_find()->set_id(id);
728
729 {
730 QMutexLocker l(&qmAuthenticatorsLock);
731 if (!authenticator->writeRead()) {
732 removeAuthenticator(s);
733 return;
734 }
735 }
736
737 auto &response = authenticator->request;
738 if (response.find().has_user() && response.find().user().has_texture()) {
739 const auto &texture = response.find().user().texture();
740 res = QByteArray(texture.data(), texture.size());
741 }
742 }
743
744 // Sends a server event to subscribed listeners.
sendServerEvent(const::Server * s,const::MurmurRPC::Server_Event & e)745 void MurmurRPCImpl::sendServerEvent(const ::Server *s, const ::MurmurRPC::Server_Event &e) {
746 auto listeners = m_serverServiceListeners;
747 auto serverID = s->iServerNum;
748 auto i = listeners.find(serverID);
749
750 for ( ; i != listeners.end() && i.key() == serverID; ++i) {
751 auto listener = i.value();
752 listener->ref();
753 auto cb = [this, listener, serverID] (::MurmurRPC::Wrapper::V1_ServerEvents *, bool ok) {
754 if (!ok && m_serverServiceListeners.remove(serverID, listener) > 0) {
755 listener->deref();
756 }
757 listener->deref();
758 };
759 listener->write(e, listener->callback(cb));
760 }
761 }
762
763 // Called when a user's state changes.
userStateChanged(const::User * user)764 void MurmurRPCImpl::userStateChanged(const ::User *user) {
765 ::Server *s = qobject_cast< ::Server *> (sender());
766
767 ::MurmurRPC::Server_Event event;
768 event.mutable_server()->set_id(s->iServerNum);
769 event.set_type(::MurmurRPC::Server_Event_Type_UserStateChanged);
770 ToRPC(s, user, event.mutable_user());
771 sendServerEvent(s, event);
772 }
773
774 // Called when a user sends a text message.
userTextMessage(const::User * user,const::TextMessage & message)775 void MurmurRPCImpl::userTextMessage(const ::User *user, const ::TextMessage &message) {
776 ::Server *s = qobject_cast< ::Server *> (sender());
777
778 ::MurmurRPC::Server_Event event;
779 event.mutable_server()->set_id(s->iServerNum);
780 event.set_type(::MurmurRPC::Server_Event_Type_UserTextMessage);
781 ToRPC(s, user, event.mutable_user());
782 ToRPC(s, user, message, event.mutable_message());
783 sendServerEvent(s, event);
784 }
785
786 // Called when a user successfully connects to a server.
userConnected(const::User * user)787 void MurmurRPCImpl::userConnected(const ::User *user) {
788 ::Server *s = qobject_cast< ::Server *> (sender());
789
790 ::MurmurRPC::Server_Event event;
791 event.mutable_server()->set_id(s->iServerNum);
792 event.set_type(::MurmurRPC::Server_Event_Type_UserConnected);
793 ToRPC(s, user, event.mutable_user());
794 sendServerEvent(s, event);
795 }
796
797 // Called when a user disconnects from a server.
userDisconnected(const::User * user)798 void MurmurRPCImpl::userDisconnected(const ::User *user) {
799 ::Server *s = qobject_cast< ::Server *> (sender());
800
801 removeUserActiveContextActions(s, user);
802
803 ::MurmurRPC::Server_Event event;
804 event.mutable_server()->set_id(s->iServerNum);
805 event.set_type(::MurmurRPC::Server_Event_Type_UserDisconnected);
806 ToRPC(s, user, event.mutable_user());
807 sendServerEvent(s, event);
808 }
809
810 // Called when a channel's state changes.
channelStateChanged(const::Channel * channel)811 void MurmurRPCImpl::channelStateChanged(const ::Channel *channel) {
812 ::Server *s = qobject_cast< ::Server *> (sender());
813
814 ::MurmurRPC::Server_Event event;
815 event.mutable_server()->set_id(s->iServerNum);
816 event.set_type(::MurmurRPC::Server_Event_Type_ChannelStateChanged);
817 ToRPC(s, channel, event.mutable_channel());
818 sendServerEvent(s, event);
819 }
820
821 // Called when a channel is created.
channelCreated(const::Channel * channel)822 void MurmurRPCImpl::channelCreated(const ::Channel *channel) {
823 ::Server *s = qobject_cast< ::Server *> (sender());
824
825 ::MurmurRPC::Server_Event event;
826 event.mutable_server()->set_id(s->iServerNum);
827 event.set_type(::MurmurRPC::Server_Event_Type_ChannelCreated);
828 ToRPC(s, channel, event.mutable_channel());
829 sendServerEvent(s, event);
830 }
831
832 // Called when a channel is removed.
channelRemoved(const::Channel * channel)833 void MurmurRPCImpl::channelRemoved(const ::Channel *channel) {
834 ::Server *s = qobject_cast< ::Server *> (sender());
835
836 ::MurmurRPC::Server_Event event;
837 event.mutable_server()->set_id(s->iServerNum);
838 event.set_type(::MurmurRPC::Server_Event_Type_ChannelRemoved);
839 ToRPC(s, channel, event.mutable_channel());
840 sendServerEvent(s, event);
841 }
842
843 // Called when a user sends a text message.
textMessageFilter(int & res,const User * user,MumbleProto::TextMessage & message)844 void MurmurRPCImpl::textMessageFilter(int &res, const User *user, MumbleProto::TextMessage &message) {
845 ::Server *s = qobject_cast< ::Server *> (sender());
846 auto filter = RPCCall::Ref<::MurmurRPC::Wrapper::V1_TextMessageFilter>(m_textMessageFilters.value(s->iServerNum));
847 if (!filter) {
848 return;
849 }
850
851 auto &request = filter->response;
852 request.Clear();
853 request.mutable_server()->set_id(s->iServerNum);
854 auto m = request.mutable_message();
855 m->mutable_server()->set_id(s->iServerNum);
856 m->mutable_actor()->mutable_server()->set_id(s->iServerNum);
857 m->mutable_actor()->set_session(user->uiSession);
858 for (int i = 0; i < message.session_size(); i++) {
859 auto u = m->add_users();
860 u->mutable_server()->set_id(s->iServerNum);
861 u->set_session(message.session(i));
862 }
863 for (int i = 0; i < message.channel_id_size(); i++) {
864 auto c = m->add_channels();
865 c->mutable_server()->set_id(s->iServerNum);
866 c->set_id(message.channel_id(i));
867 }
868 for (int i = 0; i < message.tree_id_size(); i++) {
869 auto c = m->add_trees();
870 c->mutable_server()->set_id(s->iServerNum);
871 c->set_id(message.tree_id(i));
872 }
873 m->set_text(message.message());
874
875 {
876 QMutexLocker l(&qmTextMessageFilterLock);
877 if (!filter->writeRead()) {
878 removeTextMessageFilter(s);
879 return;
880 }
881 }
882
883 auto &response = filter->request;
884 res = response.action();
885 switch (response.action()) {
886 case ::MurmurRPC::TextMessage_Filter_Action_Accept:
887 if (response.has_message() && response.message().has_text()) {
888 message.set_message(response.message().text());
889 }
890 break;
891 default:
892 break;
893 }
894 }
895
896 // Has the user been sent the given context action?
hasActiveContextAction(const::Server * s,const::User * u,const QString & action)897 bool MurmurRPCImpl::hasActiveContextAction(const ::Server *s, const ::User *u, const QString &action) {
898 const auto &m = m_activeContextActions;
899 if (!m.contains(s->iServerNum)) {
900 return false;
901 }
902 const auto &n = m.value(s->iServerNum);
903 if (!n.contains(u->uiSession)) {
904 return false;
905 }
906 const auto &o = n.value(u->uiSession);
907 if (!o.contains(action)) {
908 return false;
909 }
910 return true;
911 }
912
913 // Add the context action to the user's active context actions.
addActiveContextAction(const::Server * s,const::User * u,const QString & action)914 void MurmurRPCImpl::addActiveContextAction(const ::Server *s, const ::User *u, const QString &action) {
915 m_activeContextActions[s->iServerNum][u->uiSession].insert(action);
916 }
917
918 // Remove the context action to the user's active context actions.
removeActiveContextAction(const::Server * s,const::User * u,const QString & action)919 void MurmurRPCImpl::removeActiveContextAction(const ::Server *s, const ::User *u, const QString &action) {
920 auto &m = m_activeContextActions;
921 if (!m.contains(s->iServerNum)) {
922 return;
923 }
924 auto &n = m[s->iServerNum];
925 if (!n.contains(u->uiSession)) {
926 return;
927 }
928 auto &o = n[u->uiSession];
929 o.remove(action);
930 }
931
932 // Remove all of the user's active context actions.
removeUserActiveContextActions(const::Server * s,const::User * u)933 void MurmurRPCImpl::removeUserActiveContextActions(const ::Server *s, const ::User *u) {
934 auto &m = m_activeContextActions;
935 if (m.contains(s->iServerNum)) {
936 m[s->iServerNum].remove(u->uiSession);
937 }
938 }
939
940 // Remove all of the server's active context actions.
removeActiveContextActions(const::Server * s)941 void MurmurRPCImpl::removeActiveContextActions(const ::Server *s) {
942 auto &m = m_activeContextActions;
943 if (m.contains(s->iServerNum)) {
944 m.remove(s->iServerNum);
945 }
946 }
947
948 // Called when a context action event is triggered.
contextAction(const::User * user,const QString & action,unsigned int session,int channel)949 void MurmurRPCImpl::contextAction(const ::User *user, const QString &action, unsigned int session, int channel) {
950 ::Server *s = qobject_cast< ::Server *> (sender());
951
952 if (!hasActiveContextAction(s, user, action)) {
953 return;
954 }
955
956 ::MurmurRPC::ContextAction ca;
957 ca.mutable_server()->set_id(s->iServerNum);
958 ca.mutable_actor()->mutable_server()->set_id(s->iServerNum);
959 ca.mutable_actor()->set_session(user->uiSession);
960 ca.set_action(u8(action));
961 if (session > 0) {
962 ca.mutable_user()->mutable_server()->set_id(s->iServerNum);
963 ca.mutable_user()->set_session(session);
964 }
965 if (channel >= 0) {
966 ca.mutable_channel()->mutable_server()->set_id(s->iServerNum);
967 ca.mutable_channel()->set_id(channel);
968 }
969
970 auto serverID = s->iServerNum;
971 auto listeners = this->m_contextActionListeners.value(serverID);
972 auto i = listeners.find(action);
973 for ( ; i != listeners.end() && i.key() == action; ++i) {
974 auto listener = i.value();
975 listener->ref();
976 auto cb = [this, listener, serverID, action] (::MurmurRPC::Wrapper::V1_ContextActionEvents *, bool ok) {
977 if (!ok && m_contextActionListeners[serverID].remove(action, listener) > 0) {
978 listener->deref();
979 }
980 listener->deref();
981 };
982 listener->write(ca, listener->callback(cb));
983 }
984 }
985
986 // *Must* functions return the requested value, or throw a ::grpc::Status
987 // exception.
MustUser(const Server * server,unsigned int session)988 ::ServerUser *MustUser(const Server *server, unsigned int session) {
989 auto user = server->qhUsers.value(session);
990 if (!user || user->sState != ServerUser::Authenticated) {
991 throw ::grpc::Status(::grpc::NOT_FOUND, "invalid user");
992 }
993 return user;
994 }
995
996 template <class T>
MustUser(const::Server * server,const T & msg)997 ::ServerUser *MustUser(const ::Server *server, const T &msg) {
998 if (!msg.has_user()) {
999 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing user");
1000 }
1001 return MustUser(server, msg.user().session());
1002 }
1003
1004 template <>
MustUser(const Server * server,const::MurmurRPC::User & msg)1005 ::ServerUser *MustUser(const Server *server, const ::MurmurRPC::User &msg) {
1006 if (!msg.has_session()) {
1007 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing user session");
1008 }
1009 return MustUser(server, msg.session());
1010 }
1011
MustServer(unsigned int id)1012 ::Server *MustServer(unsigned int id) {
1013 auto server = meta->qhServers.value(id);
1014 if (!server) {
1015 throw ::grpc::Status(::grpc::NOT_FOUND, "invalid server");
1016 }
1017 return server;
1018 }
1019
MustServer(int id)1020 ::Server *MustServer(int id) {
1021 auto server = meta->qhServers.value(id);
1022 if (!server) {
1023 throw ::grpc::Status(::grpc::NOT_FOUND, "invalid server");
1024 }
1025 return server;
1026 }
1027
1028 template <class T>
MustServer(const T & msg)1029 ::Server *MustServer(const T &msg) {
1030 if (!msg.has_server()) {
1031 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing server");
1032 }
1033 if (!msg.server().has_id()) {
1034 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing server id");
1035 }
1036 return MustServer(msg.server().id());
1037 }
1038
1039 template <>
MustServer(const::MurmurRPC::Server & msg)1040 ::Server *MustServer(const ::MurmurRPC::Server &msg) {
1041 if (!msg.has_id()) {
1042 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing server id");
1043 }
1044 return MustServer(msg.id());
1045 }
1046
1047 template <class T>
MustServerID(const T & msg)1048 int MustServerID(const T &msg) {
1049 if (!msg.has_server()) {
1050 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing server");
1051 }
1052 if (!msg.server().has_id()) {
1053 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing server id");
1054 }
1055 auto id = msg.server().id();
1056 if (!ServerDB::serverExists(id)) {
1057 throw ::grpc::Status(::grpc::NOT_FOUND, "invalid server id");
1058 }
1059 return id;
1060 }
1061
MustServerID(const::MurmurRPC::Server & msg)1062 int MustServerID(const ::MurmurRPC::Server &msg) {
1063 if (!msg.has_id()) {
1064 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing server id");
1065 }
1066 auto id = msg.id();
1067 if (!ServerDB::serverExists(id)) {
1068 throw ::grpc::Status(::grpc::NOT_FOUND, "invalid server id");
1069 }
1070 return id;
1071 }
1072
MustChannel(const Server * server,int channel_id)1073 ::Channel *MustChannel(const Server *server, int channel_id) {
1074 auto channel = server->qhChannels.value(channel_id);
1075 if (!channel) {
1076 throw ::grpc::Status(::grpc::NOT_FOUND, "invalid channel");
1077 }
1078 return channel;
1079 }
1080
MustChannel(const Server * server,unsigned int channel_id)1081 ::Channel *MustChannel(const Server *server, unsigned int channel_id) {
1082 auto channel = server->qhChannels.value(channel_id);
1083 if (!channel) {
1084 throw ::grpc::Status(::grpc::NOT_FOUND, "invalid channel");
1085 }
1086 return channel;
1087 }
1088
1089 template <class T>
MustChannel(const Server * server,const T & msg)1090 ::Channel *MustChannel(const Server *server, const T &msg) {
1091 if (!msg.has_channel()) {
1092 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing channel");
1093 }
1094 return MustChannel(server, msg.channel());
1095 }
1096
1097 template <>
MustChannel(const Server * server,const::MurmurRPC::Channel & msg)1098 ::Channel *MustChannel(const Server *server, const ::MurmurRPC::Channel &msg) {
1099 if (!msg.has_id()) {
1100 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing channel id");
1101 }
1102 return MustChannel(server, msg.id());
1103 }
1104
1105 // Qt event listener for RPCExecEvents.
customEvent(QEvent * evt)1106 void MurmurRPCImpl::customEvent(QEvent *evt) {
1107 if (evt->type() == EXEC_QEVENT) {
1108 auto event = static_cast<RPCExecEvent *>(evt);
1109 try {
1110 event->execute();
1111 } catch (::grpc::Status &ex) {
1112 event->call->error(ex);
1113 }
1114 }
1115 }
1116
1117 // QThread::run() implementation that runs the grpc event loop and executes
1118 // tags as callback functions.
run()1119 void MurmurRPCImpl::run() {
1120 MurmurRPC::Wrapper::V1_Init(this, &m_V1Service);
1121
1122 while (m_isRunning) {
1123 void *tag;
1124 bool ok;
1125 if (!m_completionQueue->Next(&tag, &ok)) {
1126 break;
1127 }
1128 if (tag != nullptr) {
1129 auto op = static_cast<boost::function<void(bool)> *>(tag);
1130 (*op)(ok);
1131 delete op;
1132 }
1133 }
1134 // TODO(grpc): cleanup allocated memory? not super important, because murmur
1135 // should be exiting now.
1136 }
1137
1138 // The Wrapper implementation methods are below. Implementation methods are
1139 // executed in the main thread when its corresponding grpc method is invoked.
1140 //
1141 // Since the grpc asynchronous API is used, the implementation methods below
1142 // do not have to complete the call during the lifetime of the method (although
1143 // this is only used for streaming calls).
1144
1145 namespace MurmurRPC {
1146 namespace Wrapper {
1147
impl(bool)1148 void V1_ServerCreate::impl(bool) {
1149 auto id = ServerDB::addServer();
1150
1151 ::MurmurRPC::Server rpcServer;
1152 rpcServer.set_id(id);
1153 end(rpcServer);
1154 }
1155
impl(bool)1156 void V1_ServerQuery::impl(bool) {
1157 ::MurmurRPC::Server_List list;
1158
1159 foreach(int id, ServerDB::getAllServers()) {
1160 auto rpcServer = list.add_servers();
1161 rpcServer->set_id(id);
1162 try {
1163 auto server = MustServer(id);
1164 rpcServer->set_running(true);
1165 rpcServer->mutable_uptime()->set_secs(server->tUptime.elapsed()/1000000LL);
1166 } catch (::grpc::Status &ex) {
1167 }
1168 }
1169
1170 end(list);
1171 }
1172
impl(bool)1173 void V1_ServerGet::impl(bool) {
1174 auto serverID = MustServerID(request);
1175
1176 ::MurmurRPC::Server rpcServer;
1177 rpcServer.set_id(serverID);
1178 rpcServer.set_running(false);
1179 try {
1180 auto server = MustServer(serverID);
1181 rpcServer.set_running(true);
1182 rpcServer.mutable_uptime()->set_secs(server->tUptime.elapsed()/1000000LL);
1183 } catch (::grpc::Status &ex) {
1184 }
1185 end(rpcServer);
1186 }
1187
impl(bool)1188 void V1_ServerStart::impl(bool) {
1189 auto serverID = MustServerID(request);
1190
1191 if (!meta->boot(serverID)) {
1192 throw ::grpc::Status(::grpc::UNKNOWN, "server could not be started, or is already started");
1193 }
1194
1195 end();
1196 }
1197
impl(bool)1198 void V1_ServerStop::impl(bool) {
1199 auto server = MustServer(request);
1200 meta->kill(server->iServerNum);
1201 end();
1202 }
1203
impl(bool)1204 void V1_ServerRemove::impl(bool) {
1205 auto serverID = MustServerID(request);
1206
1207 if (meta->qhServers.value(serverID)) {
1208 throw ::grpc::Status(::grpc::FAILED_PRECONDITION, "cannot remove started server");
1209 }
1210
1211 ServerDB::deleteServer(serverID);
1212 end();
1213 }
1214
impl(bool)1215 void V1_ServerEvents::impl(bool) {
1216 auto server = MustServer(request);
1217 rpc->m_serverServiceListeners.insert(server->iServerNum, this);
1218 }
1219
done(bool)1220 void V1_ServerEvents::done(bool) {
1221 auto &ssls = rpc->m_serverServiceListeners;
1222 auto i = std::find(ssls.begin(), ssls.end(), this);
1223 if (i != ssls.end()) {
1224 ssls.erase(i);
1225 }
1226 deref();
1227 }
1228
impl(bool)1229 void V1_GetUptime::impl(bool) {
1230 ::MurmurRPC::Uptime uptime;
1231 uptime.set_secs(meta->tUptime.elapsed()/1000000LL);
1232 end(uptime);
1233 }
1234
impl(bool)1235 void V1_GetVersion::impl(bool) {
1236 ::MurmurRPC::Version version;
1237 int major, minor, patch;
1238 QString release;
1239 Meta::getVersion(major, minor, patch, release);
1240 version.set_version(major << 16 | minor << 8 | patch);
1241 version.set_release(u8(release));
1242 end(version);
1243 }
1244
impl(bool)1245 void V1_Events::impl(bool) {
1246 rpc->m_metaServiceListeners.insert(this);
1247 }
1248
done(bool)1249 void V1_Events::done(bool) {
1250 auto &msls = rpc->m_metaServiceListeners;
1251 auto i = std::find(msls.begin(), msls.end(), this);
1252 if (i != msls.end()) {
1253 msls.erase(i);
1254 }
1255 deref();
1256 }
1257
impl(bool)1258 void V1_ContextActionAdd::impl(bool) {
1259 auto server = MustServer(request);
1260 auto user = MustUser(server, request);
1261
1262 if (!request.has_action()) {
1263 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing action");
1264 }
1265 if (!request.has_text()) {
1266 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing text");
1267 }
1268 if (!request.has_context()) {
1269 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing context");
1270 }
1271
1272 rpc->addActiveContextAction(server, user, u8(request.action()));
1273
1274 ::MumbleProto::ContextActionModify mpcam;
1275 mpcam.set_action(request.action());
1276 mpcam.set_text(request.text());
1277 mpcam.set_context(request.context());
1278 mpcam.set_operation(::MumbleProto::ContextActionModify_Operation_Add);
1279 server->sendMessage(user, mpcam);
1280
1281 end();
1282 }
1283
impl(bool)1284 void V1_ContextActionRemove::impl(bool) {
1285 auto server = MustServer(request);
1286
1287 if (!request.has_action()) {
1288 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing action");
1289 }
1290
1291 auto action = u8(request.action());
1292
1293 ::MumbleProto::ContextActionModify mpcam;
1294 mpcam.set_action(request.action());
1295 mpcam.set_operation(::MumbleProto::ContextActionModify_Operation_Remove);
1296
1297 if (request.has_user()) {
1298 // Remove context action from specific user
1299 auto user = MustUser(server, request);
1300 rpc->removeActiveContextAction(server, user, action);
1301 server->sendMessage(user, mpcam);
1302 } else {
1303 // Remove context action from all users
1304 foreach(::ServerUser *user, server->qhUsers) {
1305 if (user->sState != ServerUser::Authenticated) {
1306 continue;
1307 }
1308 rpc->removeActiveContextAction(server, user, action);
1309 server->sendMessage(user, mpcam);
1310 }
1311 }
1312
1313 end();
1314 }
1315
impl(bool)1316 void V1_ContextActionEvents::impl(bool) {
1317 auto server = MustServer(request);
1318
1319 if (!request.has_action()) {
1320 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing action");
1321 }
1322
1323 rpc->m_contextActionListeners[server->iServerNum].insert(u8(request.action()), this);
1324 }
1325
done(bool)1326 void V1_ContextActionEvents::done(bool) {
1327 auto server = MustServer(request);
1328 auto &cals = rpc->m_contextActionListeners;
1329 auto &scals = cals[server->iServerNum];
1330
1331 auto i = std::find(scals.begin(), scals.end(), this);
1332 if (i != scals.end()) {
1333 scals.erase(i);
1334 }
1335 deref();
1336 if (scals.isEmpty()) {
1337 auto i = std::find(cals.begin(), cals.end(), scals);
1338 if (i != cals.end()) {
1339 cals.erase(i);
1340 }
1341 }
1342 }
1343
impl(bool)1344 void V1_TextMessageSend::impl(bool) {
1345 auto server = MustServer(request);
1346
1347 ::MumbleProto::TextMessage tm;
1348 tm.set_message(request.text());
1349 if (request.has_actor() && request.actor().has_session()) {
1350 tm.set_actor(request.actor().session());
1351 }
1352 for (int i = 0; i < request.users_size(); i++) {
1353 if (request.users(i).has_session()) {
1354 tm.add_session(request.users(i).session());
1355 }
1356 }
1357 for (int i = 0; i < request.channels_size(); i++) {
1358 if (request.channels(i).has_id()) {
1359 tm.add_channel_id(request.channels(i).id());
1360 }
1361 }
1362 for (int i = 0; i < request.trees_size(); i++) {
1363 if (request.trees(i).has_id()) {
1364 tm.add_tree_id(request.trees(i).id());
1365 }
1366 }
1367
1368 server->sendTextMessageGRPC(tm);
1369
1370 end();
1371 }
1372
impl(bool)1373 void V1_TextMessageFilter::impl(bool) {
1374 auto onInitialize = [this] (V1_TextMessageFilter *, bool ok) {
1375 if (!ok) {
1376 finish(ok);
1377 return;
1378 }
1379 auto server = MustServer(request);
1380 QMutexLocker l(&rpc->qmTextMessageFilterLock);
1381 rpc->removeTextMessageFilter(server);
1382 rpc->m_textMessageFilters.insert(server->iServerNum, this);
1383 };
1384 stream.Read(&request, callback(onInitialize));
1385 }
1386
done(bool)1387 void V1_TextMessageFilter::done(bool) {
1388 auto server = MustServer(request);
1389 auto filter = rpc->m_textMessageFilters.value(server->iServerNum);
1390 if (filter == this) {
1391 rpc->m_textMessageFilters.remove(server->iServerNum);
1392 }
1393 deref();
1394 }
1395
impl(bool)1396 void V1_LogQuery::impl(bool) {
1397 auto serverID = MustServerID(request);
1398
1399 int total = ::ServerDB::getLogLen(serverID);
1400 if (total < 0) {
1401 throw ::grpc::Status(::grpc::StatusCode::UNAVAILABLE, "could not access database");
1402 }
1403
1404 ::MurmurRPC::Log_List list;
1405 list.mutable_server()->set_id(serverID);
1406 list.set_total(total);
1407
1408 if (!request.has_min() || !request.has_max()) {
1409 end(list);
1410 return;
1411 }
1412 list.set_min(request.min());
1413 list.set_max(request.max());
1414
1415 auto dblog = ::ServerDB::getLog(serverID, request.min(), request.max());
1416 foreach(const ::ServerDB::LogRecord &record, dblog) {
1417 auto rpcLog = list.add_entries();
1418 ToRPC(serverID, record, rpcLog);
1419 }
1420
1421 end(list);
1422 }
1423
impl(bool)1424 void V1_ConfigGet::impl(bool) {
1425 auto serverID = MustServerID(request);
1426 auto config = ServerDB::getAllConf(serverID);
1427
1428 ::MurmurRPC::Config rpcConfig;
1429 rpcConfig.mutable_server()->set_id(serverID);
1430 auto &fields = *rpcConfig.mutable_fields();
1431 for (auto i = config.constBegin(); i != config.constEnd(); ++i) {
1432 fields[u8(i.key())] = u8(i.value());
1433 }
1434
1435 end(rpcConfig);
1436 }
1437
impl(bool)1438 void V1_ConfigGetField::impl(bool) {
1439 auto serverID = MustServerID(request);
1440 if (!request.has_key()) {
1441 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing key");
1442 }
1443 ::MurmurRPC::Config_Field rpcField;
1444 rpcField.mutable_server()->set_id(serverID);
1445 rpcField.set_key(request.key());
1446 rpcField.set_value(u8(ServerDB::getConf(serverID, u8(request.key()), QVariant()).toString()));
1447 end(rpcField);
1448 }
1449
impl(bool)1450 void V1_ConfigSetField::impl(bool) {
1451 auto serverID = MustServerID(request);
1452 if (!request.has_key()) {
1453 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing key");
1454 }
1455 QString key = u8(request.key());
1456 QString value;
1457 if (request.has_value()) {
1458 value = u8(request.value());
1459 }
1460 ServerDB::setConf(serverID, key, value);
1461 try {
1462 auto server = MustServer(serverID);
1463 server->setLiveConf(key, value);
1464 } catch (::grpc::Status &ex) {
1465 }
1466
1467 end();
1468 }
1469
impl(bool)1470 void V1_ConfigGetDefault::impl(bool) {
1471 ::MurmurRPC::Config rpcConfig;
1472 auto &fields = *rpcConfig.mutable_fields();
1473 for (auto i = meta->mp.qmConfig.constBegin(); i != meta->mp.qmConfig.constEnd(); ++i) {
1474 fields[u8(i.key())] = u8(i.value());
1475 }
1476
1477 end(rpcConfig);
1478 }
1479
impl(bool)1480 void V1_ChannelQuery::impl(bool) {
1481 auto server = MustServer(request);
1482
1483 ::MurmurRPC::Channel_List list;
1484 list.mutable_server()->set_id(server->iServerNum);
1485
1486 foreach(const ::Channel *channel, server->qhChannels) {
1487 auto rpcChannel = list.add_channels();
1488 ToRPC(server, channel, rpcChannel);
1489 }
1490
1491 end(list);
1492 }
1493
impl(bool)1494 void V1_ChannelGet::impl(bool) {
1495 auto server = MustServer(request);
1496 auto channel = MustChannel(server, request);
1497
1498 ::MurmurRPC::Channel rpcChannel;
1499 ToRPC(server, channel, &rpcChannel);
1500 end(rpcChannel);
1501 }
1502
impl(bool)1503 void V1_ChannelAdd::impl(bool) {
1504 auto server = MustServer(request);
1505
1506 if (!request.has_parent() || !request.has_name()) {
1507 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "parent channel and name required");
1508 }
1509 ::Channel *parent;
1510 try {
1511 parent = MustChannel(server, request.parent());
1512 } catch (::grpc::Status &ex) {
1513 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "invalid parent channel");
1514 }
1515
1516 if (!server->canNest(parent)) {
1517 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "cannot nest channel in given parent");
1518 }
1519
1520 QString qsName = u8(request.name());
1521
1522 ::Channel *nc;
1523
1524 {
1525 QWriteLocker wl(&server->qrwlVoiceThread);
1526 nc = server->addChannel(parent, qsName, request.temporary(), request.position());
1527 }
1528
1529 nc->qsDesc = u8(request.description());
1530
1531 server->updateChannel(nc);
1532 int newid = nc->iId;
1533
1534 ::MumbleProto::ChannelState mpcs;
1535 mpcs.set_channel_id(newid);
1536 mpcs.set_parent(parent->iId);
1537 mpcs.set_name(request.name());
1538 mpcs.set_temporary(request.temporary());
1539 mpcs.set_position(request.position());
1540 mpcs.set_description(request.description());
1541 server->sendAll(mpcs);
1542
1543 ::MurmurRPC::Channel resChannel;
1544 ToRPC(server, nc, &resChannel);
1545 end(resChannel);
1546 }
1547
impl(bool)1548 void V1_ChannelRemove::impl(bool) {
1549 auto server = MustServer(request);
1550 auto channel = MustChannel(server, request);
1551
1552 if (!channel->cParent) {
1553 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "cannot remove the root channel");
1554 }
1555
1556 server->removeChannel(channel);
1557
1558 end();
1559 }
1560
impl(bool)1561 void V1_ChannelUpdate::impl(bool) {
1562 auto server = MustServer(request);
1563 auto channel = MustChannel(server, request);
1564
1565 ::MumbleProto::ChannelState mpcs;
1566 mpcs.set_channel_id(channel->iId);
1567 for (int i = 0; i < request.links_size(); i++) {
1568 if (!request.links(i).has_id()) {
1569 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "invalid channel link");
1570 }
1571 mpcs.add_links(request.links(i).id());
1572 }
1573 if (request.has_parent()) {
1574 if (!request.parent().has_id()) {
1575 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "invalid channel parent");
1576 }
1577 mpcs.set_parent(request.parent().id());
1578 }
1579 if (request.has_name()) {
1580 mpcs.set_name(request.name());
1581 }
1582 if (request.has_position()) {
1583 mpcs.set_position(request.position());
1584 }
1585 if (request.has_description()) {
1586 mpcs.set_description(request.description());
1587 }
1588
1589 QString err;
1590 if (!server->setChannelStateGRPC(mpcs, err)) {
1591 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, u8(err));
1592 }
1593
1594 ::MurmurRPC::Channel rpcChannel;
1595 ToRPC(server, channel, &rpcChannel);
1596 end(rpcChannel);
1597 }
1598
impl(bool)1599 void V1_UserQuery::impl(bool) {
1600 auto server = MustServer(request);
1601
1602 ::MurmurRPC::User_List list;
1603 list.mutable_server()->set_id(server->iServerNum);
1604
1605 foreach(const ::ServerUser *user, server->qhUsers) {
1606 if (user->sState != ServerUser::Authenticated) {
1607 continue;
1608 }
1609 auto rpcUser = list.add_users();
1610 ToRPC(server, user, rpcUser);
1611 }
1612
1613 end(list);
1614 }
1615
impl(bool)1616 void V1_UserGet::impl(bool) {
1617 auto server = MustServer(request);
1618
1619 ::MurmurRPC::User rpcUser;
1620
1621 if (request.has_session()) {
1622 // Lookup user by session
1623 auto user = MustUser(server, request);
1624 ToRPC(server, user, &rpcUser);
1625 end(rpcUser);
1626 return;
1627 } else if (request.has_name()) {
1628 // Lookup user by name
1629 QString qsName = u8(request.name());
1630 foreach(const ::ServerUser *user, server->qhUsers) {
1631 if (user->sState != ServerUser::Authenticated) {
1632 continue;
1633 }
1634 if (user->qsName == qsName) {
1635 ToRPC(server, user, &rpcUser);
1636 end(rpcUser);
1637 return;
1638 }
1639 }
1640 throw ::grpc::Status(::grpc::NOT_FOUND, "invalid user");
1641 }
1642
1643 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "session or name required");
1644 }
1645
impl(bool)1646 void V1_UserUpdate::impl(bool) {
1647 auto server = MustServer(request);
1648 auto user = MustUser(server, request);
1649
1650 auto channel = user->cChannel;
1651 if (request.has_channel()) {
1652 channel = MustChannel(server, request.channel());
1653 }
1654 auto mute = user->bMute;
1655 if (request.has_mute()) {
1656 mute = request.mute();
1657 }
1658 auto deaf = user->bDeaf;
1659 if (request.has_deaf()) {
1660 deaf = request.deaf();
1661 }
1662 auto suppress = user->bSuppress;
1663 if (request.has_suppress()) {
1664 suppress = request.suppress();
1665 }
1666 auto prioritySpeaker = user->bPrioritySpeaker;
1667 if (request.has_priority_speaker()) {
1668 prioritySpeaker = request.priority_speaker();
1669 }
1670 auto name = user->qsName;
1671 if (request.has_name()) {
1672 name = u8(request.name());
1673 }
1674 auto comment = user->qsComment;
1675 if (request.has_comment()) {
1676 comment = u8(request.comment());
1677 }
1678
1679 server->setUserState(user, channel, mute, deaf, suppress, prioritySpeaker, name, comment);
1680
1681 ::MurmurRPC::User rpcUser;
1682 ToRPC(server, user, &rpcUser);
1683 end(rpcUser);
1684 }
1685
impl(bool)1686 void V1_UserKick::impl(bool) {
1687 auto server = MustServer(request);
1688 auto user = MustUser(server, request);
1689
1690 ::MumbleProto::UserRemove mpur;
1691 mpur.set_session(user->uiSession);
1692 if (request.has_reason()) {
1693 mpur.set_reason(request.reason());
1694 }
1695 if (request.has_actor() && request.actor().has_session()) {
1696 mpur.set_actor(request.actor().session());
1697 }
1698 server->sendAll(mpur);
1699 user->disconnectSocket();
1700
1701 end();
1702 }
1703
impl(bool)1704 void V1_TreeQuery::impl(bool) {
1705 auto server = MustServer(request);
1706
1707 auto channel = MustChannel(server, 0);
1708 ::MurmurRPC::Tree root;
1709
1710 QQueue< QPair<const ::Channel *, ::MurmurRPC::Tree *> > qQueue;
1711 qQueue.enqueue(qMakePair(channel, &root));
1712
1713 while (!qQueue.isEmpty()) {
1714 auto current = qQueue.dequeue();
1715 auto currentChannel = current.first;
1716 auto currentTree = current.second;
1717
1718 ToRPC(server, currentChannel, currentTree->mutable_channel());
1719
1720 QList< ::User *> users = currentChannel->qlUsers;
1721 qSort(users.begin(), users.end(), [] (const ::User *a, const ::User *b) -> bool {
1722 return ::User::lessThan(a, b);
1723 });
1724 foreach(const ::User *u, users) {
1725 auto rpcUser = currentTree->add_users();
1726 ToRPC(server, u, rpcUser);
1727 }
1728
1729 QList< ::Channel *> channels = currentChannel->qlChannels;
1730 qSort(channels.begin(), channels.end(), [] (const ::Channel *a, const ::Channel *b) -> bool {
1731 return ::Channel::lessThan(a, b);
1732 });
1733 foreach(const ::Channel *subChannel, channels) {
1734 auto subTree = currentTree->add_children();
1735 qQueue.enqueue(qMakePair(subChannel, subTree));
1736 }
1737 }
1738
1739 end(root);
1740 }
1741
impl(bool)1742 void V1_BansGet::impl(bool) {
1743 auto server = MustServer(request);
1744
1745 ::MurmurRPC::Ban_List list;
1746 list.mutable_server()->set_id(server->iServerNum);
1747 foreach(const ::Ban &ban, server->qlBans) {
1748 auto rpcBan = list.add_bans();
1749 ToRPC(server, ban, rpcBan);
1750 }
1751
1752 end(list);
1753 }
1754
impl(bool)1755 void V1_BansSet::impl(bool) {
1756 auto server = MustServer(request);
1757 server->qlBans.clear();
1758
1759 for (int i = 0; i < request.bans_size(); i++) {
1760 const auto &rpcBan = request.bans(i);
1761 ::Ban ban;
1762 FromRPC(server, rpcBan, ban);
1763 server->qlBans << ban;
1764 }
1765 server->saveBans();
1766
1767 end();
1768 }
1769
impl(bool)1770 void V1_ACLGet::impl(bool) {
1771 auto server = MustServer(request);
1772 auto channel = MustChannel(server, request);
1773
1774 ::MurmurRPC::ACL_List list;
1775 list.set_inherit(channel->bInheritACL);
1776
1777 QStack< ::Channel *> chans;
1778 ChanACL *acl;
1779 ::Channel *p = channel;
1780 while (p) {
1781 chans.push(p);
1782 if ((p == channel) || p->bInheritACL) {
1783 p = p->cParent;
1784 } else {
1785 p = NULL;
1786 }
1787 }
1788
1789 while (!chans.isEmpty()) {
1790 p = chans.pop();
1791 foreach(acl, p->qlACL) {
1792 if (p == channel || acl->bApplySubs) {
1793 auto rpcACL = list.add_acls();
1794 ToRPC(server, acl, rpcACL);
1795 if (p != channel) {
1796 rpcACL->set_inherited(true);
1797 }
1798 }
1799 }
1800 }
1801
1802 p = channel->cParent;
1803 const QSet<QString> allnames = ::Group::groupNames(channel);
1804 foreach(const QString &name, allnames) {
1805 ::Group *g = channel->qhGroups.value(name);
1806 ::Group *pg = p ? ::Group::getGroup(p, name) : NULL;
1807 if (!g && ! pg) {
1808 continue;
1809 }
1810 auto aclGroup = list.add_groups();
1811 ToRPC(server, g ? g : pg, aclGroup);
1812 QSet<int> members;
1813 if (pg) {
1814 members = pg->members();
1815 }
1816 if (g) {
1817 foreach(auto id, g->qsAdd) {
1818 auto rpcUser = aclGroup->add_users_add();
1819 rpcUser->mutable_server()->set_id(server->iServerNum);
1820 rpcUser->set_id(id);
1821 }
1822 foreach(auto id, g->qsRemove) {
1823 auto rpcUser = aclGroup->add_users_remove();
1824 rpcUser->mutable_server()->set_id(server->iServerNum);
1825 rpcUser->set_id(id);
1826 }
1827 aclGroup->set_inherited(false);
1828 members += g->qsAdd;
1829 members -= g->qsRemove;
1830 } else {
1831 aclGroup->set_inherited(true);
1832 }
1833 foreach(auto id, members) {
1834 auto rpcUser = aclGroup->add_users();
1835 rpcUser->mutable_server()->set_id(server->iServerNum);
1836 rpcUser->set_id(id);
1837 }
1838 }
1839
1840 end(list);
1841 }
1842
impl(bool)1843 void V1_ACLSet::impl(bool) {
1844 auto server = MustServer(request);
1845 auto channel = MustChannel(server, request);
1846
1847 ::Group *g;
1848 ::ChanACL *acl;
1849
1850 {
1851 QWriteLocker wl(&server->qrwlVoiceThread);
1852
1853 QHash<QString, QSet<int> > hOldTemp;
1854 foreach(g, channel->qhGroups) {
1855 hOldTemp.insert(g->qsName, g->qsTemporary);
1856 delete g;
1857 }
1858 foreach(acl, channel->qlACL) {
1859 delete acl;
1860 }
1861
1862 channel->qhGroups.clear();
1863 channel->qlACL.clear();
1864
1865 channel->bInheritACL = request.inherit();
1866
1867 for (int i = 0; i < request.groups_size(); i++) {
1868 auto &rpcGroup = request.groups(i);
1869 auto name = u8(rpcGroup.name());
1870 g = new ::Group(channel, name);
1871 g->bInherit = rpcGroup.inherit();
1872 g->bInheritable = rpcGroup.inheritable();
1873 for (int j = 0; j < rpcGroup.users_add_size(); j++) {
1874 g->qsAdd.insert(rpcGroup.users_add(j).id());
1875 }
1876 for (int j = 0; j < rpcGroup.users_remove_size(); j++) {
1877 g->qsRemove.insert(rpcGroup.users_remove(j).id());
1878 }
1879 g->qsTemporary = hOldTemp.value(name);
1880 }
1881 for (int i = 0; i < request.acls_size(); i++) {
1882 auto &rpcACL = request.acls(i);
1883 acl = new ChanACL(channel);
1884 acl->bApplyHere = rpcACL.apply_here();
1885 acl->bApplySubs = rpcACL.apply_subs();
1886 if (rpcACL.has_user()) {
1887 acl->iUserId = rpcACL.user().id();
1888 }
1889 if (rpcACL.has_group() && rpcACL.group().has_name()) {
1890 acl->qsGroup = u8(rpcACL.group().name());
1891 }
1892 acl->pDeny = static_cast<ChanACL::Permissions>(rpcACL.deny()) & ChanACL::All;
1893 acl->pAllow = static_cast<ChanACL::Permissions>(rpcACL.allow()) & ChanACL::All;
1894 }
1895 }
1896
1897 server->clearACLCache();
1898 server->updateChannel(channel);
1899
1900 end();
1901 }
1902
impl(bool)1903 void V1_ACLGetEffectivePermissions::impl(bool) {
1904 auto server = MustServer(request);
1905 auto user = MustUser(server, request);
1906 auto channel = MustChannel(server, request);
1907
1908 auto flags = int(server->effectivePermissions(user, channel));
1909
1910 ::MurmurRPC::ACL rpcACL;
1911 rpcACL.set_allow(::MurmurRPC::ACL_Permission(flags));
1912 end(rpcACL);
1913 }
1914
impl(bool)1915 void V1_ACLAddTemporaryGroup::impl(bool) {
1916 auto server = MustServer(request);
1917 auto user = MustUser(server, request);
1918 auto channel = MustChannel(server, request);
1919
1920 if (!request.has_name()) {
1921 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing name");
1922 }
1923
1924 QString qsgroup = u8(request.name());
1925 if (qsgroup.isEmpty()) {
1926 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "empty name");
1927 }
1928
1929 {
1930 QWriteLocker wl(&server->qrwlVoiceThread);
1931
1932 ::Group *g = channel->qhGroups.value(qsgroup);
1933 if (!g) {
1934 g = new ::Group(channel, qsgroup);
1935 }
1936
1937 g->qsTemporary.insert(-user->uiSession);
1938 }
1939
1940 server->clearACLCache(user);
1941
1942 end();
1943 }
1944
impl(bool)1945 void V1_ACLRemoveTemporaryGroup::impl(bool) {
1946 auto server = MustServer(request);
1947 auto user = MustUser(server, request);
1948 auto channel = MustChannel(server, request);
1949
1950 if (!request.has_name()) {
1951 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing name");
1952 }
1953
1954 QString qsgroup = u8(request.name());
1955 if (qsgroup.isEmpty()) {
1956 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "empty name");
1957 }
1958
1959 {
1960 QWriteLocker wl(&server->qrwlVoiceThread);
1961
1962 ::Group *g = channel->qhGroups.value(qsgroup);
1963 if (!g) {
1964 g = new ::Group(channel, qsgroup);
1965 }
1966
1967 g->qsTemporary.remove(-user->uiSession);
1968 }
1969
1970 server->clearACLCache(user);
1971
1972 end();
1973 }
1974
impl(bool)1975 void V1_AuthenticatorStream::impl(bool) {
1976 auto onInitialize = [this] (V1_AuthenticatorStream *, bool ok) {
1977 if (!ok) {
1978 finish(ok);
1979 return;
1980 }
1981 if (!request.has_initialize()) {
1982 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing initialize");
1983 }
1984 auto server = MustServer(request.initialize());
1985 QMutexLocker l(&rpc->qmAuthenticatorsLock);
1986 rpc->removeAuthenticator(server);
1987 rpc->m_authenticators.insert(server->iServerNum, this);
1988 };
1989 stream.Read(&request, callback(onInitialize));
1990 }
1991
done(bool)1992 void V1_AuthenticatorStream::done(bool) {
1993 auto i = std::find(rpc->m_authenticators.begin(), rpc->m_authenticators.end(), this);
1994 if (i != rpc->m_authenticators.end()) {
1995 rpc->m_authenticators.erase(i);
1996 }
1997 deref();
1998 }
1999
impl(bool)2000 void V1_DatabaseUserQuery::impl(bool) {
2001 auto server = MustServer(request);
2002
2003 QString filter;
2004 if (request.has_filter()) {
2005 filter = u8(request.filter());
2006 }
2007 auto users = server->getRegisteredUsers(filter);
2008
2009 ::MurmurRPC::DatabaseUser_List list;
2010 list.mutable_server()->set_id(server->iServerNum);
2011
2012 for (auto itr = users.constBegin(); itr != users.constEnd(); ++itr) {
2013 auto user = list.add_users();
2014 user->mutable_server()->set_id(server->iServerNum);
2015 user->set_id(itr.key());
2016 user->set_name(u8(itr.value()));
2017 }
2018
2019 end(list);
2020 }
2021
impl(bool)2022 void V1_DatabaseUserGet::impl(bool) {
2023 auto server = MustServer(request);
2024
2025 if (!request.has_id()) {
2026 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing id");
2027 }
2028 auto info = server->getRegistration(request.id());
2029 if (info.isEmpty()) {
2030 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "invalid user");
2031 }
2032 auto texture = server->getUserTexture(request.id());
2033
2034 ::MurmurRPC::DatabaseUser rpcDatabaseUser;
2035 ToRPC(server, info, texture, &rpcDatabaseUser);
2036 end(rpcDatabaseUser);
2037 }
2038
impl(bool)2039 void V1_DatabaseUserUpdate::impl(bool) {
2040 auto server = MustServer(request);
2041
2042 if (!request.has_id()) {
2043 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing id");
2044 }
2045 if (!server->isUserId(request.id())) {
2046 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "invalid user");
2047 }
2048
2049 QMap<int, QString> info;
2050 FromRPC(request, info);
2051
2052 if (!server->setInfo(request.id(), info)) {
2053 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "invalid user");
2054 }
2055 if (request.has_texture()) {
2056 server->setTexture(request.id(), QByteArray(request.texture().c_str(), request.texture().size()));
2057 }
2058
2059 if (info.contains(ServerDB::User_Name) || info.contains(ServerDB::User_Comment)) {
2060 foreach(::ServerUser *u, server->qhUsers) {
2061 if (static_cast<unsigned int>(u->iId) == request.id()) {
2062 QString name = u->qsName;
2063 QString comment = u->qsComment;
2064 if (info.contains(ServerDB::User_Name)) {
2065 name = info.value(ServerDB::User_Name);
2066 }
2067 if (info.contains(ServerDB::User_Comment)) {
2068 comment = info.value(ServerDB::User_Comment);
2069 }
2070 server->setUserState(u, u->cChannel, u->bMute, u->bDeaf, u->bSuppress, u->bPrioritySpeaker, name, comment);
2071 break;
2072 }
2073 }
2074 }
2075
2076 end();
2077 }
2078
impl(bool)2079 void V1_DatabaseUserRegister::impl(bool) {
2080 auto server = MustServer(request);
2081
2082 QMap<int, QString> info;
2083 FromRPC(request, info);
2084
2085 auto userid = server->registerUser(info);
2086 if (userid < 0) {
2087 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "invalid user");
2088 }
2089 QByteArray texture;
2090 if (request.has_texture()) {
2091 texture = QByteArray(request.texture().c_str(), request.texture().size());
2092 server->setTexture(request.id(), texture);
2093 }
2094
2095 ::MurmurRPC::DatabaseUser rpcDatabaseUser;
2096 rpcDatabaseUser.set_id(userid);
2097 ToRPC(server, info, texture, &rpcDatabaseUser);
2098 end(rpcDatabaseUser);
2099 }
2100
impl(bool)2101 void V1_DatabaseUserDeregister::impl(bool) {
2102 auto server = MustServer(request);
2103
2104 if (!request.has_id()) {
2105 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing id");
2106 }
2107 if (!server->unregisterUser(request.id())) {
2108 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "invalid user");
2109 }
2110
2111 end();
2112 }
2113
impl(bool)2114 void V1_DatabaseUserVerify::impl(bool) {
2115 auto server = MustServer(request);
2116
2117 if (!request.has_name()) {
2118 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing name");
2119 }
2120 if (!request.has_password()) {
2121 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing password");
2122 }
2123
2124 auto name = u8(request.name());
2125 auto password = u8(request.password());
2126
2127 auto ret = server->authenticate(name, password);
2128 switch (ret) {
2129 case -1:
2130 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "invalid username and/or password");
2131 case -2:
2132 throw ::grpc::Status(::grpc::NOT_FOUND, "unknown user");
2133 case -3:
2134 throw ::grpc::Status(::grpc::UNAVAILABLE, "authenticator temporarily unavailable");
2135 }
2136
2137 ::MurmurRPC::DatabaseUser rpcDatabaseUser;
2138 rpcDatabaseUser.mutable_server()->set_id(server->iServerNum);
2139 rpcDatabaseUser.set_id(ret);
2140 end(rpcDatabaseUser);
2141 }
2142
impl(bool)2143 void V1_RedirectWhisperGroupAdd::impl(bool) {
2144 auto server = MustServer(request);
2145 auto user = MustUser(server, request);
2146
2147 if (!request.source().has_name()) {
2148 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing source name");
2149 }
2150 if (!request.target().has_name()) {
2151 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing target name");
2152 }
2153
2154 QString qssource = u8(request.source().name());
2155 QString qstarget = u8(request.target().name());
2156
2157 {
2158 QWriteLocker wl(&server->qrwlVoiceThread);
2159 user->qmWhisperRedirect.insert(qssource, qstarget);
2160 }
2161
2162 server->clearACLCache(user);
2163
2164 end();
2165 }
2166
impl(bool)2167 void V1_RedirectWhisperGroupRemove::impl(bool) {
2168 auto server = MustServer(request);
2169 auto user = MustUser(server, request);
2170
2171 if (!request.source().has_name()) {
2172 throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing source name");
2173 }
2174
2175 QString qssource = u8(request.source().name());
2176
2177 {
2178 QWriteLocker wl(&server->qrwlVoiceThread);
2179 user->qmWhisperRedirect.remove(qssource);
2180 }
2181
2182 server->clearACLCache(user);
2183
2184 end();
2185 }
2186
2187 }
2188 }
2189