1 /* Copyright (C) 2009-2011, Martin Johansson <martin@fatbob.nu>
2 Copyright (C) 2005-2011, Thorvald Natvig <thorvald@natvig.com>
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
10 - Redistributions of source code must retain the above copyright notice,
11 this list of conditions and the following disclaimer.
12 - Redistributions in binary form must reproduce the above copyright notice,
13 this list of conditions and the following disclaimer in the documentation
14 and/or other materials provided with the distribution.
15 - Neither the name of the Developers nor the names of its contributors may
16 be used to endorse or promote products derived from this software without
17 specific prior written permission.
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
23 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 #include "messagehandler.h"
42 #include "voicetarget.h"
45 #define MAX_USERNAME 128
47 extern channel_t *defaultChan;
48 extern int iCodecAlpha, iCodecBeta;
49 extern bool_t bPreferAlpha;
51 static void sendServerReject(client_t *client, const char *reason, MumbleProto__Reject__RejectType type)
53 message_t *msg = Msg_create(Reject);
54 msg->payload.reject->reason = strdup(reason);
55 msg->payload.reject->type = type;
56 msg->payload.reject->has_type = true;
57 Client_send_message(client, msg);
59 Log_info_client(client, "Server reject reason: %s", reason);
62 static void sendPermissionDenied(client_t *client, const char *reason)
64 message_t *msg = Msg_create(PermissionDenied);
65 msg->payload.permissionDenied->has_type = true;
66 msg->payload.permissionDenied->type = MUMBLE_PROTO__PERMISSION_DENIED__DENY_TYPE__Text;
67 msg->payload.permissionDenied->reason = strdup(reason);
68 Client_send_message(client, msg);
71 static void addTokens(client_t *client, message_t *msg)
74 if (client->tokencount + msg->payload.authenticate->n_tokens < MAX_TOKENS) {
75 /* Check lengths first */
76 for (i = 0; i < msg->payload.authenticate->n_tokens; i++) {
77 if (strlen(msg->payload.authenticate->tokens[i]) > MAX_TOKENSIZE - 1) {
78 sendPermissionDenied(client, "Too long token");
83 for (i = 0; i < msg->payload.authenticate->n_tokens; i++) {
84 Log_debug("Adding token '%s' to client '%s'", msg->payload.authenticate->tokens[i], client->username);
85 Client_token_add(client, msg->payload.authenticate->tokens[i]);
89 sendPermissionDenied(client, "Too many tokens");
92 void Mh_handle_message(client_t *client, message_t *msg)
94 message_t *sendmsg = NULL;
95 channel_t *ch_itr = NULL;
98 if (!client->authenticated && !(msg->messageType == Authenticate ||
99 msg->messageType == Version)) {
103 switch (msg->messageType) {
109 case PermissionQuery:
112 Timer_restart(&client->idleTime);
115 switch (msg->messageType) {
117 Log_debug("Authenticate message received");
119 if (IS_AUTH(client) || !msg->payload.authenticate->username) {
120 /* Authenticate message might be sent when a tokens are changed by the user.*/
121 Client_token_free(client); /* Clear the token list */
122 if (msg->payload.authenticate->n_tokens > 0) {
123 Log_debug("Tokens in auth message from '%s'. n_tokens = %d", client->username,
124 msg->payload.authenticate->n_tokens);
125 addTokens(client, msg);
130 client->authenticated = true;
133 while (Client_iterate(&client_itr) != NULL) {
134 if (!IS_AUTH(client_itr))
136 if (client_itr->username && strncmp(client_itr->username, msg->payload.authenticate->username, MAX_USERNAME) == 0) {
138 sprintf(buf, "Username already in use");
139 Log_debug("Username already in use");
140 sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__UsernameInUse);
144 if (strlen(getStrConf(PASSPHRASE)) > 0) {
145 if (!msg->payload.authenticate->password ||
146 (msg->payload.authenticate->password &&
147 strncmp(getStrConf(PASSPHRASE), msg->payload.authenticate->password, MAX_TEXT) != 0)) {
149 sprintf(buf, "Wrong server password");
150 sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__WrongServerPW);
151 Log_debug("Wrong server password: '%s'", msg->payload.authenticate->password != NULL ?
152 msg->payload.authenticate->password : "(null)");
156 if (strlen(msg->payload.authenticate->username) == 0 ||
157 strlen(msg->payload.authenticate->username) >= MAX_USERNAME) { /* XXX - other invalid names? */
159 sprintf(buf, "Invalid username");
160 Log_debug("Invalid username");
161 sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__InvalidUsername);
165 if (Client_count() >= getIntConf(MAX_CLIENTS)) {
167 snprintf(buf, 64, "Server is full (max %d users)", getIntConf(MAX_CLIENTS));
168 sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__ServerFull);
173 client->username = strdup(msg->payload.authenticate->username);
176 if (msg->payload.authenticate->n_tokens > 0)
177 addTokens(client, msg);
180 /* Setup UDP encryption */
181 CryptState_init(&client->cryptState);
182 CryptState_genKey(&client->cryptState);
183 sendmsg = Msg_create(CryptSetup);
184 sendmsg->payload.cryptSetup->has_key = true;
185 sendmsg->payload.cryptSetup->key.data = client->cryptState.raw_key;
186 sendmsg->payload.cryptSetup->key.len = AES_BLOCK_SIZE;
187 sendmsg->payload.cryptSetup->has_server_nonce = true;
188 sendmsg->payload.cryptSetup->server_nonce.data = client->cryptState.encrypt_iv;
189 sendmsg->payload.cryptSetup->server_nonce.len = AES_BLOCK_SIZE;
190 sendmsg->payload.cryptSetup->has_client_nonce = true;
191 sendmsg->payload.cryptSetup->client_nonce.data = client->cryptState.decrypt_iv;
192 sendmsg->payload.cryptSetup->client_nonce.len = AES_BLOCK_SIZE;
193 Client_send_message(client, sendmsg);
196 Chan_userJoin(defaultChan, client); /* Join default channel */
199 Log_debug("Client %d has %d CELT codecs", client->sessionId,
200 msg->payload.authenticate->n_celt_versions);
201 if (msg->payload.authenticate->n_celt_versions > 0) {
204 client->codec_count = msg->payload.authenticate->n_celt_versions;
206 for (i = 0; i < client->codec_count; i++)
207 Client_codec_add(client, msg->payload.authenticate->celt_versions[i]);
209 while (Client_codec_iterate(client, &codec_itr) != NULL)
210 Log_debug("Client %d CELT codec ver 0x%x", client->sessionId, codec_itr->codec);
213 Client_codec_add(client, (int32_t)0x8000000a);
214 client->codec_count = 1;
217 recheckCodecVersions();
219 sendmsg = Msg_create(CodecVersion);
220 sendmsg->payload.codecVersion->alpha = iCodecAlpha;
221 sendmsg->payload.codecVersion->beta = iCodecBeta;
222 sendmsg->payload.codecVersion->prefer_alpha = bPreferAlpha;
223 Client_send_message(client, sendmsg);
225 /* Iterate channels and send channel info */
227 while (Chan_iterate(&ch_itr) != NULL) {
228 sendmsg = Msg_create(ChannelState);
229 sendmsg->payload.channelState->has_channel_id = true;
230 sendmsg->payload.channelState->channel_id = ch_itr->id;
231 if (ch_itr->id != 0) {
232 sendmsg->payload.channelState->has_parent = true;
233 sendmsg->payload.channelState->parent = ch_itr->parent->id;
235 sendmsg->payload.channelState->name = strdup(ch_itr->name);
237 sendmsg->payload.channelState->description = strdup(ch_itr->desc);
238 Log_debug("Send channel info: %s", sendmsg->payload.channelState->name);
239 Client_send_message(client, sendmsg);
242 /* Iterate channels and send channel links info */
244 while (Chan_iterate(&ch_itr) != NULL) {
245 if (ch_itr->linkcount > 0) { /* Has links */
250 sendmsg = Msg_create(ChannelState);
251 sendmsg->payload.channelState->has_channel_id = true;
252 sendmsg->payload.channelState->channel_id = ch_itr->id;
253 sendmsg->payload.channelState->n_links = ch_itr->linkcount;
255 links = (uint32_t *)malloc(ch_itr->linkcount * sizeof(uint32_t));
256 list_iterate(itr, &ch_itr->channel_links) { /* Iterate links */
258 ch = list_get_entry(itr, channel_t, link_node);
261 sendmsg->payload.channelState->links = links;
262 Client_send_message(client, sendmsg);
266 /* Send user state for connecting user to other users */
267 sendmsg = Msg_create(UserState);
268 sendmsg->payload.userState->has_session = true;
269 sendmsg->payload.userState->session = client->sessionId;
270 sendmsg->payload.userState->name = strdup(client->username);
271 sendmsg->payload.userState->has_channel_id = true;
272 sendmsg->payload.userState->channel_id = ((channel_t *)client->channel)->id;
274 Client_send_message_except(client, sendmsg);
277 while (Client_iterate(&client_itr) != NULL) {
278 if (!IS_AUTH(client_itr))
280 sendmsg = Msg_create(UserState);
281 sendmsg->payload.userState->has_session = true;
282 sendmsg->payload.userState->session = client_itr->sessionId;
283 sendmsg->payload.userState->name = strdup(client_itr->username);
284 sendmsg->payload.userState->has_channel_id = true;
285 sendmsg->payload.userState->channel_id = ((channel_t *)client_itr->channel)->id;
287 /* Only self_mute/deaf supported */
288 if (client_itr->deaf) {
289 sendmsg->payload.userState->has_self_deaf = true;
290 sendmsg->payload.userState->self_deaf = true;
292 if (client_itr->mute) {
293 sendmsg->payload.userState->has_self_mute = true;
294 sendmsg->payload.userState->self_mute = true;
296 if (client_itr->recording) {
297 sendmsg->payload.userState->has_recording = true;
298 sendmsg->payload.userState->recording = true;
300 Client_send_message(client, sendmsg);
304 sendmsg = Msg_create(ServerSync);
305 sendmsg->payload.serverSync->has_session = true;
306 sendmsg->payload.serverSync->session = client->sessionId;
307 sendmsg->payload.serverSync->welcome_text = strdup(getStrConf(WELCOMETEXT));
308 sendmsg->payload.serverSync->has_max_bandwidth = true;
309 sendmsg->payload.serverSync->max_bandwidth = getIntConf(MAX_BANDWIDTH);
310 Client_send_message(client, sendmsg);
312 /* Server config message */
313 sendmsg = Msg_create(ServerConfig);
314 sendmsg->payload.serverConfig->has_allow_html = true;
315 sendmsg->payload.serverConfig->allow_html = true; /* Support this? */
316 sendmsg->payload.serverConfig->has_message_length = true;
317 sendmsg->payload.serverConfig->message_length = MAX_TEXT; /* Hardcoded */
318 sendmsg->payload.serverConfig->has_image_message_length = true;
319 sendmsg->payload.serverConfig->image_message_length = 0; /* XXX */
320 Client_send_message(client, sendmsg);
322 Log_info_client(client, "User %s authenticated", client->username);
326 if (msg->payload.ping->has_good)
327 client->cryptState.uiRemoteGood = msg->payload.ping->good;
328 if (msg->payload.ping->has_late)
329 client->cryptState.uiRemoteLate = msg->payload.ping->late;
330 if (msg->payload.ping->has_lost)
331 client->cryptState.uiRemoteLost = msg->payload.ping->lost;
332 if (msg->payload.ping->has_resync)
333 client->cryptState.uiRemoteResync = msg->payload.ping->resync;
335 Log_debug("Ping <-: %d %d %d %d",
336 client->cryptState.uiRemoteGood, client->cryptState.uiRemoteLate,
337 client->cryptState.uiRemoteLost, client->cryptState.uiRemoteResync
340 client->UDPPingAvg = msg->payload.ping->udp_ping_avg;
341 client->UDPPingVar = msg->payload.ping->udp_ping_var;
342 client->TCPPingAvg = msg->payload.ping->tcp_ping_avg;
343 client->TCPPingVar = msg->payload.ping->tcp_ping_var;
344 client->UDPPackets = msg->payload.ping->udp_packets;
345 client->TCPPackets = msg->payload.ping->tcp_packets;
347 sendmsg = Msg_create(Ping);
349 sendmsg->payload.ping->timestamp = msg->payload.ping->timestamp;
350 sendmsg->payload.ping->has_timestamp = true;
351 sendmsg->payload.ping->good = client->cryptState.uiGood;
352 sendmsg->payload.ping->has_good = true;
353 sendmsg->payload.ping->late = client->cryptState.uiLate;
354 sendmsg->payload.ping->has_late = true;
355 sendmsg->payload.ping->lost = client->cryptState.uiLost;
356 sendmsg->payload.ping->has_lost = true;
357 sendmsg->payload.ping->resync = client->cryptState.uiResync;
358 sendmsg->payload.ping->has_resync = true;
360 Client_send_message(client, sendmsg);
361 Log_debug("Ping ->: %d %d %d %d",
362 client->cryptState.uiGood, client->cryptState.uiLate,
363 client->cryptState.uiLost, client->cryptState.uiResync);
367 Log_debug("Voice channel crypt resync requested");
368 if (!msg->payload.cryptSetup->has_client_nonce) {
369 sendmsg = Msg_create(CryptSetup);
370 sendmsg->payload.cryptSetup->has_server_nonce = true;
371 sendmsg->payload.cryptSetup->server_nonce.data = client->cryptState.decrypt_iv;
372 sendmsg->payload.cryptSetup->server_nonce.len = AES_BLOCK_SIZE;
373 Client_send_message(client, sendmsg);
375 memcpy(client->cryptState.decrypt_iv, msg->payload.cryptSetup->client_nonce.data, AES_BLOCK_SIZE);
376 client->cryptState.uiResync++;
380 /* Only allow state changes for for the self user */
381 if (msg->payload.userState->has_session &&
382 msg->payload.userState->session != client->sessionId) {
383 sendPermissionDenied(client, "Permission denied");
386 if (msg->payload.userState->has_user_id || msg->payload.userState->has_mute ||
387 msg->payload.userState->has_deaf || msg->payload.userState->has_suppress ||
388 msg->payload.userState->has_texture) {
390 sendPermissionDenied(client, "Not supported by uMurmur");
394 msg->payload.userState->has_session = true;
395 msg->payload.userState->session = client->sessionId;
396 msg->payload.userState->has_actor = true;
397 msg->payload.userState->actor = client->sessionId;
399 if (msg->payload.userState->has_self_deaf) {
400 client->deaf = msg->payload.userState->self_deaf;
402 if (msg->payload.userState->has_self_mute) {
403 client->mute = msg->payload.userState->self_mute;
405 msg->payload.userState->has_self_deaf = true;
406 msg->payload.userState->self_deaf = false;
407 client->deaf = false;
410 if (msg->payload.userState->has_recording &&
411 msg->payload.userState->recording != client->recording) {
412 client->recording = msg->payload.userState->recording;
416 message = malloc(strlen(client->username) + 32);
418 Log_fatal("Out of memory");
419 tree_id = malloc(sizeof(uint32_t));
421 Log_fatal("Out of memory");
423 sendmsg = Msg_create(TextMessage);
424 sendmsg->payload.textMessage->message = message;
425 sendmsg->payload.textMessage->n_tree_id = 1;
426 sendmsg->payload.textMessage->tree_id = tree_id;
427 if (client->recording)
428 sprintf(message, "User %s started recording", client->username);
430 sprintf(message, "User %s stopped recording", client->username);
431 Client_send_message_except_ver(NULL, sendmsg, ~0x010203);
434 if (msg->payload.userState->has_channel_id) {
436 channelJoinResult_t chjoin_rc = Chan_userJoin_id_test(msg->payload.userState->channel_id, client);
438 if (chjoin_rc != CHJOIN_OK) {
439 if (chjoin_rc == CHJOIN_WRONGPW) {
440 sendPermissionDenied(client, "Wrong channel password");
445 leave_id = Chan_userJoin_id(msg->payload.userState->channel_id, client);
447 Log_debug("Removing channel ID %d", leave_id);
448 sendmsg = Msg_create(ChannelRemove);
449 sendmsg->payload.channelRemove->channel_id = leave_id;
452 if (msg->payload.userState->has_plugin_context) {
454 free(client->context);
455 client->context = malloc(msg->payload.userState->plugin_context.len);
456 if (client->context == NULL)
457 Log_fatal("Out of memory");
458 memcpy(client->context, msg->payload.userState->plugin_context.data,
459 msg->payload.userState->plugin_context.len);
461 break; /* Don't inform other users about this state */
466 Client_send_message_except(NULL, msg);
468 /* Need to send remove channel message _after_ UserState message */
470 Client_send_message_except(NULL, sendmsg);
474 msg->payload.textMessage->has_actor = true;
475 msg->payload.textMessage->actor = client->sessionId;
477 /* XXX - HTML is allowed and can't be turned off */
478 if (msg->payload.textMessage->n_tree_id > 0) {
479 sendPermissionDenied(client, "Tree message not supported");
483 if (msg->payload.textMessage->n_channel_id > 0) { /* To channel */
486 for (i = 0; i < msg->payload.textMessage->n_channel_id; i++) {
489 Chan_iterate(&ch_itr);
490 } while (ch_itr != NULL && ch_itr->id != msg->payload.textMessage->channel_id[i]);
491 if (ch_itr != NULL) {
493 list_iterate(itr, &ch_itr->clients) {
495 c = list_get_entry(itr, client_t, chan_node);
496 if (c != client && !c->deaf) {
498 Client_send_message(c, msg);
499 Log_debug("Text message to session ID %d", c->sessionId);
505 if (msg->payload.textMessage->n_session > 0) { /* To user */
508 for (i = 0; i < msg->payload.textMessage->n_session; i++) {
510 while (Client_iterate(&itr) != NULL) {
513 if (itr->sessionId == msg->payload.textMessage->session[i]) {
516 Client_send_message(itr, msg);
517 Log_debug("Text message to session ID %d", itr->sessionId);
523 Log_warn("TextMessage: Session ID %d not found", msg->payload.textMessage->session[i]);
530 int i, j, count, targetId = msg->payload.voiceTarget->id;
531 struct _MumbleProto__VoiceTarget__Target *target;
533 if (!targetId || targetId >= 0x1f)
535 Voicetarget_add_id(client, targetId);
536 count = msg->payload.voiceTarget->n_targets;
539 for (i = 0; i < count; i++) {
540 target = msg->payload.voiceTarget->targets[i];
541 for (j = 0; j < target->n_session; j++)
542 Voicetarget_add_session(client, targetId, target->session[j]);
543 if (target->has_channel_id) {
544 bool_t linked = false, children = false;
545 if (target->has_links)
546 linked = target->links;
547 if (target->has_children)
548 children = target->children;
549 Voicetarget_add_channel(client, targetId, target->channel_id, linked, children);
555 Log_debug("Version message received");
556 if (msg->payload.version->has_version) {
557 client->version = msg->payload.version->version;
558 Log_debug("Client version 0x%x", client->version);
560 if (msg->payload.version->release) {
561 if (client->release) free(client->release);
562 client->release = strdup(msg->payload.version->release);
563 Log_debug("Client release %s", client->release);
565 if (msg->payload.version->os) {
566 if (client->os) free(client->os);
567 client->os = strdup(msg->payload.version->os);
568 Log_debug("Client OS %s", client->os);
570 if (msg->payload.version->os_version) {
571 if (client->os_version) free(client->os_version);
572 client->os_version = strdup(msg->payload.version->os_version);
573 Log_debug("Client OS version %s", client->os_version);
576 case PermissionQuery:
577 Msg_inc_ref(msg); /* Re-use message */
578 msg->payload.permissionQuery->has_permissions = true;
579 msg->payload.permissionQuery->permissions = PERM_DEFAULT;
581 Client_send_message(client, msg);
584 client->bUDP = false;
585 Client_voiceMsg(client, msg->payload.UDPTunnel->packet.data, msg->payload.UDPTunnel->packet.len);
589 channel_t *ch_itr, *parent, *newchan;
591 /* Don't allow any changes to existing channels */
592 if (msg->payload.channelState->has_channel_id) {
593 sendPermissionDenied(client, "Not supported by uMurmur");
596 /* Must have parent */
597 if (!msg->payload.channelState->has_parent) {
598 sendPermissionDenied(client, "Not supported by uMurmur");
602 if (msg->payload.channelState->name == NULL) {
603 sendPermissionDenied(client, "Not supported by uMurmur");
606 /* Must be temporary channel */
607 if (msg->payload.channelState->temporary != true) {
608 sendPermissionDenied(client, "Only temporary channels are supported by uMurmur");
611 /* Check channel name is OK */
612 if (strlen(msg->payload.channelState->name) > MAX_TEXT) {
613 sendPermissionDenied(client, "Channel name too long");
617 parent = Chan_fromId(msg->payload.channelState->parent);
621 while (Chan_iterate_siblings(parent, &ch_itr) != NULL) {
622 if (strcmp(ch_itr->name, msg->payload.channelState->name) == 0) {
623 sendPermissionDenied(client, "Channel already exists");
630 /* Disallow temporary channels as siblings to temporary channels */
631 if (parent->temporary) {
632 sendPermissionDenied(client, "Parent channel is temporary channel");
636 /* XXX - Murmur looks for "\\w" and sends perm denied if not found.
637 * I don't know why so I don't do that here...
640 /* Create the channel */
641 newchan = Chan_createChannel(msg->payload.channelState->name,
642 msg->payload.channelState->description);
643 newchan->temporary = true;
644 Chan_addChannel(parent, newchan);
645 msg->payload.channelState->has_channel_id = true;
646 msg->payload.channelState->channel_id = newchan->id;
648 Client_send_message_except(NULL, msg);
650 /* Join the creating user */
651 sendmsg = Msg_create(UserState);
652 sendmsg->payload.userState->has_session = true;
653 sendmsg->payload.userState->session = client->sessionId;
654 sendmsg->payload.userState->has_channel_id = true;
655 sendmsg->payload.userState->channel_id = newchan->id;
656 Client_send_message_except(NULL, sendmsg);
658 leave_id = Chan_userJoin(newchan, client);
660 Log_debug("Removing channel ID %d", leave_id);
661 sendmsg = Msg_create(ChannelRemove);
662 sendmsg->payload.channelRemove->channel_id = leave_id;
663 Client_send_message_except(NULL, sendmsg);
670 client_t *target = NULL;
671 codec_t *codec_itr = NULL;
673 bool_t details = true;
675 if (msg->payload.userStats->has_stats_only)
676 details = !msg->payload.userStats->stats_only;
678 if (!msg->payload.userStats->has_session)
679 sendPermissionDenied(client, "Not supported by uMurmur");
680 while (Client_iterate(&target) != NULL) {
681 if (!IS_AUTH(target))
683 if (target->sessionId == msg->payload.userStats->session)
686 if (!target) /* Not found */
690 * Differences from Murmur:
691 * o Ignoring certificates intentionally
692 * o Ignoring channel local determining
695 sendmsg = Msg_create(UserStats);
696 sendmsg->payload.userStats->session = msg->payload.userStats->session;
697 sendmsg->payload.userStats->from_client->has_good = true;
698 sendmsg->payload.userStats->from_client->good = target->cryptState.uiGood;
699 sendmsg->payload.userStats->from_client->has_late = true;
700 sendmsg->payload.userStats->from_client->late = target->cryptState.uiLate;
701 sendmsg->payload.userStats->from_client->has_lost = true;
702 sendmsg->payload.userStats->from_client->lost = target->cryptState.uiLost;
703 sendmsg->payload.userStats->from_client->has_resync = true;
704 sendmsg->payload.userStats->from_client->resync = target->cryptState.uiResync;
706 sendmsg->payload.userStats->from_server->has_good = true;
707 sendmsg->payload.userStats->from_server->good = target->cryptState.uiRemoteGood;
708 sendmsg->payload.userStats->from_server->has_late = true;
709 sendmsg->payload.userStats->from_server->late = target->cryptState.uiRemoteLate;
710 sendmsg->payload.userStats->from_server->has_lost = true;
711 sendmsg->payload.userStats->from_server->lost = target->cryptState.uiRemoteLost;
712 sendmsg->payload.userStats->from_server->has_resync = true;
713 sendmsg->payload.userStats->from_server->resync = target->cryptState.uiRemoteResync;
715 sendmsg->payload.userStats->has_udp_packets = true;
716 sendmsg->payload.userStats->udp_packets = target->UDPPackets;
717 sendmsg->payload.userStats->has_udp_ping_avg = true;
718 sendmsg->payload.userStats->udp_ping_avg = target->UDPPingAvg;
719 sendmsg->payload.userStats->has_udp_ping_var = true;
720 sendmsg->payload.userStats->udp_ping_var = target->UDPPingVar;
722 sendmsg->payload.userStats->has_tcp_ping_avg = true;
723 sendmsg->payload.userStats->tcp_ping_avg = target->TCPPingAvg;
724 sendmsg->payload.userStats->has_tcp_ping_var = true;
725 sendmsg->payload.userStats->tcp_ping_var = target->TCPPingVar;
726 sendmsg->payload.userStats->has_tcp_packets = true;
727 sendmsg->payload.userStats->tcp_packets = target->TCPPackets;
731 sendmsg->payload.userStats->version->has_version = true;
732 sendmsg->payload.userStats->version->version = target->version;
733 sendmsg->payload.userStats->version->release = strdup(target->release);
734 sendmsg->payload.userStats->version->os = strdup(target->os);
735 sendmsg->payload.userStats->version->os_version = strdup(target->os_version);
737 sendmsg->payload.userStats->n_celt_versions = target->codec_count;
738 sendmsg->payload.userStats->celt_versions = malloc(sizeof(int32_t) * target->codec_count);
739 if (!sendmsg->payload.userStats->celt_versions)
740 Log_fatal("Out of memory");
742 while (Client_codec_iterate(target, &codec_itr) != NULL)
743 sendmsg->payload.userStats->celt_versions[i++] = codec_itr->codec;
746 sendmsg->payload.userStats->has_address = true;
747 sendmsg->payload.userStats->address.data = malloc(sizeof(uint8_t) * 16);
748 if (!sendmsg->payload.userStats->address.data)
749 Log_fatal("Out of memory");
750 memset(sendmsg->payload.userStats->address.data, 0, 16);
751 /* ipv4 representation as ipv6 address. Supposedly correct. */
752 memcpy(&sendmsg->payload.userStats->address.data[12], &target->remote_tcp.sin_addr, 4);
753 sendmsg->payload.userStats->address.len = 16;
756 sendmsg->payload.userStats->has_bandwidth = true;
757 sendmsg->payload.userStats->bandwidth = target->availableBandwidth;
760 sendmsg->payload.userStats->has_onlinesecs = true;
761 sendmsg->payload.userStats->onlinesecs = Timer_elapsed(&target->connectTime) / 1000000LL;
763 sendmsg->payload.userStats->has_idlesecs = true;
764 sendmsg->payload.userStats->idlesecs = Timer_elapsed(&target->idleTime) / 1000000LL;
765 Client_send_message(client, sendmsg);
768 /* Permission denied for all these messages. Not implemented. */
771 case ContextActionAdd:
776 sendPermissionDenied(client, "Not supported by uMurmur");
780 Log_warn("Message %d not handled", msg->messageType);
789 Client_close(client);