protocol.c (43579B)
1/* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 20#include "config.h" 21 22#include "guacamole/error.h" 23#include "guacamole/layer.h" 24#include "guacamole/object.h" 25#include "guacamole/protocol.h" 26#include "guacamole/protocol-types.h" 27#include "guacamole/socket.h" 28#include "guacamole/stream.h" 29#include "guacamole/unicode.h" 30#include "palette.h" 31 32#include <cairo/cairo.h> 33 34#include <inttypes.h> 35#include <setjmp.h> 36#include <stdarg.h> 37#include <stdint.h> 38#include <stdio.h> 39#include <stdlib.h> 40#include <string.h> 41#include <sys/types.h> 42 43/** 44 * A structure mapping the enum value of a Guacamole protocol version to the 45 * string representation of the version. 46 */ 47typedef struct guac_protocol_version_mapping { 48 49 /** 50 * The enum value of the protocol version. 51 */ 52 guac_protocol_version version; 53 54 /** 55 * The string value representing the protocol version. 56 */ 57 char* version_string; 58 59} guac_protocol_version_mapping; 60 61/** 62 * The map of known protocol versions to the corresponding string value. 63 */ 64guac_protocol_version_mapping guac_protocol_version_table[] = { 65 { GUAC_PROTOCOL_VERSION_1_0_0, "VERSION_1_0_0" }, 66 { GUAC_PROTOCOL_VERSION_1_1_0, "VERSION_1_1_0" }, 67 { GUAC_PROTOCOL_VERSION_1_3_0, "VERSION_1_3_0" }, 68 { GUAC_PROTOCOL_VERSION_1_5_0, "VERSION_1_5_0" }, 69 { GUAC_PROTOCOL_VERSION_UNKNOWN, NULL } 70}; 71 72/* Output formatting functions */ 73 74ssize_t __guac_socket_write_length_string(guac_socket* socket, const char* str) { 75 76 return 77 guac_socket_write_int(socket, guac_utf8_strlen(str)) 78 || guac_socket_write_string(socket, ".") 79 || guac_socket_write_string(socket, str); 80 81} 82 83ssize_t __guac_socket_write_length_int(guac_socket* socket, int64_t i) { 84 85 char buffer[128]; 86 snprintf(buffer, sizeof(buffer), "%"PRIi64, i); 87 return __guac_socket_write_length_string(socket, buffer); 88 89} 90 91ssize_t __guac_socket_write_length_double(guac_socket* socket, double d) { 92 93 char buffer[128]; 94 snprintf(buffer, sizeof(buffer), "%.16g", d); 95 return __guac_socket_write_length_string(socket, buffer); 96 97} 98 99/** 100 * Loop through the provided NULL-terminated array, writing the values in the 101 * array to the given socket. Values are written as a series of Guacamole 102 * protocol elements, including the leading comma and the value length in 103 * addition to the value itself. Returns zero on success, non-zero on error. 104 * 105 * @param socket 106 * The socket to which the data should be written. 107 * 108 * @param array 109 * The NULL-terminated array of values to write. 110 * 111 * @return 112 * Zero on success, non-zero on error. 113 */ 114static int guac_socket_write_array(guac_socket* socket, const char** array) { 115 116 /* Loop through array, writing provided values to the socket. */ 117 for (int i=0; array[i] != NULL; i++) { 118 119 if (guac_socket_write_string(socket, ",")) 120 return -1; 121 122 if (__guac_socket_write_length_string(socket, array[i])) 123 return -1; 124 125 } 126 127 return 0; 128 129} 130 131/* Protocol functions */ 132 133int guac_protocol_send_ack(guac_socket* socket, guac_stream* stream, 134 const char* error, guac_protocol_status status) { 135 136 int ret_val; 137 138 guac_socket_instruction_begin(socket); 139 ret_val = 140 guac_socket_write_string(socket, "3.ack,") 141 || __guac_socket_write_length_int(socket, stream->index) 142 || guac_socket_write_string(socket, ",") 143 || __guac_socket_write_length_string(socket, error) 144 || guac_socket_write_string(socket, ",") 145 || __guac_socket_write_length_int(socket, status) 146 || guac_socket_write_string(socket, ";"); 147 148 guac_socket_instruction_end(socket); 149 return ret_val; 150 151} 152 153static int __guac_protocol_send_args(guac_socket* socket, const char** args) { 154 155 if (guac_socket_write_string(socket, "4.args")) return -1; 156 157 /* Send protocol version ahead of other args. */ 158 if (guac_socket_write_string(socket, ",") 159 || __guac_socket_write_length_string(socket, GUACAMOLE_PROTOCOL_VERSION)) 160 return -1; 161 162 if (guac_socket_write_array(socket, args)) 163 return -1; 164 165 return guac_socket_write_string(socket, ";"); 166 167} 168 169int guac_protocol_send_args(guac_socket* socket, const char** args) { 170 171 int ret_val; 172 173 guac_socket_instruction_begin(socket); 174 ret_val = __guac_protocol_send_args(socket, args); 175 guac_socket_instruction_end(socket); 176 177 return ret_val; 178 179} 180 181int guac_protocol_send_argv(guac_socket* socket, guac_stream* stream, 182 const char* mimetype, const char* name) { 183 184 int ret_val; 185 186 guac_socket_instruction_begin(socket); 187 ret_val = 188 guac_socket_write_string(socket, "4.argv,") 189 || __guac_socket_write_length_int(socket, stream->index) 190 || guac_socket_write_string(socket, ",") 191 || __guac_socket_write_length_string(socket, mimetype) 192 || guac_socket_write_string(socket, ",") 193 || __guac_socket_write_length_string(socket, name) 194 || guac_socket_write_string(socket, ";"); 195 196 guac_socket_instruction_end(socket); 197 return ret_val; 198 199} 200 201int guac_protocol_send_arc(guac_socket* socket, const guac_layer* layer, 202 int x, int y, int radius, double startAngle, double endAngle, 203 int negative) { 204 205 int ret_val; 206 207 guac_socket_instruction_begin(socket); 208 ret_val = 209 guac_socket_write_string(socket, "3.arc,") 210 || __guac_socket_write_length_int(socket, layer->index) 211 || guac_socket_write_string(socket, ",") 212 || __guac_socket_write_length_int(socket, x) 213 || guac_socket_write_string(socket, ",") 214 || __guac_socket_write_length_int(socket, y) 215 || guac_socket_write_string(socket, ",") 216 || __guac_socket_write_length_int(socket, radius) 217 || guac_socket_write_string(socket, ",") 218 || __guac_socket_write_length_double(socket, startAngle) 219 || guac_socket_write_string(socket, ",") 220 || __guac_socket_write_length_double(socket, endAngle) 221 || guac_socket_write_string(socket, ",") 222 || guac_socket_write_string(socket, negative ? "1.1" : "1.0") 223 || guac_socket_write_string(socket, ";"); 224 guac_socket_instruction_end(socket); 225 226 return ret_val; 227 228} 229 230int guac_protocol_send_audio(guac_socket* socket, const guac_stream* stream, 231 const char* mimetype) { 232 233 int ret_val; 234 235 guac_socket_instruction_begin(socket); 236 ret_val = 237 guac_socket_write_string(socket, "5.audio,") 238 || __guac_socket_write_length_int(socket, stream->index) 239 || guac_socket_write_string(socket, ",") 240 || __guac_socket_write_length_string(socket, mimetype) 241 || guac_socket_write_string(socket, ";"); 242 guac_socket_instruction_end(socket); 243 244 return ret_val; 245 246} 247 248int guac_protocol_send_blob(guac_socket* socket, const guac_stream* stream, 249 const void* data, int count) { 250 251 int base64_length = (count + 2) / 3 * 4; 252 253 int ret_val; 254 255 guac_socket_instruction_begin(socket); 256 ret_val = 257 guac_socket_write_string(socket, "4.blob,") 258 || __guac_socket_write_length_int(socket, stream->index) 259 || guac_socket_write_string(socket, ",") 260 || guac_socket_write_int(socket, base64_length) 261 || guac_socket_write_string(socket, ".") 262 || guac_socket_write_base64(socket, data, count) 263 || guac_socket_flush_base64(socket) 264 || guac_socket_write_string(socket, ";"); 265 266 guac_socket_instruction_end(socket); 267 return ret_val; 268 269} 270 271int guac_protocol_send_blobs(guac_socket* socket, const guac_stream* stream, 272 const void* data, int count) { 273 274 int ret_val = 0; 275 276 /* Send blob instructions while data remains and instructions are being 277 * sent successfully */ 278 while (count > 0 && ret_val == 0) { 279 280 /* Limit blob size to maximum allowed */ 281 int blob_size = count; 282 if (blob_size > GUAC_PROTOCOL_BLOB_MAX_LENGTH) 283 blob_size = GUAC_PROTOCOL_BLOB_MAX_LENGTH; 284 285 /* Send next blob of data */ 286 ret_val = guac_protocol_send_blob(socket, stream, data, blob_size); 287 288 /* Advance to next blob */ 289 data = (const char*) data + blob_size; 290 count -= blob_size; 291 292 } 293 294 return ret_val; 295 296} 297 298int guac_protocol_send_body(guac_socket* socket, const guac_object* object, 299 const guac_stream* stream, const char* mimetype, const char* name) { 300 301 int ret_val; 302 303 guac_socket_instruction_begin(socket); 304 ret_val = 305 guac_socket_write_string(socket, "4.body,") 306 || __guac_socket_write_length_int(socket, object->index) 307 || guac_socket_write_string(socket, ",") 308 || __guac_socket_write_length_int(socket, stream->index) 309 || guac_socket_write_string(socket, ",") 310 || __guac_socket_write_length_string(socket, mimetype) 311 || guac_socket_write_string(socket, ",") 312 || __guac_socket_write_length_string(socket, name) 313 || guac_socket_write_string(socket, ";"); 314 315 guac_socket_instruction_end(socket); 316 return ret_val; 317 318} 319 320int guac_protocol_send_cfill(guac_socket* socket, 321 guac_composite_mode mode, const guac_layer* layer, 322 int r, int g, int b, int a) { 323 324 int ret_val; 325 326 guac_socket_instruction_begin(socket); 327 ret_val = 328 guac_socket_write_string(socket, "5.cfill,") 329 || __guac_socket_write_length_int(socket, mode) 330 || guac_socket_write_string(socket, ",") 331 || __guac_socket_write_length_int(socket, layer->index) 332 || guac_socket_write_string(socket, ",") 333 || __guac_socket_write_length_int(socket, r) 334 || guac_socket_write_string(socket, ",") 335 || __guac_socket_write_length_int(socket, g) 336 || guac_socket_write_string(socket, ",") 337 || __guac_socket_write_length_int(socket, b) 338 || guac_socket_write_string(socket, ",") 339 || __guac_socket_write_length_int(socket, a) 340 || guac_socket_write_string(socket, ";"); 341 342 guac_socket_instruction_end(socket); 343 return ret_val; 344 345} 346 347int guac_protocol_send_close(guac_socket* socket, const guac_layer* layer) { 348 349 int ret_val; 350 351 guac_socket_instruction_begin(socket); 352 ret_val = 353 guac_socket_write_string(socket, "5.close,") 354 || __guac_socket_write_length_int(socket, layer->index) 355 || guac_socket_write_string(socket, ";"); 356 357 guac_socket_instruction_end(socket); 358 return ret_val; 359 360} 361 362static int __guac_protocol_send_connect(guac_socket* socket, const char** args) { 363 364 if (guac_socket_write_string(socket, "7.connect")) 365 return -1; 366 367 if (guac_socket_write_array(socket, args)) 368 return -1; 369 370 return guac_socket_write_string(socket, ";"); 371 372} 373 374int guac_protocol_send_connect(guac_socket* socket, const char** args) { 375 376 int ret_val; 377 378 guac_socket_instruction_begin(socket); 379 ret_val = __guac_protocol_send_connect(socket, args); 380 guac_socket_instruction_end(socket); 381 382 return ret_val; 383 384} 385 386int guac_protocol_send_clip(guac_socket* socket, const guac_layer* layer) { 387 388 int ret_val; 389 390 guac_socket_instruction_begin(socket); 391 ret_val = 392 guac_socket_write_string(socket, "4.clip,") 393 || __guac_socket_write_length_int(socket, layer->index) 394 || guac_socket_write_string(socket, ";"); 395 396 guac_socket_instruction_end(socket); 397 return ret_val; 398 399} 400 401int guac_protocol_send_clipboard(guac_socket* socket, const guac_stream* stream, 402 const char* mimetype) { 403 404 int ret_val; 405 406 guac_socket_instruction_begin(socket); 407 ret_val = 408 guac_socket_write_string(socket, "9.clipboard,") 409 || __guac_socket_write_length_int(socket, stream->index) 410 || guac_socket_write_string(socket, ",") 411 || __guac_socket_write_length_string(socket, mimetype) 412 || guac_socket_write_string(socket, ";"); 413 414 guac_socket_instruction_end(socket); 415 return ret_val; 416 417} 418 419int guac_protocol_send_copy(guac_socket* socket, 420 const guac_layer* srcl, int srcx, int srcy, int w, int h, 421 guac_composite_mode mode, const guac_layer* dstl, int dstx, int dsty) { 422 423 int ret_val; 424 425 guac_socket_instruction_begin(socket); 426 ret_val = 427 guac_socket_write_string(socket, "4.copy,") 428 || __guac_socket_write_length_int(socket, srcl->index) 429 || guac_socket_write_string(socket, ",") 430 || __guac_socket_write_length_int(socket, srcx) 431 || guac_socket_write_string(socket, ",") 432 || __guac_socket_write_length_int(socket, srcy) 433 || guac_socket_write_string(socket, ",") 434 || __guac_socket_write_length_int(socket, w) 435 || guac_socket_write_string(socket, ",") 436 || __guac_socket_write_length_int(socket, h) 437 || guac_socket_write_string(socket, ",") 438 || __guac_socket_write_length_int(socket, mode) 439 || guac_socket_write_string(socket, ",") 440 || __guac_socket_write_length_int(socket, dstl->index) 441 || guac_socket_write_string(socket, ",") 442 || __guac_socket_write_length_int(socket, dstx) 443 || guac_socket_write_string(socket, ",") 444 || __guac_socket_write_length_int(socket, dsty) 445 || guac_socket_write_string(socket, ";"); 446 447 guac_socket_instruction_end(socket); 448 return ret_val; 449 450} 451 452int guac_protocol_send_cstroke(guac_socket* socket, 453 guac_composite_mode mode, const guac_layer* layer, 454 guac_line_cap_style cap, guac_line_join_style join, int thickness, 455 int r, int g, int b, int a) { 456 457 int ret_val; 458 459 guac_socket_instruction_begin(socket); 460 ret_val = 461 guac_socket_write_string(socket, "7.cstroke,") 462 || __guac_socket_write_length_int(socket, mode) 463 || guac_socket_write_string(socket, ",") 464 || __guac_socket_write_length_int(socket, layer->index) 465 || guac_socket_write_string(socket, ",") 466 || __guac_socket_write_length_int(socket, cap) 467 || guac_socket_write_string(socket, ",") 468 || __guac_socket_write_length_int(socket, join) 469 || guac_socket_write_string(socket, ",") 470 || __guac_socket_write_length_int(socket, thickness) 471 || guac_socket_write_string(socket, ",") 472 || __guac_socket_write_length_int(socket, r) 473 || guac_socket_write_string(socket, ",") 474 || __guac_socket_write_length_int(socket, g) 475 || guac_socket_write_string(socket, ",") 476 || __guac_socket_write_length_int(socket, b) 477 || guac_socket_write_string(socket, ",") 478 || __guac_socket_write_length_int(socket, a) 479 || guac_socket_write_string(socket, ";"); 480 481 guac_socket_instruction_end(socket); 482 return ret_val; 483 484} 485 486int guac_protocol_send_cursor(guac_socket* socket, int x, int y, 487 const guac_layer* srcl, int srcx, int srcy, int w, int h) { 488 int ret_val; 489 490 guac_socket_instruction_begin(socket); 491 ret_val = 492 guac_socket_write_string(socket, "6.cursor,") 493 || __guac_socket_write_length_int(socket, x) 494 || guac_socket_write_string(socket, ",") 495 || __guac_socket_write_length_int(socket, y) 496 || guac_socket_write_string(socket, ",") 497 || __guac_socket_write_length_int(socket, srcl->index) 498 || guac_socket_write_string(socket, ",") 499 || __guac_socket_write_length_int(socket, srcx) 500 || guac_socket_write_string(socket, ",") 501 || __guac_socket_write_length_int(socket, srcy) 502 || guac_socket_write_string(socket, ",") 503 || __guac_socket_write_length_int(socket, w) 504 || guac_socket_write_string(socket, ",") 505 || __guac_socket_write_length_int(socket, h) 506 || guac_socket_write_string(socket, ";"); 507 508 guac_socket_instruction_end(socket); 509 return ret_val; 510 511} 512 513int guac_protocol_send_curve(guac_socket* socket, const guac_layer* layer, 514 int cp1x, int cp1y, int cp2x, int cp2y, int x, int y) { 515 516 int ret_val; 517 518 guac_socket_instruction_begin(socket); 519 ret_val = 520 guac_socket_write_string(socket, "5.curve,") 521 || __guac_socket_write_length_int(socket, layer->index) 522 || guac_socket_write_string(socket, ",") 523 || __guac_socket_write_length_int(socket, cp1x) 524 || guac_socket_write_string(socket, ",") 525 || __guac_socket_write_length_int(socket, cp1y) 526 || guac_socket_write_string(socket, ",") 527 || __guac_socket_write_length_int(socket, cp2x) 528 || guac_socket_write_string(socket, ",") 529 || __guac_socket_write_length_int(socket, cp2y) 530 || guac_socket_write_string(socket, ",") 531 || __guac_socket_write_length_int(socket, x) 532 || guac_socket_write_string(socket, ",") 533 || __guac_socket_write_length_int(socket, y) 534 || guac_socket_write_string(socket, ";"); 535 536 guac_socket_instruction_end(socket); 537 return ret_val; 538 539} 540 541int guac_protocol_send_disconnect(guac_socket* socket) { 542 int ret_val; 543 544 guac_socket_instruction_begin(socket); 545 ret_val = guac_socket_write_string(socket, "10.disconnect;"); 546 guac_socket_instruction_end(socket); 547 return ret_val; 548 549} 550 551int guac_protocol_send_dispose(guac_socket* socket, const guac_layer* layer) { 552 553 int ret_val; 554 555 guac_socket_instruction_begin(socket); 556 ret_val = 557 guac_socket_write_string(socket, "7.dispose,") 558 || __guac_socket_write_length_int(socket, layer->index) 559 || guac_socket_write_string(socket, ";"); 560 561 guac_socket_instruction_end(socket); 562 return ret_val; 563 564} 565 566int guac_protocol_send_distort(guac_socket* socket, const guac_layer* layer, 567 double a, double b, double c, 568 double d, double e, double f) { 569 570 int ret_val; 571 572 guac_socket_instruction_begin(socket); 573 ret_val = 574 guac_socket_write_string(socket, "7.distort,") 575 || __guac_socket_write_length_int(socket, layer->index) 576 || guac_socket_write_string(socket, ",") 577 || __guac_socket_write_length_double(socket, a) 578 || guac_socket_write_string(socket, ",") 579 || __guac_socket_write_length_double(socket, b) 580 || guac_socket_write_string(socket, ",") 581 || __guac_socket_write_length_double(socket, c) 582 || guac_socket_write_string(socket, ",") 583 || __guac_socket_write_length_double(socket, d) 584 || guac_socket_write_string(socket, ",") 585 || __guac_socket_write_length_double(socket, e) 586 || guac_socket_write_string(socket, ",") 587 || __guac_socket_write_length_double(socket, f) 588 || guac_socket_write_string(socket, ";"); 589 590 guac_socket_instruction_end(socket); 591 return ret_val; 592 593} 594 595int guac_protocol_send_end(guac_socket* socket, const guac_stream* stream) { 596 597 int ret_val; 598 599 guac_socket_instruction_begin(socket); 600 ret_val = 601 guac_socket_write_string(socket, "3.end,") 602 || __guac_socket_write_length_int(socket, stream->index) 603 || guac_socket_write_string(socket, ";"); 604 605 guac_socket_instruction_end(socket); 606 return ret_val; 607 608} 609 610int guac_protocol_send_error(guac_socket* socket, const char* error, 611 guac_protocol_status status) { 612 613 int ret_val; 614 615 guac_socket_instruction_begin(socket); 616 ret_val = 617 guac_socket_write_string(socket, "5.error,") 618 || __guac_socket_write_length_string(socket, error) 619 || guac_socket_write_string(socket, ",") 620 || __guac_socket_write_length_int(socket, status) 621 || guac_socket_write_string(socket, ";"); 622 623 guac_socket_instruction_end(socket); 624 return ret_val; 625 626} 627 628int vguac_protocol_send_log(guac_socket* socket, const char* format, 629 va_list args) { 630 631 int ret_val; 632 633 /* Copy log message into buffer */ 634 char message[4096]; 635 vsnprintf(message, sizeof(message), format, args); 636 637 /* Log to instruction */ 638 guac_socket_instruction_begin(socket); 639 ret_val = 640 guac_socket_write_string(socket, "3.log,") 641 || __guac_socket_write_length_string(socket, message) 642 || guac_socket_write_string(socket, ";"); 643 644 guac_socket_instruction_end(socket); 645 return ret_val; 646 647} 648 649int guac_protocol_send_log(guac_socket* socket, const char* format, ...) { 650 651 int ret_val; 652 653 va_list args; 654 va_start(args, format); 655 ret_val = vguac_protocol_send_log(socket, format, args); 656 va_end(args); 657 658 return ret_val; 659 660} 661 662int guac_protocol_send_msg(guac_socket* socket, guac_message_type msg, 663 const char** args) { 664 665 int ret_val; 666 667 guac_socket_instruction_begin(socket); 668 ret_val = 669 guac_socket_write_string(socket, "3.msg,") 670 || __guac_socket_write_length_int(socket, msg) 671 || guac_socket_write_array(socket, args) 672 || guac_socket_write_string(socket, ";"); 673 674 guac_socket_instruction_end(socket); 675 return ret_val; 676 677} 678 679int guac_protocol_send_file(guac_socket* socket, const guac_stream* stream, 680 const char* mimetype, const char* name) { 681 682 int ret_val; 683 684 guac_socket_instruction_begin(socket); 685 ret_val = 686 guac_socket_write_string(socket, "4.file,") 687 || __guac_socket_write_length_int(socket, stream->index) 688 || guac_socket_write_string(socket, ",") 689 || __guac_socket_write_length_string(socket, mimetype) 690 || guac_socket_write_string(socket, ",") 691 || __guac_socket_write_length_string(socket, name) 692 || guac_socket_write_string(socket, ";"); 693 694 guac_socket_instruction_end(socket); 695 return ret_val; 696 697} 698 699int guac_protocol_send_filesystem(guac_socket* socket, 700 const guac_object* object, const char* name) { 701 702 int ret_val; 703 704 guac_socket_instruction_begin(socket); 705 ret_val = 706 guac_socket_write_string(socket, "10.filesystem,") 707 || __guac_socket_write_length_int(socket, object->index) 708 || guac_socket_write_string(socket, ",") 709 || __guac_socket_write_length_string(socket, name) 710 || guac_socket_write_string(socket, ";"); 711 712 guac_socket_instruction_end(socket); 713 return ret_val; 714 715} 716 717int guac_protocol_send_identity(guac_socket* socket, const guac_layer* layer) { 718 719 int ret_val; 720 721 guac_socket_instruction_begin(socket); 722 ret_val = 723 guac_socket_write_string(socket, "8.identity,") 724 || __guac_socket_write_length_int(socket, layer->index) 725 || guac_socket_write_string(socket, ";"); 726 727 guac_socket_instruction_end(socket); 728 return ret_val; 729 730} 731 732int guac_protocol_send_key(guac_socket* socket, int keysym, int pressed, 733 guac_timestamp timestamp) { 734 735 int ret_val; 736 737 guac_socket_instruction_begin(socket); 738 ret_val = 739 guac_socket_write_string(socket, "3.key,") 740 || __guac_socket_write_length_int(socket, keysym) 741 || guac_socket_write_string(socket, pressed ? ",1.1," : ",1.0,") 742 || __guac_socket_write_length_int(socket, timestamp) 743 || guac_socket_write_string(socket, ";"); 744 745 guac_socket_instruction_end(socket); 746 return ret_val; 747 748} 749 750int guac_protocol_send_lfill(guac_socket* socket, 751 guac_composite_mode mode, const guac_layer* layer, 752 const guac_layer* srcl) { 753 754 int ret_val; 755 756 guac_socket_instruction_begin(socket); 757 ret_val = 758 guac_socket_write_string(socket, "5.lfill,") 759 || __guac_socket_write_length_int(socket, mode) 760 || guac_socket_write_string(socket, ",") 761 || __guac_socket_write_length_int(socket, layer->index) 762 || guac_socket_write_string(socket, ",") 763 || __guac_socket_write_length_int(socket, srcl->index) 764 || guac_socket_write_string(socket, ";"); 765 766 guac_socket_instruction_end(socket); 767 return ret_val; 768 769} 770 771int guac_protocol_send_line(guac_socket* socket, const guac_layer* layer, 772 int x, int y) { 773 774 int ret_val; 775 776 guac_socket_instruction_begin(socket); 777 ret_val = 778 guac_socket_write_string(socket, "4.line,") 779 || __guac_socket_write_length_int(socket, layer->index) 780 || guac_socket_write_string(socket, ",") 781 || __guac_socket_write_length_int(socket, x) 782 || guac_socket_write_string(socket, ",") 783 || __guac_socket_write_length_int(socket, y) 784 || guac_socket_write_string(socket, ";"); 785 786 guac_socket_instruction_end(socket); 787 return ret_val; 788 789} 790 791int guac_protocol_send_lstroke(guac_socket* socket, 792 guac_composite_mode mode, const guac_layer* layer, 793 guac_line_cap_style cap, guac_line_join_style join, int thickness, 794 const guac_layer* srcl) { 795 796 int ret_val; 797 798 guac_socket_instruction_begin(socket); 799 ret_val = 800 guac_socket_write_string(socket, "7.lstroke,") 801 || __guac_socket_write_length_int(socket, mode) 802 || guac_socket_write_string(socket, ",") 803 || __guac_socket_write_length_int(socket, layer->index) 804 || guac_socket_write_string(socket, ",") 805 || __guac_socket_write_length_int(socket, cap) 806 || guac_socket_write_string(socket, ",") 807 || __guac_socket_write_length_int(socket, join) 808 || guac_socket_write_string(socket, ",") 809 || __guac_socket_write_length_int(socket, thickness) 810 || guac_socket_write_string(socket, ",") 811 || __guac_socket_write_length_int(socket, srcl->index) 812 || guac_socket_write_string(socket, ";"); 813 814 guac_socket_instruction_end(socket); 815 return ret_val; 816 817} 818 819int guac_protocol_send_mouse(guac_socket* socket, int x, int y, 820 int button_mask, guac_timestamp timestamp) { 821 822 int ret_val; 823 824 guac_socket_instruction_begin(socket); 825 ret_val = 826 guac_socket_write_string(socket, "5.mouse,") 827 || __guac_socket_write_length_int(socket, x) 828 || guac_socket_write_string(socket, ",") 829 || __guac_socket_write_length_int(socket, y) 830 || guac_socket_write_string(socket, ",") 831 || __guac_socket_write_length_int(socket, button_mask) 832 || guac_socket_write_string(socket, ",") 833 || __guac_socket_write_length_int(socket, timestamp) 834 || guac_socket_write_string(socket, ";"); 835 836 guac_socket_instruction_end(socket); 837 return ret_val; 838 839} 840 841int guac_protocol_send_touch(guac_socket* socket, int id, int x, int y, 842 int x_radius, int y_radius, double angle, double force, 843 guac_timestamp timestamp) { 844 845 int ret_val; 846 847 guac_socket_instruction_begin(socket); 848 ret_val = 849 guac_socket_write_string(socket, "5.touch,") 850 || __guac_socket_write_length_int(socket, id) 851 || guac_socket_write_string(socket, ",") 852 || __guac_socket_write_length_int(socket, x) 853 || guac_socket_write_string(socket, ",") 854 || __guac_socket_write_length_int(socket, y) 855 || guac_socket_write_string(socket, ",") 856 || __guac_socket_write_length_int(socket, x_radius) 857 || guac_socket_write_string(socket, ",") 858 || __guac_socket_write_length_int(socket, y_radius) 859 || guac_socket_write_string(socket, ",") 860 || __guac_socket_write_length_double(socket, angle) 861 || guac_socket_write_string(socket, ",") 862 || __guac_socket_write_length_double(socket, force) 863 || guac_socket_write_string(socket, ",") 864 || __guac_socket_write_length_int(socket, timestamp) 865 || guac_socket_write_string(socket, ";"); 866 867 guac_socket_instruction_end(socket); 868 return ret_val; 869 870} 871 872int guac_protocol_send_move(guac_socket* socket, const guac_layer* layer, 873 const guac_layer* parent, int x, int y, int z) { 874 875 int ret_val; 876 877 guac_socket_instruction_begin(socket); 878 ret_val = 879 guac_socket_write_string(socket, "4.move,") 880 || __guac_socket_write_length_int(socket, layer->index) 881 || guac_socket_write_string(socket, ",") 882 || __guac_socket_write_length_int(socket, parent->index) 883 || guac_socket_write_string(socket, ",") 884 || __guac_socket_write_length_int(socket, x) 885 || guac_socket_write_string(socket, ",") 886 || __guac_socket_write_length_int(socket, y) 887 || guac_socket_write_string(socket, ",") 888 || __guac_socket_write_length_int(socket, z) 889 || guac_socket_write_string(socket, ";"); 890 891 guac_socket_instruction_end(socket); 892 return ret_val; 893 894} 895 896int guac_protocol_send_name(guac_socket* socket, const char* name) { 897 898 int ret_val; 899 900 guac_socket_instruction_begin(socket); 901 ret_val = 902 guac_socket_write_string(socket, "4.name,") 903 || __guac_socket_write_length_string(socket, name) 904 || guac_socket_write_string(socket, ";"); 905 906 guac_socket_instruction_end(socket); 907 return ret_val; 908 909} 910 911int guac_protocol_send_nest(guac_socket* socket, int index, 912 const char* data) { 913 914 int ret_val; 915 916 guac_socket_instruction_begin(socket); 917 ret_val = 918 guac_socket_write_string(socket, "4.nest,") 919 || __guac_socket_write_length_int(socket, index) 920 || guac_socket_write_string(socket, ",") 921 || __guac_socket_write_length_string(socket, data) 922 || guac_socket_write_string(socket, ";"); 923 924 guac_socket_instruction_end(socket); 925 return ret_val; 926 927} 928 929int guac_protocol_send_nop(guac_socket* socket) { 930 931 int ret_val; 932 933 guac_socket_instruction_begin(socket); 934 ret_val = guac_socket_write_string(socket, "3.nop;"); 935 guac_socket_instruction_end(socket); 936 937 return ret_val; 938 939} 940 941int guac_protocol_send_pipe(guac_socket* socket, const guac_stream* stream, 942 const char* mimetype, const char* name) { 943 944 int ret_val; 945 946 guac_socket_instruction_begin(socket); 947 ret_val = 948 guac_socket_write_string(socket, "4.pipe,") 949 || __guac_socket_write_length_int(socket, stream->index) 950 || guac_socket_write_string(socket, ",") 951 || __guac_socket_write_length_string(socket, mimetype) 952 || guac_socket_write_string(socket, ",") 953 || __guac_socket_write_length_string(socket, name) 954 || guac_socket_write_string(socket, ";"); 955 956 guac_socket_instruction_end(socket); 957 return ret_val; 958 959} 960 961int guac_protocol_send_img(guac_socket* socket, const guac_stream* stream, 962 guac_composite_mode mode, const guac_layer* layer, 963 const char* mimetype, int x, int y) { 964 965 int ret_val; 966 967 guac_socket_instruction_begin(socket); 968 ret_val = 969 guac_socket_write_string(socket, "3.img,") 970 || __guac_socket_write_length_int(socket, stream->index) 971 || guac_socket_write_string(socket, ",") 972 || __guac_socket_write_length_int(socket, mode) 973 || guac_socket_write_string(socket, ",") 974 || __guac_socket_write_length_int(socket, layer->index) 975 || guac_socket_write_string(socket, ",") 976 || __guac_socket_write_length_string(socket, mimetype) 977 || guac_socket_write_string(socket, ",") 978 || __guac_socket_write_length_int(socket, x) 979 || guac_socket_write_string(socket, ",") 980 || __guac_socket_write_length_int(socket, y) 981 || guac_socket_write_string(socket, ";"); 982 983 guac_socket_instruction_end(socket); 984 return ret_val; 985 986} 987 988int guac_protocol_send_pop(guac_socket* socket, const guac_layer* layer) { 989 990 int ret_val; 991 992 guac_socket_instruction_begin(socket); 993 ret_val = 994 guac_socket_write_string(socket, "3.pop,") 995 || __guac_socket_write_length_int(socket, layer->index) 996 || guac_socket_write_string(socket, ";"); 997 998 guac_socket_instruction_end(socket); 999 return ret_val; 1000 1001} 1002 1003int guac_protocol_send_push(guac_socket* socket, const guac_layer* layer) { 1004 1005 int ret_val; 1006 1007 guac_socket_instruction_begin(socket); 1008 ret_val = 1009 guac_socket_write_string(socket, "4.push,") 1010 || __guac_socket_write_length_int(socket, layer->index) 1011 || guac_socket_write_string(socket, ";"); 1012 1013 guac_socket_instruction_end(socket); 1014 return ret_val; 1015 1016} 1017 1018int guac_protocol_send_ready(guac_socket* socket, const char* id) { 1019 1020 int ret_val; 1021 1022 guac_socket_instruction_begin(socket); 1023 ret_val = 1024 guac_socket_write_string(socket, "5.ready,") 1025 || __guac_socket_write_length_string(socket, id) 1026 || guac_socket_write_string(socket, ";"); 1027 1028 guac_socket_instruction_end(socket); 1029 return ret_val; 1030 1031} 1032 1033int guac_protocol_send_rect(guac_socket* socket, 1034 const guac_layer* layer, int x, int y, int width, int height) { 1035 1036 int ret_val; 1037 1038 guac_socket_instruction_begin(socket); 1039 ret_val = 1040 guac_socket_write_string(socket, "4.rect,") 1041 || __guac_socket_write_length_int(socket, layer->index) 1042 || guac_socket_write_string(socket, ",") 1043 || __guac_socket_write_length_int(socket, x) 1044 || guac_socket_write_string(socket, ",") 1045 || __guac_socket_write_length_int(socket, y) 1046 || guac_socket_write_string(socket, ",") 1047 || __guac_socket_write_length_int(socket, width) 1048 || guac_socket_write_string(socket, ",") 1049 || __guac_socket_write_length_int(socket, height) 1050 || guac_socket_write_string(socket, ";"); 1051 1052 guac_socket_instruction_end(socket); 1053 return ret_val; 1054 1055} 1056 1057int guac_protocol_send_required(guac_socket* socket, const char** required) { 1058 1059 int ret_val; 1060 1061 guac_socket_instruction_begin(socket); 1062 1063 ret_val = guac_socket_write_string(socket, "8.required") 1064 || guac_socket_write_array(socket, required) 1065 || guac_socket_write_string(socket, ";") 1066 || guac_socket_flush(socket); 1067 1068 guac_socket_instruction_end(socket); 1069 1070 return ret_val; 1071 1072} 1073 1074int guac_protocol_send_reset(guac_socket* socket, const guac_layer* layer) { 1075 1076 int ret_val; 1077 1078 guac_socket_instruction_begin(socket); 1079 ret_val = 1080 guac_socket_write_string(socket, "5.reset,") 1081 || __guac_socket_write_length_int(socket, layer->index) 1082 || guac_socket_write_string(socket, ";"); 1083 1084 guac_socket_instruction_end(socket); 1085 return ret_val; 1086 1087} 1088 1089int guac_protocol_send_set(guac_socket* socket, const guac_layer* layer, 1090 const char* name, const char* value) { 1091 1092 int ret_val; 1093 1094 guac_socket_instruction_begin(socket); 1095 ret_val = 1096 guac_socket_write_string(socket, "3.set,") 1097 || __guac_socket_write_length_int(socket, layer->index) 1098 || guac_socket_write_string(socket, ",") 1099 || __guac_socket_write_length_string(socket, name) 1100 || guac_socket_write_string(socket, ",") 1101 || __guac_socket_write_length_string(socket, value) 1102 || guac_socket_write_string(socket, ";"); 1103 1104 guac_socket_instruction_end(socket); 1105 return ret_val; 1106 1107} 1108 1109int guac_protocol_send_set_int(guac_socket* socket, const guac_layer* layer, 1110 const char* name, int value) { 1111 1112 int ret_val; 1113 1114 guac_socket_instruction_begin(socket); 1115 ret_val = 1116 guac_socket_write_string(socket, "3.set,") 1117 || __guac_socket_write_length_int(socket, layer->index) 1118 || guac_socket_write_string(socket, ",") 1119 || __guac_socket_write_length_string(socket, name) 1120 || guac_socket_write_string(socket, ",") 1121 || __guac_socket_write_length_int(socket, value) 1122 || guac_socket_write_string(socket, ";"); 1123 1124 guac_socket_instruction_end(socket); 1125 return ret_val; 1126 1127} 1128 1129int guac_protocol_send_select(guac_socket* socket, const char* protocol) { 1130 1131 int ret_val; 1132 1133 guac_socket_instruction_begin(socket); 1134 ret_val = 1135 guac_socket_write_string(socket, "6.select,") 1136 || __guac_socket_write_length_string(socket, protocol) 1137 || guac_socket_write_string(socket, ";"); 1138 1139 guac_socket_instruction_end(socket); 1140 return ret_val; 1141 1142} 1143 1144int guac_protocol_send_shade(guac_socket* socket, const guac_layer* layer, 1145 int a) { 1146 1147 int ret_val; 1148 1149 guac_socket_instruction_begin(socket); 1150 ret_val = 1151 guac_socket_write_string(socket, "5.shade,") 1152 || __guac_socket_write_length_int(socket, layer->index) 1153 || guac_socket_write_string(socket, ",") 1154 || __guac_socket_write_length_int(socket, a) 1155 || guac_socket_write_string(socket, ";"); 1156 1157 guac_socket_instruction_end(socket); 1158 return ret_val; 1159 1160} 1161 1162int guac_protocol_send_size(guac_socket* socket, const guac_layer* layer, 1163 int w, int h) { 1164 1165 int ret_val; 1166 1167 guac_socket_instruction_begin(socket); 1168 ret_val = 1169 guac_socket_write_string(socket, "4.size,") 1170 || __guac_socket_write_length_int(socket, layer->index) 1171 || guac_socket_write_string(socket, ",") 1172 || __guac_socket_write_length_int(socket, w) 1173 || guac_socket_write_string(socket, ",") 1174 || __guac_socket_write_length_int(socket, h) 1175 || guac_socket_write_string(socket, ";"); 1176 1177 guac_socket_instruction_end(socket); 1178 return ret_val; 1179 1180} 1181 1182int guac_protocol_send_start(guac_socket* socket, const guac_layer* layer, 1183 int x, int y) { 1184 1185 int ret_val; 1186 1187 guac_socket_instruction_begin(socket); 1188 ret_val = 1189 guac_socket_write_string(socket, "5.start,") 1190 || __guac_socket_write_length_int(socket, layer->index) 1191 || guac_socket_write_string(socket, ",") 1192 || __guac_socket_write_length_int(socket, x) 1193 || guac_socket_write_string(socket, ",") 1194 || __guac_socket_write_length_int(socket, y) 1195 || guac_socket_write_string(socket, ";"); 1196 1197 guac_socket_instruction_end(socket); 1198 return ret_val; 1199 1200} 1201 1202int guac_protocol_send_sync(guac_socket* socket, guac_timestamp timestamp) { 1203 1204 int ret_val; 1205 1206 guac_socket_instruction_begin(socket); 1207 ret_val = 1208 guac_socket_write_string(socket, "4.sync,") 1209 || __guac_socket_write_length_int(socket, timestamp) 1210 || guac_socket_write_string(socket, ";"); 1211 1212 guac_socket_instruction_end(socket); 1213 return ret_val; 1214 1215} 1216 1217int guac_protocol_send_transfer(guac_socket* socket, 1218 const guac_layer* srcl, int srcx, int srcy, int w, int h, 1219 guac_transfer_function fn, const guac_layer* dstl, int dstx, int dsty) { 1220 1221 int ret_val; 1222 1223 guac_socket_instruction_begin(socket); 1224 ret_val = 1225 guac_socket_write_string(socket, "8.transfer,") 1226 || __guac_socket_write_length_int(socket, srcl->index) 1227 || guac_socket_write_string(socket, ",") 1228 || __guac_socket_write_length_int(socket, srcx) 1229 || guac_socket_write_string(socket, ",") 1230 || __guac_socket_write_length_int(socket, srcy) 1231 || guac_socket_write_string(socket, ",") 1232 || __guac_socket_write_length_int(socket, w) 1233 || guac_socket_write_string(socket, ",") 1234 || __guac_socket_write_length_int(socket, h) 1235 || guac_socket_write_string(socket, ",") 1236 || __guac_socket_write_length_int(socket, fn) 1237 || guac_socket_write_string(socket, ",") 1238 || __guac_socket_write_length_int(socket, dstl->index) 1239 || guac_socket_write_string(socket, ",") 1240 || __guac_socket_write_length_int(socket, dstx) 1241 || guac_socket_write_string(socket, ",") 1242 || __guac_socket_write_length_int(socket, dsty) 1243 || guac_socket_write_string(socket, ";"); 1244 1245 guac_socket_instruction_end(socket); 1246 return ret_val; 1247 1248} 1249 1250int guac_protocol_send_transform(guac_socket* socket, const guac_layer* layer, 1251 double a, double b, double c, 1252 double d, double e, double f) { 1253 1254 int ret_val; 1255 1256 guac_socket_instruction_begin(socket); 1257 ret_val = 1258 guac_socket_write_string(socket, "9.transform,") 1259 || __guac_socket_write_length_int(socket, layer->index) 1260 || guac_socket_write_string(socket, ",") 1261 || __guac_socket_write_length_double(socket, a) 1262 || guac_socket_write_string(socket, ",") 1263 || __guac_socket_write_length_double(socket, b) 1264 || guac_socket_write_string(socket, ",") 1265 || __guac_socket_write_length_double(socket, c) 1266 || guac_socket_write_string(socket, ",") 1267 || __guac_socket_write_length_double(socket, d) 1268 || guac_socket_write_string(socket, ",") 1269 || __guac_socket_write_length_double(socket, e) 1270 || guac_socket_write_string(socket, ",") 1271 || __guac_socket_write_length_double(socket, f) 1272 || guac_socket_write_string(socket, ";"); 1273 1274 guac_socket_instruction_end(socket); 1275 return ret_val; 1276 1277} 1278 1279int guac_protocol_send_undefine(guac_socket* socket, 1280 const guac_object* object) { 1281 1282 int ret_val; 1283 1284 guac_socket_instruction_begin(socket); 1285 ret_val = 1286 guac_socket_write_string(socket, "8.undefine,") 1287 || __guac_socket_write_length_int(socket, object->index) 1288 || guac_socket_write_string(socket, ";"); 1289 1290 guac_socket_instruction_end(socket); 1291 return ret_val; 1292 1293} 1294 1295int guac_protocol_send_video(guac_socket* socket, const guac_stream* stream, 1296 const guac_layer* layer, const char* mimetype) { 1297 1298 int ret_val; 1299 1300 guac_socket_instruction_begin(socket); 1301 ret_val = 1302 guac_socket_write_string(socket, "5.video,") 1303 || __guac_socket_write_length_int(socket, stream->index) 1304 || guac_socket_write_string(socket, ",") 1305 || __guac_socket_write_length_int(socket, layer->index) 1306 || guac_socket_write_string(socket, ",") 1307 || __guac_socket_write_length_string(socket, mimetype) 1308 || guac_socket_write_string(socket, ";"); 1309 guac_socket_instruction_end(socket); 1310 1311 return ret_val; 1312 1313} 1314 1315/** 1316 * Returns the value of a single base64 character. 1317 */ 1318static int __guac_base64_value(char c) { 1319 1320 if (c >= 'A' && c <= 'Z') 1321 return c - 'A'; 1322 1323 if (c >= 'a' && c <= 'z') 1324 return c - 'a' + 26; 1325 1326 if (c >= '0' && c <= '9') 1327 return c - '0' + 52; 1328 1329 if (c == '+') 1330 return 62; 1331 1332 if (c == '/') 1333 return 63; 1334 1335 return 0; 1336 1337} 1338 1339int guac_protocol_decode_base64(char* base64) { 1340 1341 char* input = base64; 1342 char* output = base64; 1343 1344 int length = 0; 1345 int bits_read = 0; 1346 int value = 0; 1347 char current; 1348 1349 /* For all characters in string */ 1350 while ((current = *(input++)) != 0) { 1351 1352 /* If we've reached padding, then we're done */ 1353 if (current == '=') 1354 break; 1355 1356 /* Otherwise, shift on the latest 6 bits */ 1357 value = (value << 6) | __guac_base64_value(current); 1358 bits_read += 6; 1359 1360 /* If we have at least one byte, write out the latest whole byte */ 1361 if (bits_read >= 8) { 1362 *(output++) = (value >> (bits_read % 8)) & 0xFF; 1363 bits_read -= 8; 1364 length++; 1365 } 1366 1367 } 1368 1369 /* Return number of bytes written */ 1370 return length; 1371 1372} 1373 1374guac_protocol_version guac_protocol_string_to_version(const char* version_string) { 1375 1376 guac_protocol_version_mapping* current = guac_protocol_version_table; 1377 while (current->version != GUAC_PROTOCOL_VERSION_UNKNOWN) { 1378 1379 if (strcmp(current->version_string, version_string) == 0) 1380 return current->version; 1381 1382 current++; 1383 1384 } 1385 1386 return GUAC_PROTOCOL_VERSION_UNKNOWN; 1387 1388} 1389 1390const char* guac_protocol_version_to_string(guac_protocol_version version) { 1391 1392 guac_protocol_version_mapping* current = guac_protocol_version_table; 1393 while (current->version != GUAC_PROTOCOL_VERSION_UNKNOWN) { 1394 1395 if (current->version == version) 1396 return (const char*) current->version_string; 1397 1398 current++; 1399 1400 } 1401 1402 return NULL; 1403 1404} 1405