| #ifdef HAVE_CONFIG_H |
| #include "config.h" |
| #endif |
| |
| #include "gst/gst.h" |
| |
| #include <rfb.h> |
| #include <unistd.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #include <sys/socket.h> |
| #include <netinet/in.h> |
| #include <arpa/inet.h> |
| #include <errno.h> |
| |
| #include "vncauth.h" |
| |
| #define RFB_GET_UINT32(ptr) GUINT32_FROM_BE (*(guint32 *)(ptr)) |
| #define RFB_GET_UINT16(ptr) GUINT16_FROM_BE (*(guint16 *)(ptr)) |
| #define RFB_GET_UINT8(ptr) (*(guint8 *)(ptr)) |
| |
| #define RFB_SET_UINT32(ptr, val) (*(guint32 *)(ptr) = GUINT32_TO_BE (val)) |
| #define RFB_SET_UINT16(ptr, val) (*(guint16 *)(ptr) = GUINT16_TO_BE (val)) |
| #define RFB_SET_UINT8(ptr, val) (*(guint8 *)(ptr) = val) |
| |
| GST_DEBUG_CATEGORY_STATIC (rfbdecoder_debug); |
| #define GST_CAT_DEFAULT rfbdecoder_debug |
| |
| #if 0 |
| struct _RfbSocketPrivate |
| { |
| gint fd; |
| sockaddr sa; |
| } |
| #endif |
| |
| static gboolean rfb_decoder_state_wait_for_protocol_version (RfbDecoder * |
| decoder); |
| static gboolean rfb_decoder_state_wait_for_security (RfbDecoder * decoder); |
| static gboolean rfb_decoder_state_send_client_initialisation (RfbDecoder * |
| decoder); |
| static gboolean rfb_decoder_state_wait_for_server_initialisation (RfbDecoder * |
| decoder); |
| static gboolean rfb_decoder_state_security_result (RfbDecoder * decoder); |
| static gboolean rfb_decoder_state_normal (RfbDecoder * decoder); |
| static gboolean rfb_decoder_state_framebuffer_update (RfbDecoder * decoder); |
| static gboolean rfb_decoder_state_framebuffer_update_rectangle (RfbDecoder * |
| decoder); |
| static gboolean rfb_decoder_state_set_colour_map_entries (RfbDecoder * decoder); |
| static gboolean rfb_decoder_state_server_cut_text (RfbDecoder * decoder); |
| static RfbBuffer *rfb_socket_get_buffer (gint length, gpointer user_data); |
| static gint rfb_socket_send_buffer (guint8 * buffer, gint length, |
| gpointer user_data); |
| |
| RfbDecoder * |
| rfb_decoder_new (void) |
| { |
| RfbDecoder *decoder = g_new0 (RfbDecoder, 1); |
| |
| decoder->fd = -1; |
| decoder->bytestream = rfb_bytestream_new (); |
| |
| decoder->password = NULL; |
| |
| decoder->offset_x = 0; |
| decoder->offset_y = 0; |
| decoder->rect_width = 0; |
| decoder->rect_height = 0; |
| |
| return decoder; |
| } |
| |
| void |
| rfb_decoder_free (RfbDecoder * decoder) |
| { |
| g_return_if_fail (decoder != NULL); |
| |
| rfb_bytestream_free (decoder->bytestream); |
| if (decoder->fd >= 0) |
| close (decoder->fd); |
| } |
| |
| void |
| rfb_decoder_use_file_descriptor (RfbDecoder * decoder, gint fd) |
| { |
| g_return_if_fail (decoder != NULL); |
| g_return_if_fail (decoder->fd == -1); |
| g_return_if_fail (!decoder->inited); |
| g_return_if_fail (fd >= 0); |
| |
| decoder->fd = fd; |
| |
| decoder->bytestream->get_buffer = rfb_socket_get_buffer; |
| decoder->bytestream->user_data = GINT_TO_POINTER (fd); |
| |
| decoder->send_data = rfb_socket_send_buffer; |
| decoder->buffer_handler_data = GINT_TO_POINTER (fd); |
| } |
| |
| gboolean |
| rfb_decoder_connect_tcp (RfbDecoder * decoder, gchar * addr, guint port) |
| { |
| struct sockaddr_in sa; |
| |
| GST_DEBUG ("connecting to the rfb server"); |
| |
| g_return_val_if_fail (decoder != NULL, FALSE); |
| g_return_val_if_fail (decoder->fd == -1, FALSE); |
| g_return_val_if_fail (addr != NULL, FALSE); |
| |
| decoder->fd = socket (PF_INET, SOCK_STREAM, 0); |
| if (decoder->fd == -1) { |
| GST_WARNING ("creating socket failed"); |
| return FALSE; |
| } |
| |
| sa.sin_family = AF_INET; |
| sa.sin_port = htons (port); |
| inet_pton (AF_INET, addr, &sa.sin_addr); |
| if (connect (decoder->fd, (struct sockaddr *) &sa, |
| sizeof (struct sockaddr)) == -1) { |
| close (decoder->fd); |
| GST_WARNING ("connection failed"); |
| return FALSE; |
| } |
| //rfb_decoder_use_file_descriptor (decoder, fd); |
| return TRUE; |
| } |
| |
| /** |
| * rfb_decoder_iterate: |
| * @decoder: The rfb context |
| * |
| * Initializes the connection with the rfb server |
| * |
| * Returns: TRUE if initialization was succesfull, FALSE on fail. |
| */ |
| gboolean |
| rfb_decoder_iterate (RfbDecoder * decoder) |
| { |
| GST_DEBUG_CATEGORY_INIT (rfbdecoder_debug, "rfbdecoder", 0, "Rfb source"); |
| |
| g_return_val_if_fail (decoder != NULL, FALSE); |
| g_return_val_if_fail (decoder->fd != -1, FALSE); |
| |
| if (decoder->state == NULL) { |
| GST_DEBUG ("First iteration: set state to -> wait for protocol version"); |
| decoder->state = rfb_decoder_state_wait_for_protocol_version; |
| } |
| |
| GST_DEBUG ("Executing next state in initialization"); |
| return decoder->state (decoder); |
| } |
| |
| guint8 * |
| rfb_decoder_read (RfbDecoder * decoder, guint32 len) |
| { |
| guint32 total = 0; |
| guint32 now = 0; |
| guint8 *address = NULL; |
| |
| g_return_val_if_fail (decoder->fd > 0, NULL); |
| g_return_val_if_fail (len > 0, NULL); |
| |
| address = g_malloc (len); |
| g_return_val_if_fail (address, NULL); |
| |
| while (total < len) { |
| now = recv (decoder->fd, address + total, len - total, 0); |
| if (now <= 0) { |
| GST_WARNING ("rfb read error on socket"); |
| return NULL; |
| } |
| total += now; |
| } |
| return address; |
| } |
| |
| static gint |
| rfb_decoder_send (RfbDecoder * decoder, guint8 * buffer, guint len) |
| { |
| g_return_val_if_fail (decoder->fd != 0, FALSE); |
| g_return_val_if_fail (buffer != NULL, FALSE); |
| g_return_val_if_fail (len > 0, FALSE); |
| |
| return write (decoder->fd, buffer, len); |
| } |
| |
| void |
| rfb_decoder_send_update_request (RfbDecoder * decoder, |
| gboolean incremental, gint x, gint y, gint width, gint height) |
| { |
| guint8 data[10]; |
| |
| g_return_if_fail (decoder != NULL); |
| g_return_if_fail (decoder->fd != -1); |
| |
| data[0] = 3; |
| data[1] = incremental; |
| RFB_SET_UINT16 (data + 2, x); |
| RFB_SET_UINT16 (data + 4, y); |
| RFB_SET_UINT16 (data + 6, width); |
| RFB_SET_UINT16 (data + 8, height); |
| |
| rfb_decoder_send (decoder, data, 10); |
| } |
| |
| void |
| rfb_decoder_send_key_event (RfbDecoder * decoder, guint key, gboolean down_flag) |
| { |
| guint8 data[8]; |
| |
| g_return_if_fail (decoder != NULL); |
| g_return_if_fail (decoder->fd != -1); |
| |
| data[0] = 4; |
| data[1] = down_flag; |
| RFB_SET_UINT16 (data + 2, 0); |
| RFB_SET_UINT32 (data + 4, key); |
| |
| rfb_decoder_send (decoder, data, 8); |
| } |
| |
| void |
| rfb_decoder_send_pointer_event (RfbDecoder * decoder, |
| gint button_mask, gint x, gint y) |
| { |
| guint8 data[6]; |
| |
| g_return_if_fail (decoder != NULL); |
| g_return_if_fail (decoder->fd != -1); |
| |
| data[0] = 5; |
| data[1] = button_mask; |
| RFB_SET_UINT16 (data + 2, x); |
| RFB_SET_UINT16 (data + 4, y); |
| |
| rfb_decoder_send (decoder, data, 6); |
| } |
| |
| /** |
| * rfb_decoder_state_wait_for_protocol_version: |
| * |
| * Negotiate the rfb version used |
| * |
| * \TODO Support for versions 3.7 and 3.8 |
| */ |
| static gboolean |
| rfb_decoder_state_wait_for_protocol_version (RfbDecoder * decoder) |
| { |
| guint8 *buffer = NULL; |
| |
| buffer = rfb_decoder_read (decoder, 12); |
| |
| g_return_val_if_fail (memcmp (buffer, "RFB 003.00", 10) == 0, FALSE); |
| g_return_val_if_fail (*(buffer + 11) == 0x0a, FALSE); |
| |
| GST_DEBUG ("\"%.11s\"", buffer); |
| *(buffer + 7) = 0x00; |
| *(buffer + 11) = 0x00; |
| decoder->protocol_major = atoi ((char *) (buffer + 4)); |
| decoder->protocol_minor = atoi ((char *) (buffer + 8)); |
| GST_DEBUG ("Major version : %d", decoder->protocol_major); |
| GST_DEBUG ("Minor version : %d", decoder->protocol_minor); |
| |
| if (decoder->protocol_major != 3) { |
| GST_INFO |
| ("A major protocol version of %d is not supported, falling back to 3", |
| decoder->protocol_major); |
| decoder->protocol_major = 3; |
| } |
| switch (decoder->protocol_minor) { |
| case 3: |
| break; |
| default: |
| GST_INFO ("Minor version %d is not supported, using 3", |
| decoder->protocol_minor); |
| decoder->protocol_minor = 3; |
| } |
| rfb_decoder_send (decoder, (guint8 *) "RFB 003.003\n", 12); |
| |
| decoder->state = rfb_decoder_state_wait_for_security; |
| g_free (buffer); |
| return TRUE; |
| } |
| |
| /** |
| * a string describing the reason (where a string is specified as a length followed |
| * by that many ASCII characters) |
| **/ |
| static gboolean |
| rfb_decoder_state_reason (RfbDecoder * decoder) |
| { |
| gint reason_length; |
| guint8 *buffer = NULL; |
| |
| buffer = rfb_decoder_read (decoder, 4); |
| |
| reason_length = RFB_GET_UINT32 (buffer); |
| g_free (buffer); |
| buffer = NULL; |
| buffer = rfb_decoder_read (decoder, reason_length); |
| GST_WARNING ("Reason by server: %s", buffer); |
| |
| g_free (buffer); |
| |
| return FALSE; |
| } |
| |
| static gboolean |
| rfb_decoder_state_wait_for_security (RfbDecoder * decoder) |
| { |
| guint8 *buffer = NULL; |
| |
| /** |
| * Version 3.3 The server decides the security type and sends a single word |
| * |
| * The security-type may only take the value 0, 1 or 2. A value of 0 means that the |
| * connection has failed and is followed by a string giving the reason, as described |
| * above. |
| */ |
| if (IS_VERSION_3_3 (decoder)) { |
| buffer = rfb_decoder_read (decoder, 4); |
| |
| decoder->security_type = RFB_GET_UINT32 (buffer); |
| GST_DEBUG ("security = %d", decoder->security_type); |
| |
| g_return_val_if_fail (decoder->security_type < 3, FALSE); |
| g_return_val_if_fail (decoder->security_type != SECURITY_FAIL, |
| rfb_decoder_state_reason (decoder)); |
| g_free (buffer); |
| buffer = NULL; |
| } else { |
| /* \TODO Add behavoir for the rfb 3.7 and 3.8 servers */ |
| GST_WARNING ("Other versions are not yet supported"); |
| } |
| |
| switch (decoder->security_type) { |
| case SECURITY_NONE: |
| GST_DEBUG ("Security type is None"); |
| if (IS_VERSION_3_8 (decoder)) { |
| decoder->state = rfb_decoder_state_security_result; |
| } else { |
| decoder->state = rfb_decoder_state_send_client_initialisation; |
| } |
| break; |
| case SECURITY_VNC: |
| /** |
| * VNC authentication is to be used and protocol data is to be sent unencrypted. The |
| * server sends a random 16-byte challenge |
| */ |
| GST_DEBUG ("Security type is VNC Authentication"); |
| /* VNC Authentication can't be used if the password is not set */ |
| if (!decoder->password) { |
| GST_WARNING |
| ("VNC Authentication can't be used if the password is not set"); |
| return FALSE; |
| } |
| |
| buffer = rfb_decoder_read (decoder, 16); |
| vncEncryptBytes ((unsigned char *) buffer, decoder->password); |
| rfb_decoder_send (decoder, buffer, 16); |
| g_free (buffer); |
| |
| GST_DEBUG ("Encrypted challenge send to server"); |
| |
| decoder->state = rfb_decoder_state_security_result; |
| break; |
| default: |
| GST_WARNING ("Security type is not known"); |
| return FALSE; |
| break; |
| } |
| return TRUE; |
| } |
| |
| /** |
| * The server sends a word to inform the client whether the security handshaking was |
| * successful. |
| */ |
| static gboolean |
| rfb_decoder_state_security_result (RfbDecoder * decoder) |
| { |
| guint8 *buffer = NULL; |
| |
| buffer = rfb_decoder_read (decoder, 4); |
| if (RFB_GET_UINT32 (buffer) != 0) { |
| GST_WARNING ("Security handshaking failed"); |
| if (IS_VERSION_3_8 (decoder)) { |
| decoder->state = rfb_decoder_state_reason; |
| return TRUE; |
| } |
| return FALSE; |
| } |
| |
| GST_DEBUG ("Security handshaking succesfull"); |
| decoder->state = rfb_decoder_state_send_client_initialisation; |
| |
| return TRUE; |
| } |
| |
| static gboolean |
| rfb_decoder_state_send_client_initialisation (RfbDecoder * decoder) |
| { |
| guint8 shared_flag; |
| |
| shared_flag = decoder->shared_flag; |
| rfb_decoder_send (decoder, &shared_flag, 1); |
| GST_DEBUG ("shared_flag is %d", shared_flag); |
| |
| decoder->state = rfb_decoder_state_wait_for_server_initialisation; |
| return TRUE; |
| } |
| |
| static gboolean |
| rfb_decoder_state_wait_for_server_initialisation (RfbDecoder * decoder) |
| { |
| guint8 *buffer = NULL; |
| guint32 name_length; |
| |
| buffer = rfb_decoder_read (decoder, 24); |
| |
| decoder->width = RFB_GET_UINT16 (buffer + 0); |
| decoder->height = RFB_GET_UINT16 (buffer + 2); |
| decoder->bpp = RFB_GET_UINT8 (buffer + 4); |
| decoder->depth = RFB_GET_UINT8 (buffer + 5); |
| decoder->big_endian = RFB_GET_UINT8 (buffer + 6); |
| decoder->true_colour = RFB_GET_UINT8 (buffer + 7); |
| decoder->red_max = RFB_GET_UINT16 (buffer + 8); |
| decoder->green_max = RFB_GET_UINT16 (buffer + 10); |
| decoder->blue_max = RFB_GET_UINT16 (buffer + 12); |
| decoder->red_shift = RFB_GET_UINT8 (buffer + 14); |
| decoder->green_shift = RFB_GET_UINT8 (buffer + 15); |
| decoder->blue_shift = RFB_GET_UINT8 (buffer + 16); |
| |
| GST_DEBUG ("Server Initialization"); |
| GST_DEBUG ("width = %d", decoder->width); |
| GST_DEBUG ("height = %d", decoder->height); |
| GST_DEBUG ("bpp = %d", decoder->bpp); |
| GST_DEBUG ("depth = %d", decoder->depth); |
| GST_DEBUG ("big_endian = %d", decoder->big_endian); |
| GST_DEBUG ("true_colour= %d", decoder->true_colour); |
| GST_DEBUG ("red_max = %d", decoder->red_max); |
| GST_DEBUG ("green_max = %d", decoder->green_max); |
| GST_DEBUG ("blue_max = %d", decoder->blue_max); |
| GST_DEBUG ("red_shift = %d", decoder->red_shift); |
| GST_DEBUG ("green_shift= %d", decoder->green_shift); |
| GST_DEBUG ("blue_shift = %d", decoder->blue_shift); |
| |
| name_length = RFB_GET_UINT32 (buffer + 20); |
| |
| buffer = rfb_decoder_read (decoder, name_length); |
| |
| decoder->name = g_strndup ((gchar *) (buffer), name_length); |
| g_free (buffer); |
| GST_DEBUG ("name = %s", decoder->name); |
| |
| decoder->state = rfb_decoder_state_normal; |
| decoder->inited = TRUE; |
| |
| /* check if we need cropping */ |
| |
| if (decoder->offset_x > 0) { |
| if (decoder->offset_x > decoder->width) { |
| GST_WARNING ("Trying to crop more than the width of the server"); |
| } else { |
| decoder->width -= decoder->offset_x; |
| } |
| } |
| if (decoder->offset_y > 0) { |
| if (decoder->offset_y > decoder->height) { |
| GST_WARNING ("Trying to crop more than the height of the server"); |
| } else { |
| decoder->height -= decoder->offset_y; |
| } |
| } |
| if (decoder->rect_width > 0) { |
| if (decoder->rect_width > decoder->width) { |
| GST_WARNING ("Trying to crop more than the width of the server"); |
| } else { |
| decoder->width = decoder->rect_width; |
| } |
| } |
| if (decoder->rect_height > 0) { |
| if (decoder->rect_height > decoder->height) { |
| GST_WARNING ("Trying to crop more than the height of the server"); |
| } else { |
| decoder->height = decoder->rect_height; |
| } |
| } |
| |
| return TRUE; |
| } |
| |
| static gboolean |
| rfb_decoder_state_normal (RfbDecoder * decoder) |
| { |
| guint8 *buffer; |
| gint message_type; |
| |
| buffer = rfb_decoder_read (decoder, 1); |
| message_type = RFB_GET_UINT8 (buffer); |
| |
| switch (message_type) { |
| case 0: |
| GST_DEBUG ("Receiving framebuffer update"); |
| decoder->state = rfb_decoder_state_framebuffer_update; |
| break; |
| case 1: |
| decoder->state = rfb_decoder_state_set_colour_map_entries; |
| break; |
| case 2: |
| /* bell, ignored */ |
| decoder->state = rfb_decoder_state_normal; |
| break; |
| case 3: |
| decoder->state = rfb_decoder_state_server_cut_text; |
| break; |
| default: |
| g_critical ("unknown message type %d", message_type); |
| } |
| |
| g_free (buffer); |
| return TRUE; |
| } |
| |
| static gboolean |
| rfb_decoder_state_framebuffer_update (RfbDecoder * decoder) |
| { |
| guint8 *buffer; |
| |
| buffer = rfb_decoder_read (decoder, 3); |
| |
| decoder->n_rects = RFB_GET_UINT16 (buffer + 1); |
| GST_DEBUG ("Number of rectangles : %d", decoder->n_rects); |
| |
| decoder->state = rfb_decoder_state_framebuffer_update_rectangle; |
| |
| return TRUE; |
| } |
| |
| /* |
| static gboolean |
| rfb_decoder_state_framebuffer_update (RfbDecoder *decoder) |
| { |
| RfbBuffer *buffer; |
| gint ret; |
| gint x, y, w, h; |
| gint encoding; |
| gint size; |
| |
| ret = rfb_bytestream_peek (decoder->bytestream, &buffer, 12); |
| if (ret < 12) |
| return FALSE; |
| |
| x = RFB_GET_UINT16 (buffer->data + 0); |
| y = RFB_GET_UINT16 (buffer->data + 2); |
| w = RFB_GET_UINT16 (buffer->data + 4); |
| h = RFB_GET_UINT16 (buffer->data + 6); |
| encoding = RFB_GET_UINT32 (buffer->data + 8); |
| |
| GST_DEBUG(" UPDATE Receiver"); |
| GST_DEBUG("x:%d y:%d", x, y); |
| GST_DEBUG("w:%d h:%d", w, h); |
| GST_DEBUG("encoding: %d", encoding); |
| |
| switch (encoding) |
| { |
| default: |
| GST_WARNING("encoding type(%d) is not supported", encoding); |
| return FALSE; |
| } |
| return TRUE; |
| } |
| */ |
| static gboolean |
| rfb_decoder_state_framebuffer_update_rectangle (RfbDecoder * decoder) |
| { |
| guint8 *buffer; |
| gint x, y, w, h; |
| gint encoding; |
| gint size; |
| |
| buffer = rfb_decoder_read (decoder, 12); |
| |
| x = RFB_GET_UINT16 (buffer + 0) - decoder->offset_x; |
| y = RFB_GET_UINT16 (buffer + 2) - decoder->offset_y; |
| w = RFB_GET_UINT16 (buffer + 4); |
| h = RFB_GET_UINT16 (buffer + 6); |
| encoding = RFB_GET_UINT32 (buffer + 8); |
| |
| GST_DEBUG ("update recieved"); |
| GST_DEBUG ("x:%d y:%d", x, y); |
| GST_DEBUG ("w:%d h:%d", w, h); |
| GST_DEBUG ("encoding: %d", encoding); |
| |
| if (encoding != 0) |
| g_critical ("unimplemented encoding\n"); |
| |
| g_free (buffer); |
| |
| size = w * h * decoder->bpp / 8; |
| GST_DEBUG ("Reading %d bytes", size); |
| buffer = rfb_decoder_read (decoder, size); |
| GST_DEBUG ("Reading %d bytes", size); |
| |
| if (decoder->paint_rect) { |
| decoder->paint_rect (decoder, x, y, w, h, buffer); |
| } |
| |
| g_free (buffer); |
| decoder->n_rects--; |
| if (decoder->n_rects == 0) { |
| decoder->state = rfb_decoder_state_normal; |
| } |
| return TRUE; |
| } |
| |
| static gboolean |
| rfb_decoder_state_set_colour_map_entries (RfbDecoder * decoder) |
| { |
| g_critical ("not implemented"); |
| |
| return FALSE; |
| } |
| |
| static gboolean |
| rfb_decoder_state_server_cut_text (RfbDecoder * decoder) |
| { |
| g_critical ("not implemented"); |
| |
| return FALSE; |
| } |
| |
| static RfbBuffer * |
| rfb_socket_get_buffer (gint length, gpointer user_data) |
| { |
| RfbBuffer *buffer; |
| gint fd = GPOINTER_TO_INT (user_data); |
| gint ret; |
| |
| buffer = rfb_buffer_new (); |
| |
| buffer->data = g_malloc (length); |
| buffer->free_data = (RfbBufferFreeFunc) g_free; |
| |
| // g_print ("calling read(%d, %p, %d)\n", fd, buffer->data, length); |
| ret = read (fd, buffer->data, length); |
| if (ret <= 0) { |
| g_critical ("read: %s", strerror (errno)); |
| rfb_buffer_free (buffer); |
| return NULL; |
| } |
| |
| buffer->length = ret; |
| |
| return buffer; |
| } |
| |
| static gint |
| rfb_socket_send_buffer (guint8 * buffer, gint length, gpointer user_data) |
| { |
| gint fd = GPOINTER_TO_INT (user_data); |
| gint ret; |
| |
| // g_print ("calling write(%d, %p, %d)\n", fd, buffer, length); |
| ret = write (fd, buffer, length); |
| if (ret < 0) { |
| g_critical ("write: %s", strerror (errno)); |
| return 0; |
| } |
| |
| g_assert (ret == length); |
| |
| return ret; |
| } |