diff --git a/CMakeLists.txt b/CMakeLists.txt index cbdf3516d..aa541170c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -426,10 +426,25 @@ if(MSVC) install(PROGRAMS ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS} DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT libraries) + + + set(EXTRA_DATA_DIR "pre-requisites/") + file(GLOB EXTRA_FILES "${CMAKE_SOURCE_DIR}/extra/*") + install(FILES ${EXTRA_FILES} + DESTINATION ${EXTRA_DATA_DIR} + COMPONENT extra) + + set(REV_DATA_DIR "REV/") + file(GLOB REV_FILES "${CMAKE_SOURCE_DIR}/REV/*") + install(FILES ${REV_FILES} + DESTINATION ${REV_DATA_DIR} + COMPONENT rev) endif() endif() -set(CPACK_COMPONENTS_ALL client server libraries headers) + +set(CPACK_COMPONENTS_ALL client server libraries headers extra rev) + set(CPACK_COMPONENT_CLIENT_DISPLAY_NAME "Client") set(CPACK_COMPONENT_CLIENT_GROUP "Applications") diff --git a/channels/cliprdr/client/cliprdr_format.c b/channels/cliprdr/client/cliprdr_format.c index 7f368537e..2c6db2308 100644 --- a/channels/cliprdr/client/cliprdr_format.c +++ b/channels/cliprdr/client/cliprdr_format.c @@ -144,6 +144,7 @@ void cliprdr_process_short_format_names(cliprdrPlugin* cliprdr, STREAM* s, UINT3 } else { + format_name->name = NULL; format_name->length = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) s->p, 32 / 2, &format_name->name, 0, NULL, NULL); } diff --git a/channels/drive/client/drive_file.c b/channels/drive/client/drive_file.c index 78701f8fd..4d4e6e8dd 100644 --- a/channels/drive/client/drive_file.c +++ b/channels/drive/client/drive_file.c @@ -430,7 +430,7 @@ BOOL drive_file_query_information(DRIVE_FILE* file, UINT32 FsInformationClass, S BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UINT32 Length, STREAM* input) { - char* s; + char* s = NULL; mode_t m; UINT64 size; int status; diff --git a/channels/drive/client/drive_main.c b/channels/drive/client/drive_main.c index 7571297e8..f6f48554c 100644 --- a/channels/drive/client/drive_main.c +++ b/channels/drive/client/drive_main.c @@ -471,7 +471,7 @@ static void drive_process_irp_query_volume_information(DRIVE_DEVICE* disk, IRP* static void drive_process_irp_query_directory(DRIVE_DEVICE* disk, IRP* irp) { - char* path; + char* path = NULL; int status; DRIVE_FILE* file; BYTE InitialQuery; diff --git a/channels/parallel/client/parallel_main.c b/channels/parallel/client/parallel_main.c index 3f1e06ccc..9ac56a8ca 100644 --- a/channels/parallel/client/parallel_main.c +++ b/channels/parallel/client/parallel_main.c @@ -72,7 +72,7 @@ typedef struct _PARALLEL_DEVICE PARALLEL_DEVICE; static void parallel_process_irp_create(PARALLEL_DEVICE* parallel, IRP* irp) { - char* path; + char* path = NULL; int status; UINT32 PathLength; diff --git a/channels/serial/client/serial_main.c b/channels/serial/client/serial_main.c index c882cb7a1..83694bdee 100644 --- a/channels/serial/client/serial_main.c +++ b/channels/serial/client/serial_main.c @@ -79,7 +79,7 @@ static BOOL serial_check_fds(SERIAL_DEVICE* serial); static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp) { - char* path; + char* path = NULL; int status; SERIAL_TTY* tty; UINT32 PathLength; diff --git a/client/Windows/wf_gdi.c b/client/Windows/wf_gdi.c index fcb681a97..41e268e90 100644 --- a/client/Windows/wf_gdi.c +++ b/client/Windows/wf_gdi.c @@ -544,6 +544,19 @@ void wf_gdi_surface_bits(rdpContext* context, SURFACE_BITS_COMMAND* surface_bits free(tile_bitmap); } +void wf_gdi_surface_frame_marker(rdpContext* context, SURFACE_FRAME_MARKER* surface_frame_marker) +{ + wfInfo* wfi; + rdpSettings* settings; + + wfi = ((wfContext*) context)->wfi; + settings = wfi->instance->settings; + if (surface_frame_marker->frameAction == SURFACECMD_FRAMEACTION_END && settings->FrameAcknowledge > 0) + { + IFCALL(wfi->instance->update->SurfaceFrameAcknowledge, context, surface_frame_marker->frameId); + } +} + void wf_gdi_register_update_callbacks(rdpUpdate* update) { rdpPrimaryUpdate* primary = update->primary; @@ -575,4 +588,5 @@ void wf_gdi_register_update_callbacks(rdpUpdate* update) primary->EllipseCB = NULL; update->SurfaceBits = wf_gdi_surface_bits; + update->SurfaceFrameMarker = wf_gdi_surface_frame_marker; } diff --git a/client/Windows/wfreerdp.c b/client/Windows/wfreerdp.c index 0c4c839af..e82d1858b 100644 --- a/client/Windows/wfreerdp.c +++ b/client/Windows/wfreerdp.c @@ -259,7 +259,7 @@ BOOL wf_pre_connect(freerdp* instance) wfi->cursor = g_default_cursor; wfi->fullscreen = settings->Fullscreen; - wfi->fs_toggle = wfi->fullscreen; + wfi->fs_toggle = 1; wfi->sw_gdi = settings->SoftwareGdi; wfi->clrconv = (HCLRCONV) malloc(sizeof(CLRCONV)); @@ -279,7 +279,7 @@ BOOL wf_pre_connect(freerdp* instance) settings->DesktopHeight = i1; } - if (wfi->fs_toggle) + if (wfi->fullscreen) { settings->DesktopWidth = GetSystemMetrics(SM_CXSCREEN); settings->DesktopHeight = GetSystemMetrics(SM_CYSCREEN); diff --git a/client/X11/xf_gdi.c b/client/X11/xf_gdi.c index 7448577af..6f2683a2a 100644 --- a/client/X11/xf_gdi.c +++ b/client/X11/xf_gdi.c @@ -880,8 +880,11 @@ void xf_gdi_ellipse_cb(rdpContext* context, ELLIPSE_CB_ORDER* ellipse_cb) void xf_gdi_surface_frame_marker(rdpContext* context, SURFACE_FRAME_MARKER* surface_frame_marker) { - xfInfo* xfi = ((xfContext*) context)->xfi; + xfInfo* xfi; + rdpSettings* settings; + xfi = ((xfContext*) context)->xfi; + settings = xfi->instance->settings; switch (surface_frame_marker->frameAction) { case SURFACECMD_FRAMEACTION_BEGIN: @@ -906,6 +909,10 @@ void xf_gdi_surface_frame_marker(rdpContext* context, SURFACE_FRAME_MARKER* surf gdi_InvalidateRegion(xfi->hdc, xfi->frame_x1, xfi->frame_y1, xfi->frame_x2 - xfi->frame_x1, xfi->frame_y2 - xfi->frame_y1); } + if (settings->FrameAcknowledge > 0) + { + IFCALL(xfi->instance->update->SurfaceFrameAcknowledge, context, surface_frame_marker->frameId); + } break; } } diff --git a/include/freerdp/update.h b/include/freerdp/update.h index 526f22f0d..6aa15ea30 100644 --- a/include/freerdp/update.h +++ b/include/freerdp/update.h @@ -152,6 +152,7 @@ typedef void (*pSuppressOutput)(rdpContext* context, BYTE allow, RECTANGLE_16* a typedef void (*pSurfaceCommand)(rdpContext* context, STREAM* s); typedef void (*pSurfaceBits)(rdpContext* context, SURFACE_BITS_COMMAND* surface_bits_command); typedef void (*pSurfaceFrameMarker)(rdpContext* context, SURFACE_FRAME_MARKER* surface_frame_marker); +typedef void (*pSurfaceFrameAcknowledge)(rdpContext* context, UINT32 frameId); struct rdp_update { @@ -182,7 +183,8 @@ struct rdp_update pSurfaceCommand SurfaceCommand; /* 64 */ pSurfaceBits SurfaceBits; /* 65 */ pSurfaceFrameMarker SurfaceFrameMarker; /* 66 */ - UINT32 paddingE[80 - 67]; /* 67 */ + pSurfaceFrameAcknowledge SurfaceFrameAcknowledge; /* 67 */ + UINT32 paddingE[80 - 68]; /* 68 */ /* internal */ diff --git a/libfreerdp/core/activation.c b/libfreerdp/core/activation.c index 0554c5711..115cd1218 100644 --- a/libfreerdp/core/activation.c +++ b/libfreerdp/core/activation.c @@ -145,9 +145,7 @@ BOOL rdp_send_server_control_cooperate_pdu(rdpRdp* rdp) stream_write_UINT16(s, 0); /* grantId (2 bytes) */ stream_write_UINT32(s, 0); /* controlId (4 bytes) */ - rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_CONTROL, rdp->mcs->user_id); - - return TRUE; + return rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_CONTROL, rdp->mcs->user_id); } BOOL rdp_send_server_control_granted_pdu(rdpRdp* rdp) @@ -160,9 +158,7 @@ BOOL rdp_send_server_control_granted_pdu(rdpRdp* rdp) stream_write_UINT16(s, rdp->mcs->user_id); /* grantId (2 bytes) */ stream_write_UINT32(s, 0x03EA); /* controlId (4 bytes) */ - rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_CONTROL, rdp->mcs->user_id); - - return TRUE; + return rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_CONTROL, rdp->mcs->user_id); } BOOL rdp_send_client_control_pdu(rdpRdp* rdp, UINT16 action) @@ -288,9 +284,17 @@ BOOL rdp_recv_deactivate_all(rdpRdp* rdp, STREAM* s) */ if (stream_get_left(s) > 0) { - stream_read_UINT32(s, rdp->settings->ShareId); /* shareId (4 bytes) */ - stream_read_UINT16(s, lengthSourceDescriptor); /* lengthSourceDescriptor (2 bytes) */ - stream_seek(s, lengthSourceDescriptor); /* sourceDescriptor (should be 0x00) */ + do { + if(stream_get_left(s) < 4) + break; + stream_read_UINT32(s, rdp->settings->ShareId); /* shareId (4 bytes) */ + if(stream_get_left(s) < 2) + break; + stream_read_UINT16(s, lengthSourceDescriptor); /* lengthSourceDescriptor (2 bytes) */ + if(stream_get_left(s) < lengthSourceDescriptor) + break; + stream_seek(s, lengthSourceDescriptor); /* sourceDescriptor (should be 0x00) */ + } while(0); } rdp->state = CONNECTION_STATE_CAPABILITY; diff --git a/libfreerdp/core/capabilities.c b/libfreerdp/core/capabilities.c index 5bfe0867e..edb682902 100644 --- a/libfreerdp/core/capabilities.c +++ b/libfreerdp/core/capabilities.c @@ -2147,9 +2147,7 @@ BOOL rdp_send_demand_active(rdpRdp* rdp) rdp_write_demand_active(s, rdp->settings); - rdp_send_pdu(rdp, s, PDU_TYPE_DEMAND_ACTIVE, rdp->mcs->user_id); - - return TRUE; + return rdp_send_pdu(rdp, s, PDU_TYPE_DEMAND_ACTIVE, rdp->mcs->user_id); } BOOL rdp_recv_confirm_active(rdpRdp* rdp, STREAM* s) diff --git a/libfreerdp/core/certificate.c b/libfreerdp/core/certificate.c index 150892de7..c5834cb55 100644 --- a/libfreerdp/core/certificate.c +++ b/libfreerdp/core/certificate.c @@ -123,6 +123,29 @@ * */ +static const char *certificate_read_errors[] = { + "Certificate tag", + "TBSCertificate", + "Explicit Contextual Tag [0]", + "version", + "CertificateSerialNumber", + "AlgorithmIdentifier", + "Issuer Name", + "Validity", + "Subject Name", + "SubjectPublicKeyInfo Tag", + "subjectPublicKeyInfo::AlgorithmIdentifier", + "subjectPublicKeyInfo::subjectPublicKey", + "RSAPublicKey Tag", + "modulusLength", + "zero padding", + "modulusLength", + "modulus", + "publicExponent length", + "publicExponent" +}; + + /** * Read X.509 Certificate * @param certificate certificate module @@ -137,88 +160,105 @@ BOOL certificate_read_x509_certificate(rdpCertBlob* cert, rdpCertInfo* info) UINT32 version; int modulus_length; int exponent_length; + int error = 0; s = stream_new(0); stream_attach(s, cert->data, cert->length); + info->Modulus = 0; if(!ber_read_sequence_tag(s, &length)) /* Certificate (SEQUENCE) */ goto error1; + error++; if(!ber_read_sequence_tag(s, &length)) /* TBSCertificate (SEQUENCE) */ goto error1; + error++; - /* Explicit Contextual Tag [0] */ - if(!ber_read_contextual_tag(s, 0, &length, TRUE)) + if(!ber_read_contextual_tag(s, 0, &length, TRUE)) /* Explicit Contextual Tag [0] */ goto error1; + error++; if(!ber_read_integer(s, &version)) /* version (INTEGER) */ goto error1; + error++; version++; /* serialNumber */ if(!ber_read_integer(s, NULL)) /* CertificateSerialNumber (INTEGER) */ goto error1; + error++; /* signature */ if(!ber_read_sequence_tag(s, &length) || !stream_skip(s, length)) /* AlgorithmIdentifier (SEQUENCE) */ goto error1; + error++; /* issuer */ if(!ber_read_sequence_tag(s, &length) || !stream_skip(s, length)) /* Name (SEQUENCE) */ goto error1; + error++; /* validity */ if(!ber_read_sequence_tag(s, &length) || !stream_skip(s, length)) /* Validity (SEQUENCE) */ goto error1; + error++; /* subject */ if(!ber_read_sequence_tag(s, &length) || !stream_skip(s, length)) /* Name (SEQUENCE) */ goto error1; + error++; /* subjectPublicKeyInfo */ if(!ber_read_sequence_tag(s, &length)) /* SubjectPublicKeyInfo (SEQUENCE) */ goto error1; + error++; /* subjectPublicKeyInfo::AlgorithmIdentifier */ if(!ber_read_sequence_tag(s, &length) || !stream_skip(s, length)) /* AlgorithmIdentifier (SEQUENCE) */ goto error1; + error++; /* subjectPublicKeyInfo::subjectPublicKey */ if(!ber_read_bit_string(s, &length, &padding)) /* BIT_STRING */ goto error1; + error++; /* RSAPublicKey (SEQUENCE) */ if(!ber_read_sequence_tag(s, &length)) /* SEQUENCE */ goto error1; + error++; if(!ber_read_integer_length(s, &modulus_length)) /* modulus (INTEGER) */ goto error1; + error++; /* skip zero padding, if any */ do { - if(stream_get_left(s) < padding) + if(stream_get_left(s) < 1) goto error1; stream_peek_BYTE(s, padding); if (padding == 0) { - if(stream_get_left(s) < 1) + if(!stream_skip(s, 1)) goto error1; - stream_seek(s, 1); modulus_length--; } } while (padding == 0); + error++; if(stream_get_left(s) < modulus_length) goto error1; info->ModulusLength = modulus_length; info->Modulus = (BYTE*) malloc(info->ModulusLength); stream_read(s, info->Modulus, info->ModulusLength); + error++; if(!ber_read_integer_length(s, &exponent_length)) /* publicExponent (INTEGER) */ goto error2; - if(stream_get_left(s) < exponent_length) + error++; + if(stream_get_left(s) < exponent_length || exponent_length > 4) goto error2; stream_read(s, &info->exponent[4 - exponent_length], exponent_length); crypto_reverse(info->Modulus, info->ModulusLength); @@ -232,6 +272,7 @@ error2: free(info->Modulus); info->Modulus = 0; error1: + printf("error reading when reading certificate: part=%s error=%d\n", certificate_read_errors[error], error); stream_detach(s); stream_free(s); return FALSE; @@ -490,7 +531,8 @@ BOOL certificate_read_server_x509_certificate_chain(rdpCertificate* certificate, DEBUG_CERTIFICATE("License Server Certificate"); ret = certificate_read_x509_certificate(&certificate->x509_cert_chain->array[i], &cert_info); DEBUG_LICENSE("modulus length:%d", (int) cert_info.ModulusLength); - free(cert_info.Modulus); + if(cert_info.Modulus) + free(cert_info.Modulus); if(!ret) return FALSE; } diff --git a/libfreerdp/core/connection.c b/libfreerdp/core/connection.c index 5eb43b1ee..8f65d3dc0 100644 --- a/libfreerdp/core/connection.c +++ b/libfreerdp/core/connection.c @@ -337,7 +337,8 @@ static BOOL rdp_server_establish_keys(rdpRdp* rdp, STREAM* s) return FALSE; } - rdp_read_security_header(s, &sec_flags); + if (!rdp_read_security_header(s, &sec_flags)) + return FALSE; if ((sec_flags & SEC_EXCHANGE_PKT) == 0) { @@ -345,7 +346,12 @@ static BOOL rdp_server_establish_keys(rdpRdp* rdp, STREAM* s) return FALSE; } + if(stream_get_left(s) < 4) + return FALSE; stream_read_UINT32(s, rand_len); + if(stream_get_left(s) < rand_len + 8) /* include 8 bytes of padding */ + return FALSE; + key_len = rdp->settings->RdpServerRsaKey->ModulusLength; if (rand_len != key_len + 8) @@ -547,9 +553,7 @@ BOOL rdp_client_connect_demand_active(rdpRdp* rdp, STREAM* s) rdp->state = CONNECTION_STATE_FINALIZATION; update_reset_state(rdp->update); - rdp_client_connect_finalize(rdp); - - return TRUE; + return rdp_client_connect_finalize(rdp); } BOOL rdp_client_connect_finalize(rdpRdp* rdp) diff --git a/libfreerdp/core/gcc.c b/libfreerdp/core/gcc.c index 4d9131af4..1a761e4be 100644 --- a/libfreerdp/core/gcc.c +++ b/libfreerdp/core/gcc.c @@ -488,7 +488,7 @@ void gcc_write_user_data_header(STREAM* s, UINT16 type, UINT16 length) BOOL gcc_read_client_core_data(STREAM* s, rdpSettings* settings, UINT16 blockLength) { - char* str; + char* str = NULL; UINT32 version; UINT32 color_depth; UINT16 colorDepth = 0; @@ -518,6 +518,7 @@ BOOL gcc_read_client_core_data(STREAM* s, rdpSettings* settings, UINT16 blockLen sprintf_s(settings->ClientHostname, 31, "%s", str); settings->ClientHostname[31] = 0; free(str); + str = NULL; stream_read_UINT32(s, settings->KeyboardType); /* KeyboardType */ stream_read_UINT32(s, settings->KeyboardSubType); /* KeyboardSubType */ diff --git a/libfreerdp/core/info.c b/libfreerdp/core/info.c index 40e1aa48a..fbcbd1c12 100644 --- a/libfreerdp/core/info.c +++ b/libfreerdp/core/info.c @@ -439,7 +439,9 @@ BOOL rdp_recv_client_info(rdpRdp* rdp, STREAM* s) if (!rdp_read_header(rdp, s, &length, &channelId)) return FALSE; - rdp_read_security_header(s, &securityFlags); + if (!rdp_read_security_header(s, &securityFlags)) + return FALSE; + if ((securityFlags & SEC_INFO_PKT) == 0) return FALSE; diff --git a/libfreerdp/core/license.c b/libfreerdp/core/license.c index 3f3829d2d..c5a945493 100644 --- a/libfreerdp/core/license.c +++ b/libfreerdp/core/license.c @@ -932,9 +932,7 @@ BOOL license_send_valid_client_error_packet(rdpLicense* license) license_write_binary_blob(s, license->error_info); - license_send(license, s, ERROR_ALERT); - - return TRUE; + return license_send(license, s, ERROR_ALERT); } /** diff --git a/libfreerdp/core/mcs.c b/libfreerdp/core/mcs.c index 8ca2ccf4e..a436f3c5a 100644 --- a/libfreerdp/core/mcs.c +++ b/libfreerdp/core/mcs.c @@ -532,6 +532,7 @@ BOOL mcs_send_connect_response(rdpMcs* mcs) { STREAM* s; int length; + int ret; BYTE *bm, *em; STREAM* gcc_CCrsp; STREAM* server_data; @@ -556,12 +557,12 @@ BOOL mcs_send_connect_response(rdpMcs* mcs) tpdu_write_data(s); stream_set_mark(s, em); - transport_write(mcs->transport, s); + ret = transport_write(mcs->transport, s); stream_free(gcc_CCrsp); stream_free(server_data); - return TRUE; + return (ret < 0) ? FALSE : TRUE; } /** diff --git a/libfreerdp/core/orders.c b/libfreerdp/core/orders.c index bbccaf6b0..4232a5c67 100644 --- a/libfreerdp/core/orders.c +++ b/libfreerdp/core/orders.c @@ -501,8 +501,10 @@ static INLINE BOOL update_read_delta_points(STREAM* s, DELTA_POINT* points, int do {\ if (orderInfo->fieldFlags & (1 << (NO-1))) \ { \ - if (stream_get_left(s) < 1) \ + if (stream_get_left(s) < 1) {\ + printf("%s: error reading %s\n", __func__, #TARGET); \ return FALSE; \ + } \ stream_read_BYTE(s, TARGET); \ } \ } while(0) @@ -511,8 +513,10 @@ static INLINE BOOL update_read_delta_points(STREAM* s, DELTA_POINT* points, int do {\ if (orderInfo->fieldFlags & (1 << (NO-1))) \ { \ - if (stream_get_left(s) < 2) \ + if (stream_get_left(s) < 2) { \ + printf("%s: error reading %s or %s\n", __func__, #TARGET1, #TARGET2); \ return FALSE; \ + } \ stream_read_BYTE(s, TARGET1); \ stream_read_BYTE(s, TARGET2); \ } \ @@ -522,8 +526,10 @@ static INLINE BOOL update_read_delta_points(STREAM* s, DELTA_POINT* points, int do {\ if (orderInfo->fieldFlags & (1 << (NO-1))) \ { \ - if (stream_get_left(s) < 2) \ + if (stream_get_left(s) < 2) { \ + printf("%s: error reading %s\n", __func__, #TARGET); \ return FALSE; \ + } \ stream_read_UINT16(s, TARGET); \ } \ } while(0) @@ -531,26 +537,42 @@ static INLINE BOOL update_read_delta_points(STREAM* s, DELTA_POINT* points, int do {\ if (orderInfo->fieldFlags & (1 << (NO-1))) \ { \ - if (stream_get_left(s) < 4) \ + if (stream_get_left(s) < 4) { \ + printf("%s: error reading %s\n", __func__, #TARGET); \ return FALSE; \ + } \ stream_read_UINT32(s, TARGET); \ } \ } while(0) #define ORDER_FIELD_COORD(NO, TARGET) \ - if ((orderInfo->fieldFlags & (1 << (NO-1))) && !update_read_coord(s, &TARGET, orderInfo->deltaCoordinates)) \ - return FALSE + do { \ + if ((orderInfo->fieldFlags & (1 << (NO-1))) && !update_read_coord(s, &TARGET, orderInfo->deltaCoordinates)) { \ + printf("%s: error reading %s\n", __func__, #TARGET); \ + return FALSE; \ + } \ + } while(0) #define ORDER_FIELD_COLOR(NO, TARGET) \ - if ((orderInfo->fieldFlags & (1 << (NO-1))) && !update_read_color(s, &TARGET)) \ - return FALSE + do { \ + if ((orderInfo->fieldFlags & (1 << (NO-1))) && !update_read_color(s, &TARGET)) { \ + printf("%s: error reading %s\n", __func__, #TARGET); \ + return FALSE; \ + } \ + } while(0) + #define FIELD_SKIP_BUFFER16(s, TARGET_LEN) \ - if (stream_get_left(s) < 2) \ + do { \ + if (stream_get_left(s) < 2) {\ + printf("%s: error reading length %s\n", __func__, #TARGET_LEN); \ return FALSE; \ + }\ stream_read_UINT16(s, TARGET_LEN); \ - if (!stream_skip(s, TARGET_LEN)) \ - return FALSE - + if (!stream_skip(s, TARGET_LEN)) { \ + printf("%s: error skipping %d bytes\n", __func__, TARGET_LEN); \ + return FALSE; \ + } \ + } while(0) /* Primary Drawing Orders */ diff --git a/libfreerdp/core/peer.c b/libfreerdp/core/peer.c index e8e4fc58d..8b5a651e5 100644 --- a/libfreerdp/core/peer.c +++ b/libfreerdp/core/peer.c @@ -135,6 +135,8 @@ static BOOL peer_recv_data_pdu(freerdp_peer* client, STREAM* s) return FALSE; case DATA_PDU_TYPE_FRAME_ACKNOWLEDGE: + if(stream_get_left(s) < 4) + return FALSE; stream_read_UINT32(s, client->ack_frame_id); break; @@ -176,7 +178,8 @@ static int peer_recv_tpkt_pdu(freerdp_peer* client, STREAM* s) if (rdp->settings->DisableEncryption) { - rdp_read_security_header(s, &securityFlags); + if (!rdp_read_security_header(s, &securityFlags)) + return -1; if (securityFlags & SEC_ENCRYPT) { @@ -224,8 +227,10 @@ static int peer_recv_fastpath_pdu(freerdp_peer* client, STREAM* s) rdp = client->context->rdp; fastpath = rdp->fastpath; - if (!fastpath_read_header_rdp(fastpath, s, &length)) - return -1; + //if (!fastpath_read_header_rdp(fastpath, s, &length)) + // return -1; + + fastpath_read_header_rdp(fastpath, s, &length); if ((length == 0) || (length > stream_get_left(s))) { @@ -235,7 +240,7 @@ static int peer_recv_fastpath_pdu(freerdp_peer* client, STREAM* s) if (fastpath->encryptionFlags & FASTPATH_OUTPUT_ENCRYPTED) { - if(!rdp_decrypt(rdp, s, length, (fastpath->encryptionFlags & FASTPATH_OUTPUT_SECURE_CHECKSUM) ? SEC_SECURE_CHECKSUM : 0)) + if (!rdp_decrypt(rdp, s, length, (fastpath->encryptionFlags & FASTPATH_OUTPUT_SECURE_CHECKSUM) ? SEC_SECURE_CHECKSUM : 0)) return -1; } @@ -327,7 +332,7 @@ static BOOL peer_recv_callback(rdpTransport* transport, STREAM* s, void* extra) break; case CONNECTION_STATE_ACTIVE: - if (!peer_recv_pdu(client, s)) + if (peer_recv_pdu(client, s) < 0) return -1; break; diff --git a/libfreerdp/core/surface.c b/libfreerdp/core/surface.c index 46d3838ed..3d43a4ba5 100644 --- a/libfreerdp/core/surface.c +++ b/libfreerdp/core/surface.c @@ -161,4 +161,3 @@ void update_write_surfcmd_frame_marker(STREAM* s, UINT16 frameAction, UINT32 fra stream_write_UINT16(s, frameAction); stream_write_UINT32(s, frameId); } - diff --git a/libfreerdp/core/timezone.c b/libfreerdp/core/timezone.c index 958b0c8ab..f5cb0b46c 100644 --- a/libfreerdp/core/timezone.c +++ b/libfreerdp/core/timezone.c @@ -76,7 +76,7 @@ void rdp_write_system_time(STREAM* s, SYSTEM_TIME* system_time) BOOL rdp_read_client_time_zone(STREAM* s, rdpSettings* settings) { - char* str; + char* str = NULL; TIME_ZONE_INFO* clientTimeZone; if (stream_get_left(s) < 172) @@ -91,6 +91,7 @@ BOOL rdp_read_client_time_zone(STREAM* s, rdpSettings* settings) stream_seek(s, 64); strncpy(clientTimeZone->standardName, str, sizeof(clientTimeZone->standardName)); free(str); + str = NULL; rdp_read_system_time(s, &clientTimeZone->standardDate); /* StandardDate */ stream_read_UINT32(s, clientTimeZone->standardBias); /* StandardBias */ diff --git a/libfreerdp/core/transport.c b/libfreerdp/core/transport.c index f89410149..7d5f06d6b 100644 --- a/libfreerdp/core/transport.c +++ b/libfreerdp/core/transport.c @@ -259,6 +259,9 @@ BOOL transport_accept_nla(rdpTransport* transport) if (transport->TlsIn == NULL) transport->TlsIn = tls_new(transport->settings); + if (transport->TlsOut == NULL) + transport->TlsOut = transport->TlsIn; + transport->layer = TRANSPORT_LAYER_TLS; transport->TlsIn->sockfd = transport->TcpIn->sockfd; diff --git a/libfreerdp/core/update.c b/libfreerdp/core/update.c index cdcd1fec5..de14b8944 100644 --- a/libfreerdp/core/update.c +++ b/libfreerdp/core/update.c @@ -508,6 +508,16 @@ static void update_send_surface_frame_marker(rdpContext* context, SURFACE_FRAME_ fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_SURFCMDS, s); } +static void update_send_frame_acknowledge(rdpContext* context, UINT32 frameId) +{ + STREAM* s; + rdpRdp* rdp = context->rdp; + + s = rdp_data_pdu_init(rdp); + stream_write_UINT32(s, frameId); + rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_FRAME_ACKNOWLEDGE, rdp->mcs->user_id); +} + static void update_send_synchronize(rdpContext* context) { STREAM* s; @@ -687,6 +697,7 @@ void update_register_client_callbacks(rdpUpdate* update) { update->RefreshRect = update_send_refresh_rect; update->SuppressOutput = update_send_suppress_output; + update->SurfaceFrameAcknowledge = update_send_frame_acknowledge; } static void* update_thread(void* arg) diff --git a/libfreerdp/locale/keyboard_x11.c b/libfreerdp/locale/keyboard_x11.c index a572c551d..99c1524f3 100644 --- a/libfreerdp/locale/keyboard_x11.c +++ b/libfreerdp/locale/keyboard_x11.c @@ -232,14 +232,17 @@ UINT32 freerdp_keyboard_init_x11(UINT32 keyboardLayoutId, RDP_SCANCODE x11_keyco #else { char* keymap; - char* xkb_layout; - char* xkb_variant; + char* xkb_layout = 0; + char* xkb_variant = 0; if (keyboardLayoutId == 0) { keyboardLayoutId = freerdp_detect_keyboard_layout_from_xkb(&xkb_layout, &xkb_variant); - free(xkb_layout); - free(xkb_variant); + if (xkb_layout) + free(xkb_layout); + if (xkb_variant) + free(xkb_variant); + } keymap = freerdp_detect_keymap_from_xkb(); diff --git a/libfreerdp/rail/window.c b/libfreerdp/rail/window.c index 7819beafb..35a55e3b7 100644 --- a/libfreerdp/rail/window.c +++ b/libfreerdp/rail/window.c @@ -325,7 +325,10 @@ void rail_UpdateWindow(rdpRail* rail, rdpWindow* window) if (window->fieldFlags & WINDOW_ORDER_FIELD_TITLE) { if (window->title != NULL) + { free(window->title); + window->title = NULL; + } ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) window->titleInfo.string, window->titleInfo.length / 2, &window->title, 0, NULL, NULL); diff --git a/libfreerdp/utils/time.c b/libfreerdp/utils/time.c index 27cbfebf3..62209ec9d 100644 --- a/libfreerdp/utils/time.c +++ b/libfreerdp/utils/time.c @@ -34,7 +34,7 @@ UINT64 freerdp_windows_gmtime() time_t unix_time; UINT64 windows_time; - gmtime(&unix_time); + time(&unix_time); windows_time = freerdp_get_windows_time_from_unix_time(unix_time); return windows_time; diff --git a/server/Mac/CMakeLists.txt b/server/Mac/CMakeLists.txt index 7c50f16c8..39584139a 100644 --- a/server/Mac/CMakeLists.txt +++ b/server/Mac/CMakeLists.txt @@ -18,17 +18,48 @@ set(MODULE_NAME "mfreerdp-server") set(MODULE_PREFIX "FREERDP_SERVER_MAC") +FIND_LIBRARY(CORE_VIDEO CoreVideo) +FIND_LIBRARY(CORE_GRAPHICS CoreGraphics) +FIND_LIBRARY(APP_SERVICES ApplicationServices) +FIND_LIBRARY(IOKIT IOKit) +FIND_LIBRARY(IOSURFACE IOSurface) + set(${MODULE_PREFIX}_SRCS mfreerdp.c mfreerdp.h - mf_audin.c - mf_audin.h - mf_rdpsnd.c - mf_rdpsnd.h) + mf_interface.c + mf_interface.h + mf_event.c + mf_event.h + mf_peer.c + mf_peer.h + mf_info.c + mf_info.h + mf_mountain_lion.c + mf_mountain_lion.h) +if(CHANNEL_AUDIN_SERVER) + set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} + mf_audin.c + mf_audin.h) +endif() + +if(CHANNEL_RDPSND_SERVER) + set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} + mf_rdpsnd.c + mf_rdpsnd.h) + +endif() + add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) -set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-server) +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} + freerdp-server + ${CORE_VIDEO} + ${CORE_GRAPHICS} + ${APP_SERVICES} + ${IOKIT} + ${IOSURFACE}) set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHIC_BUILD} diff --git a/server/Mac/mf_event.c b/server/Mac/mf_event.c new file mode 100644 index 000000000..46678d7db --- /dev/null +++ b/server/Mac/mf_event.c @@ -0,0 +1,214 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * OS X Server Event Handling + * + * Copyright 2012 Corey Clayton + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include + +#include "mf_event.h" + +int mf_is_event_set(mfEventQueue* event_queue) +{ + fd_set rfds; + int num_set; + struct timeval time; + + FD_ZERO(&rfds); + FD_SET(event_queue->pipe_fd[0], &rfds); + memset(&time, 0, sizeof(time)); + num_set = select(event_queue->pipe_fd[0] + 1, &rfds, 0, 0, &time); + + return (num_set == 1); +} + +void mf_signal_event(mfEventQueue* event_queue) +{ + int length; + + length = write(event_queue->pipe_fd[1], "sig", 4); + + if (length != 4) + printf("mf_signal_event: error\n"); +} + +void mf_set_event(mfEventQueue* event_queue) +{ + int length; + + length = write(event_queue->pipe_fd[1], "sig", 4); + + if (length != 4) + printf("mf_set_event: error\n"); +} + +void mf_clear_events(mfEventQueue* event_queue) +{ + int length; + + while (mf_is_event_set(event_queue)) + { + length = read(event_queue->pipe_fd[0], &length, 4); + + if (length != 4) + printf("mf_clear_event: error\n"); + } +} + +void mf_clear_event(mfEventQueue* event_queue) +{ + int length; + + length = read(event_queue->pipe_fd[0], &length, 4); + + if (length != 4) + printf("mf_clear_event: error\n"); +} + +void mf_event_push(mfEventQueue* event_queue, mfEvent* event) +{ + pthread_mutex_lock(&(event_queue->mutex)); + + if (event_queue->count >= event_queue->size) + { + event_queue->size *= 2; + event_queue->events = (mfEvent**) realloc((void*) event_queue->events, sizeof(mfEvent*) * event_queue->size); + } + + event_queue->events[(event_queue->count)++] = event; + + pthread_mutex_unlock(&(event_queue->mutex)); + + mf_set_event(event_queue); +} + +mfEvent* mf_event_peek(mfEventQueue* event_queue) +{ + mfEvent* event; + + pthread_mutex_lock(&(event_queue->mutex)); + + if (event_queue->count < 1) + event = NULL; + else + event = event_queue->events[0]; + + pthread_mutex_unlock(&(event_queue->mutex)); + + return event; +} + +mfEvent* mf_event_pop(mfEventQueue* event_queue) +{ + mfEvent* event; + + pthread_mutex_lock(&(event_queue->mutex)); + + if (event_queue->count < 1) + return NULL; + + /* remove event signal */ + mf_clear_event(event_queue); + + event = event_queue->events[0]; + (event_queue->count)--; + + memmove(&event_queue->events[0], &event_queue->events[1], event_queue->count * sizeof(void*)); + + pthread_mutex_unlock(&(event_queue->mutex)); + + return event; +} + +mfEventRegion* mf_event_region_new(int x, int y, int width, int height) +{ + mfEventRegion* event_region = xnew(mfEventRegion); + + if (event_region != NULL) + { + event_region->x = x; + event_region->y = y; + event_region->width = width; + event_region->height = height; + } + + return event_region; +} + +void mf_event_region_free(mfEventRegion* event_region) +{ + free(event_region); +} + +mfEvent* mf_event_new(int type) +{ + mfEvent* event = xnew(mfEvent); + event->type = type; + return event; +} + +void mf_event_free(mfEvent* event) +{ + free(event); +} + +mfEventQueue* mf_event_queue_new() +{ + mfEventQueue* event_queue = xnew(mfEventQueue); + + if (event_queue != NULL) + { + event_queue->pipe_fd[0] = -1; + event_queue->pipe_fd[1] = -1; + + event_queue->size = 16; + event_queue->count = 0; + event_queue->events = (mfEvent**) xzalloc(sizeof(mfEvent*) * event_queue->size); + + if (pipe(event_queue->pipe_fd) < 0) + printf("mf_event_queue_new: pipe failed\n"); + + pthread_mutex_init(&(event_queue->mutex), NULL); + } + + return event_queue; +} + +void mf_event_queue_free(mfEventQueue* event_queue) +{ + if (event_queue->pipe_fd[0] != -1) + { + close(event_queue->pipe_fd[0]); + event_queue->pipe_fd[0] = -1; + } + + if (event_queue->pipe_fd[1] != -1) + { + close(event_queue->pipe_fd[1]); + event_queue->pipe_fd[1] = -1; + } + + pthread_mutex_destroy(&(event_queue->mutex)); +} \ No newline at end of file diff --git a/server/Mac/mf_event.h b/server/Mac/mf_event.h new file mode 100644 index 000000000..d77ce4764 --- /dev/null +++ b/server/Mac/mf_event.h @@ -0,0 +1,75 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * OS X Server Event Handling + * + * Copyright 2012 Corey Clayton + * + * 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. + */ + +#ifndef __MF_EVENT_H +#define __XMF_EVENT_H + +typedef struct mf_event mfEvent; +typedef struct mf_event_queue mfEventQueue; +typedef struct mf_event_region mfEventRegion; + +#include +#include "mfreerdp.h" + +//#include "mf_peer.h" + +enum mf_event_type +{ + MF_EVENT_TYPE_REGION, + MF_EVENT_TYPE_FRAME_TICK +}; + +struct mf_event +{ + int type; +}; + +struct mf_event_queue +{ + int size; + int count; + int pipe_fd[2]; + mfEvent** events; + pthread_mutex_t mutex; +}; + +struct mf_event_region +{ + int type; + + int x; + int y; + int width; + int height; +}; + +void mf_event_push(mfEventQueue* event_queue, mfEvent* event); +mfEvent* mf_event_peek(mfEventQueue* event_queue); +mfEvent* mf_event_pop(mfEventQueue* event_queue); + +mfEventRegion* mf_event_region_new(int x, int y, int width, int height); +void mf_event_region_free(mfEventRegion* event_region); + +mfEvent* mf_event_new(int type); +void mf_event_free(mfEvent* event); + +mfEventQueue* mf_event_queue_new(); +void mf_event_queue_free(mfEventQueue* event_queue); + +#endif /* __MF_EVENT_H */ \ No newline at end of file diff --git a/server/Mac/mf_info.c b/server/Mac/mf_info.c new file mode 100644 index 000000000..1af0ef13a --- /dev/null +++ b/server/Mac/mf_info.c @@ -0,0 +1,308 @@ +/** +* FreeRDP: A Remote Desktop Protocol Client +* FreeRDP Mac OS X Server +* +* Copyright 2012 Corey Clayton +* +* 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. +*/ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include "mf_info.h" +#include "mf_mountain_lion.h" +//#include "mf_update.h" + +static mfInfo* mfInfoInstance = NULL; +//static int _IDcount = 0; + +int mf_info_lock(mfInfo* mfi) +{ + + int status = pthread_mutex_lock(&mfi->mutex); + + switch (status) { + case 0: + return TRUE; + break; + + default: + printf("mf_info_lock failed with %#X\n", status); + return -1; + break; + } + +} + +int mf_info_try_lock(mfInfo* mfi, UINT32 ms) +{ + + int status = pthread_mutex_trylock(&mfi->mutex); + + switch (status) { + case 0: + return TRUE; + break; + + case EBUSY: + return FALSE; + break; + + default: + printf("mf_info_try_lock failed with %#X\n", status); + return -1; + break; + } + +} + +int mf_info_unlock(mfInfo* mfi) +{ + int status = pthread_mutex_unlock(&mfi->mutex); + + switch (status) { + case 0: + return TRUE; + break; + + default: + printf("mf_info_unlock failed with %#X\n", status); + return -1; + break; + } + +} + +mfInfo* mf_info_init() +{ + mfInfo* mfi; + + mfi = (mfInfo*) malloc(sizeof(mfInfo)); + memset(mfi, 0, sizeof(mfInfo)); + + + if (mfi != NULL) + { +/* HKEY hKey; + LONG status; + DWORD dwType; + DWORD dwSize; + DWORD dwValue; +*/ + + int mutexInitStatus = pthread_mutex_init(&mfi->mutex, NULL); + + if (mutexInitStatus != 0) + { + printf(_T("CreateMutex error: %#X\n"), mutexInitStatus); + } + + mfi->peers = (freerdp_peer**) malloc(sizeof(freerdp_peer*) * MF_INFO_MAXPEERS); + memset(mfi->peers, 0, sizeof(freerdp_peer*) * MF_INFO_MAXPEERS); + + //Set FPS + mfi->framesPerSecond = MF_INFO_DEFAULT_FPS; + + /*status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\FreeRDP\\Server"), 0, KEY_READ | KEY_WOW64_64KEY, &hKey); + if (status == ERROR_SUCCESS) + { + if (RegQueryValueEx(hKey, _T("FramesPerSecond"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS) + mfi->framesPerSecond = dwValue; + } + RegCloseKey(hKey);*/ + + //Set input toggle + mfi->input_disabled = FALSE; + + /*status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\FreeRDP\\Server"), 0, KEY_READ | KEY_WOW64_64KEY, &hKey); + if (status == ERROR_SUCCESS) + { + if (RegQueryValueEx(hKey, _T("DisableInput"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS) + { + if (dwValue != 0) + mfi->input_disabled = TRUE; + } + } + RegCloseKey(hKey);*/ + + + } + + return mfi; +} + +mfInfo* mf_info_get_instance() +{ + if (mfInfoInstance == NULL) + mfInfoInstance = mf_info_init(); + + return mfInfoInstance; +} + +void mf_info_peer_register(mfInfo* mfi, mfPeerContext* context) +{ + if (mf_info_lock(mfi) > 0) + { + int i; + int peerId; + if (mfi->peerCount == MF_INFO_MAXPEERS) + { + printf("TODO: socketClose on OS X\n"); + //context->socketClose = TRUE; + mf_info_unlock(mfi); + return; + } + + context->info = mfi; + + //get the offset of the top left corner of selected screen + //EnumDisplayMonitors(NULL, NULL, mf_info_monEnumCB, 0); + //_IDcount = 0; + + //initialize screen capture + if (mfi->peerCount == 0) + { + mf_mlion_display_info(&mfi->servscreen_width, &mfi->servscreen_height, &mfi->scale); + mf_mlion_screen_updates_init(); + mf_mlion_start_getting_screen_updates(); + } + + //look trhough the array of peers until an empty slot + for(i=0; ipeers[i] == NULL) + { + peerId = i; + break; + } + } + + mfi->peers[peerId] = ((rdpContext*) context)->peer; + mfi->peers[peerId]->pId = peerId; + mfi->peerCount++; + printf("Registering Peer: id=%d #=%d\n", peerId, mfi->peerCount); + + mf_info_unlock(mfi); + + //mfreerdp_server_peer_callback_event(peerId, MF_SRV_CALLBACK_EVENT_CONNECT); + } +} + +void mf_info_peer_unregister(mfInfo* mfi, mfPeerContext* context) +{ + if (mf_info_lock(mfi) > 0) + { + int peerId; + + peerId = ((rdpContext*) context)->peer->pId; + mfi->peers[peerId] = NULL; + mfi->peerCount--; + + printf("Unregistering Peer: id=%d, #=%d\n", peerId, mfi->peerCount); + + //screen capture cleanup + if (mfi->peerCount == 0) + { + mf_mlion_stop_getting_screen_updates(); + } + mf_info_unlock(mfi); + + //mfreerdp_server_peer_callback_event(peerId, MF_SRV_CALLBACK_EVENT_DISCONNECT); + } +} + +BOOL mf_info_have_updates(mfInfo* mfi) +{ + if(mfi->framesWaiting == 0) + return FALSE; + + return TRUE; +} + +void mf_info_update_changes(mfInfo* mfi) +{ +/*#ifdef WITH_WIN8 + mf_dxgi_nextFrame(mfi, mfi->framesPerSecond * 1000); +#else + GETCHANGESBUF* buf; + + buf = (GETCHANGESBUF*) mfi->changeBuffer; + mfi->nextUpdate = buf->buffer->counter; +#endif*/ +} + +void mf_info_find_invalid_region(mfInfo* mfi) +{ + mf_mlion_get_dirty_region(&mfi->invalid); +} + +void mf_info_clear_invalid_region(mfInfo* mfi) +{ + mf_mlion_clear_dirty_region(); + mfi->invalid.height = 0; + mfi->invalid.width = 0; +} + +void mf_info_invalidate_full_screen(mfInfo* mfi) +{ + mfi->invalid.x = 0; + mfi->invalid.y = 0; + mfi->invalid.height = mfi->servscreen_height; + mfi->invalid.height = mfi->servscreen_width; +} + +BOOL mf_info_have_invalid_region(mfInfo* mfi) +{ + if (mfi->invalid.width * mfi->invalid.height == 0) { + return FALSE; + } + return TRUE; +} + +void mf_info_getScreenData(mfInfo* mfi, long* width, long* height, BYTE** pBits, int* pitch) +{ + *width = mfi->invalid.width / mfi->scale; + *height = mfi->invalid.height / mfi->scale; + *pitch = mfi->servscreen_width * mfi->scale * 4; + + mf_mlion_get_pixelData(mfi->invalid.x / mfi->scale, mfi->invalid.y / mfi->scale, *width, *height, pBits); + + *pBits = *pBits + (mfi->invalid.x * 4) + (*pitch * mfi->invalid.y); + +} + +/* +BOOL CALLBACK mf_info_monEnumCB(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) +{ + mfInfo * mfi; + + mfi = mf_info_get_instance(); + + if(_IDcount == mfi->screenID) + { + mfi->servscreen_xoffset = lprcMonitor->left; + mfi->servscreen_yoffset = lprcMonitor->top; + } + + _IDcount++; + + return TRUE; +} +*/ diff --git a/server/Mac/mf_info.h b/server/Mac/mf_info.h new file mode 100644 index 000000000..7d0168862 --- /dev/null +++ b/server/Mac/mf_info.h @@ -0,0 +1,50 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * FreeRDP Mac OS X Server + * + * Copyright 2012 Corey Clayton + * + * 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. + */ + +#ifndef MF_INFO_H +#define MF_INFO_H + +#define MF_INFO_DEFAULT_FPS 1 +#define MF_INFO_MAXPEERS 1 + + + +#include +#include + +#include "mf_interface.h" + +int mf_info_lock(mfInfo* mfi); +int mf_info_try_lock(mfInfo* mfi, UINT32 ms); +int mf_info_unlock(mfInfo* mfi); + +mfInfo* mf_info_get_instance(); +void mf_info_peer_register(mfInfo* mfi, mfPeerContext* context); +void mf_info_peer_unregister(mfInfo* mfi, mfPeerContext* context); + +BOOL mf_info_have_updates(mfInfo* mfi); +void mf_info_update_changes(mfInfo* mfi); +void mf_info_find_invalid_region(mfInfo* mfi); +void mf_info_clear_invalid_region(mfInfo* mfi); +void mf_info_invalidate_full_screen(mfInfo* mfi); +BOOL mf_info_have_invalid_region(mfInfo* mfi); +void mf_info_getScreenData(mfInfo* mfi, long* width, long* height, BYTE** pBits, int* pitch); +//BOOL CALLBACK mf_info_monEnumCB(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData); + +#endif /* mf_info_H */ \ No newline at end of file diff --git a/server/Mac/mf_interface.c b/server/Mac/mf_interface.c new file mode 100644 index 000000000..e69de29bb diff --git a/server/Mac/mf_interface.h b/server/Mac/mf_interface.h new file mode 100644 index 000000000..919cb39bd --- /dev/null +++ b/server/Mac/mf_interface.h @@ -0,0 +1,116 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * FreeRDP Mac OS X Server + * + * Copyright 2012 Marc-Andre Moreau + * Copyright 2012 Corey Clayton + * + * 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. + */ + +#ifndef MF_INTERFACE_H +#define MF_INTERFACE_H + +#include + +#include +#include +#include + +#ifdef WITH_SERVER_CHANNELS +#include +#endif + +#ifdef CHANNEL_RDPSND_SERVER +#include +#include "mf_rdpsnd.h" +#endif + +#ifdef CHANNEL_AUDIN_SERVER +#include "mf_audin.h" +#endif + +typedef struct mf_info mfInfo; +typedef struct mf_peer_context mfPeerContext; + +struct mf_peer_context +{ + rdpContext _p; + + mfInfo* info; + STREAM* s; + BOOL activated; + UINT32 frame_id; + BOOL audin_open; + RFX_CONTEXT* rfx_context; + NSC_CONTEXT* nsc_context; + +#ifdef WITH_SERVER_CHANNELS + WTSVirtualChannelManager* vcm; +#endif +#ifdef CHANNEL_AUDIN_SERVER + audin_server_context* audin; +#endif + +#ifdef CHANNEL_RDPSND_SERVER + rdpsnd_server_context* rdpsnd; +#endif +}; + + +struct mf_info +{ + //STREAM* s; + + //screen and monitor info + UINT32 screenID; + UINT32 virtscreen_width; + UINT32 virtscreen_height; + UINT32 servscreen_width; + UINT32 servscreen_height; + UINT32 servscreen_xoffset; + UINT32 servscreen_yoffset; + + //int frame_idx; + int bitsPerPixel; + //HDC driverDC; + int peerCount; + int activePeerCount; + //void* changeBuffer; + int framesPerSecond; + //LPTSTR deviceKey; + //TCHAR deviceName[32]; + freerdp_peer** peers; + //BOOL mirrorDriverActive; + unsigned int framesWaiting; + UINT32 scale; + + //HANDLE snd_mutex; + //BOOL snd_stop; + + RFX_RECT invalid; + pthread_mutex_t mutex; + //BOOL updatePending; + //HANDLE updateEvent; + //HANDLE updateThread; + //HANDLE updateSemaphore; + //RFX_CONTEXT* rfx_context; + //unsigned long lastUpdate; + //unsigned long nextUpdate; + //SURFACE_BITS_COMMAND cmd; + + BOOL input_disabled; + BOOL force_all_disconnect; +}; + +#endif \ No newline at end of file diff --git a/server/Mac/mf_mountain_lion.c b/server/Mac/mf_mountain_lion.c new file mode 100644 index 000000000..c9d2c00b8 --- /dev/null +++ b/server/Mac/mf_mountain_lion.c @@ -0,0 +1,306 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * OS X Server Event Handling + * + * Copyright 2012 Corey Clayton + * + * 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 +#include +#include +#include +#include + +#include "mf_mountain_lion.h" + +dispatch_semaphore_t region_sem; +dispatch_semaphore_t data_sem; +dispatch_queue_t screen_update_q; +CGDisplayStreamRef stream; + +CGDisplayStreamUpdateRef lastUpdate = NULL; + +BYTE* localBuf = NULL; + +//CVPixelBufferRef pxbuffer = NULL; +//void *baseAddress = NULL; + +//CGContextRef bitmapcontext = NULL; + +//CGImageRef image = NULL; + +BOOL ready = FALSE; + +void (^streamHandler)(CGDisplayStreamFrameStatus, uint64_t, IOSurfaceRef, CGDisplayStreamUpdateRef) = ^(CGDisplayStreamFrameStatus status, uint64_t displayTime, IOSurfaceRef frameSurface, CGDisplayStreamUpdateRef updateRef) +{ + + dispatch_semaphore_wait(region_sem, DISPATCH_TIME_FOREVER); + + //may need to move this down + if(ready == TRUE) + { + + RFX_RECT rect; + unsigned long offset_beg; + unsigned long stride; + + rect.x = 0; + rect.y = 0; + rect.width = 0; + rect.height = 0; + mf_mlion_peek_dirty_region(&rect); + + + //lock surface + IOSurfaceLock(frameSurface, kIOSurfaceLockReadOnly, NULL); + //get pointer + void* baseAddress = IOSurfaceGetBaseAddress(frameSurface); + //copy region + + stride = IOSurfaceGetBytesPerRow(frameSurface); + //memcpy(localBuf, baseAddress + offset_beg, surflen); + for(int i = 0; i < rect.height; i++) + { + offset_beg = (stride * (rect.y + i) + (rect.x * 4)); + memcpy(localBuf + offset_beg, + baseAddress + offset_beg, + rect.width * 4); + } + + //unlock surface + IOSurfaceUnlock(frameSurface, kIOSurfaceLockReadOnly, NULL); + + ready = FALSE; + dispatch_semaphore_signal(data_sem); + } + + if (status != kCGDisplayStreamFrameStatusFrameComplete) + { + //unhandled + switch(status) + { + case kCGDisplayStreamFrameStatusFrameIdle: + printf("kCGDisplayStreamFrameStatusFrameIdle\n"); + break; + + case kCGDisplayStreamFrameStatusStopped: + printf("kCGDisplayStreamFrameStatusStopped\n"); + break; + + case kCGDisplayStreamFrameStatusFrameBlank: + printf("kCGDisplayStreamFrameStatusFrameBlank\n"); + break; + + default: + printf("Unhandled Frame Status!!!\n"); + + } + } + else if (lastUpdate == NULL) + { + CFRetain(updateRef); + lastUpdate = updateRef; + } + else + { + CGDisplayStreamUpdateRef tmpRef; + tmpRef = lastUpdate; + lastUpdate = CGDisplayStreamUpdateCreateMergedUpdate(tmpRef, updateRef); + CFRelease(tmpRef); + } + + dispatch_semaphore_signal(region_sem); +}; + +int mf_mlion_display_info(UINT32* disp_width, UINT32* disp_height, UINT32* scale) +{ + CGDirectDisplayID display_id; + + display_id = CGMainDisplayID(); + + CGDisplayModeRef mode = CGDisplayCopyDisplayMode(display_id); + + size_t pixelWidth = CGDisplayModeGetPixelWidth(mode); + //size_t pixelHeight = CGDisplayModeGetPixelHeight(mode); + + size_t wide = CGDisplayPixelsWide(display_id); + size_t high = CGDisplayPixelsHigh(display_id); + + CGDisplayModeRelease(mode); + + *disp_width = wide;//pixelWidth; + *disp_height = high;//pixelHeight; + *scale = pixelWidth / wide; + + return 0; +} + +int mf_mlion_screen_updates_init() +{ + printf("mf_mlion_screen_updates_init()\n"); + CGDirectDisplayID display_id; + + display_id = CGMainDisplayID(); + + screen_update_q = dispatch_queue_create("mfreerdp.server.screenUpdate", NULL); + + region_sem = dispatch_semaphore_create(1); + data_sem = dispatch_semaphore_create(1); + + UINT32 pixelWidth; + UINT32 pixelHeight; + UINT32 scale; + + mf_mlion_display_info(&pixelWidth, &pixelHeight, &scale); + + localBuf = malloc(pixelWidth * pixelHeight * 4); + + + stream = CGDisplayStreamCreateWithDispatchQueue(display_id, + pixelWidth, + pixelHeight, + 'BGRA', + NULL, + screen_update_q, + streamHandler); + + + return 0; + +} + +int mf_mlion_start_getting_screen_updates() +{ + CGError err; + + err = CGDisplayStreamStart(stream); + if(err != kCGErrorSuccess) + { + printf("Failed to start displaystream!! err = %d\n", err); + return 1; + } + + return 0; + +} +int mf_mlion_stop_getting_screen_updates() +{ + CGError err; + + err = CGDisplayStreamStop(stream); + if(err != kCGErrorSuccess) + { + printf("Failed to stop displaystream!! err = %d\n", err); + return 1; + } + + return 0; + + return 0; +} + +int mf_mlion_get_dirty_region(RFX_RECT* invalid) +{ + dispatch_semaphore_wait(region_sem, DISPATCH_TIME_FOREVER); + + if (lastUpdate != NULL) + { + mf_mlion_peek_dirty_region(invalid); + + //CFRelease(lastUpdate); + + //lastUpdate = NULL; + + } + + + dispatch_semaphore_signal(region_sem); + + return 0; +} + +int mf_mlion_peek_dirty_region(RFX_RECT* invalid) +{ + size_t num_rects; + CGRect dirtyRegion; + + const CGRect * rects = CGDisplayStreamUpdateGetRects(lastUpdate, kCGDisplayStreamUpdateDirtyRects, &num_rects); + + //printf("\trectangles: %zd\n", num_rects); + + if (num_rects == 0) { + //dispatch_semaphore_signal(region_sem); + return 0; + } + + dirtyRegion = *rects; + for (size_t i = 0; i < num_rects; i++) + { + dirtyRegion = CGRectUnion(dirtyRegion, *(rects+i)); + } + + invalid->x = dirtyRegion.origin.x; + invalid->y = dirtyRegion.origin.y; + invalid->height = dirtyRegion.size.height; + invalid->width = dirtyRegion.size.width; + + return 0; +} + +int mf_mlion_clear_dirty_region() +{ + dispatch_semaphore_wait(region_sem, DISPATCH_TIME_FOREVER); + + CFRelease(lastUpdate); + lastUpdate = NULL; + + dispatch_semaphore_signal(region_sem); + + + return 0; +} + +int mf_mlion_get_pixelData(long x, long y, long width, long height, BYTE** pxData) +{ + dispatch_semaphore_wait(region_sem, DISPATCH_TIME_FOREVER); + ready = TRUE; + dispatch_semaphore_wait(data_sem, DISPATCH_TIME_FOREVER); + dispatch_semaphore_signal(region_sem); + + //this second wait allows us to block until data is copied... more on this later + dispatch_semaphore_wait(data_sem, DISPATCH_TIME_FOREVER); + *pxData = localBuf; + dispatch_semaphore_signal(data_sem); + + /* + if (image != NULL) { + CGImageRelease(image); + } + image = CGDisplayCreateImageForRect( + kCGDirectMainDisplay, + CGRectMake(x, y, width, height) ); + + CGContextDrawImage( + bitmapcontext, + CGRectMake(0, 1800 - height, width, height), + image); + + *pxData = baseAddress; + + */ + + return 0; +} + diff --git a/server/Mac/mf_mountain_lion.h b/server/Mac/mf_mountain_lion.h new file mode 100644 index 000000000..fb634243e --- /dev/null +++ b/server/Mac/mf_mountain_lion.h @@ -0,0 +1,39 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * OS X Server Event Handling + * + * Copyright 2012 Corey Clayton + * + * 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. + */ + +#ifndef MF_MLION_H +#define MF_MLION_H + +#include + + +int mf_mlion_display_info(UINT32* disp_width, UINT32* dispHeight, UINT32* scale); + +int mf_mlion_screen_updates_init(); + +int mf_mlion_start_getting_screen_updates(); +int mf_mlion_stop_getting_screen_updates(); + +int mf_mlion_get_dirty_region(RFX_RECT* invalid); +int mf_mlion_peek_dirty_region(RFX_RECT* invalid); +int mf_mlion_clear_dirty_region(); + +int mf_mlion_get_pixelData(long x, long y, long width, long height, BYTE **pxData); + +#endif \ No newline at end of file diff --git a/server/Mac/mf_peer.c b/server/Mac/mf_peer.c new file mode 100644 index 000000000..5a9675ac0 --- /dev/null +++ b/server/Mac/mf_peer.c @@ -0,0 +1,608 @@ +/** +* FreeRDP: A Remote Desktop Protocol Client +* FreeRDP Mac OS X Server +* +* Copyright 2012 Corey Clayton +* +* 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +#include + +#include "mf_peer.h" +#include "mf_info.h" +#include "mf_event.h" + +#include +#include +#include + +#include "OpenGL/OpenGL.h" +#include "OpenGL/gl.h" + +#include "CoreVideo/CoreVideo.h" + +//refactor these +int info_last_sec = 0; +int info_last_nsec = 0; + +dispatch_source_t info_timer; +dispatch_queue_t info_queue; + +mfEventQueue* info_event_queue; + + +CGLContextObj glContext; +CGContextRef bmp; +CGImageRef img; + + + +BOOL mf_peer_get_fds(freerdp_peer* client, void** rfds, int* rcount) +{ + if (info_event_queue->pipe_fd[0] == -1) + return TRUE; + + rfds[*rcount] = (void *)(long) info_event_queue->pipe_fd[0]; + (*rcount)++; + + return TRUE; +} + +BOOL mf_peer_check_fds(freerdp_peer* client) +{ + mfPeerContext* context = (mfPeerContext*) client->context; + mfEvent* event; + //HGDI_RGN invalid_region; + + if (context->activated == FALSE) + return TRUE; + + event = mf_event_peek(info_event_queue); + + if (event != NULL) + { + if (event->type == MF_EVENT_TYPE_REGION) + { + printf("unhandled event\n"); + /*mfEventRegion* region = (mfEventRegion*) mf_event_pop(info_event_queue); + gdi_InvalidateRegion(xfp->hdc, region->x, region->y, region->width, region->height); + xf_event_region_free(region);*/ + } + else if (event->type == MF_EVENT_TYPE_FRAME_TICK) + { + event = mf_event_pop(info_event_queue); + + mf_peer_rfx_update(client); + + mf_event_free(event); + } + } + + return TRUE; +} + +void mf_peer_rfx_update(freerdp_peer* client) +{ + //check + mfInfo* mfi = mf_info_get_instance(); + + mf_info_find_invalid_region(mfi); + + if (mf_info_have_invalid_region(mfi) == false) { + return; + } + + + long width; + long height; + int pitch; + BYTE* dataBits = NULL; + + mf_info_getScreenData(mfi, &width, &height, &dataBits, &pitch); + + mf_info_clear_invalid_region(mfi); + + //encode + + STREAM* s; + RFX_RECT rect; + rdpUpdate* update; + mfPeerContext* mfp; + SURFACE_BITS_COMMAND* cmd; + + update = client->update; + mfp = (mfPeerContext*) client->context; + cmd = &update->surface_bits_command; + + + s = mfp->s; + stream_clear(s); + stream_set_pos(s, 0); + + UINT32 x = mfi->invalid.x / mfi->scale; + UINT32 y = mfi->invalid.y / mfi->scale; + + rect.x = 0; + rect.y = 0; + rect.width = width; + rect.height = height; + + rfx_compose_message(mfp->rfx_context, s, &rect, 1, + (BYTE*) dataBits, rect.width, rect.height, pitch); + + cmd->destLeft = x; + cmd->destTop = y; + cmd->destRight = x + rect.width; + cmd->destBottom = y + rect.height; + + + cmd->bpp = 32; + cmd->codecID = 3; + cmd->width = rect.width; + cmd->height = rect.height; + cmd->bitmapDataLength = stream_get_length(s); + cmd->bitmapData = stream_get_head(s); + + //send + + update->SurfaceBits(update->context, cmd); + + //clean up + + // note: need to stop getting new dirty rects until here + + + /* + CGColorSpaceRelease(rgbColorSpace); + CGImageRelease(image); + CGContextRelease(context); + + CVPixelBufferUnlockBaseAddress(pxbuffer, 0); + CVPixelBufferRelease(pxbuffer); + */ +} + +/* Called when we have a new peer connecting */ +void mf_peer_context_new(freerdp_peer* client, mfPeerContext* context) +{ + context->info = mf_info_get_instance(); + context->rfx_context = rfx_context_new(); + context->rfx_context->mode = RLGR3; + context->rfx_context->width = client->settings->DesktopWidth; + context->rfx_context->height = client->settings->DesktopHeight; + rfx_context_set_pixel_format(context->rfx_context, RDP_PIXEL_FORMAT_B8G8R8A8); + rfx_context_set_cpu_opt(context->rfx_context, CPU_SSE2); + + //context->nsc_context = nsc_context_new(); + //nsc_context_set_pixel_format(context->nsc_context, RDP_PIXEL_FORMAT_B8G8R8A8); + + context->s = stream_new(0xFFFF); + +#ifdef WITH_SERVER_CHANNELS + context->vcm = WTSCreateVirtualChannelManager(client); +#endif + + mf_info_peer_register(context->info, context); +} + + +/* Called after a peer disconnects */ +void mf_peer_context_free(freerdp_peer* client, mfPeerContext* context) +{ + if (context) + { + mf_info_peer_unregister(context->info, context); + + dispatch_suspend(info_timer); + + stream_free(context->s); + + rfx_context_free(context->rfx_context); + //nsc_context_free(context->nsc_context); + +#ifdef CHANNEL_AUDIN_SERVER + if (context->audin) + audin_server_context_free(context->audin); +#endif + +#ifdef CHANNEL_RDPSND_SERVER + if (context->rdpsnd) + rdpsnd_server_context_free(context->rdpsnd); +#endif + +#ifdef WITH_SERVER_CHANNELS + WTSDestroyVirtualChannelManager(context->vcm); +#endif + } +} + +/* Called when a new client connects */ +void mf_peer_init(freerdp_peer* client) +{ + client->context_size = sizeof(mfPeerContext); + client->ContextNew = (psPeerContextNew) mf_peer_context_new; + client->ContextFree = (psPeerContextFree) mf_peer_context_free; + freerdp_peer_context_new(client); + + info_event_queue = mf_event_queue_new(); + + info_queue = dispatch_queue_create("testing.101", DISPATCH_QUEUE_SERIAL); + info_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, info_queue); + + if(info_timer) + { + //printf("created timer\n"); + dispatch_source_set_timer(info_timer, DISPATCH_TIME_NOW, 33ull * NSEC_PER_MSEC, 100ull * NSEC_PER_MSEC); + dispatch_source_set_event_handler(info_timer, ^{ + //printf("dispatch\n"); + mfEvent* event = mf_event_new(MF_EVENT_TYPE_FRAME_TICK); + mf_event_push(info_event_queue, (mfEvent*) event);} + ); + dispatch_resume(info_timer); + } +} + + +BOOL mf_peer_post_connect(freerdp_peer* client) +{ + //mfPeerContext* context = (mfPeerContext*) client->context; + rdpSettings* settings = client->settings; + + printf("Client %s is activated\n", client->hostname); + + if (client->settings->AutoLogonEnabled) + { + printf(" and wants to login automatically as %s\\%s", + client->settings->Domain ? client->settings->Domain : "", + client->settings->Username); + + /* A real server may perform OS login here if NLA is not executed previously. */ + } + printf("\n"); + + mfInfo* mfi = mf_info_get_instance(); + mfi->scale = 1; + + //mfi->servscreen_width = 2880 / mfi->scale; + //mfi->servscreen_height = 1800 / mfi->scale; + UINT32 bitsPerPixel = 32; + + if ((settings->DesktopWidth != mfi->servscreen_width) || (settings->DesktopHeight != mfi->servscreen_height)) + { + printf("Client requested resolution %dx%d, but will resize to %dx%d\n", + settings->DesktopWidth, settings->DesktopHeight, mfi->servscreen_width, mfi->servscreen_height); + } + + settings->DesktopWidth = mfi->servscreen_width; + settings->DesktopHeight = mfi->servscreen_height; + settings->ColorDepth = bitsPerPixel; + + client->update->DesktopResize(client->update->context); + + + /*printf("Client requested desktop: %dx%dx%d\n", + client->settings->DesktopWidth, client->settings->DesktopHeight, client->settings->ColorDepth); + */ +#ifdef WITH_SERVER_CHANNELS + /* Iterate all channel names requested by the client and activate those supported by the server */ + int i; + for (i = 0; i < client->settings->ChannelCount; i++) + { + if (client->settings->ChannelDefArray[i].joined) + { +#ifdef CHANNEL_RDPSND_SERVER + if (strncmp(client->settings->ChannelDefArray[i].Name, "rdpsnd", 6) == 0) + { + mf_peer_rdpsnd_init(context); /* Audio Output */ + } +#endif + } + } + + /* Dynamic Virtual Channels */ +#endif + +#ifdef CHANNEL_AUDIN_SERVER + mf_peer_audin_init(context); /* Audio Input */ +#endif + + return TRUE; +} + + +BOOL mf_peer_activate(freerdp_peer* client) +{ + mfPeerContext* context = (mfPeerContext*) client->context; + + rfx_context_reset(context->rfx_context); + context->activated = TRUE; + + return TRUE; +} + +/*BOOL wf_peer_logon(freerdp_peer* client, SEC_WINNT_AUTH_IDENTITY* identity, BOOL automatic) +{ + printf("PeerLogon\n"); + + if (automatic) + { + _tprintf(_T("Logon: User:%s Domain:%s Password:%s\n"), + identity->User, identity->Domain, identity->Password); + } + + + wfreerdp_server_peer_callback_event(((rdpContext*) client->context)->peer->pId, WF_SRV_CALLBACK_EVENT_AUTH); + return TRUE; +}*/ + +void mf_peer_synchronize_event(rdpInput* input, UINT32 flags) +{ + printf("Client sent a synchronize event (flags:0x%08X)\n", flags); +} + +void mf_peer_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code) +{ + printf("Client sent a keyboard event (flags:0x%04X code:0x%04X)\n", flags, code); + + UINT16 down = 0x4000; + //UINT16 up = 0x8000; + + bool state_down = FALSE; + + if (flags == down) + { + state_down = TRUE; + } + + CGEventRef event; + event = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)code, state_down); + CGEventPost(kCGHIDEventTap, event); + CFRelease(event); +} + +void mf_peer_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code) +{ + printf("Client sent a unicode keyboard event (flags:0x%04X code:0x%04X)\n", flags, code); +} + +void mf_peer_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y) +{ + //printf("Client sent a mouse event (flags:0x%04X pos: %d,%d)\n", flags, x, y); +} + +void mf_peer_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y) +{ + //printf("Client sent an extended mouse event (flags:0x%04X pos: %d,%d)\n", flags, x, y); +} + +/*static void mf_peer_refresh_rect(rdpContext* context, BYTE count, RECTANGLE_16* areas) +{ + BYTE i; + + printf("Client requested to refresh:\n"); + + for (i = 0; i < count; i++) + { + printf(" (%d, %d) (%d, %d)\n", areas[i].left, areas[i].top, areas[i].right, areas[i].bottom); + } +}*/ + +static void mf_peer_suppress_output(rdpContext* context, BYTE allow, RECTANGLE_16* area) +{ + if (allow > 0) + { + printf("Client restore output (%d, %d) (%d, %d).\n", area->left, area->top, area->right, area->bottom); + } + else + { + printf("Client minimized and suppress output.\n"); + } +} + +void mf_peer_accepted(freerdp_listener* instance, freerdp_peer* client) +{ + pthread_t th; + + pthread_create(&th, 0, mf_peer_main_loop, client); + pthread_detach(th); +} + +/*DWORD WINAPI wf_peer_socket_listener(LPVOID lpParam) +{ + int i, fds; + int rcount; + int max_fds; + void* rfds[32]; + fd_set rfds_set; + wfPeerContext* context; + freerdp_peer* client = (freerdp_peer*) lpParam; + + ZeroMemory(rfds, sizeof(rfds)); + context = (wfPeerContext*) client->context; + + printf("PeerSocketListener\n"); + + while (1) + { + rcount = 0; + + if (client->GetFileDescriptor(client, rfds, &rcount) != TRUE) + { + printf("Failed to get peer file descriptor\n"); + break; + } + + max_fds = 0; + FD_ZERO(&rfds_set); + + for (i = 0; i < rcount; i++) + { + fds = (int)(long)(rfds[i]); + + if (fds > max_fds) + max_fds = fds; + + FD_SET(fds, &rfds_set); + } + + if (max_fds == 0) + break; + + select(max_fds + 1, &rfds_set, NULL, NULL, NULL); + + SetEvent(context->socketEvent); + WaitForSingleObject(context->socketSemaphore, INFINITE); + + if (context->socketClose) + break; + } + + printf("Exiting Peer Socket Listener Thread\n"); + + return 0; +} + +void wf_peer_read_settings(freerdp_peer* client) +{ + if (!wf_settings_read_string_ascii(HKEY_LOCAL_MACHINE, _T("Software\\FreeRDP\\Server"), _T("CertificateFile"), &(client->settings->CertificateFile))) + client->settings->CertificateFile = _strdup("server.crt"); + + if (!wf_settings_read_string_ascii(HKEY_LOCAL_MACHINE, _T("Software\\FreeRDP\\Server"), _T("PrivateKeyFile"), &(client->settings->PrivateKeyFile))) + client->settings->PrivateKeyFile = _strdup("server.key"); +}*/ + +void* mf_peer_main_loop(void* arg) +{ + int i; + int fds; + int max_fds; + int rcount; + void* rfds[32]; + fd_set rfds_set; + mfPeerContext* context; + freerdp_peer* client = (freerdp_peer*) arg; + + memset(rfds, 0, sizeof(rfds)); + + mf_peer_init(client); + + /* Initialize the real server settings here */ + client->settings->CertificateFile = _strdup("server.crt"); + client->settings->PrivateKeyFile = _strdup("server.key"); + client->settings->NlaSecurity = FALSE; + client->settings->RemoteFxCodec = TRUE; + client->settings->SuppressOutput = TRUE; + client->settings->RefreshRect = FALSE; + + client->PostConnect = mf_peer_post_connect; + client->Activate = mf_peer_activate; + + client->input->SynchronizeEvent = mf_peer_synchronize_event; + client->input->KeyboardEvent = mf_peer_keyboard_event; + client->input->UnicodeKeyboardEvent = mf_peer_unicode_keyboard_event; + client->input->MouseEvent = mf_peer_mouse_event; + client->input->ExtendedMouseEvent = mf_peer_extended_mouse_event; + + //client->update->RefreshRect = mf_peer_refresh_rect; + client->update->SuppressOutput = mf_peer_suppress_output; + + client->Initialize(client); + context = (mfPeerContext*) client->context; + + printf("We've got a client %s\n", client->local ? "(local)" : client->hostname); + + while (1) + { + rcount = 0; + + if (client->GetFileDescriptor(client, rfds, &rcount) != TRUE) + { + printf("Failed to get FreeRDP file descriptor\n"); + break; + } + if (mf_peer_get_fds(client, rfds, &rcount) != TRUE) + { + printf("Failed to get mfreerdp file descriptor\n"); + break; + } + +#ifdef WITH_SERVER_CHANNELS + WTSVirtualChannelManagerGetFileDescriptor(context->vcm, rfds, &rcount); +#endif + + max_fds = 0; + FD_ZERO(&rfds_set); + + for (i = 0; i < rcount; i++) + { + fds = (int)(long)(rfds[i]); + + if (fds > max_fds) + max_fds = fds; + + FD_SET(fds, &rfds_set); + } + + if (max_fds == 0) + break; + + if (select(max_fds + 1, &rfds_set, NULL, NULL, NULL) == -1) + { + /* these are not really errors */ + if (!((errno == EAGAIN) || + (errno == EWOULDBLOCK) || + (errno == EINPROGRESS) || + (errno == EINTR))) /* signal occurred */ + { + printf("select failed\n"); + break; + } + } + + if (client->CheckFileDescriptor(client) != TRUE) + { + printf("Failed to check freerdp file descriptor\n"); + break; + } + if ((mf_peer_check_fds(client)) != TRUE) + { + printf("Failed to check mfreerdp file descriptor\n"); + break; + } + + +#ifdef WITH_SERVER_CHANNELS + if (WTSVirtualChannelManagerCheckFileDescriptor(context->vcm) != TRUE) + break; +#endif + + } + + printf("Client %s disconnected.\n", client->local ? "(local)" : client->hostname); + + client->Disconnect(client); + freerdp_peer_context_free(client); + freerdp_peer_free(client); + + return NULL; +} \ No newline at end of file diff --git a/server/Mac/mf_peer.h b/server/Mac/mf_peer.h new file mode 100644 index 000000000..0f8096ab2 --- /dev/null +++ b/server/Mac/mf_peer.h @@ -0,0 +1,44 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * FreeRDP Mac OS X Server + * + * Copyright 2012 Corey Clayton + * + * 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. + */ + +#ifndef WF_PEER_H +#define WF_PEER_H + +#include "mf_interface.h" + +BOOL mf_peer_get_fds(freerdp_peer* client, void** rfds, int* rcount); +BOOL mf_peer_check_fds(freerdp_peer* client); + +void mf_peer_rfx_update(freerdp_peer* client); + +void mf_peer_context_new(freerdp_peer* client, mfPeerContext* context); +void mf_peer_context_free(freerdp_peer* client, mfPeerContext* context); + +void mf_peer_init(freerdp_peer* client); + +BOOL mf_peer_post_connect(freerdp_peer* client); +BOOL mf_peer_activate(freerdp_peer* client); + +void mf_peer_synchronize_event(rdpInput* input, UINT32 flags); + +void mf_peer_accepted(freerdp_listener* instance, freerdp_peer* client); + +void* mf_peer_main_loop(void* arg); + +#endif /* MF_PEER_H */ diff --git a/server/Mac/mfreerdp.c b/server/Mac/mfreerdp.c index 2056570e6..db0adc8c9 100644 --- a/server/Mac/mfreerdp.c +++ b/server/Mac/mfreerdp.c @@ -3,6 +3,7 @@ * FreeRDP Mac OS X Server * * Copyright 2012 Marc-Andre Moreau + * Copyright 2012 Corey Clayton * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,260 +30,16 @@ #include #include +#include + #include #include -#include - -#include "mf_audin.h" -#include "mf_rdpsnd.h" +#include +#include #include "mfreerdp.h" - -void mf_peer_context_new(freerdp_peer* client, mfPeerContext* context) -{ - context->rfx_context = rfx_context_new(); - context->rfx_context->mode = RLGR3; - context->rfx_context->width = client->settings->DesktopWidth; - context->rfx_context->height = client->settings->DesktopHeight; - rfx_context_set_pixel_format(context->rfx_context, RDP_PIXEL_FORMAT_R8G8B8); - - context->nsc_context = nsc_context_new(); - nsc_context_set_pixel_format(context->nsc_context, RDP_PIXEL_FORMAT_R8G8B8); - - context->s = stream_new(0xFFFF); - - context->vcm = WTSCreateVirtualChannelManager(client); -} - -void mf_peer_context_free(freerdp_peer* client, mfPeerContext* context) -{ - if (context) - { - stream_free(context->s); - - rfx_context_free(context->rfx_context); - nsc_context_free(context->nsc_context); - - if (context->audin) - audin_server_context_free(context->audin); - - if (context->rdpsnd) - rdpsnd_server_context_free(context->rdpsnd); - - WTSDestroyVirtualChannelManager(context->vcm); - } -} - -static void mf_peer_init(freerdp_peer* client) -{ - client->context_size = sizeof(mfPeerContext); - client->ContextNew = (psPeerContextNew) mf_peer_context_new; - client->ContextFree = (psPeerContextFree) mf_peer_context_free; - freerdp_peer_context_new(client); -} - -BOOL mf_peer_post_connect(freerdp_peer* client) -{ - int i; - mfPeerContext* context = (mfPeerContext*) client->context; - - printf("Client %s is activated\n", client->hostname); - - if (client->settings->AutoLogonEnabled) - { - printf(" and wants to login automatically as %s\\%s", - client->settings->Domain ? client->settings->Domain : "", - client->settings->Username); - - /* A real server may perform OS login here if NLA is not executed previously. */ - } - printf("\n"); - - printf("Client requested desktop: %dx%dx%d\n", - client->settings->DesktopWidth, client->settings->DesktopHeight, client->settings->ColorDepth); - - /* Iterate all channel names requested by the client and activate those supported by the server */ - - for (i = 0; i < client->settings->ChannelCount; i++) - { - if (client->settings->ChannelDefArray[i].joined) - { - if (strncmp(client->settings->ChannelDefArray[i].Name, "rdpsnd", 6) == 0) - { - mf_peer_rdpsnd_init(context); /* Audio Output */ - } - } - } - - /* Dynamic Virtual Channels */ - - mf_peer_audin_init(context); /* Audio Input */ - - return TRUE; -} - -BOOL mf_peer_activate(freerdp_peer* client) -{ - mfPeerContext* context = (mfPeerContext*) client->context; - - rfx_context_reset(context->rfx_context); - context->activated = TRUE; - - return TRUE; -} - -void mf_peer_synchronize_event(rdpInput* input, UINT32 flags) -{ - printf("Client sent a synchronize event (flags:0x%08X)\n", flags); -} - -void mf_peer_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code) -{ - printf("Client sent a keyboard event (flags:0x%04X code:0x%04X)\n", flags, code); -} - -void mf_peer_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code) -{ - printf("Client sent a unicode keyboard event (flags:0x%04X code:0x%04X)\n", flags, code); -} - -void mf_peer_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y) -{ - //printf("Client sent a mouse event (flags:0x%04X pos: %d,%d)\n", flags, x, y); -} - -void mf_peer_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y) -{ - //printf("Client sent an extended mouse event (flags:0x%04X pos: %d,%d)\n", flags, x, y); -} - -static void mf_peer_refresh_rect(rdpContext* context, BYTE count, RECTANGLE_16* areas) -{ - BYTE i; - - printf("Client requested to refresh:\n"); - - for (i = 0; i < count; i++) - { - printf(" (%d, %d) (%d, %d)\n", areas[i].left, areas[i].top, areas[i].right, areas[i].bottom); - } -} - -static void mf_peer_suppress_output(rdpContext* context, BYTE allow, RECTANGLE_16* area) -{ - if (allow > 0) - { - printf("Client restore output (%d, %d) (%d, %d).\n", area->left, area->top, area->right, area->bottom); - } - else - { - printf("Client minimized and suppress output.\n"); - } -} - -static void* mf_peer_main_loop(void* arg) -{ - int i; - int fds; - int max_fds; - int rcount; - void* rfds[32]; - fd_set rfds_set; - mfPeerContext* context; - freerdp_peer* client = (freerdp_peer*) arg; - - memset(rfds, 0, sizeof(rfds)); - - mf_peer_init(client); - - /* Initialize the real server settings here */ - client->settings->CertificateFile = _strdup("server.crt"); - client->settings->PrivateKeyFile = _strdup("server.key"); - client->settings->NlaSecurity = FALSE; - client->settings->RemoteFxCodec = TRUE; - client->settings->SuppressOutput = TRUE; - client->settings->RefreshRect = TRUE; - - client->PostConnect = mf_peer_post_connect; - client->Activate = mf_peer_activate; - - client->input->SynchronizeEvent = mf_peer_synchronize_event; - client->input->KeyboardEvent = mf_peer_keyboard_event; - client->input->UnicodeKeyboardEvent = mf_peer_unicode_keyboard_event; - client->input->MouseEvent = mf_peer_mouse_event; - client->input->ExtendedMouseEvent = mf_peer_extended_mouse_event; - - client->update->RefreshRect = mf_peer_refresh_rect; - client->update->SuppressOutput = mf_peer_suppress_output; - - client->Initialize(client); - context = (mfPeerContext*) client->context; - - printf("We've got a client %s\n", client->local ? "(local)" : client->hostname); - - while (1) - { - rcount = 0; - - if (client->GetFileDescriptor(client, rfds, &rcount) != TRUE) - { - printf("Failed to get FreeRDP file descriptor\n"); - break; - } - WTSVirtualChannelManagerGetFileDescriptor(context->vcm, rfds, &rcount); - - max_fds = 0; - FD_ZERO(&rfds_set); - - for (i = 0; i < rcount; i++) - { - fds = (int)(long)(rfds[i]); - - if (fds > max_fds) - max_fds = fds; - - FD_SET(fds, &rfds_set); - } - - if (max_fds == 0) - break; - - if (select(max_fds + 1, &rfds_set, NULL, NULL, NULL) == -1) - { - /* these are not really errors */ - if (!((errno == EAGAIN) || - (errno == EWOULDBLOCK) || - (errno == EINPROGRESS) || - (errno == EINTR))) /* signal occurred */ - { - printf("select failed\n"); - break; - } - } - - if (client->CheckFileDescriptor(client) != TRUE) - break; - if (WTSVirtualChannelManagerCheckFileDescriptor(context->vcm) != TRUE) - break; - } - - printf("Client %s disconnected.\n", client->local ? "(local)" : client->hostname); - - client->Disconnect(client); - freerdp_peer_context_free(client); - freerdp_peer_free(client); - - return NULL; -} - -static void mf_peer_accepted(freerdp_listener* instance, freerdp_peer* client) -{ - pthread_t th; - - pthread_create(&th, 0, mf_peer_main_loop, client); - pthread_detach(th); -} +#include "mf_peer.h" static void mf_server_main_loop(freerdp_listener* instance) { diff --git a/server/Mac/mfreerdp.h b/server/Mac/mfreerdp.h index 63344761e..153485cb2 100644 --- a/server/Mac/mfreerdp.h +++ b/server/Mac/mfreerdp.h @@ -3,6 +3,7 @@ * FreeRDP Mac OS X Server * * Copyright 2012 Marc-Andre Moreau + * Copyright 2012 Corey Clayton * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,25 +24,5 @@ #include #include #include -#include -#include -#include -#include - -struct mf_peer_context -{ - rdpContext _p; - - STREAM* s; - BOOL activated; - UINT32 frame_id; - BOOL audin_open; - RFX_CONTEXT* rfx_context; - NSC_CONTEXT* nsc_context; - WTSVirtualChannelManager* vcm; - audin_server_context* audin; - rdpsnd_server_context* rdpsnd; -}; -typedef struct mf_peer_context mfPeerContext; #endif /* MFREERDP_SERVER_H */ diff --git a/server/Windows/cli/wfreerdp.c b/server/Windows/cli/wfreerdp.c index b40e796de..c7aba35fd 100644 --- a/server/Windows/cli/wfreerdp.c +++ b/server/Windows/cli/wfreerdp.c @@ -32,14 +32,100 @@ #include "wfreerdp.h" +int IDcount = 0; + +BOOL CALLBACK moncb(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) +{ + + printf("%d\t(%d, %d), (%d, %d)\n", + IDcount, + lprcMonitor->left, + lprcMonitor->top, + lprcMonitor->right, + lprcMonitor->bottom); + + + IDcount++; + + return TRUE; +} + int main(int argc, char* argv[]) { + int index; wfServer* server; server = wfreerdp_server_new(); - if (argc == 2) - server->port = (DWORD) atoi(argv[1]); + set_screen_id(0); + + //handle args + index = 1; + while (index < argc) + { + //first the args that will cause the program to terminate + if (strcmp("--list-screens", argv[index]) == 0) + { + _TCHAR name[128]; + int width; + int height; + int bpp; + int i; + + _tprintf(_T("Detecting screens...\n")); + _tprintf(_T("\nID\tResolution\t\tName (Interface)\n\n")); + + for (i=0; ; i++) + { + if (get_screen_info(i, name, &width, &height, &bpp) != 0) + { + if ( (width * height * bpp) == 0 ) + continue; + + _tprintf(_T("%d\t%dx%dx%d\t"), i, width, height, bpp); + _tprintf(_T("%s\n"), name); + } + else + { + break; + } + } + + { + int vscreen_w; + int vscreen_h; + vscreen_w = GetSystemMetrics(SM_CXVIRTUALSCREEN); + vscreen_h = GetSystemMetrics(SM_CYVIRTUALSCREEN); + + printf("\n"); + EnumDisplayMonitors(NULL, NULL, moncb, 0); + IDcount = 0; + printf("\nVirtual Screen = %dx%d\n", vscreen_w, vscreen_h); + } + + return 0; + } + + if (strcmp("--screen", argv[index]) == 0) + { + index++; + if (index == argc) + { + printf("missing screen id parameter\n"); + return 0; + } + + set_screen_id(atoi(argv[index])); + index++; + } + + + if (index == argc - 1) + { + server->port = (DWORD) atoi(argv[index]); + break; + } + } printf("Starting server\n"); diff --git a/server/Windows/wf_dxgi.c b/server/Windows/wf_dxgi.c index c50de40af..dd5ac3421 100644 --- a/server/Windows/wf_dxgi.c +++ b/server/Windows/wf_dxgi.c @@ -65,26 +65,38 @@ ID3D11Texture2D* sStage; DXGI_OUTDUPL_FRAME_INFO FrameInfo; -int wf_dxgi_init(wfInfo* context) +int wf_dxgi_init(wfInfo* wfi) +{ + //not sure if needed + gAcquiredDesktopImage = NULL; + + if (wf_dxgi_createDevice(wfi) != 0) + { + return 1; + } + + if (wf_dxgi_getDuplication(wfi) != 0) + { + return 1; + } + + return 0; + +} + +int wf_dxgi_createDevice(wfInfo* wfi) { HRESULT status; - UINT dTop, i = 0; - DXGI_OUTPUT_DESC desc; - IDXGIOutput * pOutput; UINT DriverTypeIndex; - IDXGIDevice* DxgiDevice = NULL; - IDXGIAdapter* DxgiAdapter = NULL; - IDXGIOutput* DxgiOutput = NULL; - IDXGIOutput1* DxgiOutput1 = NULL; - - gAcquiredDesktopImage = NULL; for (DriverTypeIndex = 0; DriverTypeIndex < NumDriverTypes; ++DriverTypeIndex) { - status = D3D11CreateDevice(NULL, DriverTypes[DriverTypeIndex], NULL, D3D11_CREATE_DEVICE_DEBUG, FeatureLevels, NumFeatureLevels, + status = D3D11CreateDevice(NULL, DriverTypes[DriverTypeIndex], NULL, 0, FeatureLevels, NumFeatureLevels, D3D11_SDK_VERSION, &gDevice, &FeatureLevel, &gContext); if (SUCCEEDED(status)) break; + + _tprintf(_T("D3D11CreateDevice returned [%d] for Driver Type %d\n"), status, DriverTypes[DriverTypeIndex]); } if (FAILED(status)) @@ -92,7 +104,21 @@ int wf_dxgi_init(wfInfo* context) _tprintf(_T("Failed to create device in InitializeDx\n")); return 1; } - + + return 0; +} + +int wf_dxgi_getDuplication(wfInfo* wfi) +{ + HRESULT status; + UINT dTop, i = 0; + DXGI_OUTPUT_DESC desc; + IDXGIOutput * pOutput; + IDXGIDevice* DxgiDevice = NULL; + IDXGIAdapter* DxgiAdapter = NULL; + IDXGIOutput* DxgiOutput = NULL; + IDXGIOutput1* DxgiOutput1 = NULL; + status = gDevice->lpVtbl->QueryInterface(gDevice, &IID_IDXGIDevice, (void**) &DxgiDevice); if (FAILED(status)) @@ -135,7 +161,7 @@ int wf_dxgi_init(wfInfo* context) ++i; } - dTop = 0; + dTop = wfi->screenID; status = DxgiAdapter->lpVtbl->EnumOutputs(DxgiAdapter, dTop, &DxgiOutput); DxgiAdapter->lpVtbl->Release(DxgiAdapter); @@ -169,13 +195,14 @@ int wf_dxgi_init(wfInfo* context) return 1; } - _tprintf(_T("Failed to get duplicate output\n")); + _tprintf(_T("Failed to get duplicate output. Status = %#X\n"), status); return 1; } return 0; } + int wf_dxgi_cleanup(wfInfo* wfi) { if (wfi->framesWaiting > 0) @@ -212,7 +239,7 @@ int wf_dxgi_cleanup(wfInfo* wfi) int wf_dxgi_nextFrame(wfInfo* wfi, UINT timeout) { - HRESULT status; + HRESULT status = 0; UINT i = 0; UINT DataBufferSize = 0; BYTE* DataBuffer = NULL; @@ -238,16 +265,39 @@ int wf_dxgi_nextFrame(wfInfo* wfi, UINT timeout) if (FAILED(status)) { - //_tprintf(_T("Failed to acquire next frame\n")); - - status = gOutputDuplication->lpVtbl->ReleaseFrame(gOutputDuplication); - - if (FAILED(status)) + if (status == DXGI_ERROR_ACCESS_LOST) { - //_tprintf(_T("Failed to release frame\n")); + _tprintf(_T("Failed to acquire next frame with status=%#X\n"), status); + _tprintf(_T("Trying to reinitialize due to ACCESS LOST...")); + if (gAcquiredDesktopImage) + { + gAcquiredDesktopImage->lpVtbl->Release(gAcquiredDesktopImage); + gAcquiredDesktopImage = NULL; + } + + if (gOutputDuplication) + { + gOutputDuplication->lpVtbl->Release(gOutputDuplication); + gOutputDuplication = NULL; + } + + wf_dxgi_getDuplication(wfi); + + return 1; } + else + { + _tprintf(_T("Failed to acquire next frame with status=%#X\n"), status); + + status = gOutputDuplication->lpVtbl->ReleaseFrame(gOutputDuplication); + + if (FAILED(status)) + { + _tprintf(_T("Failed to release frame with status=%d\n"), status); + } - return 1; + return 1; + } } status = DesktopResource->lpVtbl->QueryInterface(DesktopResource, &IID_ID3D11Texture2D, (void**) &gAcquiredDesktopImage); @@ -261,10 +311,20 @@ int wf_dxgi_nextFrame(wfInfo* wfi, UINT timeout) wfi->framesWaiting = FrameInfo.AccumulatedFrames; + if (FrameInfo.AccumulatedFrames == 0) + { + status = gOutputDuplication->lpVtbl->ReleaseFrame(gOutputDuplication); + + if (FAILED(status)) + { + _tprintf(_T("Failed to release frame with status=%d\n"), status); + } + } + return 0; } -int wf_dxgi_getPixelData(wfInfo* context, BYTE** data, int* pitch, RECT* invalid) +int wf_dxgi_getPixelData(wfInfo* wfi, BYTE** data, int* pitch, RECT* invalid) { HRESULT status; D3D11_BOX Box; diff --git a/server/Windows/wf_dxgi.h b/server/Windows/wf_dxgi.h index c7b73b803..1f47ee3a8 100644 --- a/server/Windows/wf_dxgi.h +++ b/server/Windows/wf_dxgi.h @@ -24,6 +24,10 @@ int wf_dxgi_init(wfInfo* context); +int wf_dxgi_createDevice(wfInfo* context); + +int wf_dxgi_getDuplication(wfInfo* context); + int wf_dxgi_cleanup(wfInfo* context); int wf_dxgi_nextFrame(wfInfo* context, UINT timeout); diff --git a/server/Windows/wf_info.c b/server/Windows/wf_info.c index 5974f98d8..5c0b3999a 100644 --- a/server/Windows/wf_info.c +++ b/server/Windows/wf_info.c @@ -32,6 +32,7 @@ #include "wf_dxgi.h" static wfInfo* wfInfoInstance = NULL; +static int _IDcount = 0; int wf_info_lock(wfInfo* wfi) { @@ -215,6 +216,10 @@ void wf_info_peer_register(wfInfo* wfi, wfPeerContext* context) context->info = wfi; context->updateEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + //get the offset of the top left corner of selected screen + EnumDisplayMonitors(NULL, NULL, wf_info_monEnumCB, 0); + _IDcount = 0; + #ifdef WITH_WIN8 if (wfi->peerCount == 0) wf_dxgi_init(wfi); @@ -282,7 +287,7 @@ BOOL wf_info_have_updates(wfInfo* wfi) void wf_info_update_changes(wfInfo* wfi) { #ifdef WITH_WIN8 - wf_dxgi_nextFrame(wfi, wfi->framesPerSecond / 1000); + wf_dxgi_nextFrame(wfi, wfi->framesPerSecond * 1000); #else GETCHANGESBUF* buf; @@ -303,7 +308,20 @@ void wf_info_find_invalid_region(wfInfo* wfi) for (i = wfi->lastUpdate; i != wfi->nextUpdate; i = (i + 1) % MAXCHANGES_BUF) { - UnionRect(&wfi->invalid, &wfi->invalid, &buf->buffer->pointrect[i].rect); + LPRECT lpR = &buf->buffer->pointrect[i].rect; + + //need to make sure we only get updates from the selected screen + if ( (lpR->left >= wfi->servscreen_xoffset) && + (lpR->right <= (wfi->servscreen_xoffset + wfi->servscreen_width) ) && + (lpR->top >= wfi->servscreen_yoffset) && + (lpR->bottom <= (wfi->servscreen_yoffset + wfi->servscreen_height) ) ) + { + UnionRect(&wfi->invalid, &wfi->invalid, lpR); + } + else + { + continue; + } } #endif @@ -313,11 +331,13 @@ void wf_info_find_invalid_region(wfInfo* wfi) if (wfi->invalid.top < 0) wfi->invalid.top = 0; - if (wfi->invalid.right >= wfi->width) - wfi->invalid.right = wfi->width - 1; + if (wfi->invalid.right >= wfi->servscreen_width) + wfi->invalid.right = wfi->servscreen_width - 1; - if (wfi->invalid.bottom >= wfi->height) - wfi->invalid.bottom = wfi->height - 1; + if (wfi->invalid.bottom >= wfi->servscreen_height) + wfi->invalid.bottom = wfi->servscreen_height - 1; + + //printf("invalid region: (%d, %d), (%d, %d)\n", wfi->invalid.left, wfi->invalid.top, wfi->invalid.right, wfi->invalid.bottom); } void wf_info_clear_invalid_region(wfInfo* wfi) @@ -328,7 +348,7 @@ void wf_info_clear_invalid_region(wfInfo* wfi) void wf_info_invalidate_full_screen(wfInfo* wfi) { - SetRect(&wfi->invalid, 0, 0, wfi->width, wfi->height); + SetRect(&wfi->invalid, 0, 0, wfi->servscreen_width, wfi->servscreen_height); } BOOL wf_info_have_invalid_region(wfInfo* wfi) @@ -352,9 +372,26 @@ void wf_info_getScreenData(wfInfo* wfi, long* width, long* height, BYTE** pBits, *width += 1; *height += 1; - offset = (4 * wfi->invalid.left) + (wfi->invalid.top * wfi->width * 4); + offset = (4 * wfi->invalid.left) + (wfi->invalid.top * wfi->virtscreen_width * 4); *pBits = ((BYTE*) (changes->Userbuffer)) + offset; - *pitch = wfi->width * 4; + *pitch = wfi->virtscreen_width * 4; } #endif } + +BOOL CALLBACK wf_info_monEnumCB(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) +{ + wfInfo * wfi; + + wfi = wf_info_get_instance(); + + if(_IDcount == wfi->screenID) + { + wfi->servscreen_xoffset = lprcMonitor->left; + wfi->servscreen_yoffset = lprcMonitor->top; + } + + _IDcount++; + + return TRUE; +} diff --git a/server/Windows/wf_info.h b/server/Windows/wf_info.h index 3a2e8015c..8c1b6ae3f 100644 --- a/server/Windows/wf_info.h +++ b/server/Windows/wf_info.h @@ -40,5 +40,6 @@ void wf_info_clear_invalid_region(wfInfo* wfi); void wf_info_invalidate_full_screen(wfInfo* wfi); BOOL wf_info_have_invalid_region(wfInfo* wfi); void wf_info_getScreenData(wfInfo* wfi, long* width, long* height, BYTE** pBits, int* pitch); +BOOL CALLBACK wf_info_monEnumCB(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData); #endif /* WF_INFO_H */ \ No newline at end of file diff --git a/server/Windows/wf_input.c b/server/Windows/wf_input.c index 7124f2049..06b9f5350 100644 --- a/server/Windows/wf_input.c +++ b/server/Windows/wf_input.c @@ -24,6 +24,7 @@ #include #include "wf_input.h" +#include "wf_info.h" void wf_peer_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code) { @@ -82,9 +83,17 @@ void wf_peer_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y) } else { + wfInfo * wfi; + + wfi = wf_info_get_instance(); + + //width and height of primary screen (even in multimon setups width = (float) GetSystemMetrics(SM_CXSCREEN); height = (float) GetSystemMetrics(SM_CYSCREEN); + x += wfi->servscreen_xoffset; + y += wfi->servscreen_yoffset; + mouse_event.mi.dx = (LONG) ((float) x * (65535.0f / width)); mouse_event.mi.dy = (LONG) ((float) y * (65535.0f / height)); mouse_event.mi.dwFlags = MOUSEEVENTF_ABSOLUTE; @@ -138,8 +147,21 @@ void wf_peer_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT1 if (flags & PTR_FLAGS_MOVE) { - mouse_event.mi.dx = x * (0xFFFF / GetSystemMetrics(SM_CXSCREEN)); - mouse_event.mi.dy = y * (0xFFFF / GetSystemMetrics(SM_CYSCREEN)); + float width, height; + wfInfo * wfi; + + wfi = wf_info_get_instance(); + //width and height of primary screen (even in multimon setups + width = (float) GetSystemMetrics(SM_CXSCREEN); + height = (float) GetSystemMetrics(SM_CYSCREEN); + + x += wfi->servscreen_xoffset; + y += wfi->servscreen_yoffset; + + //mouse_event.mi.dx = x * (0xFFFF / width); + //mouse_event.mi.dy = y * (0xFFFF / height); + mouse_event.mi.dx = (LONG) ((float) x * (65535.0f / width)); + mouse_event.mi.dy = (LONG) ((float) y * (65535.0f / height)); mouse_event.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE; SendInput(1, &mouse_event, sizeof(INPUT)); diff --git a/server/Windows/wf_interface.c b/server/Windows/wf_interface.c index fc5512a79..79030f18a 100644 --- a/server/Windows/wf_interface.c +++ b/server/Windows/wf_interface.c @@ -36,6 +36,45 @@ cbCallback cbEvent; +int get_screen_info(int id, _TCHAR* name, int* width, int* height, int* bpp) +{ + DISPLAY_DEVICE dd; + + memset(&dd, 0, sizeof(DISPLAY_DEVICE)); + dd.cb = sizeof(DISPLAY_DEVICE); + + if (EnumDisplayDevices(NULL, id, &dd, 0) != 0) + { + HDC dc; + + if (name != NULL) + _stprintf(name, _T("%s (%s)"), dd.DeviceName, dd.DeviceString); + + dc = CreateDC(NULL, dd.DeviceName, NULL, NULL); + *width = GetDeviceCaps(dc, HORZRES); + *height = GetDeviceCaps(dc, VERTRES); + *bpp = GetDeviceCaps(dc, BITSPIXEL); + ReleaseDC(NULL, dc); + + } + else + { + return 0; + } + + return 1; +} + +void set_screen_id(int id) +{ + wfInfo* wfi; + + wfi = wf_info_get_instance(); + wfi->screenID = id; + + return; +} + DWORD WINAPI wf_server_main_loop(LPVOID lpParam) { int i, fds; diff --git a/server/Windows/wf_interface.h b/server/Windows/wf_interface.h index e7400010c..83819eac0 100644 --- a/server/Windows/wf_interface.h +++ b/server/Windows/wf_interface.h @@ -29,6 +29,7 @@ #include #include + #include #define WF_SRV_CALLBACK_EVENT_CONNECT 1 @@ -42,8 +43,18 @@ typedef struct wf_peer_context wfPeerContext; struct wf_info { STREAM* s; - int width; - int height; + + //screen and monitor info + int screenID; + int virtscreen_width; + int virtscreen_height; + int servscreen_width; + int servscreen_height; + int servscreen_xoffset; + int servscreen_yoffset; + //int width; + //int height; + int frame_idx; int bitsPerPixel; HDC driverDC; @@ -101,6 +112,9 @@ typedef struct wf_server wfServer; typedef void (__stdcall* cbCallback) (int, UINT32); +FREERDP_API int get_screen_info(int id, _TCHAR* name, int* w, int* h, int* b); +FREERDP_API void set_screen_id(int id); + FREERDP_API BOOL wfreerdp_server_start(wfServer* server); FREERDP_API BOOL wfreerdp_server_stop(wfServer* server); diff --git a/server/Windows/wf_mirage.c b/server/Windows/wf_mirage.c index 150a5caae..df3409145 100644 --- a/server/Windows/wf_mirage.c +++ b/server/Windows/wf_mirage.c @@ -26,10 +26,10 @@ /* This function will iterate over the loaded display devices until it finds the mirror device we want to load. If found, it will then copy the registry -key corresponding to the device to the context and returns TRUE. Otherwise +key corresponding to the device to the wfi and returns TRUE. Otherwise the function returns FALSE. */ -BOOL wf_mirror_driver_find_display_device(wfInfo* context) +BOOL wf_mirror_driver_find_display_device(wfInfo* wfi) { BOOL result; BOOL devFound; @@ -52,13 +52,13 @@ BOOL wf_mirror_driver_find_display_device(wfInfo* context) if (_tcsncmp(deviceInfo.DeviceKey, DEVICE_KEY_PREFIX, deviceKeyPrefixLength) == 0) { deviceKeyLength = _tcslen(deviceInfo.DeviceKey) - deviceKeyPrefixLength; - context->deviceKey = (LPTSTR) malloc((deviceKeyLength + 1) * sizeof(TCHAR)); + wfi->deviceKey = (LPTSTR) malloc((deviceKeyLength + 1) * sizeof(TCHAR)); - _tcsncpy_s(context->deviceKey, deviceKeyLength + 1, + _tcsncpy_s(wfi->deviceKey, deviceKeyLength + 1, &deviceInfo.DeviceKey[deviceKeyPrefixLength], deviceKeyLength); } - _tcsncpy_s(context->deviceName, 32, deviceInfo.DeviceName, _tcslen(deviceInfo.DeviceName)); + _tcsncpy_s(wfi->deviceName, 32, deviceInfo.DeviceName, _tcslen(deviceInfo.DeviceName)); return TRUE; } @@ -70,7 +70,7 @@ BOOL wf_mirror_driver_find_display_device(wfInfo* context) /** * This function will attempt to access the the windows registry using the device - * key stored in the current context. It will attempt to read the value of the + * key stored in the current wfi. It will attempt to read the value of the * "Attach.ToDesktop" subkey and will return TRUE if the value is already set to * val. If unable to read the subkey, this function will return FALSE. If the * subkey is not set to val it will then attempt to set it to val and return TRUE. If @@ -78,7 +78,7 @@ BOOL wf_mirror_driver_find_display_device(wfInfo* context) * FALSE. */ -BOOL wf_mirror_driver_display_device_attach(wfInfo* context, DWORD mode) +BOOL wf_mirror_driver_display_device_attach(wfInfo* wfi, DWORD mode) { HKEY hKey; LONG status; @@ -86,7 +86,7 @@ BOOL wf_mirror_driver_display_device_attach(wfInfo* context, DWORD mode) DWORD dwSize; DWORD dwValue; - status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, context->deviceKey, + status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, wfi->deviceKey, 0, KEY_READ | KEY_WOW64_64KEY, &hKey); if (status != ERROR_SUCCESS) @@ -170,7 +170,7 @@ void wf_mirror_driver_print_display_change_status(LONG status) * If unload is nonzero then the the driver will be asked to remove itself. */ -BOOL wf_mirror_driver_update(wfInfo* context, int unload) +BOOL wf_mirror_driver_update(wfInfo* wfi, int unload) { HDC dc; BOOL status; @@ -182,20 +182,25 @@ BOOL wf_mirror_driver_update(wfInfo* context, int unload) if (!unload) { + //first let's get the virtual screen dimentions + wfi->virtscreen_width = GetSystemMetrics(SM_CXVIRTUALSCREEN); + wfi->virtscreen_height = GetSystemMetrics(SM_CYVIRTUALSCREEN); + /* * Will have to come back to this for supporting non primary displays and multimonitor setups */ - dc = GetDC(NULL); - context->width = GetDeviceCaps(dc, HORZRES); - context->height = GetDeviceCaps(dc, VERTRES); - context->bitsPerPixel = GetDeviceCaps(dc, BITSPIXEL); - ReleaseDC(NULL, dc); + /*dc = GetDC(NULL); + wfi->servscreen_width = GetDeviceCaps(dc, HORZRES); + wfi->servscreen_height = GetDeviceCaps(dc, VERTRES); + wfi->bitsPerPixel = GetDeviceCaps(dc, BITSPIXEL); + ReleaseDC(NULL, dc);*/ + } else { - context->width = 0; - context->height = 0; - context->bitsPerPixel = 0; + wfi->servscreen_width = 0; + wfi->servscreen_height = 0; + wfi->bitsPerPixel = 0; } deviceMode = (DEVMODE*) malloc(sizeof(DEVMODE) + EXT_DEVMODE_SIZE_MAX); @@ -210,17 +215,17 @@ BOOL wf_mirror_driver_update(wfInfo* context, int unload) deviceMode->dmSize = sizeof(DEVMODE); deviceMode->dmDriverExtra = drvExtraSaved; - deviceMode->dmPelsWidth = context->width; - deviceMode->dmPelsHeight = context->height; - deviceMode->dmBitsPerPel = context->bitsPerPixel; - deviceMode->dmPosition.x = 0; - deviceMode->dmPosition.y = 0; + deviceMode->dmPelsWidth = wfi->virtscreen_width; + deviceMode->dmPelsHeight = wfi->virtscreen_height; + deviceMode->dmBitsPerPel = wfi->bitsPerPixel; + deviceMode->dmPosition.x = wfi->servscreen_xoffset; + deviceMode->dmPosition.y = wfi->servscreen_yoffset; deviceMode->dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_POSITION; - _tcsncpy_s(deviceMode->dmDeviceName, 32, context->deviceName, _tcslen(context->deviceName)); + _tcsncpy_s(deviceMode->dmDeviceName, 32, wfi->deviceName, _tcslen(wfi->deviceName)); - disp_change_status = ChangeDisplaySettingsEx(context->deviceName, deviceMode, NULL, CDS_UPDATEREGISTRY, NULL); + disp_change_status = ChangeDisplaySettingsEx(wfi->deviceName, deviceMode, NULL, CDS_UPDATEREGISTRY, NULL); status = (disp_change_status == DISP_CHANGE_SUCCESSFUL) ? TRUE : FALSE; @@ -230,50 +235,50 @@ BOOL wf_mirror_driver_update(wfInfo* context, int unload) return status; } -BOOL wf_mirror_driver_map_memory(wfInfo* context) +BOOL wf_mirror_driver_map_memory(wfInfo* wfi) { int status; GETCHANGESBUF* b; - context->driverDC = CreateDC(context->deviceName, NULL, NULL, NULL); + wfi->driverDC = CreateDC(wfi->deviceName, NULL, NULL, NULL); - if (context->driverDC == NULL) + if (wfi->driverDC == NULL) { - _tprintf(_T("Could not create device driver context!\n")); + _tprintf(_T("Could not create device driver wfi!\n")); return FALSE; } - context->changeBuffer = malloc(sizeof(GETCHANGESBUF)); - ZeroMemory(context->changeBuffer, sizeof(GETCHANGESBUF)); + wfi->changeBuffer = malloc(sizeof(GETCHANGESBUF)); + ZeroMemory(wfi->changeBuffer, sizeof(GETCHANGESBUF)); - status = ExtEscape(context->driverDC, dmf_esc_usm_pipe_map, 0, 0, sizeof(GETCHANGESBUF), (LPSTR) context->changeBuffer); + status = ExtEscape(wfi->driverDC, dmf_esc_usm_pipe_map, 0, 0, sizeof(GETCHANGESBUF), (LPSTR) wfi->changeBuffer); if (status <= 0) { _tprintf(_T("Failed to map shared memory from the driver! code %d\n"), status); } - b = (GETCHANGESBUF*) context->changeBuffer; + b = (GETCHANGESBUF*) wfi->changeBuffer; return TRUE; } /* Unmap the shared memory and release the DC */ -BOOL wf_mirror_driver_cleanup(wfInfo* context) +BOOL wf_mirror_driver_cleanup(wfInfo* wfi) { int status; - status = ExtEscape(context->driverDC, dmf_esc_usm_pipe_unmap, sizeof(GETCHANGESBUF), (LPSTR) context->changeBuffer, 0, 0); + status = ExtEscape(wfi->driverDC, dmf_esc_usm_pipe_unmap, sizeof(GETCHANGESBUF), (LPSTR) wfi->changeBuffer, 0, 0); if (status <= 0) { _tprintf(_T("Failed to unmap shared memory from the driver! code %d\n"), status); } - if (context->driverDC != NULL) + if (wfi->driverDC != NULL) { - status = DeleteDC(context->driverDC); + status = DeleteDC(wfi->driverDC); if (status == 0) { @@ -281,7 +286,7 @@ BOOL wf_mirror_driver_cleanup(wfInfo* context) } } - free(context->changeBuffer); + free(wfi->changeBuffer); return TRUE; } diff --git a/server/Windows/wf_mirage.h b/server/Windows/wf_mirage.h index 9287695d2..af52ab61c 100644 --- a/server/Windows/wf_mirage.h +++ b/server/Windows/wf_mirage.h @@ -200,11 +200,11 @@ typedef struct ULONG nColorBmPalEntries; } Esc_dmf_pointer_shape_get_OUT; -BOOL wf_mirror_driver_find_display_device(wfInfo* context); -BOOL wf_mirror_driver_display_device_attach(wfInfo* context, DWORD mode); -BOOL wf_mirror_driver_update(wfInfo* context, int unload); -BOOL wf_mirror_driver_map_memory(wfInfo* context); -BOOL wf_mirror_driver_cleanup(wfInfo* context); +BOOL wf_mirror_driver_find_display_device(wfInfo* wfi); +BOOL wf_mirror_driver_display_device_attach(wfInfo* wfi, DWORD mode); +BOOL wf_mirror_driver_update(wfInfo* wfi, int unload); +BOOL wf_mirror_driver_map_memory(wfInfo* wfi); +BOOL wf_mirror_driver_cleanup(wfInfo* wfi); void wf_mirror_driver_activate(wfInfo* wfi); void wf_mirror_driver_deactivate(wfInfo* wfi); diff --git a/server/Windows/wf_peer.c b/server/Windows/wf_peer.c index 8b883c4f2..8c302c54f 100644 --- a/server/Windows/wf_peer.c +++ b/server/Windows/wf_peer.c @@ -73,7 +73,6 @@ void wf_peer_init(freerdp_peer* client) BOOL wf_peer_post_connect(freerdp_peer* client) { int i; - HDC hdc; wfInfo* wfi; rdpSettings* settings; wfPeerContext* context = (wfPeerContext*) client->context; @@ -81,19 +80,23 @@ BOOL wf_peer_post_connect(freerdp_peer* client) wfi = context->info; settings = client->settings; - hdc = GetDC(NULL); - wfi->width = GetDeviceCaps(hdc, HORZRES); - wfi->height = GetDeviceCaps(hdc, VERTRES); - wfi->bitsPerPixel = GetDeviceCaps(hdc, BITSPIXEL); - ReleaseDC(NULL, hdc); + if ( + (get_screen_info(wfi->screenID, NULL, &wfi->servscreen_width, &wfi->servscreen_height, &wfi->bitsPerPixel) == 0) || + (wfi->servscreen_width == 0) || + (wfi->servscreen_height == 0) || + (wfi->bitsPerPixel == 0) ) + { + _tprintf(_T("postconnect: error getting screen info for screen %d\n"), wfi->screenID); + return FALSE; + } - if ((settings->DesktopWidth != wfi->width) || (settings->DesktopHeight != wfi->height)) + if ((settings->DesktopWidth != wfi->servscreen_width) || (settings->DesktopHeight != wfi->servscreen_height)) { printf("Client requested resolution %dx%d, but will resize to %dx%d\n", - settings->DesktopWidth, settings->DesktopHeight, wfi->width, wfi->height); + settings->DesktopWidth, settings->DesktopHeight, wfi->servscreen_width, wfi->servscreen_height); - settings->DesktopWidth = wfi->width; - settings->DesktopHeight = wfi->height; + settings->DesktopWidth = wfi->servscreen_width; + settings->DesktopHeight = wfi->servscreen_height; settings->ColorDepth = wfi->bitsPerPixel; client->update->DesktopResize(client->update->context); diff --git a/server/Windows/wf_rdpsnd.c b/server/Windows/wf_rdpsnd.c index ec90e911a..8fffe76d5 100644 --- a/server/Windows/wf_rdpsnd.c +++ b/server/Windows/wf_rdpsnd.c @@ -46,7 +46,7 @@ IDirectSoundCapture8* cap; IDirectSoundCaptureBuffer8* capBuf; DSCBUFFERDESC dscbd; -DWORD capturePos; +DWORD lastPos; #define BYTESPERSEC 176400 @@ -112,7 +112,7 @@ static void wf_peer_rdpsnd_activated(rdpsnd_server_context* context) context->SelectFormat(context, 4); context->SetVolume(context, 0x7FFF, 0x7FFF); - capturePos = 0; + lastPos = 0; CreateThread(NULL, 0, wf_rdpsnd_thread, latestPeer, 0, NULL); @@ -194,15 +194,24 @@ BOOL wf_peer_rdpsnd_init(wfPeerContext* context) DWORD WINAPI wf_rdpsnd_thread(LPVOID lpParam) { HRESULT hr; - DWORD beg, end; + DWORD beg = 0; + DWORD end = 0; DWORD diff, rate; wfPeerContext* context; wfInfo* wfi; + VOID* pbCaptureData = NULL; + DWORD dwCaptureLength = 0; + VOID* pbCaptureData2 = NULL; + DWORD dwCaptureLength2 = 0; + VOID* pbPlayData = NULL; + DWORD dwReadPos = 0; + LONG lLockSize = 0; + wfi = wf_info_get_instance(); context = (wfPeerContext*)lpParam; - rate = 1000 / 5; + rate = 1000 / 24; _tprintf(_T("Trying to start capture\n")); hr = capBuf->lpVtbl->Start(capBuf, DSCBSTART_LOOPING); @@ -214,13 +223,15 @@ DWORD WINAPI wf_rdpsnd_thread(LPVOID lpParam) while (1) { - VOID* pbCaptureData = NULL; - DWORD dwCaptureLength; - VOID* pbCaptureData2 = NULL; - DWORD dwCaptureLength2; - VOID* pbPlayData = NULL; - DWORD dwReadPos; - LONG lLockSize; + + end = GetTickCount(); + diff = end - beg; + + if (diff < rate) + { + Sleep(rate - diff); + } + beg = GetTickCount(); if (wf_rdpsnd_lock() > 0) @@ -240,9 +251,11 @@ DWORD WINAPI wf_rdpsnd_thread(LPVOID lpParam) break; } - lLockSize = dwReadPos - capturePos;//dscbd.dwBufferBytes; + lLockSize = dwReadPos - lastPos;//dscbd.dwBufferBytes; if (lLockSize < 0) lLockSize += dscbd.dwBufferBytes; + //printf("Last, read, lock = [%d, %d, %d]\n", lastPos, dwReadPos, lLockSize); + if (lLockSize == 0) { wf_rdpsnd_unlock(); @@ -250,7 +263,7 @@ DWORD WINAPI wf_rdpsnd_thread(LPVOID lpParam) } - hr = capBuf->lpVtbl->Lock(capBuf, capturePos, lLockSize, &pbCaptureData, &dwCaptureLength, &pbCaptureData2, &dwCaptureLength2, 0L); + hr = capBuf->lpVtbl->Lock(capBuf, lastPos, lLockSize, &pbCaptureData, &dwCaptureLength, &pbCaptureData2, &dwCaptureLength2, 0L); if (FAILED(hr)) { _tprintf(_T("Failed to lock sound capture buffer\n")); @@ -276,21 +289,15 @@ DWORD WINAPI wf_rdpsnd_thread(LPVOID lpParam) } //TODO keep track of location in buffer - capturePos += dwCaptureLength; - capturePos %= dscbd.dwBufferBytes; - capturePos += dwCaptureLength2; - capturePos %= dscbd.dwBufferBytes; + lastPos += dwCaptureLength; + lastPos %= dscbd.dwBufferBytes; + lastPos += dwCaptureLength2; + lastPos %= dscbd.dwBufferBytes; wf_rdpsnd_unlock(); } - end = GetTickCount(); - diff = end - beg; - - if (diff < rate) - { - Sleep(rate - diff); - } + } _tprintf(_T("Trying to stop sound capture\n")); @@ -300,7 +307,10 @@ DWORD WINAPI wf_rdpsnd_thread(LPVOID lpParam) _tprintf(_T("Failed to stop capture\n")); } _tprintf(_T("Capture stopped\n")); + capBuf->lpVtbl->Release(capBuf); + cap->lpVtbl->Release(cap); + lastPos = 0; return 0; } diff --git a/server/Windows/wf_update.c b/server/Windows/wf_update.c index d4a5ff9d9..b4faa4d65 100644 --- a/server/Windows/wf_update.c +++ b/server/Windows/wf_update.c @@ -199,8 +199,8 @@ void wf_update_encoder_reset(wfInfo* wfi) { wfi->rfx_context = rfx_context_new(); wfi->rfx_context->mode = RLGR3; - wfi->rfx_context->width = wfi->width; - wfi->rfx_context->height = wfi->height; + wfi->rfx_context->width = wfi->servscreen_width; + wfi->rfx_context->height = wfi->servscreen_height; rfx_context_set_pixel_format(wfi->rfx_context, RDP_PIXEL_FORMAT_B8G8R8A8); wfi->s = stream_new(0xFFFF); }