blob: de3510816c5239879eb0d54460460cb7a7addb03 [file] [log] [blame]
James Kuszmaul82f6c042021-01-17 11:30:16 -08001/**
2 * @file rtmp/amf_dec.c Real Time Messaging Protocol (RTMP) -- AMF Decoding
3 *
4 * Copyright (C) 2010 Creytiv.com
5 */
6#include <string.h>
7#include <re_types.h>
8#include <re_fmt.h>
9#include <re_mem.h>
10#include <re_mbuf.h>
11#include <re_net.h>
12#include <re_sa.h>
13#include <re_list.h>
14#include <re_sys.h>
15#include <re_odict.h>
16#include <re_rtmp.h>
17#include "rtmp.h"
18
19
20enum {
21 AMF_HASH_SIZE = 32
22};
23
24
25static int amf_decode_value(struct odict *dict, const char *key,
26 struct mbuf *mb);
27
28
29static int amf_decode_object(struct odict *dict, struct mbuf *mb)
30{
31 char *key = NULL;
32 uint16_t len;
33 int err = 0;
34
35 while (mbuf_get_left(mb) > 0) {
36
37 if (mbuf_get_left(mb) < 2)
38 return ENODATA;
39
40 len = ntohs(mbuf_read_u16(mb));
41
42 if (len == 0) {
43 uint8_t val;
44
45 if (mbuf_get_left(mb) < 1)
46 return ENODATA;
47
48 val = mbuf_read_u8(mb);
49
50 if (val == RTMP_AMF_TYPE_OBJECT_END)
51 return 0;
52 else
53 return EBADMSG;
54 }
55
56 if (mbuf_get_left(mb) < len)
57 return ENODATA;
58
59 err = mbuf_strdup(mb, &key, len);
60 if (err)
61 return err;
62
63 err = amf_decode_value(dict, key, mb);
64
65 key = mem_deref(key);
66
67 if (err)
68 return err;
69 }
70
71 return 0;
72}
73
74
75static int amf_decode_value(struct odict *dict, const char *key,
76 struct mbuf *mb)
77{
78 union {
79 uint64_t i;
80 double f;
81 } num;
82 struct odict *object = NULL;
83 char *str = NULL;
84 uint32_t i, array_len;
85 uint8_t type;
86 uint16_t len;
87 bool boolean;
88 int err = 0;
89
90 if (mbuf_get_left(mb) < 1)
91 return ENODATA;
92
93 type = mbuf_read_u8(mb);
94
95 switch (type) {
96
97 case RTMP_AMF_TYPE_NUMBER:
98 if (mbuf_get_left(mb) < 8)
99 return ENODATA;
100
101 num.i = sys_ntohll(mbuf_read_u64(mb));
102
103 err = odict_entry_add(dict, key, ODICT_DOUBLE, num.f);
104 break;
105
106 case RTMP_AMF_TYPE_BOOLEAN:
107 if (mbuf_get_left(mb) < 1)
108 return ENODATA;
109
110 boolean = !!mbuf_read_u8(mb);
111
112 err = odict_entry_add(dict, key, ODICT_BOOL, boolean);
113 break;
114
115 case RTMP_AMF_TYPE_STRING:
116 if (mbuf_get_left(mb) < 2)
117 return ENODATA;
118
119 len = ntohs(mbuf_read_u16(mb));
120
121 if (mbuf_get_left(mb) < len)
122 return ENODATA;
123
124 err = mbuf_strdup(mb, &str, len);
125 if (err)
126 return err;
127
128 err = odict_entry_add(dict, key, ODICT_STRING, str);
129
130 mem_deref(str);
131 break;
132
133 case RTMP_AMF_TYPE_NULL:
134 err = odict_entry_add(dict, key, ODICT_NULL);
135 break;
136
137 case RTMP_AMF_TYPE_ECMA_ARRAY:
138 if (mbuf_get_left(mb) < 4)
139 return ENODATA;
140
141 array_len = ntohl(mbuf_read_u32(mb));
142
143 (void)array_len; /* ignore array length */
144
145 /* fallthrough */
146
147 case RTMP_AMF_TYPE_OBJECT:
148 err = odict_alloc(&object, 32);
149 if (err)
150 return err;
151
152 err = amf_decode_object(object, mb);
153 if (err) {
154 mem_deref(object);
155 return err;
156 }
157
158 err = odict_entry_add(dict, key, ODICT_OBJECT, object);
159
160 mem_deref(object);
161 break;
162
163 case RTMP_AMF_TYPE_STRICT_ARRAY:
164 if (mbuf_get_left(mb) < 4)
165 return ENODATA;
166
167 array_len = ntohl(mbuf_read_u32(mb));
168 if (!array_len)
169 return EPROTO;
170
171 err = odict_alloc(&object, 32);
172 if (err)
173 return err;
174
175 for (i=0; i<array_len; i++) {
176
177 char ix[32];
178
179 re_snprintf(ix, sizeof(ix), "%u", i);
180
181 err = amf_decode_value(object, ix, mb);
182 if (err) {
183 mem_deref(object);
184 return err;
185 }
186 }
187
188 err = odict_entry_add(dict, key, ODICT_ARRAY, object);
189
190 mem_deref(object);
191 break;
192
193 default:
194 err = EPROTO;
195 break;
196 }
197
198 return err;
199}
200
201
202int rtmp_amf_decode(struct odict **msgp, struct mbuf *mb)
203{
204 struct odict *msg;
205 unsigned ix = 0;
206 int err;
207
208 if (!msgp || !mb)
209 return EINVAL;
210
211 err = odict_alloc(&msg, AMF_HASH_SIZE);
212 if (err)
213 return err;
214
215 /* decode all entries on root-level */
216 while (mbuf_get_left(mb) > 0) {
217
218 char key[16];
219
220 re_snprintf(key, sizeof(key), "%u", ix++);
221
222 /* note: key is the numerical index */
223 err = amf_decode_value(msg, key, mb);
224 if (err)
225 goto out;
226 }
227
228 out:
229 if (err)
230 mem_deref(msg);
231 else
232 *msgp = msg;
233
234 return err;
235}