1 /* Copyright (C) 2009, Martin Johansson <martin@fatbob.nu>
2 Copyright (C) 2005-2009, 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.
32 #include <sys/socket.h>
39 #include "messagehandler.h"
43 /* Version 0.2.0 XXX fixme */
44 const uint32_t versionBlob = 1<<16 | 2<<8 | 0;
46 static int Client_read(client_t *client);
47 static int Client_write(client_t *client);
48 static int Client_send_udp(client_t *client, uint8_t *data, int len);
49 void Client_free(client_t *client);
51 declare_list(clients);
52 static int clientcount; /* = 0 */
53 static int session = 1;
54 static int maxBandwidth;
56 static int iCodecAlpha, iCodecBeta;
57 static bool_t bPreferAlpha;
63 maxBandwidth = getIntConf(MAX_BANDWIDTH);
71 int Client_getfds(struct pollfd *pollfds)
75 list_iterate(itr, &clients) {
77 c = list_get_entry(itr, client_t, node);
78 pollfds[i].fd = c->tcpfd;
79 pollfds[i].events = POLLIN | POLLHUP | POLLERR;
80 if (c->txsize > 0 || c->readBlockedOnWrite) /* Data waiting to be sent? */
81 pollfds[i].events |= POLLOUT;
90 int bwTop = maxBandwidth + maxBandwidth / 4;
91 list_iterate(itr, &clients) {
93 c = list_get_entry(itr, client_t, node);
94 Log_debug("Client %s BW available %d", c->playerName, c->availableBandwidth);
95 c->availableBandwidth += maxBandwidth;
96 if (c->availableBandwidth > bwTop)
97 c->availableBandwidth = bwTop;
99 if (Timer_isElapsed(&c->lastActivity, 1000000LL * INACTICITY_TIMEOUT)) {
100 /* No activity from client - assume it is lost and close. */
101 Log_info("Session ID %d timeout - closing", c->sessionId);
107 void recheckCodecVersions()
109 int codec_map[MAX_CODECS][2];
111 int i, codecindex, max = 0, version, current_version;
114 memset(codec_map, 0, MAX_CODECS * 2 * sizeof(int));
115 while (Client_iterate(&itr) != NULL) {
116 for (i = 0; i < itr->codec_count; i++) {
117 for (codecindex = 0; codecindex < MAX_CODECS; codecindex++) {
118 if (codec_map[codecindex][0] == 0)
119 codec_map[codecindex][0] = itr->codecs[i];
120 if (itr->codecs[i] == codec_map[codecindex][0])
121 codec_map[codecindex][1]++;
125 if (codec_map[codecindex][0] == 0)
127 for (codecindex = 0; codecindex < MAX_CODECS; codecindex++) {
128 if (codec_map[codecindex][0] == 0)
130 if (codec_map[codecindex][1] > max) {
131 max = codec_map[codecindex][1];
132 version = codec_map[codecindex][0];
135 current_version = bPreferAlpha ? iCodecAlpha : iCodecBeta;
136 if (current_version == version)
138 // If we don't already use the compat bitstream version set
139 // it as alpha and announce it. If another codec now got the
140 // majority set it as the opposite of the currently valid bPreferAlpha
142 if (version == (uint32_t)0x8000000a)
145 bPreferAlpha = ! bPreferAlpha;
148 iCodecAlpha = version;
150 iCodecBeta = version;
152 sendmsg = Msg_create(CodecVersion);
153 sendmsg->payload.codecVersion->alpha = version;
154 sendmsg->payload.codecVersion->beta = version;
155 sendmsg->payload.codecVersion->beta = bPreferAlpha;
156 Client_send_message_except(NULL, sendmsg);
160 int Client_add(int fd, struct sockaddr_in *remote)
165 newclient = malloc(sizeof(client_t));
166 if (newclient == NULL)
167 Log_fatal("Out of memory");
168 memset(newclient, 0, sizeof(client_t));
170 newclient->tcpfd = fd;
171 memcpy(&newclient->remote_tcp, remote, sizeof(struct sockaddr_in));
172 newclient->ssl = SSL_newconnection(newclient->tcpfd, &newclient->SSLready);
173 if (newclient->ssl == NULL) {
174 Log_warn("SSL negotiation failed");
178 newclient->availableBandwidth = maxBandwidth;
179 Timer_init(&newclient->lastActivity);
180 newclient->sessionId = session++; /* XXX - more elaborate? */
182 init_list_entry(&newclient->txMsgQueue);
183 init_list_entry(&newclient->chan_node);
184 init_list_entry(&newclient->node);
186 list_add_tail(&newclient->node, &clients);
189 /* Send version message to client */
190 sendmsg = Msg_create(Version);
191 sendmsg->payload.version->has_version = true;
192 sendmsg->payload.version->version = (1 << 16) | (2 << 8) | 0; /* XXX fix */
193 sendmsg->payload.version->release = strdup("1.2.0");
194 sendmsg->payload.version->os = strdup("Linux/OpenWRT");
196 Client_send_message(newclient, sendmsg);
201 void Client_free(client_t *client)
203 struct dlist *itr, *save;
206 Log_info("Disconnect client ID %d addr %s port %d", client->sessionId,
207 inet_ntoa(client->remote_tcp.sin_addr),
208 ntohs(client->remote_tcp.sin_port));
210 if (client->authenticated) {
211 sendmsg = Msg_create(UserRemove);
212 sendmsg->payload.userRemove->session = client->sessionId;
213 Client_send_message_except(client, sendmsg);
215 list_iterate_safe(itr, save, &client->txMsgQueue) {
216 list_del(&list_get_entry(itr, message_t, node)->node);
217 Msg_free(list_get_entry(itr, message_t, node));
220 list_del(&client->node);
221 list_del(&client->chan_node);
223 SSL_free(client->ssl);
224 close(client->tcpfd);
229 void Client_close(client_t *client)
231 SSL_shutdown(client->ssl);
232 client->shutdown_wait = true;
235 void Client_disconnect_all()
237 struct dlist *itr, *save;
239 list_iterate_safe(itr, save, &clients) {
240 Client_free(list_get_entry(itr, client_t, node));
244 int Client_read_fd(int fd)
247 client_t *client = NULL;
249 list_iterate(itr, &clients) {
250 if(fd == list_get_entry(itr, client_t, node)->tcpfd) {
251 client = list_get_entry(itr, client_t, node);
256 Log_fatal("No client found for fd %d", fd);
258 return Client_read(client);
261 int Client_read(client_t *client)
265 Timer_restart(&client->lastActivity);
267 if (client->writeBlockedOnRead) {
268 client->writeBlockedOnRead = false;
269 Log_debug("Client_read: writeBlockedOnRead == true");
270 return Client_write(client);
273 if (client->shutdown_wait) {
277 if (!client->SSLready) {
279 rc = SSL_nonblockaccept(client->ssl, &client->SSLready);
288 if (!client->msgsize)
289 rc = SSL_read(client->ssl, client->rxbuf, 6 - client->rxcount);
290 else if (client->drainleft > 0)
291 rc = SSL_read(client->ssl, client->rxbuf, client->drainleft > BUFSIZE ? BUFSIZE : client->drainleft);
293 rc = SSL_read(client->ssl, &client->rxbuf[client->rxcount], client->msgsize);
296 if (client->drainleft > 0)
297 client->drainleft -= rc;
299 client->rxcount += rc;
300 if (!client->msgsize && client->rxcount >= 6) {
301 uint32_t *msgLen = (uint32_t *) &client->rxbuf[2];
302 client->msgsize = ntohl(*msgLen);
304 if (client->msgsize > BUFSIZE - 6 && client->drainleft == 0) {
305 Log_warn("Too big message received (%d). Discarding.", client->msgsize);
306 client->rxcount = client->msgsize = 0;
307 client->drainleft = client->msgsize;
309 else if (client->rxcount == client->msgsize + 6) { /* Got all of the message */
310 msg = Msg_networkToMessage(client->rxbuf, client->msgsize + 6);
311 /* pass messsage to handler */
313 Mh_handle_message(client, msg);
314 client->rxcount = client->msgsize = 0;
317 } else /* rc <= 0 */ {
318 if (SSL_get_error(client->ssl, rc) == SSL_ERROR_WANT_READ) {
321 else if (SSL_get_error(client->ssl, rc) == SSL_ERROR_WANT_WRITE) {
322 client->readBlockedOnWrite = true;
325 else if (SSL_get_error(client->ssl, rc) == SSL_ERROR_ZERO_RETURN) {
326 Log_warn("Error: Zero return - closing");
327 if (!client->shutdown_wait)
328 Client_close(client);
331 if (SSL_get_error(client->ssl, rc) == SSL_ERROR_SYSCALL) {
332 /* Hmm. This is where we end up when the client closes its connection.
335 Log_info("Connection closed by peer");
338 Log_warn("SSL error: %d - Closing connection.", SSL_get_error(client->ssl, rc));
344 } while (SSL_pending(client->ssl));
348 int Client_write_fd(int fd)
351 client_t *client = NULL;
353 list_iterate(itr, &clients) {
354 if(fd == list_get_entry(itr, client_t, node)->tcpfd) {
355 client = list_get_entry(itr, client_t, node);
360 Log_fatal("No client found for fd %d", fd);
361 Client_write(client);
365 int Client_write(client_t *client)
369 if (client->readBlockedOnWrite) {
370 client->readBlockedOnWrite = false;
371 Log_debug("Client_write: readBlockedOnWrite == true");
372 return Client_read(client);
374 rc = SSL_write(client->ssl, &client->txbuf[client->txcount], client->txsize - client->txcount);
376 client->txcount += rc;
377 if (client->txcount == client->txsize)
378 client->txsize = client->txcount = 0;
381 if (SSL_get_error(client->ssl, rc) == SSL_ERROR_WANT_READ) {
382 client->writeBlockedOnRead = true;
385 else if (SSL_get_error(client->ssl, rc) == SSL_ERROR_WANT_WRITE) {
389 if (SSL_get_error(client->ssl, rc) == SSL_ERROR_SYSCALL)
390 Log_warn("Client_write: Error: %s - Closing connection", strerror(errno));
392 Log_warn("Client_write: SSL error: %d - Closing connection.", SSL_get_error(client->ssl, rc));
397 if (client->txsize == 0 && !list_empty(&client->txMsgQueue)) {
399 msg = list_get_entry(list_get_first(&client->txMsgQueue), message_t, node);
400 list_del(list_get_first(&client->txMsgQueue));
401 client->txQueueCount--;
402 Client_send_message(client, msg);
407 int Client_send_message(client_t *client, message_t *msg)
409 if (!client->authenticated && msg->messageType != Version) {
413 if (client->txsize != 0 || !client->SSLready) {
415 if ((client->txQueueCount > 5 && msg->messageType == UDPTunnel) ||
416 client->txQueueCount > 30) {
420 client->txQueueCount++;
421 list_add_tail(&msg->node, &client->txMsgQueue);
422 Log_debug("Queueing message");
425 memset(client->txbuf, 0, BUFSIZE);
426 len = Msg_messageToNetwork(msg, client->txbuf);
427 doAssert(len < BUFSIZE);
429 client->txsize = len;
431 Client_write(client);
437 client_t *Client_iterate(client_t **client_itr)
439 client_t *c = *client_itr;
441 if (list_empty(&clients))
445 c = list_get_entry(list_get_first(&clients), client_t, node);
447 if (list_get_next(&c->node) == &clients)
450 c = list_get_entry(list_get_next(&c->node), client_t, node);
457 int Client_send_message_except(client_t *client, message_t *msg)
459 client_t *itr = NULL;
462 Msg_inc_ref(msg); /* Make sure a reference is held during the whole iteration. */
463 while (Client_iterate(&itr) != NULL) {
466 Msg_inc_ref(msg); /* One extra reference for each new copy */
467 Log_debug("Msg %d to %s refcount %d", msg->messageType, itr->playerName, msg->refcount);
468 Client_send_message(itr, msg);
471 Msg_free(msg); /* Free our reference to the message */
474 Msg_free(msg); /* If only 1 client is connected then no message is passed
475 * to Client_send_message(). Free it here. */
480 static bool_t checkDecrypt(client_t *client, const uint8_t *encrypted, uint8_t *plain, unsigned int len)
482 if (CryptState_isValid(&client->cryptState) &&
483 CryptState_decrypt(&client->cryptState, encrypted, plain, len))
486 if (Timer_elapsed(&client->cryptState.tLastGood) > 5000000ULL) {
487 if (Timer_elapsed(&client->cryptState.tLastRequest) > 5000000ULL) {
489 Timer_restart(&client->cryptState.tLastRequest);
491 sendmsg = Msg_create(CryptSetup);
492 Log_info("Requesting voice channel crypt resync");
493 Client_send_message(client, sendmsg);
499 #define UDP_PACKET_SIZE 1024
500 int Client_read_udp()
503 struct sockaddr_in from;
504 socklen_t fromlen = sizeof(struct sockaddr_in);
507 UDPMessageType_t msgType;
509 #if defined(__LP64__)
510 uint8_t encbuff[UDP_PACKET_SIZE + 8];
511 uint8_t *encrypted = encbuff + 4;
513 uint8_t encrypted[UDP_PACKET_SIZE];
515 uint8_t buffer[UDP_PACKET_SIZE];
517 len = recvfrom(udpsock, encrypted, UDP_PACKET_SIZE, MSG_TRUNC, (struct sockaddr *)&from, &fromlen);
520 } else if (len < 0) {
522 } else if (len < 5) {
523 // 4 bytes crypt header + type + session
525 } else if (len > UDP_PACKET_SIZE) {
530 if (len == 12 && *encrypted == 0) {
531 uint32_t *ping = (uint32_t *)encrypted;
532 ping[0] = htons(versionBlob);
533 // 1 and 2 will be the timestamp, which we return unmodified.
534 ping[3] = htons((uint32_t)clientcount);
535 ping[4] = htons((uint32_t)getIntConf(MAX_CLIENTS));
536 ping[5] = htons((uint32_t)getIntConf(MAX_BANDWIDTH));
538 sendto(udpsock, encrypted, 6 * sizeof(uint32_t), 0, (struct sockaddr *)&from, fromlen);
542 key = (((uint64_t)from.sin_addr.s_addr) << 16) ^ from.sin_port;
545 while (Client_iterate(&itr) != NULL) {
546 if (itr->key == key) {
547 if (!checkDecrypt(itr, encrypted, buffer, len))
552 if (itr == NULL) { /* Unknown peer */
553 while (Client_iterate(&itr) != NULL) {
554 if (itr->remote_tcp.sin_addr.s_addr == from.sin_addr.s_addr) {
555 if (checkDecrypt(itr, encrypted, buffer, len)) {
557 Log_info("New UDP connection from %s port %d sessionId %d", inet_ntoa(from.sin_addr), ntohs(from.sin_port), itr->sessionId);
558 memcpy(&itr->remote_udp, &from, sizeof(struct sockaddr_in));
561 else Log_warn("Bad cryptstate from peer");
569 msgType = (UDPMessageType_t)((buffer[0] >> 5) & 0x7);
572 case UDPVoiceCELTAlpha:
573 case UDPVoiceCELTBeta:
575 Client_voiceMsg(itr, buffer, len);
578 Client_send_udp(itr, buffer, len);
581 Log_debug("Unknown UDP message type from %s port %d", inet_ntoa(from.sin_addr), ntohs(from.sin_port));
588 /* Handle decrypted voice message */
589 int Client_voiceMsg(client_t *client, uint8_t *data, int len)
591 uint8_t buffer[UDP_PACKET_SIZE];
592 pds_t *pdi = Pds_create(data + 1, len - 1);
593 pds_t *pds = Pds_create(buffer + 1, UDP_PACKET_SIZE - 1);
594 unsigned int type = data[0] & 0xe0;
595 unsigned int target = data[0] & 0x1f;
596 unsigned int poslen, counter;
597 int offset, packetsize;
599 channel_t *ch = (channel_t *)client->channel;
602 if (!client->authenticated || client->mute)
605 packetsize = 20 + 8 + 4 + len;
606 if (client->availableBandwidth - packetsize < 0)
607 goto out; /* Discard */
608 client->availableBandwidth -= packetsize;
610 counter = Pds_get_numval(pdi); /* step past session id */
612 counter = Pds_next8(pdi);
613 offset = Pds_skip(pdi, counter & 0x7f);
614 } while ((counter & 0x80) && offset > 0);
616 poslen = pdi->maxsize - pdi->offset; /* XXX - Add stripping of positional audio */
618 Pds_add_numval(pds, client->sessionId);
619 Pds_append_data_nosize(pds, data + 1, len - 1);
621 if (target & 0x1f) { /* Loopback */
622 buffer[0] = (uint8_t) type;
623 Client_send_udp(client, buffer, pds->offset + 1);
625 else if (target == 0) { /* regular channel speech */
626 buffer[0] = (uint8_t) type;
631 list_iterate(itr, &ch->clients) {
633 c = list_get_entry(itr, client_t, chan_node);
634 if (c != client && !c->deaf) {
635 Client_send_udp(c, buffer, pds->offset + 1);
639 /* XXX - Add targeted whisper here */
648 static int Client_send_udp(client_t *client, uint8_t *data, int len)
652 if (client->remote_udp.sin_port != 0 && CryptState_isValid(&client->cryptState)) {
653 #if defined(__LP64__)
654 buf = mbuf = malloc(len + 4 + 16);
657 mbuf = buf = malloc(len + 4);
660 Log_fatal("Out of memory");
662 CryptState_encrypt(&client->cryptState, data, buf, len);
664 sendto(udpsock, buf, len + 4, 0, (struct sockaddr *)&client->remote_udp, sizeof(struct sockaddr_in));
670 memcpy(buf, data, len);
671 msg = Msg_create(UDPTunnel);
673 msg->payload.UDPTunnel->packet.data = buf;
674 msg->payload.UDPTunnel->packet.len = len;
675 Client_send_message(client, msg);