-/* Copyright (C) 2009-2011, Martin Johansson <martin@fatbob.nu>
- Copyright (C) 2005-2011, Thorvald Natvig <thorvald@natvig.com>
+/* Copyright (C) 2009-2014, Martin Johansson <martin@fatbob.nu>
+ Copyright (C) 2005-2014, Thorvald Natvig <thorvald@natvig.com>
All rights reserved.
are met:
- Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
+ this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
- Neither the name of the Developers nor the names of its contributors may
- be used to endorse or promote products derived from this software without
- specific prior written permission.
+ be used to endorse or promote products derived from this software without
+ specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
+ */
#include <sys/poll.h>
#include <sys/socket.h>
#include <fcntl.h>
#include "channel.h"
#include "version.h"
#include "voicetarget.h"
+#include "ban.h"
extern char system_string[], version_string[];
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()
{
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)
if (list_empty(&client->codecs))
return NULL;
-
+
if (cd == NULL) {
cd = list_get_entry(list_get_first(&client->codecs), codec_t, node);
} else {
{
token_t *token;
struct dlist *itr;
-
+
if (list_empty(&client->tokens))
return false;
list_iterate(itr, &client->tokens) {
{
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);
client->tokencount = 0;
}
-void recheckCodecVersions()
+
+#define OPUS_WARN_USING "<strong>WARNING:</strong> 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 "<strong>WARNING:</strong> 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) {
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) {
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()
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;
}
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;
{
struct dlist *itr, *save;
message_t *sendmsg;
+ bool_t authenticatedLeft = client->authenticated;
if (client->authenticated) {
int leave_id;
Client_codec_free(client);
Voicetarget_free_all(client);
Client_token_free(client);
-
+
list_del(&client->node);
if (client->ssl)
SSLi_free(client->ssl);
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)
void Client_disconnect_all()
{
struct dlist *itr, *save;
-
+
list_iterate_safe(itr, save, &clients) {
Client_free(list_get_entry(itr, client_t, node));
}
{
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);
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;
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);
* 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; */
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));
}
}
} while (SSLi_data_pending(client->ssl));
-
+
return 0;
}
{
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);
int Client_write(client_t *client)
{
int rc;
-
+
if (client->readBlockedOnWrite) {
client->readBlockedOnWrite = false;
Log_debug("Client_write: readBlockedOnWrite == true");
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;
}
if (list_empty(&clients))
return NULL;
-
+
if (c == NULL) {
c = list_get_entry(list_get_first(&clients), client_t, node);
} else {
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) {
}
}
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;
}
{
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) {
}
}
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;
}
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);
}
}
}
#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;
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) {
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;
}
}
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);
switch (msgType) {
- case UDPVoiceSpeex:
- case UDPVoiceCELTAlpha:
- case UDPVoiceCELTBeta:
- Client_voiceMsg(itr, buffer, len);
- break;
- case UDPPing:
- Log_debug("UDP Ping reply len %d", len);
- 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));
- break;
- }
-
+ case UDPVoiceSpeex:
+ case UDPVoiceCELTAlpha:
+ case UDPVoiceCELTBeta:
+ if (bOpus)
+ break;
+ case UDPVoiceOpus:
+ Client_voiceMsg(itr, buffer, len);
+ break;
+ case UDPPing:
+ Log_debug("UDP Ping reply len %d", len);
+ Client_send_udp(itr, buffer, len);
+ break;
+ default:
+ 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);
}
}
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);
Client_send_voice(client, c, buffer, pds->offset + 1, poslen);
}
- } else if ((vt = Voicetarget_get_id(client, target)) != NULL) { /* Targeted whisper */
+ } else if ((vt = Voicetarget_get_id(client, target)) != NULL) { /* Targeted whisper */
int i;
channel_t *ch;
/* Channels */
}
Chan_freeTreeList(&chanlist);
}
- }
+ }
/* Sessions */
for (i = 0; i < TARGET_MAX_SESSIONS && vt->sessions[i] != -1; i++) {
client_t *c;
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);
#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));
-
+
+ if (client->remote_udp.ss_family == AF_INET)
+ sendto(udpsock, buf, len + 4, 0, (struct sockaddr *)&client->remote_udp, sizeof(struct sockaddr_in));
+ else
+ sendto(udpsock, buf, len + 4, 0, (struct sockaddr *)&client->remote_udp, sizeof(struct sockaddr_in6));
+
free(mbuf);
} else {
message_t *msg;