1 //
2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
3 // Free Software Foundation, Inc
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19 #ifdef HAVE_CONFIG_H
20 #include "gnashconfig.h"
21 #endif
22
23 //#ifdef HAVE_DEJAGNU_H
24 #if 1
25 #include <sys/types.h>
26 extern "C"{
27 #include "GnashSystemIOHeaders.h"
28 #ifdef HAVE_GETOPT_H
29 #include <getopt.h>
30 #endif
31 #ifndef __GNUC__
32 extern int optind, getopt(int, char *const *, const char *);
33 #endif
34 }
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <fcntl.h>
38 #include <string>
39 #include <iostream>
40 #include <string>
41
42 #include "log.h"
43 #include "dejagnu.h"
44 #include "rtmp.h"
45 #include "amf.h"
46 #include "check.h"
47
48 using namespace amf;
49 using namespace gnash;
50 using namespace std;
51
52 static void usage (void);
53
54 static int verbosity;
55
56 TestState runtest;
57
58 // These are used to print more intelligent debug messages
59 const char *astype_str[] = {
60 "Number",
61 "Boolean",
62 "String",
63 "Object",
64 "MovieClip",
65 "Null",
66 "Undefined",
67 "Reference",
68 "ECMAArray",
69 "ObjectEnd",
70 "StrictArray",
71 "Date",
72 "LongString",
73 "Unsupported",
74 "Recordset",
75 "XMLObject",
76 "TypedObject"
77 };
78
79 int
main(int argc,char * argv[])80 main(int argc, char *argv[])
81 {
82
83 char buffer[300];
84 int c;
85
86 //gnash::LogFile& dbglogfile = gnash::LogFile::getDefaultInstance();
87 //dbglogfile.setVerbosity(1);
88
89 memset(buffer, 0, 300);
90
91 while ((c = getopt (argc, argv, "hdvsm:")) != -1) {
92 switch (c) {
93 case 'h':
94 usage ();
95 break;
96
97 case 'v':
98 verbosity++;
99 break;
100
101 default:
102 usage ();
103 break;
104 }
105 }
106
107 // get the file name from the command line
108 if (optind < argc) {
109 string filespec = argv[optind];
110 cout << "Will use \"" << filespec << "\" for test " << endl;
111 }
112
113 AMF amf_obj;
114 int fd, ret;
115 unsigned char buf[AMF_PACKET_SIZE+1];
116 unsigned char *tmpptr;
117 AMF::amf_element_t el;
118
119 // First see if we can read strings. This file is produced by
120 // using a network packet sniffer, and should be binary correct.
121 memset(buf, 0, AMF_PACKET_SIZE+1);
122 string filespec = SRCDIR;
123 filespec += "/connect-object.amf";
124
125 fd = open(filespec.c_str(), O_RDONLY);
126 ret = read(fd, buf, AMF_PACKET_SIZE);
127 close(fd);
128
129 amf_obj.parseHeader(buf);
130 if (amf_obj.getTotalSize() == 269) {
131 runtest.pass("Message Header Total Size");
132 } else {
133 runtest.fail("Message Header Total Size");
134 }
135
136 if (amf_obj.getHeaderSize() == 12) {
137 runtest.pass("Message Header Size");
138 } else {
139 runtest.fail("Message Header Size");
140 }
141
142 if (amf_obj.getMysteryWord() == 0) {
143 runtest.pass("Message Mystery Word");
144 } else {
145 runtest.fail("Message Mystery Word");
146 }
147
148 if (amf_obj.getRouting() == 0) {
149 runtest.pass("Message Routing");
150 } else {
151 runtest.fail("Message Routing");
152 }
153
154 // amf_obj.parseBody(buf + amf_obj.getHeaderSize(), amf_obj.getTotalSize());
155
156 // This extracts a "connect" message from the RTMP data stream. We
157 // look for everything ourselves to be the most accurate.
158 tmpptr = buf + amf_obj.getHeaderSize();
159 int8_t *str = amf_obj.extractString(tmpptr);
160 if (strcmp(reinterpret_cast<const char *>(str), "connect") == 0) {
161 runtest.pass("Extracted \"connect\" string");
162 } else {
163 runtest.fail("Extracted \"connect\" string");
164 }
165
166 tmpptr += strlen(reinterpret_cast<const char *>(str)) + AMF_HEADER_SIZE;
167 amfnum_t *num = amf_obj.extractNumber(tmpptr);
168 char *numptr = (char *)num;
169 if ((numptr[6] == -16)
170 && (numptr[7] == 0x3f)) {
171 runtest.pass("Extracted \"connect\" number");
172 } else {
173 runtest.fail("Extracted \"connect\" number");
174 }
175 tmpptr += AMF_NUMBER_SIZE + 2;
176
177 tmpptr = amf_obj.extractVariable(&el, tmpptr);
178 if (el.name == "app") {
179 runtest.pass("Extracted \"app\" variable");
180 } else {
181 runtest.fail("Extracted \"app\" variable");
182 }
183 // cerr << el.name << endl;
184
185 tmpptr = amf_obj.extractVariable(&el, tmpptr);
186 if (el.name == "flashVer") {
187 runtest.pass("Extracted \"flashVer\" variable");
188 } else {
189 runtest.fail("Extracted \"flashVer\" variable");
190 }
191 // cerr << el.name << endl;
192
193 tmpptr = amf_obj.extractVariable(&el, tmpptr);
194 if (el.name == "swfUrl") {
195 runtest.pass("Extracted \"swfUrl\" variable");
196 } else {
197 runtest.fail("Extracted \"swfUrl\" variable");
198 }
199 // cerr << el.name << endl;
200
201 tmpptr = amf_obj.extractVariable(&el, tmpptr);
202 if (el.name == "tcUrl") {
203 runtest.pass("Extracted \"tcUrl\" variable");
204 } else {
205 runtest.fail("Extracted \"tcUrl\" variable");
206 }
207 // cerr << el.name << endl;
208
209 tmpptr = amf_obj.extractVariable(&el, tmpptr);
210 if (el.name == "fpad") {
211 runtest.pass("Extracted \"fpad\" variable");
212 } else {
213 runtest.fail("Extracted \"fpad\" variable");
214 }
215 // cerr << el.name << endl;
216
217 tmpptr = amf_obj.extractVariable(&el, tmpptr);
218 if (el.name == "audioCodecs") {
219 runtest.pass("Extracted \"audioCodecs\" variable");
220 } else {
221 runtest.fail("Extracted \"audioCodecs\" variable");
222 }
223 // cerr << el.name << endl;
224
225 tmpptr = amf_obj.extractVariable(&el, tmpptr);
226 if (el.name == "videoCodecs") {
227 runtest.pass("Extracted \"videoCodecs\" variable");
228 } else {
229 runtest.fail("Extracted \"videoCodecs\" variable");
230 }
231 // cerr << el.name << endl;
232
233 tmpptr = amf_obj.extractVariable(&el, tmpptr);
234 if (el.name == "videoFunction") {
235 runtest.pass("Extracted \"videoFunction\" variable");
236 } else {
237 runtest.fail("Extracted \"videoFunction\" variable");
238 }
239 // cerr << el.name << endl;
240
241 tmpptr = amf_obj.extractVariable(&el, tmpptr);
242 if (el.name == "pageUrl") {
243 runtest.pass("Extracted \"pageURL\" variable");
244 } else {
245 runtest.fail("Extracted \"pageURL\" variable");
246 }
247 // cerr << el.name << endl;
248
249 amf_obj.extractVariable(&el, tmpptr);
250 if (el.name == "objectEncoding") {
251 runtest.pass("Extracted \"objectEncoding\" variable");
252 } else {
253 runtest.fail("Extracted \"objectEncoding\" variable");
254 }
255 // cerr << el.name << endl;
256
257 // Now build our own connect message with the same data, which
258 // should give us an exact copy.
259 int amf_index = amf_obj.getAMFIndex();
260 AMF::amf_headersize_e head_size = AMF::HEADER_12;
261 int total_size = amf_obj.getTotalSize();
262 AMF::content_types_e type = AMF::INVOKE;
263 amfsource_e routing = amf_obj.getRouting();
264 AMF rtmp;
265
266 // First build and test the header. This uses the same data as the
267 // previous one
268 unsigned char *out = reinterpret_cast<unsigned char *>(rtmp.encodeRTMPHeader(amf_index, head_size, total_size, type, routing));
269 tmpptr = out;
270 rtmp.parseHeader(out);
271 if (rtmp.getTotalSize() == 269) {
272 runtest.pass("New Message Header Total Size");
273 } else {
274 runtest.fail("New Message Header Total Size");
275 }
276
277 if (rtmp.getHeaderSize() == 12) {
278 runtest.pass("New Message Header Size");
279 } else {
280 runtest.fail("New Message Header Size");
281 }
282
283 if (rtmp.getMysteryWord() == 0) {
284 runtest.pass("New Message Mystery Word");
285 } else {
286 runtest.fail("Message Mystery Word");
287 }
288
289 if (rtmp.getRouting() == CLIENT) {
290 runtest.pass("New Message Routing");
291 } else {
292 runtest.fail("New Message Routing");
293 }
294
295 check_equals(rtmp.getHeaderSize(), 12);
296
297 if (memcmp(out, buf, 12) == 0) {
298 runtest.pass("RTMP Headers match");
299 } else {
300 size_t s = 12;
301 runtest.fail("RTMP Headers mismatch");
302 cerr << "buf is: 0x" << hexify(buf, s, true) << endl;
303 cerr << "out is: 0x" << hexify(out, s, true) << endl;
304 }
305
306 tmpptr += rtmp.getHeaderSize();
307
308 // Now build up a body of a connect message
309 unsigned char *var;
310
311 var = (unsigned char *)rtmp.encodeString("connect");
312 int8_t *c_out = rtmp.extractString(var);
313 if ( ! c_out )
314 {
315 runtest.fail("Encoded \"connect\" string could not be extracted");
316 }
317 else
318 {
319 std::string s_in("connect");
320 std::string s_out(reinterpret_cast<const char *>(c_out));
321
322 if (s_in == s_out) {
323 runtest.pass("Encoded \"connect\" string");
324 } else {
325 runtest.fail("Encoded \"connect\" string");
326 cerr << "Encoded 'connect' returned as as" << s_out << endl;
327 }
328 }
329 tmpptr = rtmp.appendPtr(tmpptr, var, strlen("connect") + 3);
330 delete [] var;
331
332 amfnum_t bignum = 0x3ff0000000000000LL;
333 numptr = (char *)&bignum;
334 var = (unsigned char *)rtmp.encodeNumber(bignum);
335 if (*rtmp.extractNumber(var) == bignum) {
336 runtest.pass("Encoded \"connect\" number");
337 } else {
338 runtest.fail("Encoded \"connect\" number");
339 }
340
341 tmpptr = rtmp.appendPtr(tmpptr, var, AMF_NUMBER_SIZE + 1);
342 delete [] var;
343
344 // Start the object
345 *tmpptr++ = AMF::OBJECT;
346
347 var = (unsigned char *)rtmp.encodeVariable("app", "oflaDemo");
348 rtmp.extractVariable(&el, var);
349 if ((el.name == "app") && (strncmp((char *)el.data, "oflaDemo", 8) == 0)) {
350 runtest.pass("Encoded \"app\" variable");
351 } else {
352 runtest.fail("Encoded \"app\" variable");
353 }
354 tmpptr = rtmp.appendPtr(tmpptr, var, el.length + strlen("app") + 5);
355 delete [] var;
356
357 var = (unsigned char *)rtmp.encodeVariable("flashVer", "LNX 9,0,31,0");
358 rtmp.extractVariable(&el, var);
359 if ((el.name == "flashVer") && (strncmp((char *)el.data, "LNX 9,0,31,0", el.length) == 0)) {
360 runtest.pass("Encoded \"flashVer\" variable");
361 } else {
362 runtest.fail("Encoded \"flashVer\" variable");
363 }
364 tmpptr = rtmp.appendPtr(tmpptr, var, el.length + strlen("flashVer") + 5);
365 delete [] var;
366
367 var = (unsigned char *)rtmp.encodeVariable("swfUrl", "http://www.red5.nl/tools/publisher/publisher.swf");
368 rtmp.extractVariable(&el, var);
369 if ((el.name == "swfUrl") && (strncmp((char *)el.data, "http://www.red5.nl/tools/publisher/publisher.swf", el.length) == 0)) {
370 runtest.pass("Encoded \"swfUrl\" variable");
371 } else {
372 runtest.fail("Encoded \"swfUrl\" variable");
373 }
374 tmpptr = rtmp.appendPtr(tmpptr, var, el.length + strlen("swfUrl") + 5);
375 delete [] var;
376
377 var = (unsigned char *)rtmp.encodeVariable("tcUrl", "rtmp://localhost/oflaDemo");
378 rtmp.extractVariable(&el, var);
379 if ((el.name == "tcUrl") && (strncmp((char *)el.data, "rtmp://localhost/oflaDemo", 25) == 0)) {
380 runtest.pass("Encoded \"tcUrl\" variable");
381 } else {
382 runtest.fail("Encoded \"tcUrl\" variable");
383 }
384 tmpptr = rtmp.appendPtr(tmpptr, var, el.length + strlen("tcUrl") + 5);
385 delete [] var;
386
387 var = (unsigned char *)rtmp.encodeVariable("fpad", false);
388 rtmp.extractVariable(&el, var);
389 if ((el.name == "fpad") && (*el.data == 0)) {
390 runtest.pass("Encoded \"fpad\" Boolean variable");
391 } else {
392 runtest.fail("Encoded \"fpad\" Boolean variable");
393 }
394 tmpptr = rtmp.appendPtr(tmpptr, var, 1 + strlen("fpad") + 3);
395 delete [] var;
396
397 bignum = 0x388340LL;
398 numptr = (char *)&bignum;
399 var = (unsigned char *)rtmp.encodeVariable("audioCodecs", bignum);
400 rtmp.extractVariable(&el, var);
401
402 if ((el.type == amf::AMF::NUMBER)
403 && (el.name == "audioCodecs")
404 && (el.data[5] == 0x38)
405 && (el.data[6] == 0x83)
406 && (el.data[7] == 0x40)) {
407 runtest.pass("Encoded \"audioCodecs\" variable");
408 } else {
409 runtest.fail("Encoded \"audioCodecs\" variable");
410 }
411 tmpptr = rtmp.appendPtr(tmpptr, var, el.name.size() + AMF_NUMBER_SIZE + 3);
412 delete [] var;
413
414 bignum = 0x5f40LL;
415 numptr = (char *)&bignum;
416 var = (unsigned char *)rtmp.encodeVariable("videoCodecs", bignum);
417 rtmp.extractVariable(&el, var);
418
419 if ((el.type == amf::AMF::NUMBER)
420 && (el.name == "videoCodecs")
421 && (el.data[6] == 0x5f)
422 && (el.data[7] == 0x40)) {
423 runtest.pass("Encoded \"videoCodecs\" variable");
424 } else {
425 runtest.fail("Encoded \"videoCodecs\" variable");
426 }
427 tmpptr = rtmp.appendPtr(tmpptr, var, el.name.size() + AMF_NUMBER_SIZE + 3);
428 delete [] var;
429
430 bignum = 0xf03fLL;
431 numptr = (char *)&bignum;
432 var = (unsigned char *)rtmp.encodeVariable("videoFunction", bignum);
433 rtmp.extractVariable(&el, var);
434
435 if ((el.type == amf::AMF::NUMBER)
436 && (el.name == "videoFunction")
437 && (el.data[6] == 0xf0)
438 && (el.data[7] == 0x3f)) {
439 runtest.pass("Encoded \"videoFunction\" variable");
440 } else {
441 runtest.fail("Encoded \"videoFunction\" variable");
442 }
443 tmpptr = rtmp.appendPtr(tmpptr, var, el.name.size() + AMF_NUMBER_SIZE + 3);
444 delete [] var;
445
446 var = (unsigned char *)rtmp.encodeVariable("pageUrl");
447 rtmp.extractVariable(&el, var);
448 if ((el.type == amf::AMF::UNDEFINED)
449 && (el.name == "pageUrl")) {
450 runtest.pass("Encoded \"pageUrl\" undefined variable");
451 } else {
452 runtest.fail("Encoded \"pageUrl\" undefined variable");
453 }
454 tmpptr = rtmp.appendPtr(tmpptr, var, el.name.size() + 3);
455 delete [] var;
456
457 bignum = 0x0;
458 numptr = (char *)&bignum;
459 var = (unsigned char *)rtmp.encodeVariable("objectEncoding", bignum);
460 rtmp.extractVariable(&el, var);
461
462 if ((el.type == amf::AMF::NUMBER)
463 && (el.name == "objectEncoding")
464 && (el.data[6] == 0x0)
465 && (el.data[7] == 0x0)) {
466 runtest.pass("Encoded \"objectEncoding\" variable");
467 } else {
468 runtest.fail("Encoded \"objectEncoding\" variable");
469 }
470 tmpptr = rtmp.appendPtr(tmpptr, var, el.name.size() + AMF_NUMBER_SIZE + 3);
471 delete [] var;
472
473 // Start the object
474 *tmpptr++ = AMF::OBJECT_END;
475
476 if (memcmp(buf, out, amf_obj.getTotalSize()) == 0) {
477 runtest.pass("Object Packets match");
478 } else {
479 runtest.fail("Object Packets mismatch");
480 }
481
482 size_t hexsize = std::max(AMF_PACKET_SIZE, amf_obj.getTotalSize())*2;
483 cerr << "buf is: 0x" << hexify(buf, amf_obj.getTotalSize() + 10, true) << ", size is: " << amf_obj.getTotalSize() << endl;
484 cerr << "out is: 0x" << hexify(out, rmtp.getTotalSize() + 10, true) << ", size is: " << rtmp.getTotalSize() << endl;
485
486 // delete out;
487 }
488
489 static void
usage(void)490 usage (void)
491 {
492 cerr << "This program tests Shared Object support in the AMF library." << endl;
493 cerr << "Usage: test_object [hv]" << endl;
494 cerr << "-h\tHelp" << endl;
495 cerr << "-v\tVerbose" << endl;
496 exit (-1);
497 }
498
499 #else
500
501 int
main(int,char)502 main(int /*argc*/, char /* *argv[]*/)
503 {
504 // nop
505 return 0;
506 }
507 #endif
508