Fix confusion regarding message creation from net and later freeing.
[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 static message_t *Msg_create_nopayload(messageType_t messageType);
45
46 void Msg_addPreamble(uint8_t *buffer, uint16_t type, uint32_t len)
47 {
48         uint16_t *msgType = (uint16_t *) &buffer[0];
49         uint32_t *msgLen = (uint32_t *) &buffer[2];
50         
51         *msgType = htons(type);
52         *msgLen = htonl(len);
53 }
54
55 static void Msg_getPreamble(uint8_t *buffer, int *type, int *len)
56 {
57         uint16_t *msgType = (uint16_t *) &buffer[0];
58         uint32_t *msgLen = (uint32_t *) &buffer[2];
59         
60         *type = (int)ntohs(*msgType);
61         *len = (int)ntohl(*msgLen);
62 }
63
64 #define MAX_MSGSIZE (BUFSIZE - 6)
65 int Msg_messageToNetwork(message_t *msg, uint8_t *buffer)
66 {
67         int len;
68         uint8_t *bufptr = buffer + 6;
69                 
70         Log_debug("To net: msg type %d", msg->messageType);
71         switch (msg->messageType) {
72         case Version:
73                 len = mumble_proto__version__get_packed_size(msg->payload.version);
74                 if (len > MAX_MSGSIZE) {
75                         Log_warn("Too big tx message. Discarding");
76                         break;
77                 }
78                 Msg_addPreamble(buffer, msg->messageType, len);
79                 Log_debug("To net: Version->release: %s Version->os: %s",
80                                   msg->payload.version->release, msg->payload.version->os);
81                 mumble_proto__version__pack(msg->payload.version, bufptr);
82                 break;
83         case UDPTunnel: /* Non-standard handling of tunneled voice traffic. */
84                 if (msg->payload.UDPTunnel->packet.len > MAX_MSGSIZE) {
85                         Log_warn("Too big tx message. Discarding");
86                         break;
87                 }
88                 Msg_addPreamble(buffer, msg->messageType, msg->payload.UDPTunnel->packet.len);
89                 memcpy(bufptr, msg->payload.UDPTunnel->packet.data, msg->payload.UDPTunnel->packet.len);
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_nopayload(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         return msg;
227 }
228
229 message_t *Msg_create(messageType_t messageType)
230 {
231         message_t *msg = Msg_create_nopayload(messageType);
232         
233         switch (messageType) {
234         case Version:
235                 msg->payload.version = malloc(sizeof(MumbleProto__Version));
236                 mumble_proto__version__init(msg->payload.version);
237                 break;
238         case UDPTunnel:
239                 msg->payload.UDPTunnel = malloc(sizeof(MumbleProto__UDPTunnel));
240                 mumble_proto__udptunnel__init(msg->payload.UDPTunnel);
241                 break;
242         case Authenticate:
243                 msg->payload.authenticate = malloc(sizeof(MumbleProto__Authenticate));
244                 mumble_proto__authenticate__init(msg->payload.authenticate);
245                 break;
246         case Ping:
247                 msg->payload.ping = malloc(sizeof(MumbleProto__Ping));
248                 mumble_proto__ping__init(msg->payload.ping);
249                 break;
250         case Reject:
251                 msg->payload.reject = malloc(sizeof(MumbleProto__Reject));
252                 mumble_proto__reject__init(msg->payload.reject);
253                 break;
254         case ServerSync:
255                 msg->payload.serverSync = malloc(sizeof(MumbleProto__ServerSync));
256                 mumble_proto__server_sync__init(msg->payload.serverSync);
257                 break;
258         case TextMessage:
259                 msg->payload.textMessage = malloc(sizeof(MumbleProto__TextMessage));
260                 mumble_proto__text_message__init(msg->payload.textMessage);
261                 break;
262         case PermissionDenied:
263                 msg->payload.permissionDenied = malloc(sizeof(MumbleProto__PermissionDenied));
264                 mumble_proto__permission_denied__init(msg->payload.permissionDenied);
265                 break;
266         case CryptSetup:
267                 msg->payload.cryptSetup = malloc(sizeof(MumbleProto__CryptSetup));
268                 mumble_proto__crypt_setup__init(msg->payload.cryptSetup);
269                 break;
270         case UserList:
271                 msg->payload.userList = malloc(sizeof(MumbleProto__UserList));
272                 mumble_proto__user_list__init(msg->payload.userList);
273                 break;
274         case UserState:
275                 msg->payload.userState = malloc(sizeof(MumbleProto__UserState));
276                 mumble_proto__user_state__init(msg->payload.userState);
277                 break;
278         case UserRemove:
279                 msg->payload.userRemove = malloc(sizeof(MumbleProto__UserRemove));
280                 mumble_proto__user_remove__init(msg->payload.userRemove);
281                 break;
282         case VoiceTarget:
283                 msg->payload.voiceTarget = malloc(sizeof(MumbleProto__VoiceTarget));
284                 mumble_proto__voice_target__init(msg->payload.voiceTarget);
285                 break;
286         case CodecVersion:
287                 msg->payload.codecVersion = malloc(sizeof(MumbleProto__CodecVersion));
288                 mumble_proto__codec_version__init(msg->payload.codecVersion);
289                 break;
290         case ChannelState:
291                 msg->payload.channelState = malloc(sizeof(MumbleProto__ChannelState));
292                 mumble_proto__channel_state__init(msg->payload.channelState);
293                 break;
294         case PermissionQuery:
295                 msg->payload.permissionQuery = malloc(sizeof(MumbleProto__PermissionQuery));
296                 mumble_proto__permission_query__init(msg->payload.permissionQuery);
297                 break;
298
299         default:
300                 Log_warn("Msg_create: Unsupported message %d", msg->messageType);
301                 break;
302         }
303
304         return msg;
305 }
306
307 void Msg_inc_ref(message_t *msg)
308 {
309         msg->refcount++;
310 }
311
312 void Msg_free(message_t *msg)
313 {
314         if (msg->refcount) msg->refcount--;
315         if (msg->refcount > 0)
316                 return;
317
318         switch (msg->messageType) {
319         case Version:
320                 if (msg->unpacked)
321                         mumble_proto__version__free_unpacked(msg->payload.version, NULL);
322                 else {
323                         if (msg->payload.version->release)
324                                 free(msg->payload.version->release);
325                         if (msg->payload.version->os)
326                                 free(msg->payload.version->os);
327                         if (msg->payload.version->os_version)
328                                 free(msg->payload.version->os_version);
329                         free(msg->payload.version);
330                 }
331                 break;
332         case UDPTunnel:
333                 if (msg->unpacked)
334                         mumble_proto__udptunnel__free_unpacked(msg->payload.UDPTunnel, NULL);
335                 else {
336                         free(msg->payload.UDPTunnel->packet.data);
337                         free(msg->payload.UDPTunnel);
338                 }
339                 break;
340         case Authenticate:
341                 if (msg->unpacked)
342                         mumble_proto__authenticate__free_unpacked(msg->payload.authenticate, NULL);
343                 else
344                         free(msg->payload.authenticate);
345                 break;
346         case Ping:
347                 if (msg->unpacked)
348                         mumble_proto__ping__free_unpacked(msg->payload.ping, NULL);
349                 else {
350                         free(msg->payload.ping);
351                 }
352                 break;
353         case Reject:
354                 if (msg->unpacked)
355                         mumble_proto__reject__free_unpacked(msg->payload.reject, NULL);
356                 else {
357                         free(msg->payload.reject->reason);
358                         free(msg->payload.reject);
359                 }
360                 break;
361         case ServerSync:
362                 if (msg->unpacked)
363                         mumble_proto__server_sync__free_unpacked(msg->payload.serverSync, NULL);
364                 else {
365                         free(msg->payload.serverSync->welcome_text);
366                         free(msg->payload.serverSync);
367                 }
368                 break;
369         case TextMessage:
370                 if (msg->unpacked)
371                         mumble_proto__text_message__free_unpacked(msg->payload.textMessage, NULL);
372                 else {
373                         free(msg->payload.textMessage);
374                 }
375                 break;
376         case PermissionDenied:
377                 if (msg->unpacked)
378                         mumble_proto__permission_denied__free_unpacked(msg->payload.permissionDenied, NULL);
379                 else {
380                         free(msg->payload.permissionDenied->reason);
381                         free(msg->payload.permissionDenied);
382                 }
383                 break;
384         case CryptSetup:
385                 if (msg->unpacked)
386                         mumble_proto__crypt_setup__free_unpacked(msg->payload.cryptSetup, NULL);
387                 else {
388                         free(msg->payload.cryptSetup);
389                 }
390                 break;
391         case UserList:
392                 if (msg->unpacked)
393                         mumble_proto__user_list__free_unpacked(msg->payload.userList, NULL);
394                 else {
395                         free(msg->payload.userList);
396                 }
397                 break;
398         case UserState:
399                 if (msg->unpacked)
400                         mumble_proto__user_state__free_unpacked(msg->payload.userState, NULL);
401                 else {
402                         free(msg->payload.userState->name);
403                         free(msg->payload.userState);
404                 }
405                 break;
406         case UserRemove:
407                 if (msg->unpacked)
408                         mumble_proto__user_remove__free_unpacked(msg->payload.userRemove, NULL);
409                 else {
410                         free(msg->payload.userRemove);
411                 }
412                 break;
413         case VoiceTarget:
414                 if (msg->unpacked)
415                         mumble_proto__voice_target__free_unpacked(msg->payload.voiceTarget, NULL);
416                 else {
417                         free(msg->payload.voiceTarget);
418                 }
419                 break;
420         case CodecVersion:
421                 if (msg->unpacked)
422                         mumble_proto__codec_version__free_unpacked(msg->payload.codecVersion, NULL);
423                 else {
424                         free(msg->payload.codecVersion);
425                 }
426                 break;
427         case ChannelState:
428                 if (msg->unpacked)
429                         mumble_proto__channel_state__free_unpacked(msg->payload.channelState, NULL);
430                 else {
431                         if (msg->payload.channelState->description)
432                                 free(msg->payload.channelState->description);
433                         free(msg->payload.channelState->name);
434                         free(msg->payload.channelState);
435                 }
436                 break;
437         case PermissionQuery:
438                 if (msg->unpacked)
439                         mumble_proto__permission_query__free_unpacked(msg->payload.permissionQuery, NULL);
440                 else {
441                         free(msg->payload.permissionQuery);
442                 }
443                 break;
444
445         default:
446                 Log_warn("Msg_free: Unsupported message %d", msg->messageType);
447                 break;
448         }
449         free(msg);
450 }
451
452 void dumpmsg(uint8_t *data, int size)
453 {
454         int i, r = 0, offset = 0;
455         char buf[512];
456         
457         while (r * 8 + i < size) {
458                 for (i = 0; i < 8 && r * 8 + i < size; i++) {
459                         offset += sprintf(buf + offset, "%x ", data[r * 8 + i]);
460                 }
461                 sprintf(buf + offset, "\n");
462                 printf(buf);
463                 offset = 0;
464                 r++;
465                 i = 0;
466         } 
467 }
468
469 message_t *Msg_networkToMessage(uint8_t *data, int size)
470 {
471         message_t *msg = NULL;
472         uint8_t *msgData = &data[6];
473         int messageType, msgLen;
474
475         Msg_getPreamble(data, &messageType, &msgLen);
476
477         Log_debug("Message type %d size %d", messageType, msgLen);
478         //dumpmsg(data, size);
479         
480         switch (messageType) {
481         case Version:
482         {
483                 msg = Msg_create_nopayload(Version);
484                 msg->unpacked = true;
485                 msg->payload.version = mumble_proto__version__unpack(NULL, msgLen, msgData);
486                 break;
487         }
488         case UDPTunnel: /* Non-standard handling of tunneled voice data */
489         {
490                 msg = Msg_create_nopayload(UDPTunnel);
491                 msg->unpacked = false;
492                 msg->payload.UDPTunnel = malloc(sizeof(struct _MumbleProto__UDPTunnel));
493                 if (msg->payload.UDPTunnel == NULL)
494                         Log_fatal("Out of memory");
495                 msg->payload.UDPTunnel->packet.data = malloc(msgLen);
496                 if (msg->payload.UDPTunnel->packet.data == NULL)
497                         Log_fatal("Out of memory");
498                 memcpy(msg->payload.UDPTunnel->packet.data, msgData, msgLen);
499                 msg->payload.UDPTunnel->packet.len = msgLen;
500                 break;
501         }
502         case Authenticate:
503         {
504                 msg = Msg_create_nopayload(Authenticate);
505                 msg->unpacked = true;
506                 msg->payload.authenticate = mumble_proto__authenticate__unpack(NULL, msgLen, msgData);
507                 break;
508         }
509         case Ping:
510         {
511                 msg = Msg_create_nopayload(Ping);
512                 msg->unpacked = true;
513                 msg->payload.ping = mumble_proto__ping__unpack(NULL, msgLen, msgData);
514                 break;
515         }
516         case Reject:
517         {
518                 msg = Msg_create_nopayload(Reject);
519                 msg->unpacked = true;
520                 msg->payload.reject = mumble_proto__reject__unpack(NULL, msgLen, msgData);
521                 break;
522         }
523         case ServerSync:
524         {
525                 msg = Msg_create_nopayload(ServerSync);
526                 msg->unpacked = true;
527                 msg->payload.serverSync = mumble_proto__server_sync__unpack(NULL, msgLen, msgData);
528                 break;
529         }
530         case TextMessage:
531         {
532                 msg = Msg_create_nopayload(TextMessage);
533                 msg->unpacked = true;
534                 msg->payload.textMessage = mumble_proto__text_message__unpack(NULL, msgLen, msgData);
535                 break;
536         }
537         case PermissionDenied:
538         {
539                 msg = Msg_create_nopayload(PermissionDenied);
540                 msg->unpacked = true;
541                 msg->payload.permissionDenied = mumble_proto__permission_denied__unpack(NULL, msgLen, msgData);
542                 break;
543         }
544         case CryptSetup:
545         {
546                 msg = Msg_create_nopayload(CryptSetup);
547                 msg->unpacked = true;
548                 msg->payload.cryptSetup = mumble_proto__crypt_setup__unpack(NULL, msgLen, msgData);
549                 break;
550         }
551         case UserList:
552         {
553                 msg = Msg_create_nopayload(UserList);
554                 msg->unpacked = true;
555                 msg->payload.userList = mumble_proto__user_list__unpack(NULL, msgLen, msgData);
556                 break;
557         }
558         case UserState:
559         {
560                 msg = Msg_create_nopayload(UserState);
561                 msg->unpacked = true;
562                 msg->payload.userState = mumble_proto__user_state__unpack(NULL, msgLen, msgData);
563                 break;
564         }
565         case VoiceTarget:
566         {
567                 msg = Msg_create_nopayload(VoiceTarget);
568                 msg->unpacked = true;
569                 msg->payload.voiceTarget = mumble_proto__voice_target__unpack(NULL, msgLen, msgData);
570                 break;
571         }
572         case CodecVersion:
573         {
574                 msg = Msg_create_nopayload(CodecVersion);
575                 msg->unpacked = true;
576                 msg->payload.codecVersion = mumble_proto__codec_version__unpack(NULL, msgLen, msgData);
577                 break;
578         }
579         case PermissionQuery:
580         {
581                 msg = Msg_create_nopayload(PermissionQuery);
582                 msg->unpacked = true;
583                 msg->payload.permissionQuery = mumble_proto__permission_query__unpack(NULL, msgLen, msgData);
584                 break;
585         }
586
587         default:
588                 Log_warn("Unsupported message %d", messageType);
589                 break;
590         }
591         return msg;
592 }