1 /* Copyright (C) 2009-2010, Martin Johansson <martin@fatbob.nu>
2 Copyright (C) 2005-2010, 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 void Mh_handle_message(client_t *client, message_t *msg)
73 message_t *sendmsg = NULL;
74 channel_t *ch_itr = NULL;
77 if (!client->authenticated && !(msg->messageType == Authenticate ||
78 msg->messageType == Version)) {
82 switch (msg->messageType) {
91 Timer_restart(&client->idleTime);
94 switch (msg->messageType) {
96 Log_debug("Authenticate message received");
98 if (IS_AUTH(client) || !msg->payload.authenticate->username) {
99 /* Authenticate message might be sent when a token is set by the user.*/
100 if (msg->payload.authenticate->n_tokens > 0) {
101 Log_debug("Tokens in auth message from %s", client->username);
106 client->authenticated = true;
109 while (Client_iterate(&client_itr) != NULL) {
110 if (!IS_AUTH(client_itr))
112 if (client_itr->username && strncmp(client_itr->username, msg->payload.authenticate->username, MAX_USERNAME) == 0) {
114 sprintf(buf, "Username already in use");
115 Log_debug("Username already in use");
116 sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__UsernameInUse);
120 if (strlen(getStrConf(PASSPHRASE)) > 0) {
121 if (!msg->payload.authenticate->password ||
122 (msg->payload.authenticate->password &&
123 strncmp(getStrConf(PASSPHRASE), msg->payload.authenticate->password, MAX_TEXT) != 0)) {
125 sprintf(buf, "Wrong server password");
126 sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__WrongServerPW);
127 Log_debug("Wrong server password: '%s'", msg->payload.authenticate->password != NULL ?
128 msg->payload.authenticate->password : "(null)");
132 if (strlen(msg->payload.authenticate->username) == 0 ||
133 strlen(msg->payload.authenticate->username) >= MAX_USERNAME) { /* XXX - other invalid names? */
135 sprintf(buf, "Invalid username");
136 Log_debug("Invalid username");
137 sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__InvalidUsername);
141 if (Client_count() >= getIntConf(MAX_CLIENTS)) {
143 snprintf(buf, 64, "Server is full (max %d users)", getIntConf(MAX_CLIENTS));
144 sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__ServerFull);
148 /* Name & password */
149 client->username = strdup(msg->payload.authenticate->username);
151 /* Setup UDP encryption */
152 CryptState_init(&client->cryptState);
153 CryptState_genKey(&client->cryptState);
154 sendmsg = Msg_create(CryptSetup);
155 sendmsg->payload.cryptSetup->has_key = true;
156 sendmsg->payload.cryptSetup->key.data = client->cryptState.raw_key;
157 sendmsg->payload.cryptSetup->key.len = AES_BLOCK_SIZE;
158 sendmsg->payload.cryptSetup->has_server_nonce = true;
159 sendmsg->payload.cryptSetup->server_nonce.data = client->cryptState.encrypt_iv;
160 sendmsg->payload.cryptSetup->server_nonce.len = AES_BLOCK_SIZE;
161 sendmsg->payload.cryptSetup->has_client_nonce = true;
162 sendmsg->payload.cryptSetup->client_nonce.data = client->cryptState.decrypt_iv;
163 sendmsg->payload.cryptSetup->client_nonce.len = AES_BLOCK_SIZE;
164 Client_send_message(client, sendmsg);
167 Chan_userJoin(defaultChan, client); /* Join default channel */
170 Log_debug("Client %d has %d CELT codecs", client->sessionId,
171 msg->payload.authenticate->n_celt_versions);
172 if (msg->payload.authenticate->n_celt_versions > 0) {
175 client->codec_count = msg->payload.authenticate->n_celt_versions;
177 for (i = 0; i < client->codec_count; i++)
178 Client_codec_add(client, msg->payload.authenticate->celt_versions[i]);
180 while (Client_codec_iterate(client, &codec_itr) != NULL)
181 Log_debug("Client %d CELT codec ver 0x%x", client->sessionId, codec_itr->codec);
184 Client_codec_add(client, (int32_t)0x8000000a);
185 client->codec_count = 1;
188 recheckCodecVersions();
190 sendmsg = Msg_create(CodecVersion);
191 sendmsg->payload.codecVersion->alpha = iCodecAlpha;
192 sendmsg->payload.codecVersion->beta = iCodecBeta;
193 sendmsg->payload.codecVersion->prefer_alpha = bPreferAlpha;
194 Client_send_message(client, sendmsg);
196 /* Iterate channels and send channel info */
198 while (Chan_iterate(&ch_itr) != NULL) {
199 sendmsg = Msg_create(ChannelState);
200 sendmsg->payload.channelState->has_channel_id = true;
201 sendmsg->payload.channelState->channel_id = ch_itr->id;
202 if (ch_itr->id != 0) {
203 sendmsg->payload.channelState->has_parent = true;
204 sendmsg->payload.channelState->parent = ch_itr->parent->id;
206 sendmsg->payload.channelState->name = strdup(ch_itr->name);
208 sendmsg->payload.channelState->description = strdup(ch_itr->desc);
209 Log_debug("Send channel info: %s", sendmsg->payload.channelState->name);
210 Client_send_message(client, sendmsg);
213 /* Iterate channels and send channel links info */
215 while (Chan_iterate(&ch_itr) != NULL) {
216 if (ch_itr->linkcount > 0) { /* Has links */
221 sendmsg = Msg_create(ChannelState);
222 sendmsg->payload.channelState->has_channel_id = true;
223 sendmsg->payload.channelState->channel_id = ch_itr->id;
224 sendmsg->payload.channelState->n_links = ch_itr->linkcount;
226 links = (uint32_t *)malloc(ch_itr->linkcount * sizeof(uint32_t));
227 list_iterate(itr, &ch_itr->channel_links) { /* Iterate links */
229 ch = list_get_entry(itr, channel_t, link_node);
232 sendmsg->payload.channelState->links = links;
233 Client_send_message(client, sendmsg);
237 /* Send user state for connecting user to other users */
238 sendmsg = Msg_create(UserState);
239 sendmsg->payload.userState->has_session = true;
240 sendmsg->payload.userState->session = client->sessionId;
241 sendmsg->payload.userState->name = strdup(client->username);
242 sendmsg->payload.userState->has_channel_id = true;
243 sendmsg->payload.userState->channel_id = ((channel_t *)client->channel)->id;
245 Client_send_message_except(client, sendmsg);
248 while (Client_iterate(&client_itr) != NULL) {
249 if (!IS_AUTH(client_itr))
251 sendmsg = Msg_create(UserState);
252 sendmsg->payload.userState->has_session = true;
253 sendmsg->payload.userState->session = client_itr->sessionId;
254 sendmsg->payload.userState->name = strdup(client_itr->username);
255 sendmsg->payload.userState->has_channel_id = true;
256 sendmsg->payload.userState->channel_id = ((channel_t *)client_itr->channel)->id;
258 /* Only self_mute/deaf supported */
259 if (client_itr->deaf) {
260 sendmsg->payload.userState->has_self_deaf = true;
261 sendmsg->payload.userState->self_deaf = true;
263 if (client_itr->mute) {
264 sendmsg->payload.userState->has_self_mute = true;
265 sendmsg->payload.userState->self_mute = true;
267 if (client_itr->recording) {
268 sendmsg->payload.userState->has_recording = true;
269 sendmsg->payload.userState->recording = true;
271 Client_send_message(client, sendmsg);
275 sendmsg = Msg_create(ServerSync);
276 sendmsg->payload.serverSync->has_session = true;
277 sendmsg->payload.serverSync->session = client->sessionId;
278 sendmsg->payload.serverSync->welcome_text = strdup(getStrConf(WELCOMETEXT));
279 sendmsg->payload.serverSync->has_max_bandwidth = true;
280 sendmsg->payload.serverSync->max_bandwidth = getIntConf(MAX_BANDWIDTH);
281 Client_send_message(client, sendmsg);
283 /* Server config message */
284 sendmsg = Msg_create(ServerConfig);
285 sendmsg->payload.serverConfig->has_allow_html = true;
286 sendmsg->payload.serverConfig->allow_html = true; /* Support this? */
287 sendmsg->payload.serverConfig->has_message_length = true;
288 sendmsg->payload.serverConfig->message_length = MAX_TEXT; /* Hardcoded */
289 sendmsg->payload.serverConfig->has_image_message_length = true;
290 sendmsg->payload.serverConfig->image_message_length = 0; /* XXX */
291 Client_send_message(client, sendmsg);
293 Log_info_client(client, "User %s authenticated", client->username);
297 if (msg->payload.ping->has_good)
298 client->cryptState.uiRemoteGood = msg->payload.ping->good;
299 if (msg->payload.ping->has_late)
300 client->cryptState.uiRemoteLate = msg->payload.ping->late;
301 if (msg->payload.ping->has_lost)
302 client->cryptState.uiRemoteLost = msg->payload.ping->lost;
303 if (msg->payload.ping->has_resync)
304 client->cryptState.uiRemoteResync = msg->payload.ping->resync;
306 Log_debug("Ping <-: %d %d %d %d",
307 client->cryptState.uiRemoteGood, client->cryptState.uiRemoteLate,
308 client->cryptState.uiRemoteLost, client->cryptState.uiRemoteResync
311 client->UDPPingAvg = msg->payload.ping->udp_ping_avg;
312 client->UDPPingVar = msg->payload.ping->udp_ping_var;
313 client->TCPPingAvg = msg->payload.ping->tcp_ping_avg;
314 client->TCPPingVar = msg->payload.ping->tcp_ping_var;
315 client->UDPPackets = msg->payload.ping->udp_packets;
316 client->TCPPackets = msg->payload.ping->tcp_packets;
318 sendmsg = Msg_create(Ping);
320 sendmsg->payload.ping->timestamp = msg->payload.ping->timestamp;
321 sendmsg->payload.ping->has_timestamp = true;
322 sendmsg->payload.ping->good = client->cryptState.uiGood;
323 sendmsg->payload.ping->has_good = true;
324 sendmsg->payload.ping->late = client->cryptState.uiLate;
325 sendmsg->payload.ping->has_late = true;
326 sendmsg->payload.ping->lost = client->cryptState.uiLost;
327 sendmsg->payload.ping->has_lost = true;
328 sendmsg->payload.ping->resync = client->cryptState.uiResync;
329 sendmsg->payload.ping->has_resync = true;
331 Client_send_message(client, sendmsg);
332 Log_debug("Ping ->: %d %d %d %d",
333 client->cryptState.uiGood, client->cryptState.uiLate,
334 client->cryptState.uiLost, client->cryptState.uiResync);
338 Log_debug("Voice channel crypt resync requested");
339 if (!msg->payload.cryptSetup->has_client_nonce) {
340 sendmsg = Msg_create(CryptSetup);
341 sendmsg->payload.cryptSetup->has_server_nonce = true;
342 sendmsg->payload.cryptSetup->server_nonce.data = client->cryptState.decrypt_iv;
343 sendmsg->payload.cryptSetup->server_nonce.len = AES_BLOCK_SIZE;
344 Client_send_message(client, sendmsg);
346 memcpy(client->cryptState.decrypt_iv, msg->payload.cryptSetup->client_nonce.data, AES_BLOCK_SIZE);
347 client->cryptState.uiResync++;
351 /* Only allow state changes for for the self user */
352 if (msg->payload.userState->has_session &&
353 msg->payload.userState->session != client->sessionId) {
354 sendPermissionDenied(client, "Permission denied");
357 if (msg->payload.userState->has_user_id || msg->payload.userState->has_mute ||
358 msg->payload.userState->has_deaf || msg->payload.userState->has_suppress ||
359 msg->payload.userState->has_texture) {
361 sendPermissionDenied(client, "Not supported by uMurmur");
365 msg->payload.userState->has_session = true;
366 msg->payload.userState->session = client->sessionId;
367 msg->payload.userState->has_actor = true;
368 msg->payload.userState->actor = client->sessionId;
370 if (msg->payload.userState->has_self_deaf) {
371 client->deaf = msg->payload.userState->self_deaf;
373 if (msg->payload.userState->has_self_mute) {
374 client->mute = msg->payload.userState->self_mute;
376 msg->payload.userState->has_self_deaf = true;
377 msg->payload.userState->self_deaf = false;
378 client->deaf = false;
381 if (msg->payload.userState->has_recording &&
382 msg->payload.userState->recording != client->recording) {
383 client->recording = msg->payload.userState->recording;
387 message = malloc(strlen(client->username) + 32);
389 Log_fatal("Out of memory");
390 tree_id = malloc(sizeof(uint32_t));
392 Log_fatal("Out of memory");
394 sendmsg = Msg_create(TextMessage);
395 sendmsg->payload.textMessage->message = message;
396 sendmsg->payload.textMessage->n_tree_id = 1;
397 sendmsg->payload.textMessage->tree_id = tree_id;
398 if (client->recording)
399 sprintf(message, "User %s started recording", client->username);
401 sprintf(message, "User %s stopped recording", client->username);
402 Client_send_message_except_ver(NULL, sendmsg, ~0x010203);
405 if (msg->payload.userState->has_channel_id) {
407 if (!Chan_userJoin_id_test(msg->payload.userState->channel_id))
409 leave_id = Chan_userJoin_id(msg->payload.userState->channel_id, client);
411 Log_debug("Removing channel ID %d", leave_id);
412 sendmsg = Msg_create(ChannelRemove);
413 sendmsg->payload.channelRemove->channel_id = leave_id;
416 if (msg->payload.userState->has_plugin_context) {
418 free(client->context);
419 client->context = malloc(msg->payload.userState->plugin_context.len);
420 if (client->context == NULL)
421 Log_fatal("Out of memory");
422 memcpy(client->context, msg->payload.userState->plugin_context.data,
423 msg->payload.userState->plugin_context.len);
425 break; /* Don't inform other users about this state */
430 Client_send_message_except(NULL, msg);
432 /* Need to send remove channel message _after_ UserState message */
434 Client_send_message_except(NULL, sendmsg);
438 msg->payload.textMessage->has_actor = true;
439 msg->payload.textMessage->actor = client->sessionId;
441 /* XXX - HTML is allowed and can't be turned off */
442 if (msg->payload.textMessage->n_tree_id > 0) {
443 sendPermissionDenied(client, "Tree message not supported");
447 if (msg->payload.textMessage->n_channel_id > 0) { /* To channel */
450 for (i = 0; i < msg->payload.textMessage->n_channel_id; i++) {
453 Chan_iterate(&ch_itr);
454 } while (ch_itr != NULL && ch_itr->id != msg->payload.textMessage->channel_id[i]);
455 if (ch_itr != NULL) {
457 list_iterate(itr, &ch_itr->clients) {
459 c = list_get_entry(itr, client_t, chan_node);
460 if (c != client && !c->deaf) {
462 Client_send_message(c, msg);
463 Log_debug("Text message to session ID %d", c->sessionId);
469 if (msg->payload.textMessage->n_session > 0) { /* To user */
472 for (i = 0; i < msg->payload.textMessage->n_session; i++) {
474 while (Client_iterate(&itr) != NULL) {
477 if (itr->sessionId == msg->payload.textMessage->session[i]) {
480 Client_send_message(itr, msg);
481 Log_debug("Text message to session ID %d", itr->sessionId);
487 Log_warn("TextMessage: Session ID %d not found", msg->payload.textMessage->session[i]);
494 int i, j, count, targetId = msg->payload.voiceTarget->id;
495 struct _MumbleProto__VoiceTarget__Target *target;
497 if (!targetId || targetId >= 0x1f)
499 Voicetarget_add_id(client, targetId);
500 count = msg->payload.voiceTarget->n_targets;
503 for (i = 0; i < count; i++) {
504 target = msg->payload.voiceTarget->targets[i];
505 for (j = 0; j < target->n_session; j++)
506 Voicetarget_add_session(client, targetId, target->session[j]);
507 if (target->has_channel_id) {
508 bool_t linked = false, children = false;
509 if (target->has_links)
510 linked = target->links;
511 if (target->has_children)
512 children = target->children;
513 Voicetarget_add_channel(client, targetId, target->channel_id, linked, children);
519 Log_debug("Version message received");
520 if (msg->payload.version->has_version) {
521 client->version = msg->payload.version->version;
522 Log_debug("Client version 0x%x", client->version);
524 if (msg->payload.version->release) {
525 if (client->release) free(client->release);
526 client->release = strdup(msg->payload.version->release);
527 Log_debug("Client release %s", client->release);
529 if (msg->payload.version->os) {
530 if (client->os) free(client->os);
531 client->os = strdup(msg->payload.version->os);
532 Log_debug("Client OS %s", client->os);
534 if (msg->payload.version->os_version) {
535 if (client->os_version) free(client->os_version);
536 client->os_version = strdup(msg->payload.version->os_version);
537 Log_debug("Client OS version %s", client->os_version);
540 case PermissionQuery:
541 Msg_inc_ref(msg); /* Re-use message */
542 msg->payload.permissionQuery->has_permissions = true;
543 msg->payload.permissionQuery->permissions = PERM_DEFAULT;
545 Client_send_message(client, msg);
548 client->bUDP = false;
549 Client_voiceMsg(client, msg->payload.UDPTunnel->packet.data, msg->payload.UDPTunnel->packet.len);
553 channel_t *ch_itr, *parent, *newchan;
555 /* Don't allow any changes to existing channels */
556 if (msg->payload.channelState->has_channel_id) {
557 sendPermissionDenied(client, "Not supported by uMurmur");
560 /* Must have parent */
561 if (!msg->payload.channelState->has_parent) {
562 sendPermissionDenied(client, "Not supported by uMurmur");
566 if (msg->payload.channelState->name == NULL) {
567 sendPermissionDenied(client, "Not supported by uMurmur");
570 /* Must be temporary channel */
571 if (msg->payload.channelState->temporary != true) {
572 sendPermissionDenied(client, "Only temporary channels are supported by uMurmur");
575 /* Check channel name is OK */
576 if (strlen(msg->payload.channelState->name) > MAX_TEXT) {
577 sendPermissionDenied(client, "Channel name too long");
581 parent = Chan_fromId(msg->payload.channelState->parent);
585 while (Chan_iterate_siblings(parent, &ch_itr) != NULL) {
586 if (strcmp(ch_itr->name, msg->payload.channelState->name) == 0) {
587 sendPermissionDenied(client, "Channel already exists");
594 /* Disallow temporary channels as siblings to temporary channels */
595 if (parent->temporary) {
596 sendPermissionDenied(client, "Parent channel is temporary channel");
600 /* XXX - Murmur looks for "\\w" and sends perm denied if not found.
601 * I don't know why so I don't do that here...
604 /* Create the channel */
605 newchan = Chan_createChannel(msg->payload.channelState->name,
606 msg->payload.channelState->description);
607 newchan->temporary = true;
608 Chan_addChannel(parent, newchan);
609 msg->payload.channelState->has_channel_id = true;
610 msg->payload.channelState->channel_id = newchan->id;
612 Client_send_message_except(NULL, msg);
614 /* Join the creating user */
615 sendmsg = Msg_create(UserState);
616 sendmsg->payload.userState->has_session = true;
617 sendmsg->payload.userState->session = client->sessionId;
618 sendmsg->payload.userState->has_channel_id = true;
619 sendmsg->payload.userState->channel_id = newchan->id;
620 Client_send_message_except(NULL, sendmsg);
622 leave_id = Chan_userJoin(newchan, client);
624 Log_debug("Removing channel ID %d", leave_id);
625 sendmsg = Msg_create(ChannelRemove);
626 sendmsg->payload.channelRemove->channel_id = leave_id;
627 Client_send_message_except(NULL, sendmsg);
634 client_t *target = NULL;
635 codec_t *codec_itr = NULL;
637 bool_t details = true;
639 if (msg->payload.userStats->has_stats_only)
640 details = !msg->payload.userStats->stats_only;
642 if (!msg->payload.userStats->has_session)
643 sendPermissionDenied(client, "Not supported by uMurmur");
644 while (Client_iterate(&target) != NULL) {
645 if (!IS_AUTH(target))
647 if (target->sessionId == msg->payload.userStats->session)
650 if (!target) /* Not found */
654 * Differences from Murmur:
655 * o Ignoring certificates intentionally
656 * o Ignoring channel local determining
659 sendmsg = Msg_create(UserStats);
660 sendmsg->payload.userStats->session = msg->payload.userStats->session;
661 sendmsg->payload.userStats->from_client->has_good = true;
662 sendmsg->payload.userStats->from_client->good = target->cryptState.uiGood;
663 sendmsg->payload.userStats->from_client->has_late = true;
664 sendmsg->payload.userStats->from_client->late = target->cryptState.uiLate;
665 sendmsg->payload.userStats->from_client->has_lost = true;
666 sendmsg->payload.userStats->from_client->lost = target->cryptState.uiLost;
667 sendmsg->payload.userStats->from_client->has_resync = true;
668 sendmsg->payload.userStats->from_client->resync = target->cryptState.uiResync;
670 sendmsg->payload.userStats->from_server->has_good = true;
671 sendmsg->payload.userStats->from_server->good = target->cryptState.uiRemoteGood;
672 sendmsg->payload.userStats->from_server->has_late = true;
673 sendmsg->payload.userStats->from_server->late = target->cryptState.uiRemoteLate;
674 sendmsg->payload.userStats->from_server->has_lost = true;
675 sendmsg->payload.userStats->from_server->lost = target->cryptState.uiRemoteLost;
676 sendmsg->payload.userStats->from_server->has_resync = true;
677 sendmsg->payload.userStats->from_server->resync = target->cryptState.uiRemoteResync;
679 sendmsg->payload.userStats->has_udp_packets = true;
680 sendmsg->payload.userStats->udp_packets = target->UDPPackets;
681 sendmsg->payload.userStats->has_udp_ping_avg = true;
682 sendmsg->payload.userStats->udp_ping_avg = target->UDPPingAvg;
683 sendmsg->payload.userStats->has_udp_ping_var = true;
684 sendmsg->payload.userStats->udp_ping_var = target->UDPPingVar;
686 sendmsg->payload.userStats->has_tcp_ping_avg = true;
687 sendmsg->payload.userStats->tcp_ping_avg = target->TCPPingAvg;
688 sendmsg->payload.userStats->has_tcp_ping_var = true;
689 sendmsg->payload.userStats->tcp_ping_var = target->TCPPingVar;
690 sendmsg->payload.userStats->has_tcp_packets = true;
691 sendmsg->payload.userStats->tcp_packets = target->TCPPackets;
695 sendmsg->payload.userStats->version->has_version = true;
696 sendmsg->payload.userStats->version->version = target->version;
697 sendmsg->payload.userStats->version->release = strdup(target->release);
698 sendmsg->payload.userStats->version->os = strdup(target->os);
699 sendmsg->payload.userStats->version->os_version = strdup(target->os_version);
701 sendmsg->payload.userStats->n_celt_versions = target->codec_count;
702 sendmsg->payload.userStats->celt_versions = malloc(sizeof(int32_t) * target->codec_count);
703 if (!sendmsg->payload.userStats->celt_versions)
704 Log_fatal("Out of memory");
706 while (Client_codec_iterate(target, &codec_itr) != NULL)
707 sendmsg->payload.userStats->celt_versions[i++] = codec_itr->codec;
710 sendmsg->payload.userStats->has_address = true;
711 sendmsg->payload.userStats->address.data = malloc(sizeof(uint8_t) * 16);
712 if (!sendmsg->payload.userStats->address.data)
713 Log_fatal("Out of memory");
714 memset(sendmsg->payload.userStats->address.data, 0, 16);
715 /* ipv4 representation as ipv6 address. Supposedly correct. */
716 memcpy(&sendmsg->payload.userStats->address.data[12], &target->remote_tcp.sin_addr, 4);
717 sendmsg->payload.userStats->address.len = 16;
720 sendmsg->payload.userStats->has_bandwidth = true;
721 sendmsg->payload.userStats->bandwidth = target->availableBandwidth;
724 sendmsg->payload.userStats->has_onlinesecs = true;
725 sendmsg->payload.userStats->onlinesecs = Timer_elapsed(&target->connectTime) / 1000000LL;
727 sendmsg->payload.userStats->has_idlesecs = true;
728 sendmsg->payload.userStats->idlesecs = Timer_elapsed(&target->idleTime) / 1000000LL;
729 Client_send_message(client, sendmsg);
732 /* Permission denied for all these messages. Not implemented. */
735 case ContextActionAdd:
740 sendPermissionDenied(client, "Not supported by uMurmur");
744 Log_warn("Message %d not handled", msg->messageType);
753 Client_close(client);