More work toward 1.2.0:
[umurmur.git] / src / messages.c
1 /* Copyright (C) 2009, Martin Johansson <martin@fatbob.nu>
2    Copyright (C) 2005-2009, Thorvald Natvig <thorvald@natvig.com>
3
4    All rights reserved.
5
6    Redistribution and use in source and binary forms, with or without
7    modification, are permitted provided that the following conditions
8    are met:
9
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.
18
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.
30 */
31
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <arpa/inet.h>
36
37 #include "messages.h"
38 #include "client.h"
39 #include "pds.h"
40 #include "log.h"
41
42
43 void dumpmsg(uint8_t *data, int size);
44
45 void Msg_addPreamble(uint8_t *buffer, uint16_t type, uint32_t len)
46 {
47         uint16_t *msgType = (uint16_t *) &buffer[0];
48         uint32_t *msgLen = (uint32_t *) &buffer[2];
49         
50         *msgType = htons(type);
51         *msgLen = htonl(len);
52 }
53
54 static void Msg_getPreamble(uint8_t *buffer, int *type, int *len)
55 {
56         uint16_t *msgType = (uint16_t *) &buffer[0];
57         uint32_t *msgLen = (uint32_t *) &buffer[2];
58         
59         *type = (int)ntohs(*msgType);
60         *len = (int)ntohl(*msgLen);
61 }
62
63 #define MAX_MSGSIZE (BUFSIZE - 6)
64 int Msg_messageToNetwork(message_t *msg, uint8_t *buffer)
65 {
66         int len;
67         uint8_t *bufptr = buffer + 6;
68                 
69         Log_debug("To net: msg type %d", msg->messageType);
70         switch (msg->messageType) {
71         case Version:
72                 len = mumble_proto__version__get_packed_size(msg->payload.version);
73                 if (len > MAX_MSGSIZE) {
74                         Log_warn("Too big tx message. Discarding");
75                         break;
76                 }
77                 Msg_addPreamble(buffer, msg->messageType, len);
78                 Log_debug("To net: Version->release: %s Version->os: %s",
79                                   msg->payload.version->release, msg->payload.version->os);
80                 mumble_proto__version__pack(msg->payload.version, bufptr);
81                 break;
82         case UDPTunnel:
83                 len = mumble_proto__udptunnel__get_packed_size(msg->payload.UDPTunnel);
84                 if (len > MAX_MSGSIZE) {
85                         Log_warn("Too big tx message. Discarding");
86                         break;
87                 }
88                 Msg_addPreamble(buffer, msg->messageType, len);
89                 mumble_proto__udptunnel__pack(msg->payload.UDPTunnel, bufptr);          
90                 break;
91         case Authenticate:
92                 len = mumble_proto__authenticate__get_packed_size(msg->payload.authenticate);
93                 if (len > MAX_MSGSIZE) {
94                         Log_warn("Too big tx message. Discarding");
95                         break;
96                         }
97                 Msg_addPreamble(buffer, msg->messageType, len);
98                 mumble_proto__authenticate__pack(msg->payload.authenticate, bufptr);
99                 break;
100         case Ping:
101                 len = mumble_proto__ping__get_packed_size(msg->payload.ping);
102                 if (len > MAX_MSGSIZE) {
103                         Log_warn("Too big tx message. Discarding");
104                         break;
105                         }
106                 Msg_addPreamble(buffer, msg->messageType, len);
107                 mumble_proto__ping__pack(msg->payload.ping, bufptr);
108                 break;
109         case Reject:
110                 len = mumble_proto__reject__get_packed_size(msg->payload.reject);
111                 if (len > MAX_MSGSIZE) {
112                         Log_warn("Too big tx message. Discarding");
113                         break;
114                         }
115                 Msg_addPreamble(buffer, msg->messageType, len);
116                 mumble_proto__reject__pack(msg->payload.reject, bufptr);
117                 break;
118         case ServerSync:
119                 len = mumble_proto__server_sync__get_packed_size(msg->payload.serverSync);
120                 if (len > MAX_MSGSIZE) {
121                         Log_warn("Too big tx message. Discarding");
122                         break;
123                         }
124                 Msg_addPreamble(buffer, msg->messageType, len);
125                 mumble_proto__server_sync__pack(msg->payload.serverSync, bufptr);
126                 break;
127         case TextMessage:
128                 len = mumble_proto__text_message__get_packed_size(msg->payload.textMessage);
129                 if (len > MAX_MSGSIZE) {
130                         Log_warn("Too big tx message. Discarding");
131                         break;
132                         }
133                 Msg_addPreamble(buffer, msg->messageType, len);
134                 mumble_proto__text_message__pack(msg->payload.textMessage, bufptr);
135                 break;
136         case PermissionDenied:
137                 len = mumble_proto__permission_denied__get_packed_size(msg->payload.permissionDenied);
138                 if (len > MAX_MSGSIZE) {
139                         Log_warn("Too big tx message. Discarding");
140                         break;
141                         }
142                 Msg_addPreamble(buffer, msg->messageType, len);
143                 mumble_proto__permission_denied__pack(msg->payload.permissionDenied, bufptr);
144                 break;
145         case CryptSetup:
146                 len = mumble_proto__crypt_setup__get_packed_size(msg->payload.cryptSetup);
147                 if (len > MAX_MSGSIZE) {
148                         Log_warn("Too big tx message. Discarding");
149                         break;
150                         }
151                 Msg_addPreamble(buffer, msg->messageType, len);
152                 mumble_proto__crypt_setup__pack(msg->payload.cryptSetup, bufptr);
153                 break;
154         case UserList:
155                 len = mumble_proto__user_list__get_packed_size(msg->payload.userList);
156                 if (len > MAX_MSGSIZE) {
157                         Log_warn("Too big tx message. Discarding");
158                         break;
159                         }
160                 Msg_addPreamble(buffer, msg->messageType, len);
161                 mumble_proto__user_list__pack(msg->payload.userList, bufptr);
162                 break;
163         case UserState:
164                 len = mumble_proto__user_state__get_packed_size(msg->payload.userState);
165                 if (len > MAX_MSGSIZE) {
166                         Log_warn("Too big tx message. Discarding");
167                         break;
168                         }
169                 Msg_addPreamble(buffer, msg->messageType, len);
170                 mumble_proto__user_state__pack(msg->payload.userState, bufptr);
171                 break;
172         case ChannelState:
173                 len = mumble_proto__channel_state__get_packed_size(msg->payload.channelState);
174                 if (len > MAX_MSGSIZE) {
175                         Log_warn("Too big tx message. Discarding");
176                         break;
177                         }
178                 Msg_addPreamble(buffer, msg->messageType, len);
179                 mumble_proto__channel_state__pack(msg->payload.channelState, bufptr);
180                 break;
181         case VoiceTarget:
182                 len = mumble_proto__voice_target__get_packed_size(msg->payload.voiceTarget);
183                 if (len > MAX_MSGSIZE) {
184                         Log_warn("Too big tx message. Discarding");
185                         break;
186                         }
187                 Msg_addPreamble(buffer, msg->messageType, len);
188                 mumble_proto__voice_target__pack(msg->payload.voiceTarget, bufptr);
189                 break;
190         case CodecVersion:
191                 len = mumble_proto__codec_version__get_packed_size(msg->payload.codecVersion);
192                 if (len > MAX_MSGSIZE) {
193                         Log_warn("Too big tx message. Discarding");
194                         break;
195                         }
196                 Msg_addPreamble(buffer, msg->messageType, len);
197                 mumble_proto__codec_version__pack(msg->payload.codecVersion, bufptr);
198                 break;
199         case PermissionQuery:
200                 len = mumble_proto__permission_query__get_packed_size(msg->payload.permissionQuery);
201                 if (len > MAX_MSGSIZE) {
202                         Log_warn("Too big tx message. Discarding");
203                         break;
204                         }
205                 Msg_addPreamble(buffer, msg->messageType, len);
206                 mumble_proto__permission_query__pack(msg->payload.permissionQuery, bufptr);
207                 break;
208
209         default:
210                 Log_warn("Unsupported message %d", msg->messageType);
211                 return 0;
212         }
213         return len + 6;
214 }
215
216 message_t *Msg_create(messageType_t messageType)
217 {
218         message_t *msg = malloc(sizeof(message_t));
219
220         if (msg == NULL)
221                 Log_fatal("Out of memory");
222         memset(msg, 0, sizeof(message_t));
223         msg->refcount = 1;
224         msg->messageType = messageType;
225         init_list_entry(&msg->node);
226         
227         switch (messageType) {
228         case Version:
229                 msg->payload.version = malloc(sizeof(MumbleProto__Version));
230                 mumble_proto__version__init(msg->payload.version);
231                 break;
232         case UDPTunnel:
233                 msg->payload.UDPTunnel = malloc(sizeof(MumbleProto__UDPTunnel));
234                 mumble_proto__udptunnel__init(msg->payload.UDPTunnel);
235                 break;
236         case Authenticate:
237                 msg->payload.authenticate = malloc(sizeof(MumbleProto__Authenticate));
238                 mumble_proto__authenticate__init(msg->payload.authenticate);
239                 break;
240         case Ping:
241                 msg->payload.ping = malloc(sizeof(MumbleProto__Ping));
242                 mumble_proto__ping__init(msg->payload.ping);
243                 break;
244         case Reject:
245                 msg->payload.reject = malloc(sizeof(MumbleProto__Reject));
246                 mumble_proto__reject__init(msg->payload.reject);
247                 break;
248         case ServerSync:
249                 msg->payload.serverSync = malloc(sizeof(MumbleProto__ServerSync));
250                 mumble_proto__server_sync__init(msg->payload.serverSync);
251                 break;
252         case TextMessage:
253                 msg->payload.textMessage = malloc(sizeof(MumbleProto__TextMessage));
254                 mumble_proto__text_message__init(msg->payload.textMessage);
255                 break;
256         case PermissionDenied:
257                 msg->payload.permissionDenied = malloc(sizeof(MumbleProto__PermissionDenied));
258                 mumble_proto__permission_denied__init(msg->payload.permissionDenied);
259                 break;
260         case CryptSetup:
261                 msg->payload.cryptSetup = malloc(sizeof(MumbleProto__CryptSetup));
262                 mumble_proto__crypt_setup__init(msg->payload.cryptSetup);
263                 break;
264         case UserList:
265                 msg->payload.userList = malloc(sizeof(MumbleProto__UserList));
266                 mumble_proto__user_list__init(msg->payload.userList);
267                 break;
268         case UserState:
269                 msg->payload.userState = malloc(sizeof(MumbleProto__UserState));
270                 mumble_proto__user_state__init(msg->payload.userState);
271                 break;
272         case UserRemove:
273                 msg->payload.userRemove = malloc(sizeof(MumbleProto__UserRemove));
274                 mumble_proto__user_remove__init(msg->payload.userRemove);
275                 break;
276         case VoiceTarget:
277                 msg->payload.voiceTarget = malloc(sizeof(MumbleProto__VoiceTarget));
278                 mumble_proto__voice_target__init(msg->payload.voiceTarget);
279                 break;
280         case CodecVersion:
281                 msg->payload.codecVersion = malloc(sizeof(MumbleProto__CodecVersion));
282                 mumble_proto__codec_version__init(msg->payload.codecVersion);
283                 break;
284         case ChannelState:
285                 msg->payload.channelState = malloc(sizeof(MumbleProto__ChannelState));
286                 mumble_proto__channel_state__init(msg->payload.channelState);
287                 break;
288         case PermissionQuery:
289                 msg->payload.permissionQuery = malloc(sizeof(MumbleProto__PermissionQuery));
290                 mumble_proto__permission_query__init(msg->payload.permissionQuery);
291                 break;
292
293         default:
294                 Log_warn("Msg_create: Unsupported message %d", msg->messageType);
295                 break;
296         }
297
298         return msg;
299 }
300
301 void Msg_inc_ref(message_t *msg)
302 {
303         msg->refcount++;
304 }
305
306 void Msg_free(message_t *msg)
307 {
308         if (msg->refcount) msg->refcount--;
309         if (msg->refcount > 0)
310                 return;
311
312         switch (msg->messageType) {
313         case Version:
314                 if (msg->unpacked)
315                         mumble_proto__version__free_unpacked(msg->payload.version, NULL);
316                 else {
317                         if (msg->payload.version->release)
318                                 free(msg->payload.version->release);
319                         if (msg->payload.version->os)
320                                 free(msg->payload.version->os);
321                         if (msg->payload.version->os_version)
322                                 free(msg->payload.version->os_version);
323                         free(msg->payload.version);
324                 }
325                 break;
326         case UDPTunnel:
327                 if (msg->unpacked)
328                         mumble_proto__udptunnel__free_unpacked(msg->payload.UDPTunnel, NULL);
329                 else {
330                         free(msg->payload.UDPTunnel->packet.data);
331                         free(msg->payload.UDPTunnel);
332                 }
333                 break;
334         case Authenticate:
335                 if (msg->unpacked)
336                         mumble_proto__authenticate__free_unpacked(msg->payload.authenticate, NULL);
337                 break;
338         case Ping:
339                 if (msg->unpacked)
340                         mumble_proto__ping__free_unpacked(msg->payload.ping, NULL);
341                 else {
342                         free(msg->payload.ping);
343                 }
344                 break;
345         case Reject:
346                 if (msg->unpacked)
347                         mumble_proto__reject__free_unpacked(msg->payload.reject, NULL);
348                 else {
349                         free(msg->payload.reject->reason);
350                         free(msg->payload.reject);
351                 }
352                 break;
353         case ServerSync:
354                 if (msg->unpacked)
355                         mumble_proto__server_sync__free_unpacked(msg->payload.serverSync, NULL);
356                 else {
357                         free(msg->payload.serverSync->welcome_text);
358                         free(msg->payload.serverSync);
359                 }
360                 break;
361         case TextMessage:
362                 if (msg->unpacked)
363                         mumble_proto__text_message__free_unpacked(msg->payload.textMessage, NULL);
364                 else {
365                         free(msg->payload.textMessage);
366                 }
367                 break;
368         case PermissionDenied:
369                 if (msg->unpacked)
370                         mumble_proto__permission_denied__free_unpacked(msg->payload.permissionDenied, NULL);
371                 else {
372                         free(msg->payload.permissionDenied->reason);
373                         free(msg->payload.permissionDenied);
374                 }
375                 break;
376         case CryptSetup:
377                 if (msg->unpacked)
378                         mumble_proto__crypt_setup__free_unpacked(msg->payload.cryptSetup, NULL);
379                 else {
380                         free(msg->payload.cryptSetup);
381                 }
382                 break;
383         case UserList:
384                 if (msg->unpacked)
385                         mumble_proto__user_list__free_unpacked(msg->payload.userList, NULL);
386                 else {
387                         free(msg->payload.userList);
388                 }
389                 break;
390         case UserState:
391                 if (msg->unpacked)
392                         mumble_proto__user_state__free_unpacked(msg->payload.userState, NULL);
393                 else {
394                         free(msg->payload.userState->name);
395                         free(msg->payload.userState);
396                 }
397                 break;
398         case UserRemove:
399                 if (msg->unpacked)
400                         mumble_proto__user_remove__free_unpacked(msg->payload.userRemove, NULL);
401                 else {
402                         free(msg->payload.userRemove);
403                 }
404                 break;
405         case VoiceTarget:
406                 if (msg->unpacked)
407                         mumble_proto__voice_target__free_unpacked(msg->payload.voiceTarget, NULL);
408                 else {
409                         free(msg->payload.voiceTarget);
410                 }
411                 break;
412         case CodecVersion:
413                 if (msg->unpacked)
414                         mumble_proto__codec_version__free_unpacked(msg->payload.codecVersion, NULL);
415                 else {
416                         free(msg->payload.codecVersion);
417                 }
418                 break;
419         case ChannelState:
420                 if (msg->unpacked)
421                         mumble_proto__channel_state__free_unpacked(msg->payload.channelState, NULL);
422                 else {
423                         if (msg->payload.channelState->description)
424                                 free(msg->payload.channelState->description);
425                         free(msg->payload.channelState->name);
426                         free(msg->payload.channelState);
427                 }
428                 break;
429         case PermissionQuery:
430                 if (msg->unpacked)
431                         mumble_proto__permission_query__free_unpacked(msg->payload.permissionQuery, NULL);
432                 else {
433                         free(msg->payload.permissionQuery);
434                 }
435                 break;
436
437         default:
438                 Log_warn("Msg_free: Unsupported message %d", msg->messageType);
439                 break;
440         }
441         free(msg);
442 }
443
444 void dumpmsg(uint8_t *data, int size)
445 {
446         int i, r = 0, offset = 0;
447         char buf[512];
448         
449         while (r * 8 + i < size) {
450                 for (i = 0; i < 8 && r * 8 + i < size; i++) {
451                         offset += sprintf(buf + offset, "%x ", data[r * 8 + i]);
452                 }
453                 sprintf(buf + offset, "\n");
454                 printf(buf);
455                 offset = 0;
456                 r++;
457                 i = 0;
458         } 
459 }
460
461 message_t *Msg_networkToMessage(uint8_t *data, int size)
462 {
463         message_t *msg = NULL;
464         uint8_t *msgData = &data[6];
465         int messageType, msgLen;
466
467         Msg_getPreamble(data, &messageType, &msgLen);
468
469         Log_debug("Message type %d size %d", messageType, msgLen);
470         dumpmsg(data, size);
471         
472         switch (messageType) {
473         case Version:
474         {
475                 msg = Msg_create(Version);
476                 msg->unpacked = true;
477                 msg->payload.version = mumble_proto__version__unpack(NULL, msgLen, msgData);
478                 break;
479         }
480         case UDPTunnel:
481         {
482                 msg = Msg_create(UDPTunnel);
483                 msg->unpacked = true;
484                 msg->payload.UDPTunnel = mumble_proto__udptunnel__unpack(NULL, msgLen, msgData);
485                 break;
486         }
487         case Authenticate:
488         {
489                 msg = Msg_create(Authenticate);
490                 msg->unpacked = true;
491                 msg->payload.authenticate = mumble_proto__authenticate__unpack(NULL, msgLen, msgData);
492                 break;
493         }
494         case Ping:
495         {
496                 msg = Msg_create(Ping);
497                 msg->unpacked = true;
498                 msg->payload.ping = mumble_proto__ping__unpack(NULL, msgLen, msgData);
499                 break;
500         }
501         case Reject:
502         {
503                 msg = Msg_create(Reject);
504                 msg->unpacked = true;
505                 msg->payload.reject = mumble_proto__reject__unpack(NULL, msgLen, msgData);
506                 break;
507         }
508         case ServerSync:
509         {
510                 msg = Msg_create(ServerSync);
511                 msg->unpacked = true;
512                 msg->payload.serverSync = mumble_proto__server_sync__unpack(NULL, msgLen, msgData);
513                 break;
514         }
515         case TextMessage:
516         {
517                 msg = Msg_create(TextMessage);
518                 msg->unpacked = true;
519                 msg->payload.textMessage = mumble_proto__text_message__unpack(NULL, msgLen, msgData);
520                 break;
521         }
522         case PermissionDenied:
523         {
524                 msg = Msg_create(PermissionDenied);
525                 msg->unpacked = true;
526                 msg->payload.permissionDenied = mumble_proto__permission_denied__unpack(NULL, msgLen, msgData);
527                 break;
528         }
529         case CryptSetup:
530         {
531                 msg = Msg_create(CryptSetup);
532                 msg->unpacked = true;
533                 msg->payload.cryptSetup = mumble_proto__crypt_setup__unpack(NULL, msgLen, msgData);
534                 break;
535         }
536         case UserList:
537         {
538                 msg = Msg_create(UserList);
539                 msg->unpacked = true;
540                 msg->payload.userList = mumble_proto__user_list__unpack(NULL, msgLen, msgData);
541                 break;
542         }
543         case UserState:
544         {
545                 msg = Msg_create(UserState);
546                 msg->unpacked = true;
547                 msg->payload.userState = mumble_proto__user_state__unpack(NULL, msgLen, msgData);
548                 break;
549         }
550         case VoiceTarget:
551         {
552                 msg = Msg_create(VoiceTarget);
553                 msg->unpacked = true;
554                 msg->payload.voiceTarget = mumble_proto__voice_target__unpack(NULL, msgLen, msgData);
555                 break;
556         }
557         case CodecVersion:
558         {
559                 msg = Msg_create(CodecVersion);
560                 msg->unpacked = true;
561                 msg->payload.codecVersion = mumble_proto__codec_version__unpack(NULL, msgLen, msgData);
562                 break;
563         }
564         case PermissionQuery:
565         {
566                 msg = Msg_create(PermissionQuery);
567                 msg->unpacked = true;
568                 msg->payload.permissionQuery = mumble_proto__permission_query__unpack(NULL, msgLen, msgData);
569                 break;
570         }
571
572         default:
573                 Log_warn("Unsupported message %d", messageType);
574                 break;
575         }
576         return msg;
577 }