{
list_del(&ch->node);
}
+
+void Chan_buildTreeList(channel_t *ch, struct dlist *head)
+{
+ channellist_t *chl;
+ struct dlist *itr;
+ channel_t *sub;
+
+ chl = malloc(sizeof(channellist_t));
+ chl->chan = ch;
+ init_list_entry(&chl->node);
+ list_add_tail(&chl->node, head);
+
+ list_iterate(itr, &ch->subs) {
+ sub = list_get_entry(itr, channel_t, node);
+ Chan_buildTreeList(sub, head);
+ }
+}
+
+void Chan_freeTreeList(struct dlist *head)
+{
+ struct dlist *itr, *save;
+ list_iterate_safe(itr, save, head) {
+ free(list_get_entry(itr, channellist_t, node));
+ }
+}
struct dlist link_node;
} channel_t;
+typedef struct {
+ channel_t *chan;
+ struct dlist node;
+} channellist_t;
+
void Chan_init();
void Chan_free();
void Chan_addChannel(channel_t *parent, channel_t *sub);
channel_t *Chan_createChannel(const char *name, const char *desc);
channel_t *Chan_fromId(int channelid);
void Chan_freeChannel(channel_t *ch);
+void Chan_buildTreeList(channel_t *ch, struct dlist *head);
+void Chan_freeTreeList(struct dlist *head);
#endif
}
} /* while */
}
- if (itr == NULL) {
+ if (itr == NULL) { /* Couldn't find this peer among connected clients */
goto out;
}
+ len -= 4; /* Adjust for crypt header */
msgType = (UDPMessageType_t)((buffer[0] >> 5) & 0x7);
switch (msgType) {
case UDPVoiceSpeex:
case UDPVoiceCELTAlpha:
case UDPVoiceCELTBeta:
- // u->bUdp = true;
+ itr->bUDP = true;
Client_voiceMsg(itr, buffer, len);
break;
case UDPPing:
Log_debug("Unknown UDP message type from %s port %d", inet_ntoa(from.sin_addr), ntohs(from.sin_port));
break;
}
+
out:
return 0;
}
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);
}
}
c = list_get_entry(itr, client_t, chan_node);
Client_send_voice(client, c, buffer, pds->offset + 1, poslen);
}
- /* Channel links */
- if (!list_empty(&ch->channel_links)) {
- struct dlist *ch_itr;
- list_iterate(ch_itr, &ch->channel_links) {
- channel_t *ch_link;
- ch_link = list_get_entry(ch_itr, channel_t, link_node);
- list_iterate(itr, &ch_link->clients) {
- client_t *c;
- c = list_get_entry(itr, client_t, chan_node);
- Log_debug("Linked voice from %s -> %s", ch->name, ch_link->name);
- Client_send_voice(client, c, buffer, pds->offset + 1, poslen);
- }
- }
- }
} else if ((vt = Voicetarget_get_id(client, target)) != NULL) { /* Targeted whisper */
int i;
channel_t *ch;
/* Channels */
- for (i = 0; i < TARGET_MAX_CHANNELS && vt->channels[i] != -1; i++) {
+ for (i = 0; i < TARGET_MAX_CHANNELS && vt->channels[i].channel != -1; i++) {
+ buffer[0] = (uint8_t) (type | 1);
Log_debug("Whisper channel %d", vt->channels[i]);
- ch = Chan_fromId(vt->channels[i]);
+ ch = Chan_fromId(vt->channels[i].channel);
if (ch == NULL)
continue;
list_iterate(itr, &ch->clients) {
c = list_get_entry(itr, client_t, chan_node);
Client_send_voice(client, c, buffer, pds->offset + 1, poslen);
}
+ /* Channel links */
+ if (vt->channels[i].linked && !list_empty(&ch->channel_links)) {
+ struct dlist *ch_itr;
+ list_iterate(ch_itr, &ch->channel_links) {
+ channel_t *ch_link;
+ ch_link = list_get_entry(ch_itr, channel_t, link_node);
+ list_iterate(itr, &ch_link->clients) {
+ client_t *c;
+ c = list_get_entry(itr, client_t, chan_node);
+ Log_debug("Linked voice from %s -> %s", ch->name, ch_link->name);
+ Client_send_voice(client, c, buffer, pds->offset + 1, poslen);
+ }
+ }
+ }
+ /* children */
+ if (vt->channels[i].children) {
+ struct dlist chanlist, *ch_itr;
+ init_list_entry(&chanlist);
+ Chan_buildTreeList(ch, &chanlist);
+ list_iterate(ch_itr, &chanlist) {
+ channel_t *sub;
+ sub = list_get_entry(ch_itr, channellist_t, node)->chan;
+ list_iterate(itr, &sub->clients) {
+ client_t *c;
+ c = list_get_entry(itr, client_t, chan_node);
+ Log_debug("Child voice from %s -> %s", ch->name, sub->name);
+ Client_send_voice(client, c, buffer, pds->offset + 1, poslen);
+ }
+ }
+ Chan_freeTreeList(&chanlist);
+ }
}
/* Sessions */
for (i = 0; i < TARGET_MAX_SESSIONS && vt->sessions[i] != -1; i++) {
client_t *c;
+ buffer[0] = (uint8_t) (type | 2);
Log_debug("Whisper session %d", vt->sessions[i]);
while (Client_iterate(&c) != NULL) {
if (c->sessionId == vt->sessions[i]) {
{
uint8_t *buf, *mbuf;
- if (client->remote_udp.sin_port != 0 && CryptState_isValid(&client->cryptState)) {
+ if (client->remote_udp.sin_port != 0 && CryptState_isValid(&client->cryptState) &&
+ client->bUDP) {
#if defined(__LP64__)
buf = mbuf = malloc(len + 4 + 16);
buf += 4;
free(mbuf);
} else {
message_t *msg;
- buf = malloc(len);
- memcpy(buf, data, len);
- msg = Msg_create(UDPTunnel);
-
- msg->payload.UDPTunnel->packet.data = buf;
- msg->payload.UDPTunnel->packet.len = len;
+ msg = Msg_CreateVoiceMsg(data, len);
Client_send_message(client, msg);
}
return 0;
int sessionId;
uint64_t key;
char *username;
- bool_t authenticated, deaf, mute;
+ bool_t bUDP, authenticated, deaf, mute;
char *os, *release;
uint32_t version;
int codec_count;
for (j = 0; j < target->n_session; j++)
Voicetarget_add_session(client, targetId, target->session[j]);
if (target->has_channel_id) {
- if (target->has_links || target->has_children)
- Log_warn("Whisper to children or linked channels not implemented. Ignoring.");
- Voicetarget_add_channel(client, targetId, target->channel_id);
+ bool_t linked = false, children = false;
+ if (target->has_links)
+ linked = target->links;
+ if (target->has_children)
+ children = target->children;
+ Voicetarget_add_channel(client, targetId, target->channel_id, linked, children);
}
}
break;
Client_send_message(client, msg);
break;
case UDPTunnel:
+ client->bUDP = false;
Client_voiceMsg(client, msg->payload.UDPTunnel->packet.data, msg->payload.UDPTunnel->packet.len);
break;
case ChannelState:
#define PREAMBLE_SIZE 6
-void dumpmsg(uint8_t *data, int size);
+static void dumpmsg(uint8_t *data, int size);
static message_t *Msg_create_nopayload(messageType_t messageType);
-void Msg_addPreamble(uint8_t *buffer, uint16_t type, uint32_t len)
+static void Msg_addPreamble(uint8_t *buffer, uint16_t type, uint32_t len)
{
type = htons(type);
len = htonl(len);
break;
default:
- Log_warn("Msg_networkToMessage: Unsupported message %d", msg->messageType);
+ Log_warn("Msg_MessageToNetwork: Unsupported message %d", msg->messageType);
return 0;
}
return len + PREAMBLE_SIZE;
}
-message_t *Msg_create_nopayload(messageType_t messageType)
+static message_t *Msg_create_nopayload(messageType_t messageType)
{
message_t *msg = malloc(sizeof(message_t));
}
}
+message_t *Msg_CreateVoiceMsg(uint8_t *data, int size)
+{
+ message_t *msg = NULL;
+
+ msg = Msg_create_nopayload(UDPTunnel);
+ msg->unpacked = false;
+ msg->payload.UDPTunnel = malloc(sizeof(struct _MumbleProto__UDPTunnel));
+ if (msg->payload.UDPTunnel == NULL)
+ Log_fatal("Out of memory");
+ msg->payload.UDPTunnel->packet.data = malloc(size);
+ if (msg->payload.UDPTunnel->packet.data == NULL)
+ Log_fatal("Out of memory");
+ memcpy(msg->payload.UDPTunnel->packet.data, data, size);
+ msg->payload.UDPTunnel->packet.len = size;
+ return msg;
+}
+
message_t *Msg_networkToMessage(uint8_t *data, int size)
{
message_t *msg = NULL;
}
case UDPTunnel: /* Non-standard handling of tunneled voice data */
{
- msg = Msg_create_nopayload(UDPTunnel);
- msg->unpacked = false;
- msg->payload.UDPTunnel = malloc(sizeof(struct _MumbleProto__UDPTunnel));
- if (msg->payload.UDPTunnel == NULL)
- Log_fatal("Out of memory");
- msg->payload.UDPTunnel->packet.data = malloc(msgLen);
- if (msg->payload.UDPTunnel->packet.data == NULL)
- Log_fatal("Out of memory");
- memcpy(msg->payload.UDPTunnel->packet.data, msgData, msgLen);
- msg->payload.UDPTunnel->packet.len = msgLen;
+ msg = Msg_CreateVoiceMsg(msgData, msgLen);
break;
}
case Authenticate:
void Msg_free(message_t *msg);
void Msg_inc_ref(message_t *msg);
+message_t *Msg_CreateVoiceMsg(uint8_t *data, int size);
message_t *Msg_create(messageType_t messageType);
#endif
}
}
-void Voicetarget_add_channel(client_t *client, int targetId, int channelId)
+void Voicetarget_add_channel(client_t *client, int targetId, int channelId,
+ bool_t linked, bool_t children)
{
struct dlist *itr;
voicetarget_t *vt;
int i;
vt = list_get_entry(itr, voicetarget_t, node);
for (i = 0; i < TARGET_MAX_CHANNELS; i++) {
- if (vt->channels[i] == -1) {
- vt->channels[i] = channelId;
+ if (vt->channels[i].channel == -1) {
+ vt->channels[i].channel = channelId;
+ vt->channels[i].linked = linked;
+ vt->channels[i].children = children;
Log_debug("Adding channel ID %d to voicetarget ID %d", channelId, targetId);
return;
}
Log_fatal("Out of memory");
memset(newtarget, 0, sizeof(voicetarget_t));
for (i = 0; i < TARGET_MAX_CHANNELS; i++)
- newtarget->channels[i] = -1;
+ newtarget->channels[i].channel = -1;
for (i = 0; i < TARGET_MAX_SESSIONS; i++)
newtarget->sessions[i] = -1;
newtarget->id = targetId;
#define TARGET_MAX_CHANNELS 16
#define TARGET_MAX_SESSIONS 32
+typedef struct {
+ int channel;
+ bool_t linked;
+ bool_t children;
+} channeltarget_t;
+
typedef struct {
int id;
- int channels[TARGET_MAX_CHANNELS];
+ channeltarget_t channels[TARGET_MAX_CHANNELS];
int sessions[TARGET_MAX_SESSIONS];
struct dlist node;
} voicetarget_t;
void Voicetarget_del_id(client_t *client, int targetId);
void Voicetarget_add_session(client_t *client, int targetId, int sessionId);
-void Voicetarget_add_channel(client_t *client, int targetId, int channelId);
+void Voicetarget_add_channel(client_t *client, int targetId, int channelId,
+ bool_t linked, bool_t children);
voicetarget_t *Voicetarget_get_id(client_t *client, int targetId);
void Voicetarget_free_all(client_t *client);