X-Git-Url: http://git.code-monkey.de/?a=blobdiff_plain;f=src%2Fclient.c;h=e3787a4832d3c1486f3fe2a3779b345e1dddcd1b;hb=c289fc55d1fce7f474127933063ba2008a188259;hp=e190a0b9f67fa30f94ebed2fc8a6951dd8f9a765;hpb=1e4dd9a7812a66b0574df3c0af28dcf95008c5d3;p=umurmur.git diff --git a/src/client.c b/src/client.c index e190a0b..e3787a4 100644 --- a/src/client.c +++ b/src/client.c @@ -1,5 +1,5 @@ -/* Copyright (C) 2009-2011, Martin Johansson - Copyright (C) 2005-2011, Thorvald Natvig +/* Copyright (C) 2009-2014, Martin Johansson + Copyright (C) 2005-2014, Thorvald Natvig All rights reserved. @@ -45,6 +45,7 @@ #include "channel.h" #include "version.h" #include "voicetarget.h" +#include "ban.h" extern char system_string[], version_string[]; @@ -56,11 +57,12 @@ void Client_free(client_t *client); declare_list(clients); static int clientcount; /* = 0 */ static int maxBandwidth; +bool_t bOpus = true; int iCodecAlpha, iCodecBeta; bool_t bPreferAlpha; -extern int udpsock; +extern int* udpsocks; void Client_init() { @@ -90,22 +92,23 @@ int Client_getfds(struct pollfd *pollfds) void Client_janitor() { - struct dlist *itr; + struct dlist *itr, *save; int bwTop = maxBandwidth + maxBandwidth / 4; - list_iterate(itr, &clients) { + list_iterate_safe(itr, save, &clients) { client_t *c; c = list_get_entry(itr, client_t, node); Log_debug("Client %s BW available %d", c->username, c->availableBandwidth); c->availableBandwidth += maxBandwidth; if (c->availableBandwidth > bwTop) c->availableBandwidth = bwTop; - - if (Timer_isElapsed(&c->lastActivity, 1000000LL * INACTICITY_TIMEOUT)) { + + if (Timer_isElapsed(&c->lastActivity, 1000000LL * INACTIVITY_TIMEOUT)) { /* No activity from client - assume it is lost and close. */ Log_info_client(c, "Timeout, closing."); Client_free(c); } } + Ban_pruneBanned(); } void Client_codec_add(client_t *client, int codec) @@ -133,7 +136,7 @@ codec_t *Client_codec_iterate(client_t *client, codec_t **codec_itr) if (list_empty(&client->codecs)) return NULL; - + if (cd == NULL) { cd = list_get_entry(list_get_first(&client->codecs), codec_t, node); } else { @@ -146,19 +149,72 @@ codec_t *Client_codec_iterate(client_t *client, codec_t **codec_itr) return cd; } -void recheckCodecVersions() +void Client_token_add(client_t *client, char *token_string) +{ + token_t *token; + + if (client->tokencount >= MAX_TOKENS) + return; + token = malloc(sizeof(token_t)); + if (token == NULL) + Log_fatal("Out of memory"); + init_list_entry(&token->node); + token->token = strdup(token_string); + if (token->token == NULL) + Log_fatal("Out of memory"); + list_add_tail(&token->node, &client->tokens); + client->tokencount++; +} + +bool_t Client_token_match(client_t *client, char *str) +{ + token_t *token; + struct dlist *itr; + + if (list_empty(&client->tokens)) + return false; + list_iterate(itr, &client->tokens) { + token = list_get_entry(itr, token_t, node); + if (strncasecmp(token->token, str, MAX_TOKENSIZE) == 0) + return true; + } + return false; +} + +void Client_token_free(client_t *client) +{ + struct dlist *itr, *save; + token_t *token; + + list_iterate_safe(itr, save, &client->tokens) { + token = list_get_entry(itr, token_t, node); + list_del(&token->node); + free(token->token); + free(token); + } + client->tokencount = 0; +} + + +#define OPUS_WARN_USING "WARNING: Your client doesn't support the Opus codec the server is using, you won't be able to talk or hear anyone. Please upgrade your Mumble client." +#define OPUS_WARN_SWITCHING "WARNING: Your client doesn't support the Opus codec the server is switching to, you won't be able to talk or hear anyone. Please upgrade your Mumble client." +void recheckCodecVersions(client_t *connectingClient) { client_t *client_itr = NULL; int max = 0, version, current_version; + int users = 0, opus = 0; message_t *sendmsg; struct dlist codec_list, *itr, *save; codec_t *codec_itr, *cd; bool_t found; - + bool_t enableOpus; + init_list_entry(&codec_list); - + while (Client_iterate(&client_itr) != NULL) { codec_itr = NULL; + if (client_itr->codec_count == 0 && !client_itr->bOpus) + continue; while (Client_codec_iterate(client_itr, &codec_itr) != NULL) { found = false; list_iterate(itr, &codec_list) { @@ -179,8 +235,15 @@ void recheckCodecVersions() list_add_tail(&cd->node, &codec_list); } } + users++; + if (client_itr->bOpus) + opus++; } - + if (users == 0) + return; + + enableOpus = ((opus * 100 / users) >= getIntConf(OPUS_THRESHOLD)); + list_iterate(itr, &codec_list) { cd = list_get_entry(itr, codec_t, node); if (cd->count > max) { @@ -192,33 +255,49 @@ void recheckCodecVersions() list_del(&list_get_entry(itr, codec_t, node)->node); free(list_get_entry(itr, codec_t, node)); } - + current_version = bPreferAlpha ? iCodecAlpha : iCodecBeta; - if (current_version == version) + if (current_version != version) { + // If we don't already use the compat bitstream version set + // it as alpha and announce it. If another codec now got the + // majority set it as the opposite of the currently valid bPreferAlpha + // and announce it. + if (version == (uint32_t)0x8000000b) + bPreferAlpha = true; + else + bPreferAlpha = !bPreferAlpha; + + if (bPreferAlpha) + iCodecAlpha = version; + else + iCodecBeta = version; + } else if (bOpus && enableOpus) { + if (connectingClient && !connectingClient->bOpus) + Client_textmessage(connectingClient, OPUS_WARN_USING); return; - // If we don't already use the compat bitstream version set - // it as alpha and announce it. If another codec now got the - // majority set it as the opposite of the currently valid bPreferAlpha - // and announce it. - if (version == (uint32_t)0x8000000b) - bPreferAlpha = true; - else - bPreferAlpha = ! bPreferAlpha; + } - if (bPreferAlpha) - iCodecAlpha = version; - else - iCodecBeta = version; - sendmsg = Msg_create(CodecVersion); sendmsg->payload.codecVersion->alpha = iCodecAlpha; sendmsg->payload.codecVersion->beta = iCodecBeta; sendmsg->payload.codecVersion->prefer_alpha = bPreferAlpha; + sendmsg->payload.codecVersion->has_opus = true; + sendmsg->payload.codecVersion->opus = enableOpus; + Client_send_message_except(NULL, sendmsg); - - Log_info("CELT codec switch 0x%x 0x%x (prefer 0x%x)", iCodecAlpha, iCodecBeta, - bPreferAlpha ? iCodecAlpha : iCodecBeta); - + + if (enableOpus && !bOpus) { + client_itr = NULL; + while (Client_iterate(&client_itr) != NULL) { + if ((client_itr->authenticated || client_itr == connectingClient) && + !client_itr->bOpus) { + Client_textmessage(client_itr, OPUS_WARN_SWITCHING); + } + } + Log_info("OPUS codec %s", bOpus ? "enabled" : "disabled"); + } + + bOpus = enableOpus; } static int findFreeSessionId() @@ -238,22 +317,39 @@ static int findFreeSessionId() return -1; } -int Client_add(int fd, struct sockaddr_in *remote) +int Client_add(int fd, struct sockaddr_storage *remote) { - client_t *newclient; + client_t* newclient; message_t *sendmsg; - - newclient = malloc(sizeof(client_t)); - if (newclient == NULL) - Log_fatal("Out of memory"); - memset(newclient, 0, sizeof(client_t)); + char addressPresentation[INET6_ADDRSTRLEN]; + int port; + +#warning FIX BANNING BEFORE RELEASE +#if 0 + if (Ban_isBannedAddr((in_addr_t *)&remote->sin_addr)) { + Log_info("Address %s banned. Disconnecting", inet_ntoa(remote->sin_addr)); + return -1; + } +#endif + + if ((newclient = calloc(1, sizeof(client_t))) == NULL) + Log_fatal("Out of memory (%s:%s)", __FILE__, __LINE__); + + if(remote->ss_family == AF_INET) { + inet_ntop(AF_INET, &((struct sockaddr_in*)remote)->sin_addr, addressPresentation, INET6_ADDRSTRLEN); + port = ntohs(((struct sockaddr_in*)remote)->sin_port); + } else { + inet_ntop(AF_INET6, &((struct sockaddr_in6*)remote)->sin6_addr, addressPresentation, INET6_ADDRSTRLEN); + port = ntohs(((struct sockaddr_in6*)remote)->sin6_port); + } + + memcpy(newclient->addressString, addressPresentation, INET6_ADDRSTRLEN); newclient->tcpfd = fd; - memcpy(&newclient->remote_tcp, remote, sizeof(struct sockaddr_in)); + memcpy(&newclient->remote_tcp, remote, sizeof(struct sockaddr_storage)); newclient->ssl = SSLi_newconnection(&newclient->tcpfd, &newclient->SSLready); if (newclient->ssl == NULL) { - Log_warn("SSL negotiation failed with %s:%d", inet_ntoa(remote->sin_addr), - ntohs(remote->sin_port)); + Log_warn("SSL negotiation failed with %s on port %d", addressPresentation, port); free(newclient); return -1; } @@ -264,16 +360,17 @@ int Client_add(int fd, struct sockaddr_in *remote) newclient->sessionId = findFreeSessionId(); if (newclient->sessionId < 0) Log_fatal("Could not find a free session ID"); - + init_list_entry(&newclient->txMsgQueue); init_list_entry(&newclient->chan_node); init_list_entry(&newclient->node); init_list_entry(&newclient->voicetargets); init_list_entry(&newclient->codecs); - + init_list_entry(&newclient->tokens); + list_add_tail(&newclient->node, &clients); clientcount++; - + /* Send version message to client */ sendmsg = Msg_create(Version); sendmsg->payload.version->has_version = true; @@ -290,6 +387,7 @@ void Client_free(client_t *client) { struct dlist *itr, *save; message_t *sendmsg; + bool_t authenticatedLeft = client->authenticated; if (client->authenticated) { int leave_id; @@ -309,7 +407,8 @@ void Client_free(client_t *client) } Client_codec_free(client); Voicetarget_free_all(client); - + Client_token_free(client); + list_del(&client->node); if (client->ssl) SSLi_free(client->ssl); @@ -318,14 +417,17 @@ void Client_free(client_t *client) if (client->release) free(client->release); if (client->os) - free(client->os); + free(client->os); if (client->os_version) - free(client->os_version); + free(client->os_version); if (client->username) free(client->username); if (client->context) free(client->context); free(client); + + if (authenticatedLeft) + recheckCodecVersions(NULL); /* Can use better codec now? */ } void Client_close(client_t *client) @@ -337,7 +439,7 @@ void Client_close(client_t *client) void Client_disconnect_all() { struct dlist *itr, *save; - + list_iterate_safe(itr, save, &clients) { Client_free(list_get_entry(itr, client_t, node)); } @@ -347,17 +449,17 @@ int Client_read_fd(int fd) { struct dlist *itr; client_t *client = NULL; - + list_iterate(itr, &clients) { if (fd == list_get_entry(itr, client_t, node)->tcpfd) { client = list_get_entry(itr, client_t, node); break; } } - if (client == NULL) - Log_fatal("No client found for fd %d", fd); - - return Client_read(client); + if (client != NULL) + return Client_read(client); + else + return -1; } int Client_read(client_t *client) @@ -365,13 +467,13 @@ int Client_read(client_t *client) int rc; Timer_restart(&client->lastActivity); - + if (client->writeBlockedOnRead) { client->writeBlockedOnRead = false; Log_debug("Client_read: writeBlockedOnRead == true"); return Client_write(client); } - + if (client->shutdown_wait) { Client_free(client); return 0; @@ -387,7 +489,7 @@ int Client_read(client_t *client) do { errno = 0; - if (!client->msgsize) + if (!client->msgsize) rc = SSLi_read(client->ssl, &client->rxbuf[client->rxcount], 6 - client->rxcount); else rc = SSLi_read(client->ssl, &client->rxbuf[client->rxcount], client->msgsize); @@ -404,8 +506,8 @@ int Client_read(client_t *client) * 1. A valid size. The only message that is this big is UserState message with a big texture * 2. An invalid size = protocol error, e.g. connecting with a 1.1.x client */ - Log_warn("Too big message received (%d bytes). Playing safe and disconnecting client %s:%d", - client->msgsize, inet_ntoa(client->remote_tcp.sin_addr), ntohs(client->remote_tcp.sin_port)); +// Log_warn("Too big message received (%d bytes). Playing safe and disconnecting client %s:%d", +// client->msgsize, inet_ntoa(client->remote_tcp.sin_addr), ntohs(client->remote_tcp.sin_port)); Client_free(client); return -1; /* client->rxcount = client->msgsize = 0; */ @@ -425,14 +527,21 @@ int Client_read(client_t *client) client->readBlockedOnWrite = true; return 0; } - else if (SSLi_get_error(client->ssl, rc) == SSLI_ERROR_ZERO_RETURN) { + else if (SSLi_get_error(client->ssl, rc) == SSLI_ERROR_ZERO_RETURN || + SSLi_get_error(client->ssl, rc) == 0) { Log_info_client(client, "Connection closed by peer"); - if (!client->shutdown_wait) - Client_close(client); + Client_close(client); } else { if (SSLi_get_error(client->ssl, rc) == SSLI_ERROR_SYSCALL) { - Log_info_client(client, "Connection closed by peer"); + if (errno == 0) + Log_info_client(client, "Connection closed by peer"); + else + Log_info_client(client,"Error: %s - Closing connection (code %d)", + strerror(errno)); + } + else if (SSLi_get_error(client->ssl, rc) == SSLI_ERROR_CONNRESET) { + Log_info_client(client, "Connection reset by peer"); } else { Log_info_client(client, "SSL error: %d - Closing connection", SSLi_get_error(client->ssl, rc)); @@ -442,7 +551,7 @@ int Client_read(client_t *client) } } } while (SSLi_data_pending(client->ssl)); - + return 0; } @@ -450,23 +559,23 @@ int Client_write_fd(int fd) { struct dlist *itr; client_t *client = NULL; - + list_iterate(itr, &clients) { if(fd == list_get_entry(itr, client_t, node)->tcpfd) { client = list_get_entry(itr, client_t, node); break; } } - if (client == NULL) - Log_fatal("No client found for fd %d", fd); - Client_write(client); - return 0; + if (client != NULL) + return Client_write(client); + else + return -1; } int Client_write(client_t *client) { int rc; - + if (client->readBlockedOnWrite) { client->readBlockedOnWrite = false; Log_debug("Client_write: readBlockedOnWrite == true"); @@ -487,10 +596,15 @@ int Client_write(client_t *client) return 0; } else { - if (SSLi_get_error(client->ssl, rc) == SSLI_ERROR_SYSCALL) - Log_warn("Client_write: Error: %s - Closing connection", strerror(errno)); - else - Log_warn("Client_write: SSL error: %d - Closing connection.", SSLi_get_error(client->ssl, rc)); + if (SSLi_get_error(client->ssl, rc) == SSLI_ERROR_SYSCALL) { + Log_info_client(client, "Error: %s - Closing connection", strerror(errno)); + } + else if (SSLi_get_error(client->ssl, rc) == SSLI_ERROR_CONNRESET) { + Log_info_client(client, "Connection reset by peer"); + } + else { + Log_info_client(client, "SSL error: %d - Closing connection.", SSLi_get_error(client->ssl, rc)); + } Client_free(client); return -1; } @@ -549,7 +663,7 @@ client_t *Client_iterate(client_t **client_itr) if (list_empty(&clients)) return NULL; - + if (c == NULL) { c = list_get_entry(list_get_first(&clients), client_t, node); } else { @@ -562,12 +676,33 @@ client_t *Client_iterate(client_t **client_itr) return c; } +void Client_textmessage(client_t *client, char *text) +{ + char *message; + uint32_t *tree_id; + message_t *sendmsg = NULL; + + message = malloc(strlen(text) + 1); + if (!message) + Log_fatal("Out of memory"); + tree_id = malloc(sizeof(uint32_t)); + if (!tree_id) + Log_fatal("Out of memory"); + *tree_id = 0; + sendmsg = Msg_create(TextMessage); + sendmsg->payload.textMessage->message = message; + sendmsg->payload.textMessage->n_tree_id = 1; + sendmsg->payload.textMessage->tree_id = tree_id; + strcpy(message, text); + Client_send_message(client, sendmsg); +} + int Client_send_message_except(client_t *client, message_t *msg) { client_t *itr = NULL; int count = 0; - + Msg_inc_ref(msg); /* Make sure a reference is held during the whole iteration. */ while (Client_iterate(&itr) != NULL) { if (itr != client) { @@ -578,11 +713,11 @@ int Client_send_message_except(client_t *client, message_t *msg) } } Msg_free(msg); /* Free our reference to the message */ - + if (count == 0) Msg_free(msg); /* If only 1 client is connected then no message is passed * to Client_send_message(). Free it here. */ - + return 0; } @@ -590,7 +725,7 @@ int Client_send_message_except_ver(client_t *client, message_t *msg, uint32_t ve { client_t *itr = NULL; int count = 0; - + Msg_inc_ref(msg); /* Make sure a reference is held during the whole iteration. */ while (Client_iterate(&itr) != NULL) { if (itr != client) { @@ -601,11 +736,11 @@ int Client_send_message_except_ver(client_t *client, message_t *msg, uint32_t ve } } Msg_free(msg); /* Free our reference to the message */ - + if (count == 0) Msg_free(msg); /* If only 1 client is connected then no message is passed * to Client_send_message(). Free it here. */ - + return 0; } @@ -619,9 +754,9 @@ static bool_t checkDecrypt(client_t *client, const uint8_t *encrypted, uint8_t * if (Timer_elapsed(&client->cryptState.tLastRequest) > 5000000ULL) { message_t *sendmsg; Timer_restart(&client->cryptState.tLastRequest); - + sendmsg = Msg_create(CryptSetup); - Log_info_client(client, "Requesting voice channel crypt resync"); + Log_info_client(client, "Requesting voice channel crypt resync"); Client_send_message(client, sendmsg); } } @@ -629,15 +764,17 @@ static bool_t checkDecrypt(client_t *client, const uint8_t *encrypted, uint8_t * } #define UDP_PACKET_SIZE 1024 -int Client_read_udp() +int Client_read_udp(int udpsock) { int len; - struct sockaddr_in from; - socklen_t fromlen = sizeof(struct sockaddr_in); - uint64_t key; + struct sockaddr_storage from; + socklen_t fromlen = sizeof(struct sockaddr_storage); + uint8_t key[KEY_LENGTH]; client_t *itr; UDPMessageType_t msgType; - + uint8_t fromaddress[4 * sizeof(in_addr_t)]; + uint16_t fromport; + #if defined(__LP64__) uint8_t encbuff[UDP_PACKET_SIZE + 8]; uint8_t *encrypted = encbuff + 4; @@ -645,8 +782,23 @@ int Client_read_udp() uint8_t encrypted[UDP_PACKET_SIZE]; #endif uint8_t buffer[UDP_PACKET_SIZE]; - + len = recvfrom(udpsock, encrypted, UDP_PACKET_SIZE, MSG_TRUNC, (struct sockaddr *)&from, &fromlen); + + memset(key, 0, KEY_LENGTH); + + if(from.ss_family == AF_INET) { + memcpy(fromaddress, &((struct sockaddr_in*)&from)->sin_addr, sizeof(in_addr_t)); + fromport = ntohs(((struct sockaddr_in*)&from)->sin_port); + memcpy(&key[0], &fromport, 2); + memcpy(&key[2], fromaddress, sizeof(in_addr_t)); + } else { + memcpy(fromaddress, &((struct sockaddr_in6*)&from)->sin6_addr, 4 * sizeof(in_addr_t)); + fromport = ntohs(((struct sockaddr_in6*)&from)->sin6_port); + memcpy(&key[0], &fromport, 2); + memcpy(&key[2], fromaddress, 4 * sizeof(in_addr_t)); + } + if (len == 0) { return -1; } else if (len < 0) { @@ -666,28 +818,40 @@ int Client_read_udp() ping[3] = htonl((uint32_t)clientcount); ping[4] = htonl((uint32_t)getIntConf(MAX_CLIENTS)); ping[5] = htonl((uint32_t)getIntConf(MAX_BANDWIDTH)); - + sendto(udpsock, encrypted, 6 * sizeof(uint32_t), 0, (struct sockaddr *)&from, fromlen); return 0; } - - key = (((uint64_t)from.sin_addr.s_addr) << 16) ^ from.sin_port; + itr = NULL; - + while (Client_iterate(&itr) != NULL) { - if (itr->key == key) { + if (memcmp(itr->key, key, KEY_LENGTH) == 0) { if (!checkDecrypt(itr, encrypted, buffer, len)) goto out; break; } - } + } if (itr == NULL) { /* Unknown peer */ + struct sockaddr_storage itraddressstorage; + uint8_t itraddress[4 * sizeof(in_addr_t)]; + int addresslength; + while (Client_iterate(&itr) != NULL) { - if (itr->remote_tcp.sin_addr.s_addr == from.sin_addr.s_addr) { + itraddressstorage = itr->remote_tcp; + if(itraddressstorage.ss_family == AF_INET) { + memcpy(itraddress, &((struct sockaddr_in*)&from)->sin_addr, sizeof(in_addr_t)); + addresslength = sizeof(in_addr_t); + } else { + memcpy(itraddress, &((struct sockaddr_in6*)&from)->sin6_addr, 4 * sizeof(in_addr_t)); + addresslength = 4 * sizeof(in_addr_t); + } + + if (memcmp(itraddress, fromaddress, addresslength) == 0) { if (checkDecrypt(itr, encrypted, buffer, len)) { - itr->key = key; - Log_info_client(itr, "New UDP connection port %d", ntohs(from.sin_port)); - memcpy(&itr->remote_udp, &from, sizeof(struct sockaddr_in)); + memcpy(itr->key, key, KEY_LENGTH); + Log_info_client(itr, "New UDP connection from %s on port %d", itr->addressString, fromport); + memcpy(&itr->remote_udp, &from, sizeof(struct sockaddr_storage)); break; } } @@ -696,7 +860,7 @@ int Client_read_udp() if (itr == NULL) { /* Couldn't find this peer among connected clients */ goto out; } - + itr->bUDP = true; len -= 4; /* Adjust for crypt header */ msgType = (UDPMessageType_t)((buffer[0] >> 5) & 0x7); @@ -704,6 +868,9 @@ int Client_read_udp() case UDPVoiceSpeex: case UDPVoiceCELTAlpha: case UDPVoiceCELTBeta: + if (bOpus) + break; + case UDPVoiceOpus: Client_voiceMsg(itr, buffer, len); break; case UDPPing: @@ -711,22 +878,22 @@ int Client_read_udp() Client_send_udp(itr, buffer, len); break; default: - Log_debug("Unknown UDP message type from %s port %d", inet_ntoa(from.sin_addr), ntohs(from.sin_port)); + Log_debug("Unknown UDP message type from %s port %d", itr->addressString, fromport); break; } - + out: return 0; } static inline void Client_send_voice(client_t *src, client_t *dst, uint8_t *data, int len, int poslen) { - if (IS_AUTH(dst) && dst != src && !dst->deaf) { + if (IS_AUTH(dst) && dst != src && !dst->deaf && !dst->self_deaf) { if (poslen > 0 && /* Has positional data */ src->context != NULL && dst->context != NULL && /* ...both source and destination has context */ strcmp(src->context, dst->context) == 0) /* ...and the contexts match */ Client_send_udp(dst, data, len); - else + else Client_send_udp(dst, data, len - poslen); } } @@ -739,44 +906,50 @@ int Client_voiceMsg(client_t *client, uint8_t *data, int len) pds_t *pds = Pds_create(buffer + 1, UDP_PACKET_SIZE - 1); unsigned int type = data[0] & 0xe0; unsigned int target = data[0] & 0x1f; - unsigned int poslen, counter; + unsigned int poslen, counter, size; int offset, packetsize; voicetarget_t *vt; - + channel_t *ch = (channel_t *)client->channel; struct dlist *itr; - - if (!client->authenticated || client->mute) + + if (!client->authenticated || client->mute || client->self_mute || ch->silent) goto out; - + packetsize = 20 + 8 + 4 + len; if (client->availableBandwidth - packetsize < 0) goto out; /* Discard */ client->availableBandwidth -= packetsize; - + Timer_restart(&client->idleTime); - + Timer_restart(&client->lastActivity); + counter = Pds_get_numval(pdi); /* step past session id */ - do { - counter = Pds_next8(pdi); - offset = Pds_skip(pdi, counter & 0x7f); - } while ((counter & 0x80) && offset > 0); + if ((type >> 5) != UDPVoiceOpus) { + do { + counter = Pds_next8(pdi); + offset = Pds_skip(pdi, counter & 0x7f); + } while ((counter & 0x80) && offset > 0); + } else { + size = Pds_get_numval(pdi); + Pds_skip(pdi, size & 0x1fff); + } poslen = pdi->maxsize - pdi->offset; /* For stripping of positional info */ - + Pds_add_numval(pds, client->sessionId); Pds_append_data_nosize(pds, data + 1, len - 1); - + if (target == 0x1f) { /* Loopback */ buffer[0] = (uint8_t) type; Client_send_udp(client, buffer, pds->offset + 1); } else if (target == 0) { /* regular channel speech */ buffer[0] = (uint8_t) type; - + if (ch == NULL) goto out; - + list_iterate(itr, &ch->clients) { client_t *c; c = list_get_entry(itr, client_t, chan_node); @@ -828,7 +1001,7 @@ int Client_voiceMsg(client_t *client, uint8_t *data, int len) } Chan_freeTreeList(&chanlist); } - } + } /* Sessions */ for (i = 0; i < TARGET_MAX_SESSIONS && vt->sessions[i] != -1; i++) { client_t *c; @@ -845,16 +1018,22 @@ int Client_voiceMsg(client_t *client, uint8_t *data, int len) out: Pds_free(pds); Pds_free(pdi); - + return 0; } - static int Client_send_udp(client_t *client, uint8_t *data, int len) { uint8_t *buf, *mbuf; + uint16_t clientport; + int udpsock = (client->remote_udp.ss_family == AF_INET) ? udpsocks[0] : udpsocks[1]; + + if (client->remote_udp.ss_family == AF_INET) + clientport = ntohs(((struct sockaddr_in*)&client->remote_udp)->sin_port); + else + clientport = ntohs(((struct sockaddr_in6*)&client->remote_udp)->sin6_port); - if (client->remote_udp.sin_port != 0 && CryptState_isValid(&client->cryptState) && + if (clientport != 0 && CryptState_isValid(&client->cryptState) && client->bUDP) { #if defined(__LP64__) buf = mbuf = malloc(len + 4 + 16); @@ -864,11 +1043,11 @@ static int Client_send_udp(client_t *client, uint8_t *data, int len) #endif if (mbuf == NULL) Log_fatal("Out of memory"); - + CryptState_encrypt(&client->cryptState, data, buf, len); - + sendto(udpsock, buf, len + 4, 0, (struct sockaddr *)&client->remote_udp, sizeof(struct sockaddr_in)); - + free(mbuf); } else { message_t *msg;