diff --git a/cunit/CMakeLists.txt b/cunit/CMakeLists.txt index 769199cea..ef3f0e25b 100644 --- a/cunit/CMakeLists.txt +++ b/cunit/CMakeLists.txt @@ -27,6 +27,8 @@ add_executable(test_freerdp test_per.h test_ber.c test_ber.h + test_gcc.c + test_gcc.h test_color.c test_color.h test_libgdi.c diff --git a/cunit/test_freerdp.c b/cunit/test_freerdp.c index 0e22a013b..cf974aed6 100644 --- a/cunit/test_freerdp.c +++ b/cunit/test_freerdp.c @@ -21,6 +21,7 @@ #include "test_per.h" #include "test_ber.h" +#include "test_gcc.h" #include "test_color.h" #include "test_libgdi.h" #include "test_stream.h" @@ -60,16 +61,23 @@ void assert_stream(STREAM* s, uint8* data, int length, const char* func, int lin int actual_length; uint8* actual_data; + actual_data = s->buffer; actual_length = stream_get_length(s); if (actual_length != length) { - printf("\n %s (%d): length mismatch, actual:%d, expected:%d", func, line, actual_length, length); + printf("\n %s (%d): length mismatch, actual:%d, expected:%d\n", func, line, actual_length, length); + + printf("\nActual:\n"); + freerdp_hexdump(actual_data, actual_length); + + printf("Expected:\n"); + freerdp_hexdump(data, length); + CU_FAIL("assert_stream, length mismatch"); return; } - actual_data = s->buffer; for (i = 0; i < length; i++) { if (actual_data[i] != data[i]) @@ -133,6 +141,10 @@ int main(int argc, char* argv[]) { add_ber_suite(); } + else if (strcmp("gcc", argv[*pindex]) == 0) + { + add_gcc_suite(); + } *pindex = *pindex + 1; } diff --git a/cunit/test_gcc.c b/cunit/test_gcc.c new file mode 100644 index 000000000..5d2cad0dd --- /dev/null +++ b/cunit/test_gcc.c @@ -0,0 +1,102 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * T.124 Generic Conference Control (GCC) Unit Tests + * + * Copyright 2011 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "gcc.h" + +#include +#include +#include + +#include "test_gcc.h" + +int init_gcc_suite(void) +{ + return 0; +} + +int clean_gcc_suite(void) +{ + return 0; +} + +int add_gcc_suite(void) +{ + add_test_suite(gcc); + + add_test_function(gcc_write_create_conference_request); + + return 0; +} + +uint8 gcc_user_data[284] = + "\x01\xc0\xd8\x00\x04\x00\x08\x00\x00\x05\x00\x04\x01\xCA\x03\xAA" + "\x09\x04\x00\x00\xCE\x0E\x00\x00\x45\x00\x4c\x00\x54\x00\x4f\x00" + "\x4e\x00\x53\x00\x2d\x00\x44\x00\x45\x00\x56\x00\x32\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00" + "\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x01\xCA\x01\x00\x00\x00\x00\x00\x18\x00\x07\x00" + "\x01\x00\x36\x00\x39\x00\x37\x00\x31\x00\x32\x00\x2d\x00\x37\x00" + "\x38\x00\x33\x00\x2d\x00\x30\x00\x33\x00\x35\x00\x37\x00\x39\x00" + "\x37\x00\x34\x00\x2d\x00\x34\x00\x32\x00\x37\x00\x31\x00\x34\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x04\xC0\x0C\x00\x0D\x00\x00\x00" + "\x00\x00\x00\x00\x02\xC0\x0C\x00\x1B\x00\x00\x00\x00\x00\x00\x00" + "\x03\xC0\x2C\x00\x03\x00\x00\x00\x72\x64\x70\x64\x72\x00\x00\x00" + "\x00\x00\x80\x80\x63\x6c\x69\x70\x72\x64\x72\x00\x00\x00\xA0\xC0" + "\x72\x64\x70\x73\x6e\x64\x00\x00\x00\x00\x00\xc0"; + +uint8 gcc_create_conference_request_expected[307] = + "\x00\x05\x00\x14\x7C\x00\x01\x81\x2A\x00\x08\x00\x10\x00\x01\xC0" + "\x00\x44\x75\x63\x61\x81\x1c\x01\xc0\xd8\x00\x04\x00\x08\x00\x00" + "\x05\x00\x04\x01\xCA\x03\xAA\x09\x04\x00\x00\xCE\x0E\x00\x00\x45" + "\x00\x4c\x00\x54\x00\x4f\x00\x4e\x00\x53\x00\x2d\x00\x44\x00\x45" + "\x00\x56\x00\x32\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04" + "\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xCA\x01\x00\x00" + "\x00\x00\x00\x18\x00\x07\x00\x01\x00\x36\x00\x39\x00\x37\x00\x31" + "\x00\x32\x00\x2d\x00\x37\x00\x38\x00\x33\x00\x2d\x00\x30\x00\x33" + "\x00\x35\x00\x37\x00\x39\x00\x37\x00\x34\x00\x2d\x00\x34\x00\x32" + "\x00\x37\x00\x31\x00\x34\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04" + "\xC0\x0C\x00\x0D\x00\x00\x00\x00\x00\x00\x00\x02\xC0\x0C\x00\x1B" + "\x00\x00\x00\x00\x00\x00\x00\x03\xC0\x2C\x00\x03\x00\x00\x00\x72" + "\x64\x70\x64\x72\x00\x00\x00\x00\x00\x80\x80\x63\x6c\x69\x70\x72" + "\x64\x72\x00\x00\x00\xA0\xC0\x72\x64\x70\x73\x6e\x64\x00\x00\x00" + "\x00\x00\xc0"; + +void test_gcc_write_create_conference_request(void) +{ + STREAM* s; + STREAM user_data; + + user_data.buffer = gcc_user_data; + user_data.capacity = sizeof(gcc_user_data); + user_data.ptr = user_data.buffer + user_data.capacity; + + s = stream_new(sizeof(gcc_create_conference_request_expected)); + + gcc_write_create_conference_request(s, &user_data); + ASSERT_STREAM(s, (uint8*) gcc_create_conference_request_expected, sizeof(gcc_create_conference_request_expected)); +} diff --git a/cunit/test_gcc.h b/cunit/test_gcc.h new file mode 100644 index 000000000..ab3e24090 --- /dev/null +++ b/cunit/test_gcc.h @@ -0,0 +1,26 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * T.124 Generic Conference Control (GCC) Unit Tests + * + * Copyright 2011 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "test_freerdp.h" + +int init_gcc_suite(void); +int clean_gcc_suite(void); +int add_gcc_suite(void); + +void test_gcc_write_create_conference_request(void); diff --git a/libfreerdp-core/gcc.c b/libfreerdp-core/gcc.c index 3a117bcc2..1e59f5d0e 100644 --- a/libfreerdp-core/gcc.c +++ b/libfreerdp-core/gcc.c @@ -33,6 +33,12 @@ * connectPDU OCTET_STRING * } * + * Key ::= CHOICE + * { + * object OBJECT_IDENTIFIER, + * h221NonStandard H221NonStandardIdentifier + * } + * * ConnectGCCPDU ::= CHOICE * { * conferenceCreateRequest ConferenceCreateRequest, @@ -45,10 +51,80 @@ * conferenceInviteResponse ConferenceInviteResponse, * ... * } + * + * ConferenceCreateRequest ::= SEQUENCE + * { + * conferenceName ConferenceName, + * convenerPassword Password OPTIONAL, + * password Password OPTIONAL, + * lockedConference BOOLEAN, + * listedConference BOOLEAN, + * conductibleConference BOOLEAN, + * terminationMethod TerminationMethod, + * conductorPrivileges SET OF Privilege OPTIONAL, + * conductedPrivileges SET OF Privilege OPTIONAL, + * nonConductedPrivileges SET OF Privilege OPTIONAL, + * conferenceDescription TextString OPTIONAL, + * callerIdentifier TextString OPTIONAL, + * userData UserData OPTIONAL, + * ..., + * conferencePriority ConferencePriority OPTIONAL, + * conferenceMode ConferenceMode OPTIONAL + * } + * + * ConferenceName ::= SEQUENCE + * { + * numeric SimpleNumericString + * text SimpleTextString OPTIONAL, + * ... + * } + * + * SimpleNumericString ::= NumericString (SIZE (1..255)) (FROM ("0123456789")) + * + * UserData ::= SET OF SEQUENCE + * { + * key Key, + * value OCTET_STRING OPTIONAL + * } + * + * H221NonStandardIdentifier ::= OCTET STRING (SIZE (4..255)) + * */ /* http://msdn.microsoft.com/en-us/library/cc240836/ */ -uint8 t124_oid[6] = { 0, 0, 20, 124, 0, 1 }; +/* + * OID = 0.0.20.124.0.1 + * { itu-t(0) recommendation(0) t(20) t124(124) version(0) 1 } + * v.1 of ITU-T Recommendation T.124 (Feb 1998): "Generic Conference Control" + */ +uint8 t124_02_98_oid[6] = { 0, 0, 20, 124, 0, 1 }; +void +gcc_write_create_conference_request(STREAM* s, STREAM* user_data) +{ + /* ConnectData */ + per_write_choice(s, 0); /* From Key select object (0) of type OBJECT_IDENTIFIER */ + per_write_object_identifier(s, t124_02_98_oid); /* ITU-T T.124 (02/98) OBJECT_IDENTIFIER */ + /* ConnectData::connectPDU (OCTET_STRING) */ + per_write_length(s, stream_get_length(user_data) + 14); /* connectPDU length */ + + /* ConnectGCCPDU */ + per_write_choice(s, 0); /* From ConnectGCCPDU select conferenceCreateRequest (0) of type ConferenceCreateRequest */ + per_write_selection(s, 0x08); /* select optional userData from ConferenceCreateRequest */ + + /* ConferenceCreateRequest::conferenceName */ + per_write_numeric_string(s, "1", 1, 1); /* ConferenceName::numeric */ + per_write_padding(s, 1); /* padding */ + + /* UserData (SET OF SEQUENCE) */ + per_write_number_of_sets(s, 1); /* one set of UserData */ + per_write_choice(s, 0xC0); /* UserData::value present + select h221NonStandard (1) */ + + /* h221NonStandard */ + per_write_octet_string(s, "Duca", 4, 4); /* h221NonStandard, client-to-server H.221 key, "Duca" */ + + /* userData::value (OCTET_STRING) */ + per_write_octet_string(s, user_data->buffer, stream_get_length(user_data), 0); /* array of client data blocks */ +} diff --git a/libfreerdp-core/gcc.h b/libfreerdp-core/gcc.h index 69714b919..a099ce989 100644 --- a/libfreerdp-core/gcc.h +++ b/libfreerdp-core/gcc.h @@ -24,6 +24,7 @@ #include - +void +gcc_write_create_conference_request(STREAM* s, STREAM* user_data); #endif /* __GCC_H */ diff --git a/libfreerdp-core/per.c b/libfreerdp-core/per.c index 8228ab1a6..dc624b200 100644 --- a/libfreerdp-core/per.c +++ b/libfreerdp-core/per.c @@ -28,6 +28,33 @@ per_write_length(STREAM* s, int length) stream_write_uint8(s, length); } +void +per_write_choice(STREAM* s, uint8 choice) +{ + stream_write_uint8(s, choice); +} + +void +per_write_selection(STREAM* s, uint8 selection) +{ + stream_write_uint8(s, selection); +} + +void +per_write_number_of_sets(STREAM* s, uint8 number) +{ + stream_write_uint8(s, number); +} + +void +per_write_padding(STREAM* s, int length) +{ + int i; + + for (i = 0; i < length; i++) + stream_write_uint8(s, 0); +} + void per_write_object_identifier(STREAM* s, uint8 oid[6]) { @@ -39,3 +66,50 @@ per_write_object_identifier(STREAM* s, uint8 oid[6]) stream_write_uint8(s, oid[4]); /* tuple 5 */ stream_write_uint8(s, oid[5]); /* tuple 6 */ } + +void +per_write_string(STREAM* s, uint8* str, int length) +{ + int i; + + for (i = 0; i < length; i++) + stream_write_uint8(s, str[i]); +} + +void +per_write_octet_string(STREAM* s, uint8* oct_str, int length, int min) +{ + int i; + int mlength; + + mlength = (length - min >= 0) ? length - min : min; + + per_write_length(s, mlength); + + for (i = 0; i < length; i++) + stream_write_uint8(s, oct_str[i]); +} + +void +per_write_numeric_string(STREAM* s, uint8* num_str, int length, int min) +{ + int i; + int mlength; + uint8 num, c1, c2; + + mlength = (length - min >= 0) ? length - min : min; + + per_write_length(s, mlength); + + for (i = 0; i < length; i += 2) + { + c1 = num_str[i]; + c2 = ((i + 1) < length) ? num_str[i + 1] : 0x30; + + c1 = (c1 - 0x30) % 10; + c2 = (c2 - 0x30) % 10; + num = (c1 << 4) | c2; + + stream_write_uint8(s, num); /* string */ + } +} diff --git a/libfreerdp-core/per.h b/libfreerdp-core/per.h index cbb8261d9..692f91d38 100644 --- a/libfreerdp-core/per.h +++ b/libfreerdp-core/per.h @@ -25,6 +25,18 @@ void per_write_length(STREAM* s, int length); void +per_write_choice(STREAM* s, uint8 choice); +void +per_write_selection(STREAM* s, uint8 selection); +void +per_write_number_of_sets(STREAM* s, uint8 number); +void +per_write_padding(STREAM* s, int length); +void per_write_object_identifier(STREAM* s, uint8 oid[6]); +void +per_write_octet_string(STREAM* s, uint8* oct_str, int length, int min); +void +per_write_numeric_string(STREAM* s, uint8* num_str, int length, int min); #endif /* __PER_H */