freerdp: merging with master

This commit is contained in:
Marc-André Moreau 2012-10-02 16:32:41 -04:00
commit 164783904a
738 changed files with 53112 additions and 13828 deletions

18
.gitignore vendored
View File

@ -6,9 +6,11 @@ install_manifest.txt
CTestTestfile.cmake
freerdp.pc
Makefile
Testing
cmake_install.cmake
CPackConfig.cmake
CPackSourceConfig.cmake
DartConfiguration.tcl
# Eclipse
*.project
@ -25,12 +27,16 @@ client/X11/xfreerdp.1
# Windows
*.vcxproj
*.vcxproj.*
*.vcproj
*.vcproj.*
*.sdf
*.sln
*.suo
*.ncb
*.opensdf
ipch
Debug
RelWithDebInfo
# Binaries
*.a
@ -39,11 +45,19 @@ Debug
*.dylib
cunit/test_freerdp
client/X11/xfreerdp
client/test/freerdp-test
client/Mac/xcode
client/Sample/sfreerdp
client/DirectFB/dfreerdp
server/test/tfreerdp-server
server/Sample/sfreerdp-server
server/X11/xfreerdp-server
xcode
# Other
*~
*.dir
Release
Win32
default.log
*Amplifier XE*
*Inspector XE*

View File

@ -4,6 +4,7 @@
# Copyright 2011 O.S. Systems Software Ltda.
# Copyright 2011 Otavio Salvador <otavio@ossystems.com.br>
# Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
# Copyright 2012 HP Development Company, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -33,16 +34,23 @@ set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/)
include(AutoVersioning)
include(ConfigOptions)
include(BuildFeatureCheck)
include(FindOptionalPackage)
include(CheckCCompilerFlag)
include(GNUInstallDirsWrapper)
# Soname versioning
set(FREERDP_VERSION_MAJOR "1")
set(FREERDP_VERSION_MINOR "0")
set(FREERDP_VERSION_REVISION "1")
set(FREERDP_VERSION_MINOR "1")
set(FREERDP_VERSION_REVISION "0")
set(FREERDP_VERSION "${FREERDP_VERSION_MAJOR}.${FREERDP_VERSION_MINOR}")
set(FREERDP_VERSION_FULL "${FREERDP_VERSION}.${FREERDP_VERSION_REVISION}")
include(GetGitRevisionDescription)
git_describe(GIT_REVISION --match "[0-9]*" --abbrev=4 --tags --always)
message(STATUS "Git Revision ${GIT_REVISION}")
# Turn on solution folders (2.8.4+)
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
# Default to release build type
if(NOT CMAKE_BUILD_TYPE)
@ -51,7 +59,25 @@ endif()
# Default to build shared libs
if(NOT DEFINED BUILD_SHARED_LIBS)
set(BUILD_SHARED_LIBS ON)
set(BUILD_SHARED_LIBS ON)
endif()
if(NOT BUILD_SHARED_LIBS AND WITH_MONOLITHIC_BUILD)
set(WITH_STATIC_PLUGINS ON)
endif()
# Configure MSVC Runtime
if(MSVC)
include(MSVCRuntime)
if(NOT DEFINED MSVC_RUNTIME)
set(MSVC_RUNTIME "dynamic")
endif()
if(${MSVC_RUNTIME} STREQUAL "static")
message(STATUS "Use the MSVC static runtime option carefully!")
message(STATUS "OpenSSL uses /MD by default, and is very picky")
message(STATUS "Random freeing errors are a common sign of runtime issues")
endif()
configure_msvc_runtime()
endif()
# Compiler-specific flags
@ -75,17 +101,31 @@ if(CMAKE_COMPILER_IS_GNUCC)
endif()
if(MSVC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Gd /MT")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /O2 /Ob2")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_X86_")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Gd")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /MT")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /O2")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Ob2")
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_AMD64_")
else()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_X86_")
endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_UNICODE")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWINPR_EXPORTS")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DFREERDP_EXPORTS")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_WIN32_WINNT=0x0501")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_CRT_SECURE_NO_WARNINGS")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWIN32_LEAN_AND_MEAN")
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR})
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR})
endif()
# config.h definition for installable headers
check_include_files(limits.h FREERDP_HAVE_LIMITS_H)
check_include_files(stdint.h FREERDP_HAVE_STDINT_H)
check_include_files(stdbool.h FREERDP_HAVE_STDBOOL_H)
check_include_files(inttypes.h FREERDP_HAVE_INTTYPES_H)
# Include files
check_include_files(fcntl.h HAVE_FCNTL_H)
check_include_files(unistd.h HAVE_UNISTD_H)
@ -93,29 +133,38 @@ check_include_files(limits.h HAVE_LIMITS_H)
check_include_files(stdint.h HAVE_STDINT_H)
check_include_files(stdbool.h HAVE_STDBOOL_H)
check_include_files(inttypes.h HAVE_INTTYPES_H)
check_include_files(sys/modem.h HAVE_SYS_MODEM_H)
check_include_files(sys/filio.h HAVE_SYS_FILIO_H)
check_include_files(sys/strtio.h HAVE_SYS_STRTIO_H)
check_struct_has_member("struct tm" tm_gmtoff time.h HAVE_TM_GMTOFF)
# Libraries that we have a hard dependency on
if(NOT DEFINED OPENSSL_INCLUDE_DIR OR NOT DEFINED OPENSSL_LIBRARIES)
find_required_package(OpenSSL)
endif()
# Mac OS X
if(APPLE)
include_directories(/opt/local/include)
link_directories(/opt/local/lib)
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -mmacosx-version-min=10.4")
if(IS_DIRECTORY /opt/local/include)
include_directories(/opt/local/include)
link_directories(/opt/local/lib)
endif()
if(WITH_CLANG)
set(CMAKE_C_COMPILER "clang")
endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mmacosx-version-min=10.4")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl-framework,CoreFoundation")
endif()
if(NOT WIN32)
find_required_package(ZLIB)
find_optional_package(PulseAudio)
find_optional_package(MacAudio)
find_optional_package(PCSC)
find_suggested_package(Cups)
if(NOT APPLE)
find_suggested_package(FFmpeg)
find_suggested_package(XRandR)
find_suggested_package(Gstreamer)
find_suggested_package(ALSA)
else(NOT APPLE)
find_optional_package(FFmpeg)
@ -127,54 +176,77 @@ set(FREERDP_DATA_PATH "${CMAKE_INSTALL_PREFIX}/share/freerdp")
set(FREERDP_KEYMAP_PATH "${FREERDP_DATA_PATH}/keymaps")
# Path to put plugins
set(FREERDP_PLUGIN_PATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/freerdp")
set(FREERDP_PLUGIN_PATH "${CMAKE_INSTALL_FULL_LIBDIR}/freerdp")
set(FREERDP_CLIENT_PLUGIN_PATH "${FREERDP_PLUGIN_PATH}/client")
set(FREERDP_SERVER_PLUGIN_PATH "${FREERDP_PLUGIN_PATH}/server")
# Path to put extensions
set(FREERDP_EXTENSION_PATH "${CMAKE_INSTALL_FULL_LIBDIR}/freerdp/extensions")
# Include directories
include_directories(${CMAKE_CURRENT_BINARY_DIR})
include_directories(${CMAKE_SOURCE_DIR}/include)
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
# Configure files
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
add_definitions("-DHAVE_CONFIG_H")
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_SOURCE_DIR}/config.h)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/include/freerdp/config.h.in ${CMAKE_CURRENT_SOURCE_DIR}/include/freerdp/config.h)
# Unit Tests
INCLUDE(CTest)
if(BUILD_TESTING)
enable_testing()
endif()
# WinPR
set(WINPR_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/winpr/include")
include_directories(${WINPR_INCLUDE_DIR})
add_subdirectory(winpr)
# Generate pkg-config
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/freerdp.pc.in ${CMAKE_CURRENT_BINARY_DIR}/freerdp.pc @ONLY)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/freerdp.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
if(NOT MSVC)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/freerdp.pc.in ${CMAKE_CURRENT_BINARY_DIR}/freerdp.pc @ONLY)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/freerdp.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
endif()
# Intel Performance Primitives
#find_optional_package(IPP)
# Build CUnit
find_optional_package(CUnit)
if(WITH_CUNIT)
enable_testing()
add_subdirectory(cunit)
add_subdirectory(cunit)
endif()
# Sub-directories
add_subdirectory(include)
add_subdirectory(libfreerdp-utils)
add_subdirectory(libfreerdp-gdi)
add_subdirectory(libfreerdp-rail)
add_subdirectory(libfreerdp-cache)
add_subdirectory(libfreerdp-codec)
add_subdirectory(libfreerdp-crypto)
add_subdirectory(libfreerdp-sspi)
add_subdirectory(libfreerdp-channels)
add_subdirectory(libfreerdp-locale)
add_subdirectory(libfreerdp-core)
if(NOT WIN32)
add_subdirectory(include)
add_subdirectory(libfreerdp)
if(WITH_CHANNELS)
add_subdirectory(channels)
endif()
option(WITH_CLIENT "Build client binaries" ON)
if(WITH_CLIENT)
add_subdirectory(client)
endif()
option(WITH_SERVER "Build server binaries" OFF)
if(WITH_SERVER)
add_subdirectory(server)
endif()
add_subdirectory(keymaps)
if(WITH_THIRD_PARTY)
add_subdirectory(third-party)
endif()
if(NOT MSVC)
add_subdirectory(keymaps)
endif()
# Source package
set(CPACK_SOURCE_IGNORE_FILES "/\\\\.git/;/\\\\.gitignore;/CMakeCache.txt")

View File

@ -1,9 +1,7 @@
# FreeRDP: A Remote Desktop Protocol Client
# FreeRDP cmake build script
#
# Copyright 2011 O.S. Systems Software Ltda.
# Copyright 2011 Otavio Salvador <otavio@ossystems.com.br>
# Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -17,10 +15,21 @@
# See the License for the specific language governing permissions and
# limitations under the License.
add_subdirectory(cliprdr)
add_subdirectory(drdynvc)
add_subdirectory(rdpdbg)
add_subdirectory(rdpdr)
add_subdirectory(rail)
add_subdirectory(rdpsnd)
set(FILENAME "ChannelOptions.cmake")
file(GLOB FILEPATHS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*/${FILENAME}")
foreach(FILEPATH ${FILEPATHS})
if(${FILEPATH} MATCHES "^([^/]*)//${FILENAME}")
string(REGEX REPLACE "^([^/]*)//${FILENAME}" "\\1" DIR ${FILEPATH})
set(CHANNEL_OPTION)
include(${FILEPATH})
if(${CHANNEL_OPTION})
message(STATUS "Adding ${CHANNEL_TYPE} channel \"${CHANNEL_SHORT_NAME}\": ${CHANNEL_LONG_NAME}")
add_subdirectory(${DIR})
endif()
endif()
endforeach(FILEPATH)
if(WITH_SERVER_CHANNELS)
add_subdirectory(server)
endif()

View File

@ -0,0 +1,31 @@
# FreeRDP: A Remote Desktop Protocol Client
# FreeRDP cmake build script
#
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
#
# 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.
set(MODULE_NAME "audin")
set(MODULE_PREFIX "CHANNEL_AUDIN")
if(WITH_CLIENT_CHANNELS)
add_subdirectory(client)
endif()
if(WITH_SERVER_CHANNELS)
add_subdirectory(server)
set(${MODULE_PREFIX}_SERVER_SRCS ${${MODULE_PREFIX}_SERVER_SRCS} PARENT_SCOPE)
set(${MODULE_PREFIX}_SERVER_LIBS ${${MODULE_PREFIX}_SERVER_LIBS} PARENT_SCOPE)
set(CHANNEL_BUILTIN_SERVER_MODULES ${CHANNEL_BUILTIN_SERVER_MODULES} ${MODULE_NAME} PARENT_SCOPE)
endif()

View File

@ -0,0 +1,10 @@
set(CHANNEL_TYPE "dynamic")
set(CHANNEL_SHORT_NAME "audin")
set(CHANNEL_LONG_NAME "Audio Input Redirection Virtual Channel Extension")
set(CHANNEL_SPECIFICATIONS "[MS-RDPEAI]")
string(TOUPPER "WITH_${CHANNEL_SHORT_NAME}" CHANNEL_OPTION)
option(${CHANNEL_OPTION} "Build ${CHANNEL_SHORT_NAME}" ON)

View File

@ -19,15 +19,18 @@
set(AUDIN_SRCS
audin_main.c
audin_main.h
)
audin_main.h)
include_directories(..)
add_library(audin ${AUDIN_SRCS})
set_target_properties(audin PROPERTIES PREFIX "")
target_link_libraries(audin freerdp-utils)
if(WITH_MONOLITHIC_BUILD)
target_link_libraries(audin freerdp)
else()
target_link_libraries(audin freerdp-utils)
endif()
install(TARGETS audin DESTINATION ${FREERDP_PLUGIN_PATH})
@ -38,4 +41,3 @@ endif()
if(WITH_PULSEAUDIO)
add_subdirectory(pulse)
endif()

View File

@ -18,8 +18,7 @@
# limitations under the License.
set(AUDIN_ALSA_SRCS
audin_alsa.c
)
audin_alsa.c)
include_directories(..)
include_directories(${ALSA_INCLUDE_DIRS})
@ -27,7 +26,12 @@ include_directories(${ALSA_INCLUDE_DIRS})
add_library(audin_alsa ${AUDIN_ALSA_SRCS})
set_target_properties(audin_alsa PROPERTIES PREFIX "")
target_link_libraries(audin_alsa freerdp-utils)
if(WITH_MONOLITHIC_BUILD)
target_link_libraries(audin_alsa freerdp)
else()
target_link_libraries(audin_alsa freerdp-utils)
endif()
target_link_libraries(audin_alsa ${ALSA_LIBRARIES})
install(TARGETS audin_alsa DESTINATION ${FREERDP_PLUGIN_PATH})

View File

@ -17,9 +17,14 @@
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <alsa/asoundlib.h>
#include <freerdp/utils/memory.h>
#include <freerdp/utils/thread.h>
@ -41,7 +46,8 @@ typedef struct _AudinALSADevice
int bytes_per_channel;
int wformat;
int block_size;
ADPCM adpcm;
FREERDP_DSP_CONTEXT* dsp_context;
freerdp_thread* thread;
@ -96,7 +102,6 @@ static boolean audin_alsa_thread_receive(AudinALSADevice* alsa, uint8* src, int
uint8* encoded_data;
int rbytes_per_frame;
int tbytes_per_frame;
uint8* resampled_data;
rbytes_per_frame = alsa->actual_channels * alsa->bytes_per_channel;
tbytes_per_frame = alsa->target_channels * alsa->bytes_per_channel;
@ -104,18 +109,18 @@ static boolean audin_alsa_thread_receive(AudinALSADevice* alsa, uint8* src, int
if ((alsa->target_rate == alsa->actual_rate) &&
(alsa->target_channels == alsa->actual_channels))
{
resampled_data = NULL;
frames = size / rbytes_per_frame;
}
else
{
resampled_data = dsp_resample(src, alsa->bytes_per_channel,
alsa->dsp_context->resample(alsa->dsp_context, src, alsa->bytes_per_channel,
alsa->actual_channels, alsa->actual_rate, size / rbytes_per_frame,
alsa->target_channels, alsa->target_rate, &frames);
alsa->target_channels, alsa->target_rate);
frames = alsa->dsp_context->resampled_frames;
DEBUG_DVC("resampled %d frames at %d to %d frames at %d",
size / rbytes_per_frame, alsa->actual_rate, frames, alsa->target_rate);
size = frames * tbytes_per_frame;
src = resampled_data;
src = alsa->dsp_context->resampled_buffer;
}
while (frames > 0)
@ -133,9 +138,11 @@ static boolean audin_alsa_thread_receive(AudinALSADevice* alsa, uint8* src, int
{
if (alsa->wformat == 0x11)
{
encoded_data = dsp_encode_ima_adpcm(&alsa->adpcm,
alsa->dsp_context->encode_ima_adpcm(alsa->dsp_context,
alsa->buffer, alsa->buffer_frames * tbytes_per_frame,
alsa->target_channels, alsa->block_size, &encoded_size);
alsa->target_channels, alsa->block_size);
encoded_data = alsa->dsp_context->adpcm_buffer;
encoded_size = alsa->dsp_context->adpcm_size;
DEBUG_DVC("encoded %d to %d",
alsa->buffer_frames * tbytes_per_frame, encoded_size);
}
@ -153,8 +160,6 @@ static boolean audin_alsa_thread_receive(AudinALSADevice* alsa, uint8* src, int
else
ret = alsa->receive(encoded_data, encoded_size, alsa->user_data);
alsa->buffer_frames = 0;
if (encoded_data != alsa->buffer)
xfree(encoded_data);
if (!ret)
break;
}
@ -162,9 +167,6 @@ static boolean audin_alsa_thread_receive(AudinALSADevice* alsa, uint8* src, int
frames -= cframes;
}
if (resampled_data)
xfree(resampled_data);
return ret;
}
@ -184,7 +186,7 @@ static void* audin_alsa_thread_func(void* arg)
alsa->buffer = (uint8*) xzalloc(tbytes_per_frame * alsa->frames_per_packet);
alsa->buffer_frames = 0;
buffer = (uint8*) xzalloc(rbytes_per_frame * alsa->frames_per_packet);
memset(&alsa->adpcm, 0, sizeof(ADPCM));
freerdp_dsp_context_reset_adpcm(alsa->dsp_context);
do
{
if ((error = snd_pcm_open(&capture_handle, alsa->device_name, SND_PCM_STREAM_CAPTURE, 0)) < 0)
@ -233,6 +235,7 @@ static void audin_alsa_free(IAudinDevice* device)
AudinALSADevice* alsa = (AudinALSADevice*) device;
freerdp_thread_free(alsa->thread);
freerdp_dsp_context_free(alsa->dsp_context);
xfree(alsa);
}
@ -365,6 +368,8 @@ int FreeRDPAudinDeviceEntry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints)
alsa->bytes_per_channel = 2;
alsa->thread = freerdp_thread_new();
alsa->dsp_context = freerdp_dsp_context_new();
pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*) alsa);
return 0;

View File

@ -17,9 +17,14 @@
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <freerdp/utils/memory.h>
#include <freerdp/utils/stream.h>
#include <freerdp/utils/load_plugin.h>
@ -248,7 +253,7 @@ static int audin_process_open(IWTSVirtualChannelCallback* pChannelCallback, STRE
DEBUG_DVC("FramesPerPacket=%d initialFormat=%d",
FramesPerPacket, initialFormat);
if (initialFormat >= callback->formats_count)
if (initialFormat >= (uint32) callback->formats_count)
{
DEBUG_WARN("invalid format index %d (total %d)",
initialFormat, callback->formats_count);
@ -279,7 +284,7 @@ static int audin_process_format_change(IWTSVirtualChannelCallback* pChannelCallb
DEBUG_DVC("NewFormat=%d", NewFormat);
if (NewFormat >= callback->formats_count)
if (NewFormat >= (uint32) callback->formats_count)
{
DEBUG_WARN("invalid format index %d (total %d)",
NewFormat, callback->formats_count);

View File

@ -20,7 +20,19 @@
#ifndef __AUDIN_MAIN_H
#define __AUDIN_MAIN_H
#include "drdynvc_types.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <freerdp/dvc.h>
#include <freerdp/types.h>
#include <freerdp/utils/debug.h>
#ifdef WITH_DEBUG_DVC
#define DEBUG_DVC(fmt, ...) DEBUG_CLASS(DVC, fmt, ## __VA_ARGS__)
#else
#define DEBUG_DVC(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
#endif
typedef boolean (*AudinReceive) (uint8* data, int size, void* user_data);

View File

@ -22,12 +22,17 @@ set(AUDIN_PULSE_SRCS
)
include_directories(..)
include_directories(${PULSE_INCLUDE_DIRS})
include_directories(${PULSEAUDIO_INCLUDE_DIR})
add_library(audin_pulse ${AUDIN_PULSE_SRCS})
set_target_properties(audin_pulse PROPERTIES PREFIX "")
target_link_libraries(audin_pulse freerdp-utils)
if(WITH_MONOLITHIC_BUILD)
target_link_libraries(audin_pulse freerdp)
else()
target_link_libraries(audin_pulse freerdp-utils)
endif()
target_link_libraries(audin_pulse ${PULSEAUDIO_LIBRARY})
install(TARGETS audin_pulse DESTINATION ${FREERDP_PLUGIN_PATH})

View File

@ -17,9 +17,14 @@
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pulse/pulseaudio.h>
#include <freerdp/types.h>
#include <freerdp/utils/memory.h>
@ -39,7 +44,8 @@ typedef struct _AudinPulseDevice
pa_stream* stream;
int format;
int block_size;
ADPCM adpcm;
FREERDP_DSP_CONTEXT* dsp_context;
int bytes_per_frame;
uint8* buffer;
@ -145,6 +151,7 @@ static void audin_pulse_free(IAudinDevice* device)
pa_threaded_mainloop_free(pulse->mainloop);
pulse->mainloop = NULL;
}
freerdp_dsp_context_free(pulse->dsp_context);
xfree(pulse);
}
@ -297,9 +304,11 @@ static void audin_pulse_stream_request_callback(pa_stream* stream, size_t length
{
if (pulse->format == 0x11)
{
encoded_data = dsp_encode_ima_adpcm(&pulse->adpcm,
pulse->dsp_context->encode_ima_adpcm(pulse->dsp_context,
pulse->buffer, pulse->buffer_frames * pulse->bytes_per_frame,
pulse->sample_spec.channels, pulse->block_size, &encoded_size);
pulse->sample_spec.channels, pulse->block_size);
encoded_data = pulse->dsp_context->adpcm_buffer;
encoded_size = pulse->dsp_context->adpcm_size;
DEBUG_DVC("encoded %d to %d",
pulse->buffer_frames * pulse->bytes_per_frame, encoded_size);
}
@ -311,8 +320,6 @@ static void audin_pulse_stream_request_callback(pa_stream* stream, size_t length
ret = pulse->receive(encoded_data, encoded_size, pulse->user_data);
pulse->buffer_frames = 0;
if (encoded_data != pulse->buffer)
xfree(encoded_data);
if (!ret)
break;
}
@ -412,7 +419,7 @@ static void audin_pulse_open(IAudinDevice* device, AudinReceive receive, void* u
pa_threaded_mainloop_unlock(pulse->mainloop);
if (state == PA_STREAM_READY)
{
memset(&pulse->adpcm, 0, sizeof(ADPCM));
freerdp_dsp_context_reset_adpcm(pulse->dsp_context);
pulse->buffer = xzalloc(pulse->bytes_per_frame * pulse->frames_per_packet);
pulse->buffer_frames = 0;
DEBUG_DVC("connected");
@ -443,6 +450,8 @@ int FreeRDPAudinDeviceEntry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints)
strncpy(pulse->device_name, (char*)data->data[2], sizeof(pulse->device_name));
}
pulse->dsp_context = freerdp_dsp_context_new();
pulse->mainloop = pa_threaded_mainloop_new();
if (!pulse->mainloop)
{

View File

@ -0,0 +1,28 @@
# FreeRDP: A Remote Desktop Protocol Client
# FreeRDP cmake build script
#
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
#
# 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.
set(MODULE_PREFIX "CHANNEL_AUDIN_SERVER")
set(${MODULE_PREFIX}_SRCS
audin.c
PARENT_SCOPE)
if(WITH_MONOLITHIC_BUILD)
set(${MODULE_PREFIX}_LIBS freerdp PARENT_SCOPE)
else()
set(${MODULE_PREFIX}_LIBS freerdp-utils freerdp-channels PARENT_SCOPE)
endif()

View File

@ -0,0 +1,435 @@
/**
* FreeRDP: A Remote Desktop Protocol client.
* Server Audio Input Virtual Channel
*
* Copyright 2012 Vic Lee
*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <freerdp/utils/stream.h>
#include <freerdp/utils/memory.h>
#include <freerdp/utils/dsp.h>
#include <freerdp/utils/thread.h>
#include <freerdp/utils/wait_obj.h>
#include <freerdp/channels/wtsvc.h>
#include <freerdp/server/audin.h>
#define MSG_SNDIN_VERSION 0x01
#define MSG_SNDIN_FORMATS 0x02
#define MSG_SNDIN_OPEN 0x03
#define MSG_SNDIN_OPEN_REPLY 0x04
#define MSG_SNDIN_DATA_INCOMING 0x05
#define MSG_SNDIN_DATA 0x06
#define MSG_SNDIN_FORMATCHANGE 0x07
typedef struct _audin_server
{
audin_server_context context;
void* audin_channel;
freerdp_thread* audin_channel_thread;
FREERDP_DSP_CONTEXT* dsp_context;
boolean opened;
} audin_server;
static void audin_server_select_format(audin_server_context* context, int client_format_index)
{
audin_server* audin = (audin_server*) context;
if (client_format_index >= context->num_client_formats)
return;
context->selected_client_format = client_format_index;
if (audin->opened)
{
/* TODO: send MSG_SNDIN_FORMATCHANGE */
}
}
static void audin_server_send_version(audin_server* audin, STREAM* s)
{
stream_write_uint8(s, MSG_SNDIN_VERSION);
stream_write_uint32(s, 1); /* Version (4 bytes) */
WTSVirtualChannelWrite(audin->audin_channel, stream_get_head(s), stream_get_length(s), NULL);
}
static boolean audin_server_recv_version(audin_server* audin, STREAM* s, uint32 length)
{
uint32 Version;
if (length < 4)
return false;
stream_read_uint32(s, Version);
if (Version < 1)
return false;
return true;
}
static void audin_server_send_formats(audin_server* audin, STREAM* s)
{
int i;
uint32 nAvgBytesPerSec;
stream_set_pos(s, 0);
stream_write_uint8(s, MSG_SNDIN_FORMATS);
stream_write_uint32(s, audin->context.num_server_formats); /* NumFormats (4 bytes) */
stream_write_uint32(s, 0); /* cbSizeFormatsPacket (4 bytes), client-to-server only */
for (i = 0; i < audin->context.num_server_formats; i++)
{
nAvgBytesPerSec = audin->context.server_formats[i].nSamplesPerSec *
audin->context.server_formats[i].nChannels *
audin->context.server_formats[i].wBitsPerSample / 8;
stream_check_size(s, 18);
stream_write_uint16(s, audin->context.server_formats[i].wFormatTag);
stream_write_uint16(s, audin->context.server_formats[i].nChannels);
stream_write_uint32(s, audin->context.server_formats[i].nSamplesPerSec);
stream_write_uint32(s, nAvgBytesPerSec);
stream_write_uint16(s, audin->context.server_formats[i].nBlockAlign);
stream_write_uint16(s, audin->context.server_formats[i].wBitsPerSample);
stream_write_uint16(s, audin->context.server_formats[i].cbSize);
if (audin->context.server_formats[i].cbSize)
{
stream_check_size(s, audin->context.server_formats[i].cbSize);
stream_write(s, audin->context.server_formats[i].data,
audin->context.server_formats[i].cbSize);
}
}
WTSVirtualChannelWrite(audin->audin_channel, stream_get_head(s), stream_get_length(s), NULL);
}
static boolean audin_server_recv_formats(audin_server* audin, STREAM* s, uint32 length)
{
int i;
if (length < 8)
return false;
stream_read_uint32(s, audin->context.num_client_formats); /* NumFormats (4 bytes) */
stream_seek_uint32(s); /* cbSizeFormatsPacket (4 bytes) */
length -= 8;
if (audin->context.num_client_formats <= 0)
return false;
audin->context.client_formats = xzalloc(audin->context.num_client_formats * sizeof(rdpsndFormat));
for (i = 0; i < audin->context.num_client_formats; i++)
{
if (length < 18)
{
xfree(audin->context.client_formats);
audin->context.client_formats = NULL;
return false;
}
stream_read_uint16(s, audin->context.client_formats[i].wFormatTag);
stream_read_uint16(s, audin->context.client_formats[i].nChannels);
stream_read_uint32(s, audin->context.client_formats[i].nSamplesPerSec);
stream_seek_uint32(s); /* nAvgBytesPerSec */
stream_read_uint16(s, audin->context.client_formats[i].nBlockAlign);
stream_read_uint16(s, audin->context.client_formats[i].wBitsPerSample);
stream_read_uint16(s, audin->context.client_formats[i].cbSize);
if (audin->context.client_formats[i].cbSize > 0)
{
stream_seek(s, audin->context.client_formats[i].cbSize);
}
}
IFCALL(audin->context.Opening, &audin->context);
return true;
}
static void audin_server_send_open(audin_server* audin, STREAM* s)
{
if (audin->context.selected_client_format < 0)
return;
audin->opened = true;
stream_set_pos(s, 0);
stream_write_uint8(s, MSG_SNDIN_OPEN);
stream_write_uint32(s, audin->context.frames_per_packet); /* FramesPerPacket (4 bytes) */
stream_write_uint32(s, audin->context.selected_client_format); /* initialFormat (4 bytes) */
/*
* [MS-RDPEAI] 3.2.5.1.6
* The second format specify the format that SHOULD be used to capture data from
* the actual audio input device.
*/
stream_write_uint16(s, 1); /* wFormatTag = PCM */
stream_write_uint16(s, 2); /* nChannels */
stream_write_uint32(s, 44100); /* nSamplesPerSec */
stream_write_uint32(s, 44100 * 2 * 2); /* nAvgBytesPerSec */
stream_write_uint16(s, 4); /* nBlockAlign */
stream_write_uint16(s, 16); /* wBitsPerSample */
stream_write_uint16(s, 0); /* cbSize */
WTSVirtualChannelWrite(audin->audin_channel, stream_get_head(s), stream_get_length(s), NULL);
}
static boolean audin_server_recv_open_reply(audin_server* audin, STREAM* s, uint32 length)
{
uint32 Result;
if (length < 4)
return false;
stream_read_uint32(s, Result);
IFCALL(audin->context.OpenResult, &audin->context, Result);
return true;
}
static boolean audin_server_recv_data(audin_server* audin, STREAM* s, uint32 length)
{
rdpsndFormat* format;
int sbytes_per_sample;
int sbytes_per_frame;
uint8* src;
int size;
int frames;
if (audin->context.selected_client_format < 0)
return false;
format = &audin->context.client_formats[audin->context.selected_client_format];
if (format->wFormatTag == 2)
{
audin->dsp_context->decode_ms_adpcm(audin->dsp_context,
stream_get_tail(s), length, format->nChannels, format->nBlockAlign);
size = audin->dsp_context->adpcm_size;
src = audin->dsp_context->adpcm_buffer;
sbytes_per_sample = 2;
sbytes_per_frame = format->nChannels * 2;
}
else if (format->wFormatTag == 0x11)
{
audin->dsp_context->decode_ima_adpcm(audin->dsp_context,
stream_get_tail(s), length, format->nChannels, format->nBlockAlign);
size = audin->dsp_context->adpcm_size;
src = audin->dsp_context->adpcm_buffer;
sbytes_per_sample = 2;
sbytes_per_frame = format->nChannels * 2;
}
else
{
size = length;
src = stream_get_tail(s);
sbytes_per_sample = format->wBitsPerSample / 8;
sbytes_per_frame = format->nChannels * sbytes_per_sample;
}
if (format->nSamplesPerSec == audin->context.dst_format.nSamplesPerSec && format->nChannels == audin->context.dst_format.nChannels)
{
frames = size / sbytes_per_frame;
}
else
{
audin->dsp_context->resample(audin->dsp_context, src, sbytes_per_sample,
format->nChannels, format->nSamplesPerSec, size / sbytes_per_frame,
audin->context.dst_format.nChannels, audin->context.dst_format.nSamplesPerSec);
frames = audin->dsp_context->resampled_frames;
src = audin->dsp_context->resampled_buffer;
}
IFCALL(audin->context.ReceiveSamples, &audin->context, src, frames);
return true;
}
static void* audin_server_thread_func(void* arg)
{
void* fd;
STREAM* s;
void* buffer;
uint8 MessageId;
boolean ready = false;
uint32 bytes_returned = 0;
audin_server* audin = (audin_server*) arg;
freerdp_thread* thread = audin->audin_channel_thread;
if (WTSVirtualChannelQuery(audin->audin_channel, WTSVirtualFileHandle, &buffer, &bytes_returned) == true)
{
fd = *((void**)buffer);
WTSFreeMemory(buffer);
thread->signals[thread->num_signals++] = wait_obj_new_with_fd(fd);
}
/* Wait for the client to confirm that the Audio Input dynamic channel is ready */
while (1)
{
freerdp_thread_wait(thread);
if (freerdp_thread_is_stopped(thread))
break;
if (WTSVirtualChannelQuery(audin->audin_channel, WTSVirtualChannelReady, &buffer, &bytes_returned) == false)
break;
ready = *((boolean*)buffer);
WTSFreeMemory(buffer);
if (ready)
break;
}
s = stream_new(4096);
if (ready)
{
audin_server_send_version(audin, s);
}
while (ready)
{
freerdp_thread_wait(thread);
if (freerdp_thread_is_stopped(thread))
break;
stream_set_pos(s, 0);
if (WTSVirtualChannelRead(audin->audin_channel, 0, stream_get_head(s),
stream_get_size(s), &bytes_returned) == false)
{
if (bytes_returned == 0)
break;
stream_check_size(s, (int) bytes_returned);
if (WTSVirtualChannelRead(audin->audin_channel, 0, stream_get_head(s),
stream_get_size(s), &bytes_returned) == false)
break;
}
if (bytes_returned < 1)
continue;
stream_read_uint8(s, MessageId);
bytes_returned--;
switch (MessageId)
{
case MSG_SNDIN_VERSION:
if (audin_server_recv_version(audin, s, bytes_returned))
audin_server_send_formats(audin, s);
break;
case MSG_SNDIN_FORMATS:
if (audin_server_recv_formats(audin, s, bytes_returned))
audin_server_send_open(audin, s);
break;
case MSG_SNDIN_OPEN_REPLY:
audin_server_recv_open_reply(audin, s, bytes_returned);
break;
case MSG_SNDIN_DATA_INCOMING:
break;
case MSG_SNDIN_DATA:
audin_server_recv_data(audin, s, bytes_returned);
break;
case MSG_SNDIN_FORMATCHANGE:
break;
default:
printf("audin_server_thread_func: unknown MessageId %d\n", MessageId);
break;
}
}
stream_free(s);
WTSVirtualChannelClose(audin->audin_channel);
audin->audin_channel = NULL;
freerdp_thread_quit(thread);
return NULL;
}
static boolean audin_server_open(audin_server_context* context)
{
audin_server* audin = (audin_server*) context;
if (audin->audin_channel_thread == NULL)
{
audin->audin_channel = WTSVirtualChannelOpenEx(context->vcm, "AUDIO_INPUT", WTS_CHANNEL_OPTION_DYNAMIC);
if (audin->audin_channel == NULL)
return false;
audin->audin_channel_thread = freerdp_thread_new();
freerdp_thread_start(audin->audin_channel_thread, audin_server_thread_func, audin);
return true;
}
return false;
}
static boolean audin_server_close(audin_server_context* context)
{
audin_server* audin = (audin_server*) context;
if (audin->audin_channel_thread)
{
freerdp_thread_stop(audin->audin_channel_thread);
freerdp_thread_free(audin->audin_channel_thread);
audin->audin_channel_thread = NULL;
}
if (audin->audin_channel)
{
WTSVirtualChannelClose(audin->audin_channel);
audin->audin_channel = NULL;
}
audin->context.selected_client_format = -1;
return true;
}
audin_server_context* audin_server_context_new(WTSVirtualChannelManager* vcm)
{
audin_server* audin;
audin = xnew(audin_server);
audin->context.vcm = vcm;
audin->context.selected_client_format = -1;
audin->context.frames_per_packet = 4096;
audin->context.SelectFormat = audin_server_select_format;
audin->context.Open = audin_server_open;
audin->context.Close = audin_server_close;
audin->dsp_context = freerdp_dsp_context_new();
return (audin_server_context*) audin;
}
void audin_server_context_free(audin_server_context* context)
{
audin_server* audin = (audin_server*) context;
audin_server_close(context);
if (audin->dsp_context)
freerdp_dsp_context_free(audin->dsp_context);
if (audin->context.client_formats)
xfree(audin->context.client_formats);
xfree(audin);
}

View File

@ -1,9 +1,7 @@
# FreeRDP: A Remote Desktop Protocol Client
# FreeRDP cmake build script
#
# Copyright 2011 O.S. Systems Software Ltda.
# Copyright 2011 Otavio Salvador <otavio@ossystems.com.br>
# Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -17,17 +15,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
set(CLIPRDR_SRCS
cliprdr_constants.h
cliprdr_format.c
cliprdr_format.h
cliprdr_main.c
cliprdr_main.h
)
if(WITH_CLIENT_CHANNELS)
add_subdirectory(client)
endif()
add_library(cliprdr ${CLIPRDR_SRCS})
set_target_properties(cliprdr PROPERTIES PREFIX "")
target_link_libraries(cliprdr freerdp-utils)
install(TARGETS cliprdr DESTINATION ${FREERDP_PLUGIN_PATH})

View File

@ -0,0 +1,10 @@
set(CHANNEL_TYPE "static")
set(CHANNEL_SHORT_NAME "cliprdr")
set(CHANNEL_LONG_NAME "Clipboard Virtual Channel Extension")
set(CHANNEL_SPECIFICATIONS "[MS-RDPECLIP]")
string(TOUPPER "WITH_${CHANNEL_SHORT_NAME}" CHANNEL_OPTION)
option(${CHANNEL_OPTION} "Build ${CHANNEL_SHORT_NAME}" ON)

View File

@ -0,0 +1,36 @@
# FreeRDP: A Remote Desktop Protocol Client
# FreeRDP cmake build script
#
# Copyright 2011 O.S. Systems Software Ltda.
# Copyright 2011 Otavio Salvador <otavio@ossystems.com.br>
# Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
#
# 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.
set(CLIPRDR_SRCS
cliprdr_constants.h
cliprdr_format.c
cliprdr_format.h
cliprdr_main.c
cliprdr_main.h)
add_library(cliprdr ${CLIPRDR_SRCS})
set_target_properties(cliprdr PROPERTIES PREFIX "")
if(WITH_MONOLITHIC_BUILD)
target_link_libraries(cliprdr freerdp)
else()
target_link_libraries(cliprdr freerdp-utils)
endif()
install(TARGETS cliprdr DESTINATION ${FREERDP_PLUGIN_PATH})

View File

@ -18,6 +18,10 @@
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -139,8 +143,7 @@ void cliprdr_process_short_format_names(cliprdrPlugin* cliprdr, STREAM* s, uint3
}
else
{
format_name->name = freerdp_uniconv_in(cliprdr->uniconv, s->p, 32);
format_name->length = strlen(format_name->name);
format_name->length = freerdp_UnicodeToAsciiAlloc((WCHAR*) s->p, &format_name->name, 32 / 2);
}
stream_seek(s, 32);
@ -183,8 +186,7 @@ void cliprdr_process_long_format_names(cliprdrPlugin* cliprdr, STREAM* s, uint32
break;
}
format_name->name = freerdp_uniconv_in(cliprdr->uniconv, stream_get_tail(s), name_len);
format_name->length = strlen(format_name->name);
format_name->length = freerdp_UnicodeToAsciiAlloc((WCHAR*) stream_get_tail(s), &format_name->name, name_len / 2);
stream_seek(s, name_len + 2);
}
}

View File

@ -18,7 +18,10 @@
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -79,8 +82,6 @@ void cliprdr_packet_send(cliprdrPlugin* cliprdr, STREAM* s)
static void cliprdr_process_connect(rdpSvcPlugin* plugin)
{
DEBUG_CLIPRDR("connecting");
((cliprdrPlugin*) plugin)->uniconv = freerdp_uniconv_new();
}
void cliprdr_print_general_capability_flags(uint32 flags)
@ -264,11 +265,6 @@ static void cliprdr_process_event(rdpSvcPlugin* plugin, RDP_EVENT* event)
static void cliprdr_process_terminate(rdpSvcPlugin* plugin)
{
cliprdrPlugin* cliprdr_plugin = (cliprdrPlugin*) plugin;
if (cliprdr_plugin->uniconv != NULL)
freerdp_uniconv_free(cliprdr_plugin->uniconv);
xfree(plugin);
}

View File

@ -35,7 +35,6 @@ typedef struct _CLIPRDR_FORMAT_NAME CLIPRDR_FORMAT_NAME;
struct cliprdr_plugin
{
rdpSvcPlugin plugin;
UNICONV* uniconv;
boolean received_caps;
boolean use_long_format_names;
boolean stream_fileclip_enabled;

View File

@ -1,9 +1,7 @@
# FreeRDP: A Remote Desktop Protocol Client
# FreeRDP cmake build script
#
# Copyright 2011 O.S. Systems Software Ltda.
# Copyright 2011 Otavio Salvador <otavio@ossystems.com.br>
# Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -36,3 +34,8 @@ add_subdirectory(tsmf)
add_subdirectory(audin)
add_subdirectory(urbdrc)
if(WITH_CLIENT_CHANNELS)
add_subdirectory(client)
endif()

View File

@ -0,0 +1,9 @@
set(CHANNEL_TYPE "static")
set(CHANNEL_SHORT_NAME "drdynvc")
set(CHANNEL_LONG_NAME "Dynamic Virtual Channel Extension")
set(CHANNEL_SPECIFICATIONS "[MS-RDPEDYC]")
string(TOUPPER "WITH_${CHANNEL_SHORT_NAME}" CHANNEL_OPTION)
option(${CHANNEL_OPTION} "Build ${CHANNEL_SHORT_NAME}" ON)

View File

@ -0,0 +1,38 @@
# FreeRDP: A Remote Desktop Protocol Client
# FreeRDP cmake build script
#
# Copyright 2011 O.S. Systems Software Ltda.
# Copyright 2011 Otavio Salvador <otavio@ossystems.com.br>
# Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
#
# 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.
set(DRDYNVC_SRCS
drdynvc_main.c
drdynvc_main.h
drdynvc_types.h
dvcman.c
dvcman.h
)
add_library(drdynvc ${DRDYNVC_SRCS})
set_target_properties(drdynvc PROPERTIES PREFIX "")
if(WITH_MONOLITHIC_BUILD)
target_link_libraries(drdynvc freerdp)
else()
target_link_libraries(drdynvc freerdp-utils)
endif()
install(TARGETS drdynvc DESTINATION ${FREERDP_PLUGIN_PATH})

View File

@ -17,9 +17,14 @@
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <freerdp/constants.h>
#include <freerdp/utils/memory.h>
#include <freerdp/utils/stream.h>

View File

@ -20,7 +20,10 @@
#ifndef __DRDYNVC_TYPES_H
#define __DRDYNVC_TYPES_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <freerdp/dvc.h>
#include <freerdp/types.h>
#include <freerdp/utils/debug.h>

View File

@ -17,9 +17,14 @@
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <freerdp/utils/memory.h>
#include <freerdp/utils/stream.h>
#include <freerdp/utils/list.h>
@ -220,7 +225,7 @@ int dvcman_load_plugin(IWTSVirtualChannelManager* pChannelMgr, RDP_PLUGIN_DATA*
while (data && data->size > 0)
{
pDVCPluginEntry = freerdp_load_plugin((char*) data->data[0], "DVCPluginEntry");
pDVCPluginEntry = (PDVC_PLUGIN_ENTRY) freerdp_load_plugin((char*) data->data[0], "DVCPluginEntry");
if (pDVCPluginEntry != NULL)
{
@ -232,7 +237,7 @@ int dvcman_load_plugin(IWTSVirtualChannelManager* pChannelMgr, RDP_PLUGIN_DATA*
pDVCPluginEntry((IDRDYNVC_ENTRY_POINTS*) &entryPoints);
}
data = (RDP_PLUGIN_DATA*)(((void*) data) + data->size);
data = (RDP_PLUGIN_DATA*)(((uint8*) data) + data->size);
}
return 0;
@ -431,7 +436,7 @@ int dvcman_receive_channel_data(IWTSVirtualChannelManager* pChannelMgr, uint32 C
if (channel->dvc_data)
{
/* Fragmented data */
if (stream_get_length(channel->dvc_data) + data_size > stream_get_size(channel->dvc_data))
if (stream_get_length(channel->dvc_data) + data_size > (uint32) stream_get_size(channel->dvc_data))
{
DEBUG_WARN("data exceeding declared length!");
stream_free(channel->dvc_data);

View File

@ -1,9 +1,7 @@
# FreeRDP: A Remote Desktop Protocol Client
# FreeRDP cmake build script
#
# Copyright 2011 O.S. Systems Software Ltda.
# Copyright 2011 Otavio Salvador <otavio@ossystems.com.br>
# Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -17,16 +15,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
set(RAIL_SRCS
rail_main.c
rail_main.h
rail_orders.c
rail_orders.h)
add_library(rail ${RAIL_SRCS})
set_target_properties(rail PROPERTIES PREFIX "")
target_link_libraries(rail freerdp-utils)
install(TARGETS rail DESTINATION ${FREERDP_PLUGIN_PATH})
if(WITH_CLIENT_CHANNELS)
add_subdirectory(client)
endif()

View File

@ -0,0 +1,9 @@
set(CHANNEL_TYPE "static")
set(CHANNEL_SHORT_NAME "rail")
set(CHANNEL_LONG_NAME "Remote Programs Virtual Channel Extension")
set(CHANNEL_SPECIFICATIONS "[MS-RDPERP]")
string(TOUPPER "WITH_${CHANNEL_SHORT_NAME}" CHANNEL_OPTION)
option(${CHANNEL_OPTION} "Build ${CHANNEL_SHORT_NAME}" ON)

View File

@ -17,13 +17,20 @@
# See the License for the specific language governing permissions and
# limitations under the License.
set(RDPDBG_SRCS
rdpdbg_main.c
)
set(RAIL_SRCS
rail_main.c
rail_main.h
rail_orders.c
rail_orders.h)
add_library(rdpdbg ${RDPDBG_SRCS})
set_target_properties(rdpdbg PROPERTIES PREFIX "")
add_library(rail ${RAIL_SRCS})
set_target_properties(rail PROPERTIES PREFIX "")
target_link_libraries(rdpdbg freerdp-utils)
if(WITH_MONOLITHIC_BUILD)
target_link_libraries(rail freerdp)
else()
target_link_libraries(rail freerdp-utils)
endif()
install(TARGETS rail DESTINATION ${FREERDP_PLUGIN_PATH})
install(TARGETS rdpdbg DESTINATION ${FREERDP_PLUGIN_PATH})

View File

@ -19,9 +19,14 @@
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <freerdp/constants.h>
#include <freerdp/types.h>
#include <freerdp/utils/memory.h>
@ -128,7 +133,7 @@ static void rail_recv_set_sysparams_event(rdpRailOrder* rail_order, RDP_EVENT* e
while (data && data->size > 0)
{
rail_process_plugin_data(rail_order, data);
data = (RDP_PLUGIN_DATA*)(((void*) data) + data->size);
data = (RDP_PLUGIN_DATA*)((char *)(data) + data->size);
}
}

View File

@ -29,7 +29,6 @@
struct rdp_rail_order
{
UNICONV* uniconv;
RDP_PLUGIN_DATA* plugin_data;
void* plugin;
RAIL_HANDSHAKE_ORDER handshake;

View File

@ -18,8 +18,13 @@
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <freerdp/utils/rail.h>
#include <freerdp/utils/memory.h>
#include <freerdp/utils/unicode.h>
#include "rail_orders.h"
@ -60,10 +65,10 @@ static const char* const RAIL_ORDER_TYPE_STRINGS[] =
"Execute Result"
};
void rail_string_to_unicode_string(rdpRailOrder* rail_order, char* string, UNICODE_STRING* unicode_string)
void rail_string_to_unicode_string(rdpRailOrder* rail_order, char* string, RAIL_UNICODE_STRING* unicode_string)
{
char* buffer;
size_t length = 0;
WCHAR* buffer;
int length = 0;
if (unicode_string->string != NULL)
xfree(unicode_string->string);
@ -74,7 +79,7 @@ void rail_string_to_unicode_string(rdpRailOrder* rail_order, char* string, UNICO
if (string == NULL || strlen(string) < 1)
return;
buffer = freerdp_uniconv_out(rail_order->uniconv, string, &length);
length = freerdp_AsciiToUnicodeAlloc(string, &buffer, 0) * 2;
unicode_string->string = (uint8*) buffer;
unicode_string->length = (uint16) length;
@ -249,15 +254,24 @@ void rail_write_client_sysparam_order(STREAM* s, RAIL_SYSPARAM_ORDER* sysparam)
break;
case SPI_SET_WORK_AREA:
freerdp_write_rectangle_16(s, &sysparam->workArea);
stream_write_uint16(s, sysparam->workArea.left); /* left (2 bytes) */
stream_write_uint16(s, sysparam->workArea.top); /* top (2 bytes) */
stream_write_uint16(s, sysparam->workArea.right); /* right (2 bytes) */
stream_write_uint16(s, sysparam->workArea.bottom); /* bottom (2 bytes) */
break;
case SPI_DISPLAY_CHANGE:
freerdp_write_rectangle_16(s, &sysparam->displayChange);
stream_write_uint16(s, sysparam->displayChange.left); /* left (2 bytes) */
stream_write_uint16(s, sysparam->displayChange.top); /* top (2 bytes) */
stream_write_uint16(s, sysparam->displayChange.right); /* right (2 bytes) */
stream_write_uint16(s, sysparam->displayChange.bottom); /* bottom (2 bytes) */
break;
case SPI_TASKBAR_POS:
freerdp_write_rectangle_16(s, &sysparam->taskbarPos);
stream_write_uint16(s, sysparam->taskbarPos.left); /* left (2 bytes) */
stream_write_uint16(s, sysparam->taskbarPos.top); /* top (2 bytes) */
stream_write_uint16(s, sysparam->taskbarPos.right); /* right (2 bytes) */
stream_write_uint16(s, sysparam->taskbarPos.bottom); /* bottom (2 bytes) */
break;
case SPI_SET_HIGH_CONTRAST:
@ -450,6 +464,7 @@ void rail_send_handshake_order(rdpRailOrder* rail_order)
s = rail_pdu_init(RAIL_HANDSHAKE_ORDER_LENGTH);
rail_write_handshake_order(s, &rail_order->handshake);
rail_send_pdu(rail_order, s, RAIL_ORDER_TYPE_HANDSHAKE);
stream_free(s) ;
}
void rail_send_client_status_order(rdpRailOrder* rail_order)
@ -458,6 +473,7 @@ void rail_send_client_status_order(rdpRailOrder* rail_order)
s = rail_pdu_init(RAIL_CLIENT_STATUS_ORDER_LENGTH);
rail_write_client_status_order(s, &rail_order->client_status);
rail_send_pdu(rail_order, s, RAIL_ORDER_TYPE_CLIENT_STATUS);
stream_free(s) ;
}
void rail_send_client_exec_order(rdpRailOrder* rail_order)
@ -473,6 +489,7 @@ void rail_send_client_exec_order(rdpRailOrder* rail_order)
s = rail_pdu_init(RAIL_EXEC_ORDER_LENGTH);
rail_write_client_exec_order(s, &rail_order->exec);
rail_send_pdu(rail_order, s, RAIL_ORDER_TYPE_EXEC);
stream_free(s) ;
}
void rail_send_client_sysparam_order(rdpRailOrder* rail_order)
@ -505,6 +522,7 @@ void rail_send_client_sysparam_order(rdpRailOrder* rail_order)
s = rail_pdu_init(RAIL_SYSPARAM_ORDER_LENGTH + 8);
rail_write_client_sysparam_order(s, &rail_order->sysparam);
rail_send_pdu(rail_order, s, RAIL_ORDER_TYPE_SYSPARAM);
stream_free(s) ;
}
void rail_send_client_sysparams_order(rdpRailOrder* rail_order)
@ -558,6 +576,7 @@ void rail_send_client_activate_order(rdpRailOrder* rail_order)
s = rail_pdu_init(RAIL_ACTIVATE_ORDER_LENGTH);
rail_write_client_activate_order(s, &rail_order->activate);
rail_send_pdu(rail_order, s, RAIL_ORDER_TYPE_ACTIVATE);
stream_free(s) ;
}
void rail_send_client_sysmenu_order(rdpRailOrder* rail_order)
@ -566,6 +585,7 @@ void rail_send_client_sysmenu_order(rdpRailOrder* rail_order)
s = rail_pdu_init(RAIL_SYSMENU_ORDER_LENGTH);
rail_write_client_sysmenu_order(s, &rail_order->sysmenu);
rail_send_pdu(rail_order, s, RAIL_ORDER_TYPE_SYSMENU);
stream_free(s) ;
}
void rail_send_client_syscommand_order(rdpRailOrder* rail_order)
@ -574,6 +594,7 @@ void rail_send_client_syscommand_order(rdpRailOrder* rail_order)
s = rail_pdu_init(RAIL_SYSCOMMAND_ORDER_LENGTH);
rail_write_client_syscommand_order(s, &rail_order->syscommand);
rail_send_pdu(rail_order, s, RAIL_ORDER_TYPE_SYSCOMMAND);
stream_free(s) ;
}
void rail_send_client_notify_event_order(rdpRailOrder* rail_order)
@ -582,6 +603,7 @@ void rail_send_client_notify_event_order(rdpRailOrder* rail_order)
s = rail_pdu_init(RAIL_NOTIFY_EVENT_ORDER_LENGTH);
rail_write_client_notify_event_order(s, &rail_order->notify_event);
rail_send_pdu(rail_order, s, RAIL_ORDER_TYPE_NOTIFY_EVENT);
stream_free(s) ;
}
void rail_send_client_window_move_order(rdpRailOrder* rail_order)
@ -590,6 +612,7 @@ void rail_send_client_window_move_order(rdpRailOrder* rail_order)
s = rail_pdu_init(RAIL_WINDOW_MOVE_ORDER_LENGTH);
rail_write_client_window_move_order(s, &rail_order->window_move);
rail_send_pdu(rail_order, s, RAIL_ORDER_TYPE_WINDOW_MOVE);
stream_free(s) ;
}
void rail_send_client_get_appid_req_order(rdpRailOrder* rail_order)
@ -598,6 +621,7 @@ void rail_send_client_get_appid_req_order(rdpRailOrder* rail_order)
s = rail_pdu_init(RAIL_GET_APPID_REQ_ORDER_LENGTH);
rail_write_client_get_appid_req_order(s, &rail_order->get_appid_req);
rail_send_pdu(rail_order, s, RAIL_ORDER_TYPE_GET_APPID_REQ);
stream_free(s) ;
}
void rail_send_client_langbar_info_order(rdpRailOrder* rail_order)
@ -606,6 +630,7 @@ void rail_send_client_langbar_info_order(rdpRailOrder* rail_order)
s = rail_pdu_init(RAIL_LANGBAR_INFO_ORDER_LENGTH);
rail_write_langbar_info_order(s, &rail_order->langbar_info);
rail_send_pdu(rail_order, s, RAIL_ORDER_TYPE_LANGBAR_INFO);
stream_free(s) ;
}
rdpRailOrder* rail_order_new()
@ -616,7 +641,7 @@ rdpRailOrder* rail_order_new()
if (rail_order != NULL)
{
rail_order->uniconv = freerdp_uniconv_new();
}
return rail_order;
@ -626,7 +651,7 @@ void rail_order_free(rdpRailOrder* rail_order)
{
if (rail_order != NULL)
{
freerdp_uniconv_free(rail_order->uniconv);
xfree(rail_order);
}
}

View File

@ -54,7 +54,7 @@
#define RAIL_GET_APPID_REQ_ORDER_LENGTH 4 /* fixed */
#define RAIL_LANGBAR_INFO_ORDER_LENGTH 4 /* fixed */
void rail_string_to_unicode_string(rdpRailOrder* rail_order, char* string, UNICODE_STRING* unicode_string);
void rail_string_to_unicode_string(rdpRailOrder* rail_order, char* string, RAIL_UNICODE_STRING* unicode_string);
void rail_read_handshake_order(STREAM* s, RAIL_HANDSHAKE_ORDER* handshake);
void rail_read_server_exec_result_order(STREAM* s, RAIL_EXEC_RESULT_ORDER* exec_result);

View File

@ -1,69 +0,0 @@
/**
* FreeRDP: A Remote Desktop Protocol client.
* Debugging Virtual Channel
*
* Copyright 2010-2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2011 Vic Lee
*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <freerdp/constants.h>
#include <freerdp/types.h>
#include <freerdp/utils/memory.h>
#include <freerdp/utils/svc_plugin.h>
typedef struct rdpdbg_plugin rdpdbgPlugin;
struct rdpdbg_plugin
{
rdpSvcPlugin plugin;
};
static void rdpdbg_process_connect(rdpSvcPlugin* plugin)
{
DEBUG_WARN("connecting");
}
static void rdpdbg_process_receive(rdpSvcPlugin* plugin, STREAM* data_in)
{
STREAM* data_out;
DEBUG_WARN("size %d", stream_get_size(data_in));
stream_free(data_in);
data_out = stream_new(8);
stream_write(data_out, "senddata", 8);
svc_plugin_send(plugin, data_out);
}
static void rdpdbg_process_event(rdpSvcPlugin* plugin, RDP_EVENT* event)
{
DEBUG_WARN("event_type %d", event->event_type);
freerdp_event_free(event);
event = freerdp_event_new(RDP_EVENT_CLASS_DEBUG, 0, NULL, NULL);
svc_plugin_send_event(plugin, event);
}
static void rdpdbg_process_terminate(rdpSvcPlugin* plugin)
{
DEBUG_WARN("terminating");
xfree(plugin);
}
DEFINE_SVC_PLUGIN(rdpdbg, "rdpdbg",
CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP |
CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL)

View File

@ -1,9 +1,7 @@
# FreeRDP: A Remote Desktop Protocol Client
# FreeRDP cmake build script
#
# Copyright 2011 O.S. Systems Software Ltda.
# Copyright 2011 Otavio Salvador <otavio@ossystems.com.br>
# Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -17,31 +15,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
set(RDPDR_SRCS
rdpdr_constants.h
rdpdr_types.h
rdpdr_capabilities.c
rdpdr_capabilities.h
devman.c
devman.h
irp.c
irp.h
rdpdr_main.c
rdpdr_main.h
)
add_library(rdpdr ${RDPDR_SRCS})
set_target_properties(rdpdr PROPERTIES PREFIX "")
target_link_libraries(rdpdr freerdp-utils)
install(TARGETS rdpdr DESTINATION ${FREERDP_PLUGIN_PATH})
add_subdirectory(disk)
add_subdirectory(printer)
add_subdirectory(parallel)
add_subdirectory(serial)
if(WITH_PCSC)
add_subdirectory(smartcard)
if(WITH_CLIENT_CHANNELS)
add_subdirectory(client)
endif()

View File

@ -0,0 +1,14 @@
set(CHANNEL_TYPE "static")
set(CHANNEL_SHORT_NAME "rdpdr")
set(CHANNEL_LONG_NAME "Device Redirection Virtual Channel Extension")
set(CHANNEL_SPECIFICATIONS "[MS-RDPEFS] [MS-RDPEPC] [MS-RDPESC] [MS-RDPESP]")
string(TOUPPER "WITH_${CHANNEL_SHORT_NAME}" CHANNEL_OPTION)
if(WIN32)
option(${CHANNEL_OPTION} "Build ${CHANNEL_SHORT_NAME}" OFF)
else()
option(${CHANNEL_OPTION} "Build ${CHANNEL_SHORT_NAME}" ON)
endif()

View File

@ -0,0 +1,52 @@
# FreeRDP: A Remote Desktop Protocol Client
# FreeRDP cmake build script
#
# Copyright 2011 O.S. Systems Software Ltda.
# Copyright 2011 Otavio Salvador <otavio@ossystems.com.br>
# Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
#
# 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.
set(RDPDR_SRCS
rdpdr_constants.h
rdpdr_types.h
rdpdr_capabilities.c
rdpdr_capabilities.h
devman.c
devman.h
irp.c
irp.h
rdpdr_main.c
rdpdr_main.h)
add_library(rdpdr ${RDPDR_SRCS})
set_target_properties(rdpdr PROPERTIES PREFIX "")
if(WITH_MONOLITHIC_BUILD)
target_link_libraries(rdpdr freerdp)
else()
target_link_libraries(rdpdr freerdp-utils)
endif()
install(TARGETS rdpdr DESTINATION ${FREERDP_PLUGIN_PATH})
add_subdirectory(disk)
add_subdirectory(printer)
if(NOT WIN32)
add_subdirectory(parallel)
add_subdirectory(serial)
endif()
if(WITH_PCSC)
add_subdirectory(smartcard)
endif()

View File

@ -18,10 +18,14 @@
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <freerdp/types.h>
#include <freerdp/utils/memory.h>
#include <freerdp/utils/stream.h>

View File

@ -0,0 +1,47 @@
# FreeRDP: A Remote Desktop Protocol Client
# FreeRDP cmake build script
#
# Copyright 2011 O.S. Systems Software Ltda.
# Copyright 2011 Otavio Salvador <otavio@ossystems.com.br>
# Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
#
# 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.
set(MODULE_NAME "disk")
set(MODULE_PREFIX "CHANNEL_DEVICE_DISK")
set(${MODULE_PREFIX}_SRCS
disk_file.c
disk_file.h
disk_main.c)
if(WIN32)
set(${MODULE_PREFIX}_SRCS
statvfs.c
statvfs.h
dirent.h)
endif()
include_directories(..)
add_library(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
if(WITH_MONOLITHIC_BUILD)
set(${MODULE_PREFIX}_LIBS freerdp winpr)
else()
set(${MODULE_PREFIX}_LIBS freerdp-utils winpr-synch winpr-thread)
endif()
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_PLUGIN_PATH})

View File

@ -0,0 +1,374 @@
/*****************************************************************************
* dirent.h - dirent API for Microsoft Visual Studio
*
* Copyright (C) 2006 Toni Ronkko
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* ``Software''), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL TONI RONKKO BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Mar 15, 2011, Toni Ronkko
* Defined FILE_ATTRIBUTE_DEVICE for MSVC 6.0.
*
* Aug 11, 2010, Toni Ronkko
* Added d_type and d_namlen fields to dirent structure. The former is
* especially useful for determining whether directory entry represents a
* file or a directory. For more information, see
* http://www.delorie.com/gnu/docs/glibc/libc_270.html
*
* Aug 11, 2010, Toni Ronkko
* Improved conformance to the standards. For example, errno is now set
* properly on failure and assert() is never used. Thanks to Peter Brockam
* for suggestions.
*
* Aug 11, 2010, Toni Ronkko
* Fixed a bug in rewinddir(): when using relative directory names, change
* of working directory no longer causes rewinddir() to fail.
*
* Dec 15, 2009, John Cunningham
* Added rewinddir member function
*
* Jan 18, 2008, Toni Ronkko
* Using FindFirstFileA and WIN32_FIND_DATAA to avoid converting string
* between multi-byte and unicode representations. This makes the
* code simpler and also allows the code to be compiled under MingW. Thanks
* to Azriel Fasten for the suggestion.
*
* Mar 4, 2007, Toni Ronkko
* Bug fix: due to the strncpy_s() function this file only compiled in
* Visual Studio 2005. Using the new string functions only when the
* compiler version allows.
*
* Nov 2, 2006, Toni Ronkko
* Major update: removed support for Watcom C, MS-DOS and Turbo C to
* simplify the file, updated the code to compile cleanly on Visual
* Studio 2005 with both unicode and multi-byte character strings,
* removed rewinddir() as it had a bug.
*
* Aug 20, 2006, Toni Ronkko
* Removed all remarks about MSVC 1.0, which is antiqued now. Simplified
* comments by removing SGML tags.
*
* May 14 2002, Toni Ronkko
* Embedded the function definitions directly to the header so that no
* source modules need to be included in the Visual Studio project. Removed
* all the dependencies to other projects so that this very header can be
* used independently.
*
* May 28 1998, Toni Ronkko
* First version.
*****************************************************************************/
#ifndef DIRENT_H
#define DIRENT_H
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
/* Entries missing from MSVC 6.0 */
#if !defined(FILE_ATTRIBUTE_DEVICE)
# define FILE_ATTRIBUTE_DEVICE 0x40
#endif
/* File type and permission flags for stat() */
#if defined(_MSC_VER) && !defined(S_IREAD)
# define S_IFMT _S_IFMT /* file type mask */
# define S_IFDIR _S_IFDIR /* directory */
# define S_IFCHR _S_IFCHR /* character device */
# define S_IFFIFO _S_IFFIFO /* pipe */
# define S_IFREG _S_IFREG /* regular file */
# define S_IREAD _S_IREAD /* read permission */
# define S_IWRITE _S_IWRITE /* write permission */
# define S_IEXEC _S_IEXEC /* execute permission */
#endif
#define S_IFBLK 0 /* block device */
#define S_IFLNK 0 /* link */
#define S_IFSOCK 0 /* socket */
#if defined(_MSC_VER)
# define S_IRUSR S_IREAD /* read, user */
# define S_IWUSR S_IWRITE /* write, user */
# define S_IXUSR 0 /* execute, user */
# define S_IRGRP 0 /* read, group */
# define S_IWGRP 0 /* write, group */
# define S_IXGRP 0 /* execute, group */
# define S_IROTH 0 /* read, others */
# define S_IWOTH 0 /* write, others */
# define S_IXOTH 0 /* execute, others */
#endif
/* Indicates that d_type field is available in dirent structure */
#define _DIRENT_HAVE_D_TYPE
/* File type flags for d_type */
#define DT_UNKNOWN 0
#define DT_REG S_IFREG
#define DT_DIR S_IFDIR
#define DT_FIFO S_IFFIFO
#define DT_SOCK S_IFSOCK
#define DT_CHR S_IFCHR
#define DT_BLK S_IFBLK
/* Macros for converting between st_mode and d_type */
#define IFTODT(mode) ((mode) & S_IFMT)
#define DTTOIF(type) (type)
/*
* File type macros. Note that block devices, sockets and links cannot be
* distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are
* only defined for compatibility. These macros should always return false
* on Windows.
*/
#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFFIFO)
#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
#define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
#define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
#ifdef __cplusplus
extern "C" {
#endif
typedef struct dirent
{
char d_name[MAX_PATH + 1]; /* File name */
size_t d_namlen; /* Length of name without \0 */
int d_type; /* File type */
} dirent;
typedef struct DIR
{
dirent curentry; /* Current directory entry */
WIN32_FIND_DATAA find_data; /* Private file data */
int cached; /* True if data is valid */
HANDLE search_handle; /* Win32 search handle */
char patt[MAX_PATH + 3]; /* Initial directory name */
} DIR;
/* Forward declarations */
static DIR *opendir(const char *dirname);
static struct dirent *readdir(DIR *dirp);
static int closedir(DIR *dirp);
static void rewinddir(DIR* dirp);
/* Use the new safe string functions introduced in Visual Studio 2005 */
#if defined(_MSC_VER) && _MSC_VER >= 1400
# define DIRENT_STRNCPY(dest,src,size) strncpy_s((dest),(size),(src),_TRUNCATE)
#else
# define DIRENT_STRNCPY(dest,src,size) strncpy((dest),(src),(size))
#endif
/* Set errno variable */
#if defined(_MSC_VER)
#define DIRENT_SET_ERRNO(x) _set_errno (x)
#else
#define DIRENT_SET_ERRNO(x) (errno = (x))
#endif
/*****************************************************************************
* Open directory stream DIRNAME for read and return a pointer to the
* internal working area that is used to retrieve individual directory
* entries.
*/
static DIR *opendir(const char *dirname)
{
DIR *dirp;
/* ensure that the resulting search pattern will be a valid file name */
if (dirname == NULL) {
DIRENT_SET_ERRNO (ENOENT);
return NULL;
}
if (strlen (dirname) + 3 >= MAX_PATH) {
DIRENT_SET_ERRNO (ENAMETOOLONG);
return NULL;
}
/* construct new DIR structure */
dirp = (DIR*) malloc (sizeof (struct DIR));
if (dirp != NULL) {
int error;
/*
* Convert relative directory name to an absolute one. This
* allows rewinddir() to function correctly when the current working
* directory is changed between opendir() and rewinddir().
*/
if (GetFullPathNameA (dirname, MAX_PATH, dirp->patt, NULL)) {
char *p;
/* append the search pattern "\\*\0" to the directory name */
p = strchr (dirp->patt, '\0');
if (dirp->patt < p && *(p-1) != '\\' && *(p-1) != ':') {
*p++ = '\\';
}
*p++ = '*';
*p = '\0';
/* open directory stream and retrieve the first entry */
dirp->search_handle = FindFirstFileA (dirp->patt, &dirp->find_data);
if (dirp->search_handle != INVALID_HANDLE_VALUE) {
/* a directory entry is now waiting in memory */
dirp->cached = 1;
error = 0;
} else {
/* search pattern is not a directory name? */
DIRENT_SET_ERRNO (ENOENT);
error = 1;
}
} else {
/* buffer too small */
DIRENT_SET_ERRNO (ENOMEM);
error = 1;
}
if (error) {
free (dirp);
dirp = NULL;
}
}
return dirp;
}
/*****************************************************************************
* Read a directory entry, and return a pointer to a dirent structure
* containing the name of the entry in d_name field. Individual directory
* entries returned by this very function include regular files,
* sub-directories, pseudo-directories "." and "..", but also volume labels,
* hidden files and system files may be returned.
*/
static struct dirent *readdir(DIR *dirp)
{
DWORD attr;
if (dirp == NULL) {
/* directory stream did not open */
DIRENT_SET_ERRNO (EBADF);
return NULL;
}
/* get next directory entry */
if (dirp->cached != 0) {
/* a valid directory entry already in memory */
dirp->cached = 0;
} else {
/* get the next directory entry from stream */
if (dirp->search_handle == INVALID_HANDLE_VALUE) {
return NULL;
}
if (FindNextFileA (dirp->search_handle, &dirp->find_data) == FALSE) {
/* the very last entry has been processed or an error occured */
FindClose (dirp->search_handle);
dirp->search_handle = INVALID_HANDLE_VALUE;
return NULL;
}
}
/* copy as a multibyte character string */
DIRENT_STRNCPY ( dirp->curentry.d_name,
dirp->find_data.cFileName,
sizeof(dirp->curentry.d_name) );
dirp->curentry.d_name[MAX_PATH] = '\0';
/* compute the length of name */
dirp->curentry.d_namlen = strlen (dirp->curentry.d_name);
/* determine file type */
attr = dirp->find_data.dwFileAttributes;
if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {
dirp->curentry.d_type = DT_CHR;
} else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
dirp->curentry.d_type = DT_DIR;
} else {
dirp->curentry.d_type = DT_REG;
}
return &dirp->curentry;
}
/*****************************************************************************
* Close directory stream opened by opendir() function. Close of the
* directory stream invalidates the DIR structure as well as any previously
* read directory entry.
*/
static int closedir(DIR *dirp)
{
if (dirp == NULL) {
/* invalid directory stream */
DIRENT_SET_ERRNO (EBADF);
return -1;
}
/* release search handle */
if (dirp->search_handle != INVALID_HANDLE_VALUE) {
FindClose (dirp->search_handle);
dirp->search_handle = INVALID_HANDLE_VALUE;
}
/* release directory structure */
free (dirp);
return 0;
}
/*****************************************************************************
* Resets the position of the directory stream to which dirp refers to the
* beginning of the directory. It also causes the directory stream to refer
* to the current state of the corresponding directory, as a call to opendir()
* would have done. If dirp does not refer to a directory stream, the effect
* is undefined.
*/
static void rewinddir(DIR* dirp)
{
if (dirp != NULL) {
/* release search handle */
if (dirp->search_handle != INVALID_HANDLE_VALUE) {
FindClose (dirp->search_handle);
}
/* open new search handle and retrieve the first entry */
dirp->search_handle = FindFirstFileA (dirp->patt, &dirp->find_data);
if (dirp->search_handle != INVALID_HANDLE_VALUE) {
/* a directory entry is now waiting in memory */
dirp->cached = 1;
} else {
/* failed to re-open directory: no directory entry in memory */
dirp->cached = 0;
}
}
}
#ifdef __cplusplus
}
#endif
#endif /*DIRENT_H*/

View File

@ -4,6 +4,7 @@
*
* Copyright 2010-2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2010-2011 Vic Lee
* Copyright 2012 Gerald Richter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -18,6 +19,10 @@
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifndef _WIN32
#define __USE_LARGEFILE64
#define _LARGEFILE_SOURCE
@ -26,15 +31,16 @@
#include <sys/time.h>
#endif
#include "config.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/stat.h>
#include <freerdp/utils/memory.h>
#include <freerdp/utils/stream.h>
#include <freerdp/utils/unicode.h>
#include <freerdp/utils/svc_plugin.h>
#ifdef HAVE_UNISTD_H
@ -113,10 +119,12 @@ static boolean disk_file_remove_dir(const char* path)
boolean ret = true;
dir = opendir(path);
if (dir == NULL)
return false;
pdirent = readdir(dir);
while (pdirent)
{
if (strcmp(pdirent->d_name, ".") == 0 || strcmp(pdirent->d_name, "..") == 0)
@ -169,6 +177,7 @@ static void disk_file_set_fullpath(DISK_FILE* file, char* fullpath)
xfree(file->fullpath);
file->fullpath = fullpath;
file->filename = strrchr(file->fullpath, '/');
if (file->filename == NULL)
file->filename = file->fullpath;
else
@ -177,10 +186,12 @@ static void disk_file_set_fullpath(DISK_FILE* file, char* fullpath)
static boolean disk_file_init(DISK_FILE* file, uint32 DesiredAccess, uint32 CreateDisposition, uint32 CreateOptions)
{
const static int mode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH;
struct STAT st;
boolean exists;
#ifndef WIN32
#ifdef WIN32
const static int mode = _S_IREAD | _S_IWRITE ;
#else
const static int mode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH;
boolean largeFile = false;
#endif
int oflag = 0;
@ -199,10 +210,14 @@ static boolean disk_file_init(DISK_FILE* file, uint32 DesiredAccess, uint32 Crea
file->is_dir = ((CreateOptions & FILE_DIRECTORY_FILE) ? true : false);
if (file->is_dir)
{
if (mkdir(file->fullpath, mode) != 0)
//Should only create the directory if the disposition allows for it
if ((CreateDisposition == FILE_OPEN_IF) || (CreateDisposition == FILE_CREATE))
{
if (mkdir(file->fullpath, mode) != 0)
{
file->err = errno;
return true;
}
}
}
exists = false;
@ -414,11 +429,11 @@ boolean disk_file_query_information(DISK_FILE* file, uint32 FsInformationClass,
boolean disk_file_set_information(DISK_FILE* file, uint32 FsInformationClass, uint32 Length, STREAM* input)
{
char* s;
mode_t m;
mode_t m;
uint64 size;
char* fullpath;
struct STAT st;
UNICONV* uniconv;
struct timeval tv[2];
uint64 LastWriteTime;
uint32 FileAttributes;
@ -441,7 +456,9 @@ boolean disk_file_set_information(DISK_FILE* file, uint32 FsInformationClass, ui
tv[0].tv_usec = 0;
tv[1].tv_sec = (LastWriteTime > 0 ? FILE_TIME_RDP_TO_SYSTEM(LastWriteTime) : st.st_mtime);
tv[1].tv_usec = 0;
futimes(file->fd, tv);
#ifndef WIN32
/* TODO on win32 */
futimes(file->fd, tv);
if (FileAttributes > 0)
{
@ -453,7 +470,8 @@ boolean disk_file_set_information(DISK_FILE* file, uint32 FsInformationClass, ui
if (m != st.st_mode)
fchmod(file->fd, st.st_mode);
}
break;
#endif
break;
case FileEndOfFileInformation:
/* http://msdn.microsoft.com/en-us/library/cc232067.aspx */
@ -478,21 +496,21 @@ boolean disk_file_set_information(DISK_FILE* file, uint32 FsInformationClass, ui
stream_seek_uint8(input); /* ReplaceIfExists */
stream_seek_uint8(input); /* RootDirectory */
stream_read_uint32(input, FileNameLength);
uniconv = freerdp_uniconv_new();
s = freerdp_uniconv_in(uniconv, stream_get_tail(input), FileNameLength);
freerdp_uniconv_free(uniconv);
freerdp_UnicodeToAsciiAlloc((WCHAR*) stream_get_tail(input), &s, FileNameLength / 2);
fullpath = disk_file_combine_fullpath(file->basepath, s);
xfree(s);
if (rename(file->fullpath, fullpath) == 0)
/* TODO rename does not work on win32 */
if (rename(file->fullpath, fullpath) == 0)
{
DEBUG_SVC("renamed %s to %s", file->fullpath, fullpath);
disk_file_set_fullpath(file, fullpath);
}
else
{
DEBUG_WARN("rename %s to %s failed", file->fullpath, fullpath);
DEBUG_WARN("rename %s to %s failed, errno = %d", file->fullpath, fullpath, errno);
free(fullpath);
return false;
}
@ -510,12 +528,11 @@ boolean disk_file_set_information(DISK_FILE* file, uint32 FsInformationClass, ui
boolean disk_file_query_directory(DISK_FILE* file, uint32 FsInformationClass, uint8 InitialQuery,
const char* path, STREAM* output)
{
struct dirent* ent;
char* ent_path;
struct STAT st;
UNICONV* uniconv;
size_t len;
int length;
boolean ret;
WCHAR* ent_path;
struct STAT st;
struct dirent* ent;
DEBUG_SVC("path %s FsInformationClass %d InitialQuery %d", path, FsInformationClass, InitialQuery);
@ -542,6 +559,7 @@ boolean disk_file_query_directory(DISK_FILE* file, uint32 FsInformationClass, ui
do
{
ent = readdir(file->dir);
if (ent == NULL)
continue;
@ -563,27 +581,27 @@ boolean disk_file_query_directory(DISK_FILE* file, uint32 FsInformationClass, ui
}
memset(&st, 0, sizeof(struct STAT));
ent_path = xmalloc(strlen(file->fullpath) + strlen(ent->d_name) + 2);
sprintf(ent_path, "%s/%s", file->fullpath, ent->d_name);
if (STAT(ent_path, &st) != 0)
ent_path = (WCHAR*) malloc(strlen(file->fullpath) + strlen(ent->d_name) + 2);
sprintf((char*) ent_path, "%s/%s", file->fullpath, ent->d_name);
if (STAT((char*) ent_path, &st) != 0)
{
DEBUG_WARN("stat %s failed. errno = %d", ent_path, errno);
DEBUG_WARN("stat %s failed. errno = %d", (char*) ent_path, errno);
}
DEBUG_SVC(" pattern %s matched %s", file->pattern, ent_path);
xfree(ent_path);
uniconv = freerdp_uniconv_new();
ent_path = freerdp_uniconv_out(uniconv, ent->d_name, &len);
freerdp_uniconv_free(uniconv);
length = freerdp_AsciiToUnicodeAlloc(ent->d_name, &ent_path, 0) * 2;
ret = true;
switch (FsInformationClass)
{
case FileDirectoryInformation:
/* http://msdn.microsoft.com/en-us/library/cc232097.aspx */
stream_write_uint32(output, 64 + len); /* Length */
stream_check_size(output, 64 + len);
stream_write_uint32(output, 64 + length); /* Length */
stream_check_size(output, 64 + length);
stream_write_uint32(output, 0); /* NextEntryOffset */
stream_write_uint32(output, 0); /* FileIndex */
stream_write_uint64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_mtime)); /* CreationTime */
@ -593,14 +611,14 @@ boolean disk_file_query_directory(DISK_FILE* file, uint32 FsInformationClass, ui
stream_write_uint64(output, st.st_size); /* EndOfFile */
stream_write_uint64(output, st.st_size); /* AllocationSize */
stream_write_uint32(output, FILE_ATTR_SYSTEM_TO_RDP(file, st)); /* FileAttributes */
stream_write_uint32(output, len); /* FileNameLength */
stream_write(output, ent_path, len);
stream_write_uint32(output, length); /* FileNameLength */
stream_write(output, ent_path, length);
break;
case FileFullDirectoryInformation:
/* http://msdn.microsoft.com/en-us/library/cc232068.aspx */
stream_write_uint32(output, 68 + len); /* Length */
stream_check_size(output, 68 + len);
stream_write_uint32(output, 68 + length); /* Length */
stream_check_size(output, 68 + length);
stream_write_uint32(output, 0); /* NextEntryOffset */
stream_write_uint32(output, 0); /* FileIndex */
stream_write_uint64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_mtime)); /* CreationTime */
@ -610,15 +628,15 @@ boolean disk_file_query_directory(DISK_FILE* file, uint32 FsInformationClass, ui
stream_write_uint64(output, st.st_size); /* EndOfFile */
stream_write_uint64(output, st.st_size); /* AllocationSize */
stream_write_uint32(output, FILE_ATTR_SYSTEM_TO_RDP(file, st)); /* FileAttributes */
stream_write_uint32(output, len); /* FileNameLength */
stream_write_uint32(output, length); /* FileNameLength */
stream_write_uint32(output, 0); /* EaSize */
stream_write(output, ent_path, len);
stream_write(output, ent_path, length);
break;
case FileBothDirectoryInformation:
/* http://msdn.microsoft.com/en-us/library/cc232095.aspx */
stream_write_uint32(output, 93 + len); /* Length */
stream_check_size(output, 93 + len);
stream_write_uint32(output, 93 + length); /* Length */
stream_check_size(output, 93 + length);
stream_write_uint32(output, 0); /* NextEntryOffset */
stream_write_uint32(output, 0); /* FileIndex */
stream_write_uint64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_mtime)); /* CreationTime */
@ -628,22 +646,22 @@ boolean disk_file_query_directory(DISK_FILE* file, uint32 FsInformationClass, ui
stream_write_uint64(output, st.st_size); /* EndOfFile */
stream_write_uint64(output, st.st_size); /* AllocationSize */
stream_write_uint32(output, FILE_ATTR_SYSTEM_TO_RDP(file, st)); /* FileAttributes */
stream_write_uint32(output, len); /* FileNameLength */
stream_write_uint32(output, length); /* FileNameLength */
stream_write_uint32(output, 0); /* EaSize */
stream_write_uint8(output, 0); /* ShortNameLength */
/* Reserved(1), MUST NOT be added! */
stream_write_zero(output, 24); /* ShortName */
stream_write(output, ent_path, len);
stream_write(output, ent_path, length);
break;
case FileNamesInformation:
/* http://msdn.microsoft.com/en-us/library/cc232077.aspx */
stream_write_uint32(output, 12 + len); /* Length */
stream_check_size(output, 12 + len);
stream_write_uint32(output, 12 + length); /* Length */
stream_check_size(output, 12 + length);
stream_write_uint32(output, 0); /* NextEntryOffset */
stream_write_uint32(output, 0); /* FileIndex */
stream_write_uint32(output, len); /* FileNameLength */
stream_write(output, ent_path, len);
stream_write_uint32(output, length); /* FileNameLength */
stream_write(output, ent_path, length);
break;
default:

View File

@ -4,6 +4,7 @@
*
* Copyright 2010-2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2010-2011 Vic Lee
* Copyright 2012 Gerald Richter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -22,16 +23,35 @@
#define __DISK_FILE_H
#include <sys/types.h>
#include <sys/statvfs.h>
#include <sys/stat.h>
#include <dirent.h>
#if defined WIN32
#ifdef _WIN32
#include <direct.h>
#include <io.h>
#include "dirent.h"
#include "statvfs.h"
#else
#include <dirent.h>
#include <sys/statvfs.h>
#endif
#ifdef _WIN32
#define STAT stat
#define OPEN open
#define LSEEK lseek
#define OPEN _open
#define close _close
#define read _read
#define write _write
#define LSEEK _lseek
#define FSTAT fstat
#define STATVFS statvfs
#define mkdir(a,b) _mkdir(a)
#define rmdir _rmdir
#define unlink(a) _unlink(a)
#define ftruncate(a,b) _chsize(a,b)
typedef uint32 ssize_t ;
typedef uint32 mode_t ;
#elif defined(__APPLE__) || defined(__FreeBSD__)
#define STAT stat
#define OPEN open
@ -60,10 +80,6 @@
(_f->delete_pending ? FILE_ATTRIBUTE_TEMPORARY : 0) | \
(st.st_mode & S_IWUSR ? 0 : FILE_ATTRIBUTE_READONLY))
typedef struct _DISK_FILE DISK_FILE;
struct _DISK_FILE
{

View File

@ -18,6 +18,10 @@
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifndef _WIN32
#define __USE_LARGEFILE64
#define _LARGEFILE_SOURCE
@ -26,24 +30,26 @@
#include <sys/time.h>
#endif
#include "config.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <freerdp/utils/memory.h>
#include <freerdp/utils/stream.h>
#include <freerdp/utils/unicode.h>
#include <freerdp/utils/list.h>
#include <freerdp/utils/thread.h>
#include <freerdp/utils/svc_plugin.h>
#include <winpr/synch.h>
#include <winpr/thread.h>
#include "rdpdr_constants.h"
#include "rdpdr_types.h"
#include "disk_file.h"
typedef struct _DISK_DEVICE DISK_DEVICE;
struct _DISK_DEVICE
{
DEVICE device;
@ -51,15 +57,17 @@ struct _DISK_DEVICE
char* path;
LIST* files;
HANDLE mutex;
HANDLE thread;
LIST* irp_list;
freerdp_thread* thread;
HANDLE irpEvent;
HANDLE stopEvent;
DEVMAN* devman;
pcRegisterDevice UnregisterDevice;
};
static uint32
disk_map_posix_err(int fs_errno)
static uint32 disk_map_posix_err(int fs_errno)
{
uint32 rc;
@ -87,7 +95,9 @@ disk_map_posix_err(int fs_errno)
rc = STATUS_UNSUCCESSFUL;
break;
}
DEBUG_SVC("errno 0x%x mapped to 0x%x", fs_errno, rc);
return rc;
}
@ -98,7 +108,8 @@ static DISK_FILE* disk_get_file_by_id(DISK_DEVICE* disk, uint32 id)
for (item = disk->files->head; item; item = item->next)
{
file = (DISK_FILE*)item->data;
file = (DISK_FILE*) item->data;
if (file->id == id)
return file;
}
@ -112,7 +123,6 @@ static void disk_process_irp_create(DISK_DEVICE* disk, IRP* irp)
uint32 CreateDisposition;
uint32 CreateOptions;
uint32 PathLength;
UNICONV* uniconv;
char* path;
uint32 FileId;
uint8 Information;
@ -123,9 +133,7 @@ static void disk_process_irp_create(DISK_DEVICE* disk, IRP* irp)
stream_read_uint32(irp->input, CreateOptions);
stream_read_uint32(irp->input, PathLength);
uniconv = freerdp_uniconv_new();
path = freerdp_uniconv_in(uniconv, stream_get_tail(irp->input), PathLength);
freerdp_uniconv_free(uniconv);
freerdp_UnicodeToAsciiAlloc((WCHAR*) stream_get_tail(irp->input), &path, PathLength / 2);
FileId = irp->devman->id_sequence++;
@ -235,7 +243,7 @@ static void disk_process_irp_read(DISK_DEVICE* disk, IRP* irp)
}
else
{
buffer = (uint8*)xmalloc(Length);
buffer = (uint8*) xmalloc(Length);
if (!disk_file_read(file, buffer, &Length))
{
irp->IoStatus = STATUS_UNSUCCESSFUL;
@ -252,11 +260,13 @@ static void disk_process_irp_read(DISK_DEVICE* disk, IRP* irp)
}
stream_write_uint32(irp->output, Length);
if (Length > 0)
{
stream_check_size(irp->output, Length);
stream_check_size(irp->output, (int)Length);
stream_write(irp->output, buffer, Length);
}
xfree(buffer);
irp->Complete(irp);
@ -375,11 +385,10 @@ static void disk_process_irp_query_volume_information(DISK_DEVICE* disk, IRP* ir
STREAM* output = irp->output;
struct STATVFS svfst;
struct STAT st;
UNICONV* uniconv;
char *volumeLabel = {"FREERDP"}; /* TODO:: Add sub routine to correctly pick up Volume Label name for each O/S supported*/
char *diskType = {"FAT32"};
char* outStr;
size_t len;
char* volumeLabel = {"FREERDP"};
char* diskType = {"FAT32"};
WCHAR* outStr;
int length;
stream_read_uint32(irp->input, FsInformationClass);
@ -390,17 +399,15 @@ static void disk_process_irp_query_volume_information(DISK_DEVICE* disk, IRP* ir
{
case FileFsVolumeInformation:
/* http://msdn.microsoft.com/en-us/library/cc232108.aspx */
uniconv = freerdp_uniconv_new();
outStr = freerdp_uniconv_out(uniconv, volumeLabel, &len);
freerdp_uniconv_free(uniconv);
stream_write_uint32(output, 17 + len); /* Length */
stream_check_size(output, 17 + len);
length = freerdp_AsciiToUnicodeAlloc(volumeLabel, &outStr, 0) * 2;
stream_write_uint32(output, 17 + length); /* Length */
stream_check_size(output, 17 + length);
stream_write_uint64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_ctime)); /* VolumeCreationTime */
stream_write_uint32(output, svfst.f_fsid); /* VolumeSerialNumber */
stream_write_uint32(output, len); /* VolumeLabelLength */
stream_write_uint32(output, length); /* VolumeLabelLength */
stream_write_uint8(output, 0); /* SupportsObjects */
/* Reserved(1), MUST NOT be added! */
stream_write(output, outStr, len); /* VolumeLabel (Unicode) */
stream_write(output, outStr, length); /* VolumeLabel (Unicode) */
xfree(outStr);
break;
@ -416,19 +423,16 @@ static void disk_process_irp_query_volume_information(DISK_DEVICE* disk, IRP* ir
case FileFsAttributeInformation:
/* http://msdn.microsoft.com/en-us/library/cc232101.aspx */
uniconv = freerdp_uniconv_new();
outStr = freerdp_uniconv_out(uniconv, diskType, &len);
freerdp_uniconv_free(uniconv);
stream_write_uint32(output, 12 + len); /* Length */
stream_check_size(output, 12 + len);
length = freerdp_AsciiToUnicodeAlloc(diskType, &outStr, 0) * 2;
stream_write_uint32(output, 12 + length); /* Length */
stream_check_size(output, 12 + length);
stream_write_uint32(output,
FILE_CASE_SENSITIVE_SEARCH |
FILE_CASE_PRESERVED_NAMES |
FILE_UNICODE_ON_DISK); /* FileSystemAttributes */
stream_write_uint32(output, svfst.f_namemax/*510*/); /* MaximumComponentNameLength */
stream_write_uint32(output, len); /* FileSystemNameLength */
stream_write(output, outStr, len); /* FileSystemName (Unicode) */
stream_write_uint32(output, length); /* FileSystemNameLength */
stream_write(output, outStr, length); /* FileSystemName (Unicode) */
xfree(outStr);
break;
@ -467,7 +471,6 @@ static void disk_process_irp_query_directory(DISK_DEVICE* disk, IRP* irp)
uint32 FsInformationClass;
uint8 InitialQuery;
uint32 PathLength;
UNICONV* uniconv;
char* path;
stream_read_uint32(irp->input, FsInformationClass);
@ -475,9 +478,7 @@ static void disk_process_irp_query_directory(DISK_DEVICE* disk, IRP* irp)
stream_read_uint32(irp->input, PathLength);
stream_seek(irp->input, 23); /* Padding */
uniconv = freerdp_uniconv_new();
path = freerdp_uniconv_in(uniconv, stream_get_tail(irp->input), PathLength);
freerdp_uniconv_free(uniconv);
freerdp_UnicodeToAsciiAlloc((WCHAR*) stream_get_tail(irp->input), &path, PathLength / 2);
file = disk_get_file_by_id(disk, irp->FileId);
@ -578,12 +579,14 @@ static void disk_process_irp_list(DISK_DEVICE* disk)
while (1)
{
if (freerdp_thread_is_stopped(disk->thread))
if (WaitForSingleObject(disk->stopEvent, 0) == WAIT_OBJECT_0)
break;
freerdp_thread_lock(disk->thread);
irp = (IRP*)list_dequeue(disk->irp_list);
freerdp_thread_unlock(disk->thread);
WaitForSingleObject(disk->mutex, INFINITE);
irp = (IRP*) list_dequeue(disk->irp_list);
ReleaseMutex(disk->mutex);
if (irp == NULL)
break;
@ -594,63 +597,75 @@ static void disk_process_irp_list(DISK_DEVICE* disk)
static void* disk_thread_func(void* arg)
{
DISK_DEVICE* disk = (DISK_DEVICE*)arg;
DISK_DEVICE* disk = (DISK_DEVICE*) arg;
while (1)
{
freerdp_thread_wait(disk->thread);
WaitForSingleObject(disk->irpEvent, INFINITE);
if (freerdp_thread_is_stopped(disk->thread))
if (WaitForSingleObject(disk->stopEvent, 0) == WAIT_OBJECT_0)
break;
freerdp_thread_reset(disk->thread);
ResetEvent(disk->irpEvent);
disk_process_irp_list(disk);
}
freerdp_thread_quit(disk->thread);
return NULL;
}
static void disk_irp_request(DEVICE* device, IRP* irp)
{
DISK_DEVICE* disk = (DISK_DEVICE*)device;
DISK_DEVICE* disk = (DISK_DEVICE*) device;
freerdp_thread_lock(disk->thread);
WaitForSingleObject(disk->mutex, INFINITE);
list_enqueue(disk->irp_list, irp);
freerdp_thread_unlock(disk->thread);
ReleaseMutex(disk->mutex);
freerdp_thread_signal(disk->thread);
SetEvent(disk->irpEvent);
}
static void disk_free(DEVICE* device)
{
DISK_DEVICE* disk = (DISK_DEVICE*)device;
IRP* irp;
DISK_FILE* file;
DISK_DEVICE* disk = (DISK_DEVICE*) device;
freerdp_thread_stop(disk->thread);
freerdp_thread_free(disk->thread);
SetEvent(disk->stopEvent);
CloseHandle(disk->thread);
CloseHandle(disk->irpEvent);
CloseHandle(disk->mutex);
while ((irp = (IRP*)list_dequeue(disk->irp_list)) != NULL)
while ((irp = (IRP*) list_dequeue(disk->irp_list)) != NULL)
irp->Discard(irp);
list_free(disk->irp_list);
while ((file = (DISK_FILE*)list_dequeue(disk->files)) != NULL)
while ((file = (DISK_FILE*) list_dequeue(disk->files)) != NULL)
disk_file_free(file);
list_free(disk->files);
xfree(disk);
}
int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
void disk_register_disk_path(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, char *name, char *path)
{
DISK_DEVICE* disk;
char* name;
char* path;
int i, len;
int i, length ;
name = (char*)pEntryPoints->plugin_data->data[1];
path = (char*)pEntryPoints->plugin_data->data[2];
#ifdef WIN32
/*
* We cannot enter paths like c:\ because : is an arg separator
* thus, paths are entered as c+\ and the + is substituted here
*/
if ( path[1] == '+' )
{
if ( (path[0]>='a' && path[0]<='z') || (path[0]>='A' && path[0]<='Z') )
{
path[1] = ':';
}
}
#endif
if (name[0] && path[0])
{
@ -661,21 +676,82 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
disk->device.IRPRequest = disk_irp_request;
disk->device.Free = disk_free;
len = strlen(name);
disk->device.data = stream_new(len + 1);
for (i = 0; i <= len; i++)
length = strlen(name);
disk->device.data = stream_new(length + 1);
for (i = 0; i <= length; i++)
stream_write_uint8(disk->device.data, name[i] < 0 ? '_' : name[i]);
disk->path = path;
disk->files = list_new();
disk->irp_list = list_new();
disk->thread = freerdp_thread_new();
disk->mutex = CreateMutex(NULL, FALSE, NULL);
disk->irpEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
disk->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
disk->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) disk_thread_func, disk, CREATE_SUSPENDED, NULL);
pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*)disk);
pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*) disk);
freerdp_thread_start(disk->thread, disk_thread_func, disk);
ResumeThread(disk->thread);
}
return 0;
}
#ifdef WITH_STATIC_PLUGINS
int disk_entry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
#else
int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
#endif
{
char* name;
char* path;
#ifdef WIN32
char devlist[512], buf[512];
char *dev;
int len ;
#endif
name = (char*) pEntryPoints->plugin_data->data[1];
path = (char*) pEntryPoints->plugin_data->data[2];
#ifndef WIN32
disk_register_disk_path(pEntryPoints, name, path);
#else
/* Special case: path[0] == '*' -> export all drives */
/* Special case: path[0] == '%' -> user home dir */
if( path[0] == '%' )
{
_snprintf(buf, sizeof(buf), "%s\\", getenv("USERPROFILE"));
disk_register_disk_path(pEntryPoints, name, xstrdup(buf));
}
else if( path[0] == '*' )
{
int i;
/* Enumerate all devices: */
GetLogicalDriveStringsA(sizeof(devlist) - 1, devlist);
for (dev = devlist, i = 0; *dev; dev += 4, i++)
{
if (*dev > 'B')
{
/* Suppress disk drives A and B to avoid pesty messages */
_snprintf(buf, sizeof(buf) - 4, "%s", name);
len = strlen(buf);
buf[len] = '_';
buf[len + 1] = dev[0];
buf[len + 2] = 0;
buf[len + 3] = 0;
disk_register_disk_path(pEntryPoints, xstrdup(buf), xstrdup(dev));
}
}
}
else
{
disk_register_disk_path(pEntryPoints, name, path);
}
#endif
return 0;
}

View File

@ -0,0 +1,57 @@
/**
* FreeRDP: A Remote Desktop Protocol client.
* statvfs emulation für windows
*
* Copyright 2012 Gerald Richter
*
* 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 <string.h>
#include <malloc.h>
#include <winpr/crt.h>
#include <winpr/windows.h>
#include "statvfs.h"
int statvfs(const char *path, struct statvfs *buf)
{
BOOL res;
int len;
LPWSTR unicodestr;
DWORD lpSectorsPerCluster;
DWORD lpBytesPerSector;
DWORD lpNumberOfFreeClusters;
DWORD lpTotalNumberOfClusters;
len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
unicodestr = (LPWSTR) malloc(len);
MultiByteToWideChar(CP_ACP, 0, path, -1, unicodestr, len);
res = GetDiskFreeSpace(unicodestr, &lpSectorsPerCluster, &lpBytesPerSector, &lpNumberOfFreeClusters, &lpTotalNumberOfClusters);
buf->f_bsize = lpBytesPerSector; /* file system block size */
buf->f_frsize = 0; /* fragment size */
buf->f_blocks = lpTotalNumberOfClusters; /* size of fs in f_frsize units */
buf->f_bfree = lpNumberOfFreeClusters; /* # free blocks */
buf->f_bavail = lpNumberOfFreeClusters; /* # free blocks for unprivileged users */
buf->f_files = 0; /* # inodes */
buf->f_ffree = 0; /* # free inodes */
buf->f_favail = 0; /* # free inodes for unprivileged users */
buf->f_fsid = lpNumberOfFreeClusters & 0xffff; /* file system ID */
buf->f_flag = 0; /* mount flags */
buf->f_namemax = 250; /* maximum filename length */
return res;
}

View File

@ -0,0 +1,50 @@
/**
* FreeRDP: A Remote Desktop Protocol client.
* statvfs emulation for windows
*
* Copyright 2012 Gerald Richter
*
* 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 RDPDR_DISK_STATVFS_H
#define RDPDR_DISK_STATVFS_H
#ifdef __cplusplus
extern "C" {
#endif
typedef unsigned long long fsblkcnt_t;
typedef unsigned long long fsfilcnt_t;
struct statvfs {
unsigned long f_bsize; /* file system block size */
unsigned long f_frsize; /* fragment size */
fsblkcnt_t f_blocks; /* size of fs in f_frsize units */
fsblkcnt_t f_bfree; /* # free blocks */
fsblkcnt_t f_bavail; /* # free blocks for unprivileged users */
fsfilcnt_t f_files; /* # inodes */
fsfilcnt_t f_ffree; /* # free inodes */
fsfilcnt_t f_favail; /* # free inodes for unprivileged users */
unsigned long f_fsid; /* file system ID */
unsigned long f_flag; /* mount flags */
unsigned long f_namemax; /* maximum filename length */
};
int statvfs(const char *path, struct statvfs *buf);
#ifdef __cplusplus
}
#endif
#endif /* RDPDR_DISK_STATVFS_H */

View File

@ -18,7 +18,10 @@
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

View File

@ -26,6 +26,10 @@ include_directories(..)
add_library(parallel ${PARALLEL_SRCS})
set_target_properties(parallel PROPERTIES PREFIX "")
target_link_libraries(parallel freerdp-utils)
if(WITH_MONOLITHIC_BUILD)
target_link_libraries(parallel freerdp)
else()
target_link_libraries(parallel freerdp-utils)
endif()
install(TARGETS parallel DESTINATION ${FREERDP_PLUGIN_PATH})

View File

@ -18,16 +18,27 @@
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#ifndef _WIN32
#include <termios.h>
#include <strings.h>
#include <sys/ioctl.h>
#endif
#ifdef __LINUX__
#include <linux/ppdev.h>
#include <linux/parport.h>
@ -39,6 +50,7 @@
#include <freerdp/utils/thread.h>
#include <freerdp/utils/memory.h>
#include <freerdp/utils/stream.h>
#include <freerdp/utils/unicode.h>
#include <freerdp/utils/svc_plugin.h>
#include "rdpdr_constants.h"
@ -59,21 +71,19 @@ typedef struct _PARALLEL_DEVICE PARALLEL_DEVICE;
static void parallel_process_irp_create(PARALLEL_DEVICE* parallel, IRP* irp)
{
uint32 PathLength;
char* path;
UNICONV* uniconv;
uint32 PathLength;
stream_seek(irp->input, 28);
/* DesiredAccess(4) AllocationSize(8), FileAttributes(4) */
/* SharedAccess(4) CreateDisposition(4), CreateOptions(4) */
stream_read_uint32(irp->input, PathLength);
uniconv = freerdp_uniconv_new();
path = freerdp_uniconv_in(uniconv, stream_get_tail(irp->input), PathLength);
freerdp_uniconv_free(uniconv);
freerdp_UnicodeToAsciiAlloc((WCHAR*) stream_get_tail(irp->input), &path, PathLength / 2);
parallel->id = irp->devman->id_sequence++;
parallel->file = open(parallel->path, O_RDWR);
if (parallel->file < 0)
{
irp->IoStatus = STATUS_ACCESS_DENIED;
@ -163,6 +173,7 @@ static void parallel_process_irp_write(PARALLEL_DEVICE* parallel, IRP* irp)
DEBUG_SVC("Length %u Offset %llu", Length, Offset);
len = Length;
while (len > 0)
{
status = write(parallel->file, stream_get_tail(irp->input), len);

View File

@ -19,25 +19,35 @@
set(PRINTER_SRCS
printer_main.c
printer_main.h
)
printer_main.h)
if(WITH_CUPS)
set(PRINTER_SRCS
${PRINTER_SRCS}
printer_cups.c
printer_cups.h
)
printer_cups.h)
include_directories(${CUPS_INCLUDE_DIR})
add_definitions(-DWITH_CUPS)
endif()
if(WIN32)
set(PRINTER_SRCS
${PRINTER_SRCS}
printer_win.c
printer_win.h)
endif()
include_directories(..)
add_library(printer ${PRINTER_SRCS})
set_target_properties(printer PROPERTIES PREFIX "")
target_link_libraries(printer freerdp-utils)
if(WITH_MONOLITHIC_BUILD)
target_link_libraries(printer freerdp)
else()
target_link_libraries(printer freerdp-utils)
endif()
if(WITH_CUPS)
target_link_libraries(printer ${CUPS_LIBRARIES})

View File

@ -17,12 +17,18 @@
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <time.h>
#include <cups/cups.h>
#include <freerdp/utils/memory.h>
#include <freerdp/utils/svc_plugin.h>
@ -125,9 +131,8 @@ static void printer_cups_close_printjob(rdpPrintJob* printjob)
#endif
xfree(cups_printjob);
((rdpCupsPrinter*)printjob->printer)->printjob = NULL;
xfree(cups_printjob) ;
}
static rdpPrintJob* printer_cups_create_printjob(rdpPrinter* printer, uint32 id)

View File

@ -17,10 +17,14 @@
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <freerdp/utils/stream.h>
#include <freerdp/utils/unicode.h>
#include <freerdp/utils/memory.h>
@ -36,6 +40,10 @@
#include "printer_main.h"
#ifdef WIN32
#include "printer_win.h"
#endif
typedef struct _PRINTER_DEVICE PRINTER_DEVICE;
struct _PRINTER_DEVICE
{
@ -226,16 +234,15 @@ static void printer_free(DEVICE* device)
void printer_register(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, rdpPrinter* printer)
{
PRINTER_DEVICE* printer_dev;
char* port;
UNICONV* uniconv;
uint32 Flags;
size_t DriverNameLen;
char* DriverName;
size_t PrintNameLen;
char* PrintName;
int DriverNameLen;
WCHAR* DriverName;
int PrintNameLen;
WCHAR* PrintName;
uint32 CachedFieldsLen;
uint8* CachedPrinterConfigData;
PRINTER_DEVICE* printer_dev;
port = xmalloc(10);
snprintf(port, 10, "PRN%d", printer->id);
@ -255,13 +262,12 @@ void printer_register(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, rdpPrinter* pri
DEBUG_SVC("Printer %s registered", printer->name);
Flags = 0;
if (printer->is_default)
Flags |= RDPDR_PRINTER_ANNOUNCE_FLAG_DEFAULTPRINTER;
uniconv = freerdp_uniconv_new();
DriverName = freerdp_uniconv_out(uniconv, printer->driver, &DriverNameLen);
PrintName = freerdp_uniconv_out(uniconv, printer->name, &PrintNameLen);
freerdp_uniconv_free(uniconv);
DriverNameLen = freerdp_AsciiToUnicodeAlloc(printer->driver, &DriverName, 0) * 2;
PrintNameLen = freerdp_AsciiToUnicodeAlloc(printer->name, &PrintName, 0) * 2;
printer_dev->device.data = stream_new(28 + DriverNameLen + PrintNameLen + CachedFieldsLen);
@ -275,6 +281,7 @@ void printer_register(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, rdpPrinter* pri
stream_write_uint16(printer_dev->device.data, 0);
stream_write(printer_dev->device.data, PrintName, PrintNameLen);
stream_write_uint16(printer_dev->device.data, 0);
if (CachedFieldsLen > 0)
{
stream_write(printer_dev->device.data, CachedPrinterConfigData, CachedFieldsLen);
@ -291,7 +298,11 @@ void printer_register(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, rdpPrinter* pri
freerdp_thread_start(printer_dev->thread, printer_thread_func, printer_dev);
}
#ifdef WITH_STATIC_PLUGINS
int printer_entry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
#else
int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
#endif
{
rdpPrinterDriver* driver = NULL;
rdpPrinter** printers;
@ -302,6 +313,9 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
#ifdef WITH_CUPS
driver = printer_cups_get_driver();
#endif
#ifdef WIN32
driver = printer_win_get_driver();
#endif
if (driver == NULL)
{

View File

@ -0,0 +1,283 @@
/**
* FreeRDP: A Remote Desktop Protocol client.
* Print Virtual Channel - WIN driver
*
* Copyright 2012 Gerald Richter
*
* 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 <windows.h>
#include <winspool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "config.h"
#include <freerdp/utils/memory.h>
#include <freerdp/utils/svc_plugin.h>
#include "rdpdr_types.h"
#include "printer_main.h"
#include "printer_win.h"
typedef struct rdp_win_printer_driver rdpWinPrinterDriver;
typedef struct rdp_win_printer rdpWinPrinter;
typedef struct rdp_win_print_job rdpWinPrintJob;
struct rdp_win_printer_driver
{
rdpPrinterDriver driver;
int id_sequence;
};
struct rdp_win_printer
{
rdpPrinter printer;
HANDLE hPrinter;
rdpWinPrintJob* printjob;
};
struct rdp_win_print_job
{
rdpPrintJob printjob;
DOC_INFO_1 di;
DWORD handle;
void* printjob_object;
int printjob_id;
};
static void printer_win_get_printjob_name(char* buf, int size)
{
time_t tt;
struct tm* t;
DEBUG_WINPR("");
tt = time(NULL);
t = localtime(&tt);
snprintf(buf, size - 1, "FreeRDP Print Job %d%02d%02d%02d%02d%02d",
t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
t->tm_hour, t->tm_min, t->tm_sec);
DEBUG_WINPR("buf: %s", buf);
}
static void printer_win_write_printjob(rdpPrintJob* printjob, uint8* data, int size)
{
rdpWinPrintJob* win_printjob = (rdpWinPrintJob*)printjob;
LPVOID pBuf = data;
DWORD cbBuf = size;
DWORD pcWritten;
if( ! WritePrinter( ((rdpWinPrinter*)printjob->printer)->hPrinter, pBuf, cbBuf, &pcWritten ) )
DEBUG_WINPR("WritePrinter failed");
;
}
static void printer_win_close_printjob(rdpPrintJob* printjob)
{
rdpWinPrintJob* win_printjob = (rdpWinPrintJob*)printjob;
DEBUG_WINPR("");
if ( ! EndPagePrinter( ((rdpWinPrinter*)printjob->printer)->hPrinter ) )
DEBUG_WINPR("EndPagePrinter failed");;
if ( ! ClosePrinter( ((rdpWinPrinter*)printjob->printer)->hPrinter ) )
DEBUG_WINPR("ClosePrinter failed");;
((rdpWinPrinter*)printjob->printer)->printjob = NULL;
xfree(win_printjob) ;
}
static rdpPrintJob* printer_win_create_printjob(rdpPrinter* printer, uint32 id)
{
rdpWinPrinter* win_printer = (rdpWinPrinter*)printer;
rdpWinPrintJob* win_printjob;
DEBUG_WINPR("");
if (win_printer->printjob != NULL)
return NULL;
win_printjob = xnew(rdpWinPrintJob);
win_printjob->printjob.id = id;
win_printjob->printjob.printer = printer;
win_printjob->di.pDocName = L"FREERDPjob";
win_printjob->di.pDatatype= NULL;
win_printjob->di.pOutputFile = NULL;
win_printjob->handle = StartDocPrinter(win_printer->hPrinter, 1, (LPBYTE)&(win_printjob->di) );
if(! win_printjob->handle) DEBUG_WINPR("StartDocPrinter failed");
if ( ! StartPagePrinter(win_printer->hPrinter) )
DEBUG_WINPR("ClosePrinter failed");
win_printjob->printjob.Write = printer_win_write_printjob;
win_printjob->printjob.Close = printer_win_close_printjob;
win_printer->printjob = win_printjob;
return (rdpPrintJob*)win_printjob;
}
static rdpPrintJob* printer_win_find_printjob(rdpPrinter* printer, uint32 id)
{
rdpWinPrinter* win_printer = (rdpWinPrinter*)printer;
DEBUG_WINPR("");
if (win_printer->printjob == NULL)
return NULL;
if (win_printer->printjob->printjob.id != id)
return NULL;
return (rdpPrintJob*)win_printer->printjob;
}
static void printer_win_free_printer(rdpPrinter* printer)
{
rdpWinPrinter* win_printer = (rdpWinPrinter*)printer;
DEBUG_WINPR("");
if (win_printer->printjob)
win_printer->printjob->printjob.Close((rdpPrintJob*)win_printer->printjob);
xfree(printer->name);
xfree(printer);
}
static rdpPrinter* printer_win_new_printer(rdpWinPrinterDriver* win_driver, const char* name, const wchar_t* drivername, boolean is_default)
{
rdpWinPrinter* win_printer;
wchar_t wname[256];
DWORD needed;
PRINTER_INFO_2 *prninfo=NULL;
size_t charsConverted;
DEBUG_WINPR("");
win_printer = xnew(rdpWinPrinter);
win_printer->printer.id = win_driver->id_sequence++;
win_printer->printer.name = xstrdup(name);
win_printer->printer.is_default = is_default;
win_printer->printer.CreatePrintJob = printer_win_create_printjob;
win_printer->printer.FindPrintJob = printer_win_find_printjob;
win_printer->printer.Free = printer_win_free_printer;
swprintf(wname, 256, L"%hs", name);
OpenPrinter(wname, &(win_printer->hPrinter), NULL);
DEBUG_WINPR("handle: 0x%08X", win_printer->hPrinter);
GetPrinter(win_printer->hPrinter, 2, (LPBYTE) prninfo, 0, &needed);
prninfo = (PRINTER_INFO_2*) GlobalAlloc(GPTR,needed);
GetPrinter(win_printer->hPrinter, 2, (LPBYTE) prninfo, needed, &needed);
win_printer->printer.driver = xmalloc(1000);
wcstombs_s(&charsConverted, win_printer->printer.driver, 1000, prninfo->pDriverName, _TRUNCATE);
return (rdpPrinter*)win_printer;
}
static rdpPrinter** printer_win_enum_printers(rdpPrinterDriver* driver)
{
rdpPrinter** printers;
int num_printers;
int i;
char pname[1000];
size_t charsConverted;
PRINTER_INFO_2 *prninfo=NULL;
DWORD needed, returned;
DEBUG_WINPR("");
//find required size for the buffer
EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, NULL, 2, NULL, 0, &needed, &returned);
//allocate array of PRINTER_INFO structures
prninfo = (PRINTER_INFO_2*) GlobalAlloc(GPTR,needed);
//call again
if ( !EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, NULL, 2, (LPBYTE) prninfo, needed, &needed, &returned) ) {
DEBUG_WINPR("EnumPrinters failed");
} ; /* eRROR... */
DEBUG_WINPR("printers found: %d", returned);
printers = (rdpPrinter**)xzalloc(sizeof(rdpPrinter*) * (returned + 1));
num_printers = 0;
for (i = 0; i < (int)returned; i++)
{
wcstombs_s(&charsConverted, pname, 1000, prninfo[i].pPrinterName, _TRUNCATE);
printers[num_printers++] = printer_win_new_printer((rdpWinPrinterDriver*)driver,
pname, prninfo[i].pDriverName, 0);
}
GlobalFree(prninfo);
return printers;
}
static rdpPrinter* printer_win_get_printer(rdpPrinterDriver* driver, const char* name)
{
rdpWinPrinterDriver* win_driver = (rdpWinPrinterDriver*)driver;
rdpPrinter *myPrinter = NULL;
DEBUG_WINPR("printer %s", name);
myPrinter = printer_win_new_printer(win_driver, name, L"", win_driver->id_sequence == 1 ? true : false);
return myPrinter;
}
static rdpWinPrinterDriver* win_driver = NULL;
rdpPrinterDriver* printer_win_get_driver(void)
{
DEBUG_WINPR("");
if (win_driver == NULL)
{
win_driver = xnew(rdpWinPrinterDriver);
win_driver->driver.EnumPrinters = printer_win_enum_printers;
win_driver->driver.GetPrinter = printer_win_get_printer;
win_driver->id_sequence = 1;
//#ifdef _win_API_1_4
// DEBUG_SVC("using win API 1.4");
//#else
// DEBUG_SVC("using win API 1.2");
//#endif
}
return (rdpPrinterDriver*)win_driver;
}

View File

@ -0,0 +1,37 @@
/**
* FreeRDP: A Remote Desktop Protocol client.
* Print Virtual Channel - win driver
*
* Copyright 2012 Gerald Richter
*
* 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 __PRINTER_WIN_H
#define __PRINTER_WIN_H
rdpPrinterDriver* printer_win_get_driver(void);
#ifdef WITH_DEBUG_WINPR
#define DEBUG_WINPR(fmt, ...) DEBUG_CLASS(WINPR, fmt, ## __VA_ARGS__)
#else
#define DEBUG_WINPR(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
#endif
#endif
#ifdef WIN32
#define snprintf _snprintf
#endif

View File

@ -18,10 +18,14 @@
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <freerdp/utils/stream.h>
#include <freerdp/utils/svc_plugin.h>

View File

@ -124,6 +124,8 @@ enum FILE_CREATE_OPTION
};
/* DR_CREATE_REQ.DesiredAccess [MS-SMB2] */
#ifndef _WIN32
enum FILE_ACCESS
{
FILE_READ_DATA = 0x00000001,
@ -146,6 +148,7 @@ enum FILE_ACCESS
GENERIC_WRITE = 0x40000000,
GENERIC_READ = 0x80000000
};
#endif
/* DR_CREATE_RSP.Information */
/* DR_DRIVE_CREATE_RSP.DeviceCreateResponse */
@ -221,8 +224,10 @@ enum RDP_LOWIO_OP
enum NTSTATUS
{
STATUS_SUCCESS = 0x00000000,
#ifndef _WIN32
STATUS_TIMEOUT = 0x00000102,
STATUS_PENDING = 0x00000103,
#endif
STATUS_REPARSE = 0x00000104,
STATUS_MORE_ENTRIES = 0x00000105,
STATUS_NOT_ALL_ASSIGNED = 0x00000106,
@ -245,8 +250,10 @@ enum NTSTATUS
STATUS_UNSUCCESSFUL = 0xC0000001,
STATUS_NOT_IMPLEMENTED = 0xC0000002,
STATUS_INVALID_INFO_CLASS = 0xC0000003,
#ifndef _WIN32
STATUS_INVALID_HANDLE = 0xC0000008,
STATUS_INVALID_PARAMETER = 0xC000000D,
#endif
STATUS_NO_SUCH_DEVICE = 0xC000000E,
STATUS_NO_SUCH_FILE = 0xC000000F,
STATUS_INVALID_DEVICE_REQUEST = 0xC0000010,
@ -289,6 +296,9 @@ enum RDPDR_PRINTER_ANNOUNCE_FLAG
};
/* [MS-FSCC] FileAttributes */
#ifndef _WIN32
enum FILE_ATTRIBUTE
{
FILE_ATTRIBUTE_ARCHIVE = 0x00000020,
@ -306,6 +316,8 @@ enum FILE_ATTRIBUTE
FILE_ATTRIBUTE_TEMPORARY = 0x00000100
};
#endif
/* [MS-FSCC] FSCTL Structures */
enum FSCTL_STRUCTURE
{
@ -337,6 +349,9 @@ enum FSCTL_STRUCTURE
};
/* [MS-FSCC] FileFsAttributeInformation.FileSystemAttributes */
#ifndef _WIN32
enum FILE_FS_ATTRIBUTE_INFORMATION
{
FILE_SUPPORTS_USN_JOURNAL = 0x02000000,
@ -361,6 +376,8 @@ enum FILE_FS_ATTRIBUTE_INFORMATION
FILE_CASE_SENSITIVE_SEARCH = 0x00000001
};
#endif
/* [MS-FSCC] FileFsDeviceInformation.DeviceType */
enum FILE_FS_DEVICE_TYPE
{

View File

@ -18,10 +18,14 @@
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <freerdp/constants.h>
#include <freerdp/types.h>
#include <freerdp/utils/memory.h>
@ -59,7 +63,7 @@ static void rdpdr_process_connect(rdpSvcPlugin* plugin)
{
devman_load_device_service(rdpdr->devman, data);
}
data = (RDP_PLUGIN_DATA*) (((void*) data) + data->size);
data = (RDP_PLUGIN_DATA*) (((uint8*) data) + data->size);
}
}
@ -83,24 +87,22 @@ static void rdpdr_send_client_announce_reply(rdpdrPlugin* rdpdr)
stream_write_uint16(data_out, rdpdr->versionMajor);
stream_write_uint16(data_out, rdpdr->versionMinor);
stream_write_uint32(data_out, rdpdr->clientID);
stream_write_uint32(data_out, (uint32) rdpdr->clientID);
svc_plugin_send((rdpSvcPlugin*) rdpdr, data_out);
}
static void rdpdr_send_client_name_request(rdpdrPlugin* rdpdr)
{
char* s;
STREAM* data_out;
UNICONV* uniconv;
WCHAR* computerNameW;
size_t computerNameLenW;
uniconv = freerdp_uniconv_new();
if (!rdpdr->computerName[0])
gethostname(rdpdr->computerName, sizeof(rdpdr->computerName) - 1);
s = freerdp_uniconv_out(uniconv, rdpdr->computerName, &computerNameLenW);
computerNameLenW = freerdp_AsciiToUnicodeAlloc(rdpdr->computerName, &computerNameW, 0) * 2;
data_out = stream_new(16 + computerNameLenW + 2);
stream_write_uint16(data_out, RDPDR_CTYP_CORE);
@ -109,11 +111,10 @@ static void rdpdr_send_client_name_request(rdpdrPlugin* rdpdr)
stream_write_uint32(data_out, 1); /* unicodeFlag, 0 for ASCII and 1 for Unicode */
stream_write_uint32(data_out, 0); /* codePage, must be set to zero */
stream_write_uint32(data_out, computerNameLenW + 2); /* computerNameLen, including null terminator */
stream_write(data_out, s, computerNameLenW);
stream_write(data_out, computerNameW, computerNameLenW);
stream_write_uint16(data_out, 0); /* null terminator */
xfree(s);
freerdp_uniconv_free(uniconv);
xfree(computerNameW);
svc_plugin_send((rdpSvcPlugin*) rdpdr, data_out);
}
@ -231,11 +232,11 @@ static boolean rdpdr_process_irp(rdpdrPlugin* rdpdr, STREAM* data_in)
static void rdpdr_process_receive(rdpSvcPlugin* plugin, STREAM* data_in)
{
rdpdrPlugin* rdpdr = (rdpdrPlugin*) plugin;
uint16 component;
uint16 packetID;
uint32 deviceID;
uint32 status;
rdpdrPlugin* rdpdr = (rdpdrPlugin*) plugin;
stream_read_uint16(data_in, component);
stream_read_uint16(data_in, packetID);

View File

@ -21,7 +21,6 @@
#ifndef __RDPDR_TYPES_H
#define __RDPDR_TYPES_H
#include "config.h"
#include <freerdp/utils/stream.h>
#include <freerdp/utils/list.h>
#include <freerdp/utils/svc_plugin.h>

View File

@ -21,14 +21,17 @@ set(serial_SRCS
serial_tty.c
serial_tty.h
serial_constants.h
serial_main.c
)
serial_main.c)
include_directories(..)
add_library(serial ${serial_SRCS})
set_target_properties(serial PROPERTIES PREFIX "")
target_link_libraries(serial freerdp-utils)
if(WITH_MONOLITHIC_BUILD)
target_link_libraries(serial freerdp)
else()
target_link_libraries(serial freerdp-utils)
endif()
install(TARGETS serial DESTINATION ${FREERDP_PLUGIN_PATH})

View File

@ -18,13 +18,15 @@
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "config.h"
#ifdef HAVE_SYS_MODEM_H
#include <sys/modem.h>
#endif
@ -77,23 +79,21 @@ static boolean serial_check_fds(SERIAL_DEVICE* serial);
static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp)
{
char* path;
SERIAL_TTY* tty;
uint32 PathLength;
uint32 FileId;
char* path;
UNICONV* uniconv;
stream_seek(irp->input, 28); /* DesiredAccess(4) AllocationSize(8), FileAttributes(4) */
/* SharedAccess(4) CreateDisposition(4), CreateOptions(4) */
stream_read_uint32(irp->input, PathLength);
uniconv = freerdp_uniconv_new();
path = freerdp_uniconv_in(uniconv, stream_get_tail(irp->input), PathLength);
freerdp_uniconv_free(uniconv);
freerdp_UnicodeToAsciiAlloc((WCHAR*) stream_get_tail(irp->input), &path, PathLength / 2);
FileId = irp->devman->id_sequence++;
tty = serial_tty_new(serial->path, FileId);
if (tty == NULL)
{
irp->IoStatus = STATUS_UNSUCCESSFUL;
@ -120,6 +120,7 @@ static void serial_process_irp_close(SERIAL_DEVICE* serial, IRP* irp)
SERIAL_TTY* tty;
tty = serial->tty;
if (tty == NULL)
{
irp->IoStatus = STATUS_UNSUCCESSFUL;
@ -151,6 +152,7 @@ static void serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp)
DEBUG_SVC("length %u offset %llu", Length, Offset);
tty = serial->tty;
if (tty == NULL)
{
irp->IoStatus = STATUS_UNSUCCESSFUL;
@ -177,11 +179,13 @@ static void serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp)
}
stream_write_uint32(irp->output, Length);
if (Length > 0)
{
stream_check_size(irp->output, Length);
stream_write(irp->output, buffer, Length);
}
xfree(buffer);
irp->Complete(irp);
@ -200,6 +204,7 @@ static void serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp)
DEBUG_SVC("length %u offset %llu", Length, Offset);
tty = serial->tty;
if (tty == NULL)
{
irp->IoStatus = STATUS_UNSUCCESSFUL;
@ -241,6 +246,7 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp)
stream_seek(irp->input, 20); /* Padding */
tty = serial->tty;
if (tty == NULL)
{
irp->IoStatus = STATUS_UNSUCCESSFUL;

View File

@ -18,10 +18,14 @@
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <freerdp/utils/memory.h>
#include <freerdp/utils/stream.h>
#include <freerdp/utils/unicode.h>
@ -30,13 +34,16 @@
#include <freerdp/utils/svc_plugin.h>
#include <freerdp/utils/hexdump.h>
#ifndef _WIN32
#include <unistd.h>
#include <termios.h>
#include <dirent.h>
#include <sys/ioctl.h>
#endif
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <sys/ioctl.h>
#include <errno.h>
#include "rdpdr_constants.h"
@ -67,7 +74,6 @@
#define TIOCOUTQ FIONWRITE
#endif
static uint32 tty_write_data(SERIAL_TTY* tty, uint8* data, int len);
static void tty_set_termios(SERIAL_TTY* tty);
static boolean tty_get_termios(SERIAL_TTY* tty);
@ -434,13 +440,21 @@ boolean serial_tty_write(SERIAL_TTY* tty, uint8* buffer, uint32 Length)
return true;
}
/**
* This function is used to deallocated a SERIAL_TTY structure.
*
* @param tty [in] - pointer to the SERIAL_TTY structure to deallocate.
* This will typically be allocated by a call to serial_tty_new().
* On return, this pointer is invalid.
*/
void serial_tty_free(SERIAL_TTY* tty)
{
DEBUG_SVC("in");
if (tty->fd >= 0)
{
tcsetattr(tty->fd, TCSANOW, tty->pold_termios);
if (tty->pold_termios)
tcsetattr(tty->fd, TCSANOW, tty->pold_termios);
close(tty->fd);
}
@ -449,6 +463,7 @@ void serial_tty_free(SERIAL_TTY* tty)
xfree(tty);
}
SERIAL_TTY* serial_tty_new(const char* path, uint32 id)
{
SERIAL_TTY* tty;
@ -460,21 +475,32 @@ SERIAL_TTY* serial_tty_new(const char* path, uint32 id)
{
perror("open");
DEBUG_WARN("failed to open device %s", path);
serial_tty_free(tty) ;
return NULL;
}
else
DEBUG_SVC("tty fd %d successfully opened", tty->fd);
tty->ptermios = (struct termios*) malloc(sizeof(struct termios));
memset(tty->ptermios, 0, sizeof(struct termios));
tty->pold_termios = (struct termios*) malloc(sizeof(struct termios));
memset(tty->pold_termios, 0, sizeof(struct termios));
tty->ptermios = (struct termios*) xzalloc(sizeof(struct termios));
if (tty->ptermios == NULL)
{
serial_tty_free(tty) ;
return NULL ;
}
tty->pold_termios = (struct termios*) xzalloc(sizeof(struct termios));
if (tty->pold_termios == NULL)
{
serial_tty_free(tty) ;
return NULL ;
}
tcgetattr(tty->fd, tty->pold_termios);
if (!tty_get_termios(tty))
{
DEBUG_WARN("%s access denied", path);
fflush(stdout);
serial_tty_free(tty) ;
return NULL;
}
@ -497,6 +523,7 @@ SERIAL_TTY* serial_tty_new(const char* path, uint32 id)
{
DEBUG_WARN("%s fcntl", path);
perror("fcntl");
serial_tty_free(tty) ;
return NULL;
}

View File

@ -23,7 +23,10 @@
#include <sys/types.h>
#include <sys/stat.h>
#ifndef _WIN32
#include <dirent.h>
#endif
typedef struct _SERIAL_TTY SERIAL_TTY;
struct _SERIAL_TTY
@ -59,7 +62,6 @@ struct _SERIAL_TTY
int event_pending;
};
SERIAL_TTY* serial_tty_new(const char* path, uint32 id);
void serial_tty_free(SERIAL_TTY* tty);

View File

@ -28,7 +28,12 @@ include_directories(${PCSC_INCLUDE_DIRS})
add_library(scard ${SCARD_SRCS})
set_target_properties(scard PROPERTIES PREFIX "")
target_link_libraries(scard freerdp-utils)
if(WITH_MONOLITHIC_BUILD)
target_link_libraries(scard freerdp)
else()
target_link_libraries(scard freerdp-utils)
endif()
target_link_libraries(scard ${PCSC_LIBRARIES})
install(TARGETS scard DESTINATION ${FREERDP_PLUGIN_PATH})

View File

@ -0,0 +1,332 @@
/**
* FreeRDP: A Remote Desktop Protocol client.
* Smartcard Device Service Virtual Channel
*
* Copyright 2011 O.S. Systems Software Ltda.
* Copyright 2011 Eduardo Fiss Beloni <beloni@ossystems.com.br>
* Copyright 2011 Anthony Tong <atong@trustedcs.com>
*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <freerdp/utils/list.h>
#include <freerdp/utils/thread.h>
#include <freerdp/utils/svc_plugin.h>
#include <freerdp/utils/debug.h>
#include "rdpdr_types.h"
#include "rdpdr_constants.h"
#include "scard_main.h"
static void scard_free(DEVICE* dev)
{
IRP* irp;
COMPLETIONIDINFO* CompletionIdInfo;
SCARD_DEVICE* scard = (SCARD_DEVICE*) dev;
freerdp_thread_stop(scard->thread);
freerdp_thread_free(scard->thread);
while ((irp = (IRP*) list_dequeue(scard->irp_list)) != NULL)
irp->Discard(irp);
list_free(scard->irp_list);
/* Begin TS Client defect workaround. */
while ((CompletionIdInfo = (COMPLETIONIDINFO*) list_dequeue(scard->CompletionIds)) != NULL)
xfree(CompletionIdInfo);
list_free(scard->CompletionIds);
/* End TS Client defect workaround. */
xfree(dev);
return;
}
static void scard_process_irp(SCARD_DEVICE* scard, IRP* irp)
{
switch (irp->MajorFunction)
{
case IRP_MJ_DEVICE_CONTROL:
scard_device_control(scard, irp);
break;
default:
printf("MajorFunction 0x%X unexpected for smartcards.", irp->MajorFunction);
DEBUG_WARN("Smartcard MajorFunction 0x%X not supported.", irp->MajorFunction);
irp->IoStatus = STATUS_NOT_SUPPORTED;
irp->Complete(irp);
break;
}
}
static void scard_process_irp_list(SCARD_DEVICE* scard)
{
IRP* irp;
while (!freerdp_thread_is_stopped(scard->thread))
{
freerdp_thread_lock(scard->thread);
irp = (IRP*) list_dequeue(scard->irp_list);
freerdp_thread_unlock(scard->thread);
if (irp == NULL)
break;
scard_process_irp(scard, irp);
}
}
struct scard_irp_thread_args
{
SCARD_DEVICE* scard;
IRP* irp;
freerdp_thread* thread;
};
static void scard_process_irp_thread_func(struct scard_irp_thread_args* args)
{
scard_process_irp(args->scard, args->irp);
freerdp_thread_free(args->thread);
xfree(args);
}
static void* scard_thread_func(void* arg)
{
SCARD_DEVICE* scard = (SCARD_DEVICE*) arg;
while (1)
{
freerdp_thread_wait(scard->thread);
if (freerdp_thread_is_stopped(scard->thread))
break;
freerdp_thread_reset(scard->thread);
scard_process_irp_list(scard);
}
freerdp_thread_quit(scard->thread);
return NULL;
}
/* Begin TS Client defect workaround. */
static COMPLETIONIDINFO* scard_mark_duplicate_id(SCARD_DEVICE* scard, uint32 CompletionId)
{
/*
* Search from the beginning of the LIST for one outstanding "CompletionID"
* that matches the one passed in. If there is one, mark it as a duplicate
* if it is not already marked.
*/
LIST_ITEM* item;
COMPLETIONIDINFO* CompletionIdInfo;
for (item = scard->CompletionIds->head; item; item = item->next)
{
CompletionIdInfo = (COMPLETIONIDINFO*)item->data;
if (CompletionIdInfo->ID == CompletionId)
{
if (false == CompletionIdInfo->duplicate)
{
CompletionIdInfo->duplicate = true;
DEBUG_WARN("CompletionID number %u is now marked as a duplicate.", CompletionId);
}
return CompletionIdInfo;
}
}
return NULL; /* Either no items in the list or no match. */
}
static boolean scard_check_for_duplicate_id(SCARD_DEVICE* scard, uint32 CompletionId)
{
/*
* Search from the end of the LIST for one outstanding "CompletionID"
* that matches the one passed in. Remove it from the list and free the
* memory associated with it. Return whether or not it was marked
* as a duplicate.
*/
LIST_ITEM* item;
COMPLETIONIDINFO* CompletionIdInfo;
boolean duplicate;
for (item = scard->CompletionIds->tail; item; item = item->prev)
{
CompletionIdInfo = (COMPLETIONIDINFO*)item->data;
if (CompletionIdInfo->ID == CompletionId)
{
duplicate = CompletionIdInfo->duplicate;
if (true == duplicate)
{
DEBUG_WARN("CompletionID number %u was previously marked as a duplicate. The response to the command is removed.", CompletionId);
}
list_remove(scard->CompletionIds, CompletionIdInfo);
xfree(CompletionIdInfo);
return duplicate;
}
}
/* This function should only be called when there is
* at least one outstanding CompletionID item in the list.
*/
DEBUG_WARN("Error!!! No CompletionIDs (or no matching IDs) in the list!");
return false;
}
static void scard_irp_complete(IRP* irp)
{
/* This function is (mostly) a copy of the statically-declared "irp_complete()"
* function except that this function adds extra operations for the
* smart card's handling of duplicate "CompletionID"s. This function needs
* to be in this file so that "scard_irp_request()" can reference it.
*/
int pos;
boolean duplicate;
SCARD_DEVICE* scard = (SCARD_DEVICE*)irp->device;
DEBUG_SVC("DeviceId %d FileId %d CompletionId %d", irp->device->id, irp->FileId, irp->CompletionId);
pos = stream_get_pos(irp->output);
stream_set_pos(irp->output, 12);
stream_write_uint32(irp->output, irp->IoStatus);
stream_set_pos(irp->output, pos);
/* Begin TS Client defect workaround. */
WaitForSingleObject(scard->CompletionIdsMutex, INFINITE);
/* Remove from the list the item identified by the CompletionID.
* The function returns whether or not it was a duplicate CompletionID.
*/
duplicate = scard_check_for_duplicate_id(scard, irp->CompletionId);
ReleaseMutex(scard->CompletionIdsMutex);
if (false == duplicate)
{
svc_plugin_send(irp->devman->plugin, irp->output);
irp->output = NULL;
}
/* End TS Client defect workaround. */
/* irp_free(irp); The "irp_free()" function is statically-declared
* and so is not available to be called
* here. Instead, call it indirectly by calling
* the IRP's "Discard()" function,
* which has already been assigned
* to point to "irp_free()" in "irp_new()".
*/
irp->Discard(irp);
}
/* End TS Client defect workaround. */
static void scard_irp_request(DEVICE* device, IRP* irp)
{
COMPLETIONIDINFO* CompletionIdInfo;
SCARD_DEVICE* scard = (SCARD_DEVICE*) device;
/* Begin TS Client defect workaround. */
CompletionIdInfo= xnew(COMPLETIONIDINFO);
CompletionIdInfo->ID = irp->CompletionId;/* "duplicate" member is set
* to false by "xnew()"
*/
WaitForSingleObject(scard->CompletionIdsMutex, INFINITE);
scard_mark_duplicate_id(scard, irp->CompletionId);
list_enqueue(scard->CompletionIds, CompletionIdInfo);
ReleaseMutex(scard->CompletionIdsMutex);
irp->Complete = scard_irp_complete; /* Overwrite the previous
* assignment made in
* "irp_new()".
*/
/* End TS Client defect workaround. */
if (irp->MajorFunction == IRP_MJ_DEVICE_CONTROL &&
scard_async_op(irp))
{
/*
* certain potentially long running operations
* get their own thread
* TODO: revise this mechanism.. maybe worker pool
*/
struct scard_irp_thread_args *args = xmalloc(sizeof(struct scard_irp_thread_args));
args->thread = freerdp_thread_new();
args->scard = scard;
args->irp = irp;
freerdp_thread_start(args->thread, scard_process_irp_thread_func, args);
return;
}
freerdp_thread_lock(scard->thread);
list_enqueue(scard->irp_list, irp);
freerdp_thread_unlock(scard->thread);
freerdp_thread_signal(scard->thread);
}
int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
{
char* name;
char* path;
int i, length;
SCARD_DEVICE* scard;
name = (char*) pEntryPoints->plugin_data->data[1];
path = (char*) pEntryPoints->plugin_data->data[2];
if (name)
{
/* TODO: check if server supports sc redirect (version 5.1) */
scard = xnew(SCARD_DEVICE);
scard->device.type = RDPDR_DTYP_SMARTCARD;
scard->device.name = "SCARD";
scard->device.IRPRequest = scard_irp_request;
scard->device.Free = scard_free;
length = strlen(scard->device.name);
scard->device.data = stream_new(length + 1);
for (i = 0; i <= length; i++)
stream_write_uint8(scard->device.data, name[i] < 0 ? '_' : name[i]);
scard->path = path;
scard->irp_list = list_new();
scard->thread = freerdp_thread_new();
scard->CompletionIds = list_new();
scard->CompletionIdsMutex = CreateMutex(NULL, FALSE, NULL);
pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE *)scard);
freerdp_thread_start(scard->thread, scard_thread_func, scard);
}
return 0;
}

View File

@ -0,0 +1,125 @@
/**
* FreeRDP: A Remote Desktop Protocol client.
* Smartcard Device Service Virtual Channel
*
* Copyright 2011 O.S. Systems Software Ltda.
* Copyright 2011 Eduardo Fiss Beloni <beloni@ossystems.com.br>
*
* 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 __SCARD_MAIN_H
#define __SCARD_MAIN_H
#include <inttypes.h>
#include "devman.h"
#include "rdpdr_types.h"
#include <freerdp/utils/list.h>
#include <freerdp/utils/debug.h>
#include <winpr/synch.h>
/*
* When using Windows Server 2008 R2 as the Terminal Services (TS)
* server, and with a smart card reader connected to the TS client machine
* and used to authenticate to an existing login session, the TS server
* will initiate the protocol initialization of MS-RDPEFS, Section 1.3.1,
* twice as it re-establishes a connection. The TS server starts both
* initializations with a "Server Announce Request" message.
* When the TS client receives this message, as per Section 3.2.5.1.2,
*
* The client SHOULD treat this packet as the beginning
* of a new sequence. The client SHOULD also cancel all
* outstanding requests and release previous references to
* all devices.
*
* As of this writing, the code does not cancel all outstanding requests.
* This leads to a problem where, after the first MS-RDPEFS initialization,
* the TS server sends an SCARD_IOCTL_GETSTATUSCHANGEx control in a message
* that uses an available "CompletionID". The
* TS client doesn't respond immediately because it is blocking while
* waiting for a change in the smart card's status in the reader.
* Then the TS server initiates a second MS-RDPEFS initialization sequence.
* As noted above, this should cancel the outstanding
* SCARD_IOCTL_GETSTATUSCHANGEx request, but it does not.
* At this point, the TS server is free to reuse the previously used
* "CompletionID", and it does reuse it for other SCARD_IOCTLs.
* Therefore, when the user removes (for example) the card from the reader,
* the TS client sends an "IOCompetion" message in response to the
* GETSTATUSCHANGEx using the original "CompletionID". The TS server does not
* expect this "CompletionID" and so, as per Section 3.1.5.2 of MS-RDPEFS,
* it treats that "IOCompletion" message as an error and terminates the
* virtual channel.
*
* The following structure is part of a work-around for this missing
* capability of canceling outstanding requests. This work-around
* allows the TS client to send an "IOCompletion" back to the
* TS server for the second (and subsequent) SCARD_IOCTLs that use
* the same "CompletionID" as the still outstanding
* SCARD_IOCTL_GETSTATUSCHANGEx. The work-around in the TS client
* prevents the client from sending the "IOCompletion" back (when
* the user removes the card) for the SCARD_IOCTL_GETSTATUSCHANGEx.
*
* This TS client expects the responses from the PCSC daemon for the second
* and subsequent SCARD_IOCTLs that use the same "CompletionID"
* to arrive at the TS client before the daemon's response to the
* SCARD_IOCTL_GETSTATUSCHANGEx. This is a race condition.
*
* The "CompletionIDs" are a global pool of IDs across all "DeviceIDs".
* However, this problem of duplicate "CompletionIDs" only affects smart cards.
*
* This structure tracks outstanding Terminal Services server "CompletionIDs"
* used by the redirected smart card device.
*/
struct _COMPLETIONIDINFO
{
uint32 ID; /* CompletionID */
boolean duplicate; /* Indicates whether or not this
* CompletionID is a duplicate of an
* earlier, outstanding, CompletionID.
*/
};
typedef struct _COMPLETIONIDINFO COMPLETIONIDINFO;
struct _SCARD_DEVICE
{
DEVICE device;
char * name;
char * path;
LIST* irp_list;
freerdp_thread* thread;
LIST* CompletionIds;
HANDLE CompletionIdsMutex; /* Protect the LIST from
* multiple thread writers.
*/
};
typedef struct _SCARD_DEVICE SCARD_DEVICE;
#ifdef WITH_DEBUG_SCARD
#define DEBUG_SCARD(fmt, ...) DEBUG_CLASS(SCARD, fmt, ## __VA_ARGS__)
#else
#define DEBUG_SCARD(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
#endif
boolean scard_async_op(IRP*);
void scard_device_control(SCARD_DEVICE*, IRP*);
#endif

View File

@ -1,44 +1,47 @@
/*
FreeRDP: A Remote Desktop Protocol client.
Redirected Smart Card Device Service
Copyright (C) Alexi Volkov <alexi@myrealbox.com> 2006
Copyright 2011 O.S. Systems Software Ltda.
Copyright 2011 Anthony Tong <atong@trustedcs.com>
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.
*/
/**
* FreeRDP: A Remote Desktop Protocol client.
* Smartcard Device Service Virtual Channel
*
* Copyright (C) Alexi Volkov <alexi@myrealbox.com> 2006
* Copyright 2011 O.S. Systems Software Ltda.
* Copyright 2011 Anthony Tong <atong@trustedcs.com>
*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <strings.h>
#include <semaphore.h>
#include <pthread.h>
#include <semaphore.h>
#define BOOL PCSC_BOOL
#include <PCSC/pcsclite.h>
#include <PCSC/reader.h>
#include <PCSC/winscard.h>
#undef BOOL
#include <freerdp/freerdp.h>
#include <freerdp/utils/hexdump.h>
#include <freerdp/utils/memory.h>
#include <freerdp/utils/stream.h>
#include <freerdp/utils/svc_plugin.h>
#include <freerdp/utils/semaphore.h>
#include <freerdp/utils/thread.h>
#include "rdpdr_types.h"
@ -114,7 +117,12 @@ static uint32 sc_output_string(IRP* irp, char *src, boolean wide)
static void sc_output_alignment(IRP *irp, uint32 seed)
{
uint32 size = stream_get_length(irp->output) - 20;
const uint32 field_lengths = 20;/* Remove the lengths of the fields
* RDPDR_HEADER, DeviceID,
* CompletionID, and IoStatus
* of Section 2.2.1.5.5 of MS-RDPEFS.
*/
uint32 size = stream_get_length(irp->output) - field_lengths;
uint32 add = (seed - (size % seed)) % seed;
if (add > 0)
@ -270,14 +278,15 @@ static uint32 handle_EstablishContext(IRP* irp)
rv = SCardEstablishContext(scope, NULL, NULL, &hContext);
stream_write_uint32(irp->output, 4); // ?
stream_write_uint32(irp->output, -1); // ?
stream_write_uint32(irp->output, 4); // cbContext
stream_write_uint32(irp->output, -1); // ReferentID
stream_write_uint32(irp->output, 4);
stream_write_uint32(irp->output, hContext);
/* TODO: store hContext in allowed context list */
sc_output_alignment(irp, 8);
return SCARD_S_SUCCESS;
}
@ -298,6 +307,7 @@ static uint32 handle_ReleaseContext(IRP* irp)
else
DEBUG_SCARD("success 0x%08lx", hContext);
sc_output_alignment(irp, 8);
return rv;
}
@ -316,7 +326,7 @@ static uint32 handle_IsValidContext(IRP* irp)
else
DEBUG_SCARD("Success context: 0x%08x", (unsigned) hContext);
stream_write_uint32(irp->output, rv);
sc_output_alignment(irp, 8);
return rv;
}
@ -454,7 +464,6 @@ static uint32 handle_GetStatusChange(IRP* irp, boolean wide)
/* reset high bytes? */
cur->dwCurrentState &= 0x0000FFFF;
cur->dwEventState &= 0x0000FFFF;
cur->dwEventState = 0;
}
@ -576,7 +585,6 @@ static uint32 handle_Connect(IRP* irp, boolean wide)
stream_write_uint32(irp->output, dwActiveProtocol);
stream_write_uint32(irp->output, 0x00000004);
stream_write_uint32(irp->output, hCard);
stream_seek(irp->output, 28);
sc_output_alignment(irp, 8);
@ -616,8 +624,8 @@ static uint32 handle_Reconnect(IRP* irp)
else
DEBUG_SCARD("Success (proto: 0x%08x)", (unsigned) dwActiveProtocol);
stream_write_uint32(irp->output, dwActiveProtocol);
sc_output_alignment(irp, 8);
stream_write_uint32(irp->output, dwActiveProtocol); /* reversed? */
return rv;
}
@ -1165,7 +1173,7 @@ static uint32 handle_GetAttrib(IRP* irp)
static uint32 handle_AccessStartedEvent(IRP* irp)
{
stream_write_zero(irp->output, 8);
sc_output_alignment(irp, 8);
return SCARD_S_SUCCESS;
}
@ -1362,11 +1370,18 @@ boolean scard_async_op(IRP* irp)
void scard_device_control(SCARD_DEVICE* scard, IRP* irp)
{
uint32 output_len, input_len, ioctl_code;
uint32 stream_len, result;
uint32 pos, pad_len;
uint32 irp_len;
uint32 irp_result_pos, output_len_pos, result_pos;
uint32 pos;
uint32 result;
uint32 result_pos;
uint32 output_len;
uint32 input_len;
uint32 ioctl_code;
uint32 stream_len;
uint32 irp_result_pos;
uint32 output_len_pos;
const uint32 header_lengths = 16; /* MS-RPCE, Sections 2.2.6.1
* and 2.2.6.2.
*/
stream_read_uint32(irp->input, output_len);
stream_read_uint32(irp->input, input_len);
@ -1383,8 +1398,12 @@ void scard_device_control(SCARD_DEVICE* scard, IRP* irp)
irp_result_pos = stream_get_pos(irp->output);
stream_write_uint32(irp->output, 0x00081001); /* len 8, LE, v1 */
stream_write_uint32(irp->output, 0x00000000); /* MS-RDPEFS
* OutputBufferLength
* will be updated
* later in this
* function.
*/
/* [MS-RPCE] 2.2.6.1 */
stream_write_uint32(irp->output, 0x00081001); /* len 8, LE, v1 */
stream_write_uint32(irp->output, 0xcccccccc); /* filler */
@ -1510,26 +1529,21 @@ void scard_device_control(SCARD_DEVICE* scard, IRP* irp)
/* handle response packet */
pos = stream_get_pos(irp->output);
stream_len = pos - irp_result_pos - 4;
stream_len = pos - irp_result_pos - 4; /* Value of OutputBufferLength */
stream_set_pos(irp->output, irp_result_pos);
stream_write_uint32(irp->output, stream_len);
stream_set_pos(irp->output, output_len_pos);
stream_write_uint32(irp->output, stream_len - 24);
/* Remove the effect of the MS-RPCE Common Type Header and Private
* Header (Sections 2.2.6.1 and 2.2.6.2).
*/
stream_write_uint32(irp->output, stream_len - header_lengths);
stream_set_pos(irp->output, result_pos);
stream_write_uint32(irp->output, result);
stream_set_pos(irp->output, pos);
/* pad stream to 16 byte align */
pad_len = stream_len % 16;
stream_write_zero(irp->output, pad_len);
pos = stream_get_pos(irp->output);
irp_len = stream_len + pad_len;
stream_set_pos(irp->output, irp_result_pos);
stream_write_uint32(irp->output, irp_len);
stream_set_pos(irp->output, pos);
#ifdef WITH_DEBUG_SCARD
freerdp_hexdump(stream_get_data(irp->output), stream_get_length(irp->output));
#endif

View File

@ -1,204 +0,0 @@
/*
FreeRDP: A Remote Desktop Protocol client.
Redirected Smart Card Device Service
Copyright 2011 O.S. Systems Software Ltda.
Copyright 2011 Eduardo Fiss Beloni <beloni@ossystems.com.br>
Copyright 2011 Anthony Tong <atong@trustedcs.com>
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 "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <freerdp/utils/list.h>
#include <freerdp/utils/thread.h>
#include <freerdp/utils/svc_plugin.h>
#include "rdpdr_types.h"
#include "rdpdr_constants.h"
#include "scard_main.h"
static void
scard_free(DEVICE* dev)
{
SCARD_DEVICE* scard = (SCARD_DEVICE*)dev;
IRP* irp;
freerdp_thread_stop(scard->thread);
freerdp_thread_free(scard->thread);
while ((irp = (IRP*)list_dequeue(scard->irp_list)) != NULL)
irp->Discard(irp);
list_free(scard->irp_list);
xfree(dev);
return;
}
static void
scard_process_irp(SCARD_DEVICE* scard, IRP* irp)
{
switch (irp->MajorFunction)
{
case IRP_MJ_DEVICE_CONTROL:
scard_device_control(scard, irp);
break;
default:
printf("MajorFunction 0x%X unexpected for smartcards.", irp->MajorFunction);
DEBUG_WARN("Smartcard MajorFunction 0x%X not supported.", irp->MajorFunction);
irp->IoStatus = STATUS_NOT_SUPPORTED;
irp->Complete(irp);
break;
}
}
static void
scard_process_irp_list(SCARD_DEVICE* scard)
{
IRP *irp;
while (!freerdp_thread_is_stopped(scard->thread))
{
freerdp_thread_lock(scard->thread);
irp = (IRP *) list_dequeue(scard->irp_list);
freerdp_thread_unlock(scard->thread);
if (irp == NULL)
break;
scard_process_irp(scard, irp);
}
}
struct scard_irp_thread_args {
SCARD_DEVICE* scard;
IRP* irp;
freerdp_thread* thread;
};
static void
scard_process_irp_thread_func(struct scard_irp_thread_args* args)
{
scard_process_irp(args->scard, args->irp);
freerdp_thread_free(args->thread);
xfree(args);
}
static void *
scard_thread_func(void* arg)
{
SCARD_DEVICE* scard = (SCARD_DEVICE*) arg;
while (1)
{
freerdp_thread_wait(scard->thread);
if (freerdp_thread_is_stopped(scard->thread))
break;
freerdp_thread_reset(scard->thread);
scard_process_irp_list(scard);
}
freerdp_thread_quit(scard->thread);
return NULL;
}
static void
scard_irp_request(DEVICE* device, IRP* irp)
{
SCARD_DEVICE* scard = (SCARD_DEVICE*)device;
if (irp->MajorFunction == IRP_MJ_DEVICE_CONTROL &&
scard_async_op(irp))
{
/*
* certain potentially long running operations
* get their own thread
* TODO: revise this mechanism.. maybe worker pool
*/
struct scard_irp_thread_args *args = xmalloc(sizeof(struct scard_irp_thread_args));
args->thread = freerdp_thread_new();
args->scard = scard;
args->irp = irp;
freerdp_thread_start(args->thread, scard_process_irp_thread_func, args);
return;
}
freerdp_thread_lock(scard->thread);
list_enqueue(scard->irp_list, irp);
freerdp_thread_unlock(scard->thread);
freerdp_thread_signal(scard->thread);
}
int
DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
{
SCARD_DEVICE* scard;
char* name;
char* path;
int i, length;
name = (char *)pEntryPoints->plugin_data->data[1];
path = (char *)pEntryPoints->plugin_data->data[2];
if (name)
{
/* TODO: check if server supports sc redirect (version 5.1) */
scard = xnew(SCARD_DEVICE);
scard->device.type = RDPDR_DTYP_SMARTCARD;
scard->device.name = "SCARD";
scard->device.IRPRequest = scard_irp_request;
scard->device.Free = scard_free;
length = strlen(scard->device.name);
scard->device.data = stream_new(length + 1);
for (i = 0; i <= length; i++)
stream_write_uint8(scard->device.data, name[i] < 0 ? '_' : name[i]);
scard->path = path;
scard->irp_list = list_new();
scard->thread = freerdp_thread_new();
pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE *)scard);
freerdp_thread_start(scard->thread, scard_thread_func, scard);
}
return 0;
}

View File

@ -1,52 +0,0 @@
/*
FreeRDP: A Remote Desktop Protocol client.
Redirected Smart Card Device Service
Copyright 2011 O.S. Systems Software Ltda.
Copyright 2011 Eduardo Fiss Beloni <beloni@ossystems.com.br>
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 __SCARD_MAIN_H
#define __SCARD_MAIN_H
#include <inttypes.h>
#include "devman.h"
#include "rdpdr_types.h"
#include <freerdp/utils/debug.h>
struct _SCARD_DEVICE
{
DEVICE device;
char * name;
char * path;
LIST* irp_list;
freerdp_thread* thread;
};
typedef struct _SCARD_DEVICE SCARD_DEVICE;
#ifdef WITH_DEBUG_SCARD
#define DEBUG_SCARD(fmt, ...) DEBUG_CLASS(SCARD, fmt, ## __VA_ARGS__)
#else
#define DEBUG_SCARD(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
#endif
boolean scard_async_op(IRP*);
void scard_device_control(SCARD_DEVICE*, IRP*);
#endif

View File

@ -1,9 +1,7 @@
# FreeRDP: A Remote Desktop Protocol Client
# FreeRDP cmake build script
#
# Copyright 2011 O.S. Systems Software Ltda.
# Copyright 2011 Otavio Salvador <otavio@ossystems.com.br>
# Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -17,23 +15,18 @@
# See the License for the specific language governing permissions and
# limitations under the License.
set(RDPSND_SRCS
rdpsnd_main.c
rdpsnd_main.h
)
set(MODULE_NAME "rdpsnd")
set(MODULE_PREFIX "CHANNEL_RDPSND")
add_library(rdpsnd ${RDPSND_SRCS})
set_target_properties(rdpsnd PROPERTIES PREFIX "")
target_link_libraries(rdpsnd freerdp-utils)
install(TARGETS rdpsnd DESTINATION ${FREERDP_PLUGIN_PATH})
if(WITH_ALSA)
add_subdirectory(alsa)
if(WITH_CLIENT_CHANNELS)
add_subdirectory(client)
endif()
if(WITH_PULSEAUDIO)
add_subdirectory(pulse)
if(WITH_SERVER_CHANNELS)
add_subdirectory(server)
set(${MODULE_PREFIX}_SERVER_SRCS ${${MODULE_PREFIX}_SERVER_SRCS} PARENT_SCOPE)
set(${MODULE_PREFIX}_SERVER_LIBS ${${MODULE_PREFIX}_SERVER_LIBS} PARENT_SCOPE)
set(CHANNEL_BUILTIN_SERVER_MODULES ${CHANNEL_BUILTIN_SERVER_MODULES} ${MODULE_NAME} PARENT_SCOPE)
endif()

View File

@ -0,0 +1,14 @@
set(CHANNEL_TYPE "static")
set(CHANNEL_SHORT_NAME "rdpsnd")
set(CHANNEL_LONG_NAME "Audio Output Virtual Channel Extension")
set(CHANNEL_SPECIFICATIONS "[MS-RDPEA]")
string(TOUPPER "WITH_${CHANNEL_SHORT_NAME}" CHANNEL_OPTION)
if(WIN32)
option(${CHANNEL_OPTION} "Build ${CHANNEL_SHORT_NAME}" OFF)
else()
option(${CHANNEL_OPTION} "Build ${CHANNEL_SHORT_NAME}" ON)
endif()

View File

@ -0,0 +1,46 @@
# FreeRDP: A Remote Desktop Protocol Client
# FreeRDP cmake build script
#
# Copyright 2011 O.S. Systems Software Ltda.
# Copyright 2011 Otavio Salvador <otavio@ossystems.com.br>
# Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
#
# 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.
set(RDPSND_SRCS
rdpsnd_main.c
rdpsnd_main.h)
add_library(rdpsnd ${RDPSND_SRCS})
set_target_properties(rdpsnd PROPERTIES PREFIX "")
if(WITH_MONOLITHIC_BUILD)
target_link_libraries(rdpsnd freerdp)
else()
target_link_libraries(rdpsnd freerdp-utils)
endif()
install(TARGETS rdpsnd DESTINATION ${FREERDP_PLUGIN_PATH})
if(WITH_ALSA)
add_subdirectory(alsa)
endif()
if(WITH_PULSEAUDIO)
add_subdirectory(pulse)
endif()
if(WITH_MACAUDIO)
add_subdirectory(mac_audio)
endif()

View File

@ -27,7 +27,12 @@ include_directories(${ALSA_INCLUDE_DIRS})
add_library(rdpsnd_alsa ${RDPSND_ALSA_SRCS})
set_target_properties(rdpsnd_alsa PROPERTIES PREFIX "")
target_link_libraries(rdpsnd_alsa freerdp-utils)
if(WITH_MONOLITHIC_BUILD)
target_link_libraries(rdpsnd_alsa freerdp)
else()
target_link_libraries(rdpsnd_alsa freerdp-utils)
endif()
target_link_libraries(rdpsnd_alsa ${ALSA_LIBRARIES})
install(TARGETS rdpsnd_alsa DESTINATION ${FREERDP_PLUGIN_PATH})

View File

@ -18,10 +18,16 @@
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <alsa/asoundlib.h>
#include <freerdp/types.h>
#include <freerdp/utils/memory.h>
#include <freerdp/utils/dsp.h>
@ -36,6 +42,7 @@ struct rdpsnd_alsa_plugin
char* device_name;
snd_pcm_t* out_handle;
snd_mixer_t* mixer_handle;
uint32 source_rate;
uint32 actual_rate;
snd_pcm_format_t format;
@ -45,7 +52,8 @@ struct rdpsnd_alsa_plugin
int wformat;
int block_size;
int latency;
ADPCM adpcm;
FREERDP_DSP_CONTEXT* dsp_context;
};
static void rdpsnd_alsa_set_params(rdpsndAlsaPlugin* alsa)
@ -74,7 +82,7 @@ static void rdpsnd_alsa_set_params(rdpsndAlsaPlugin* alsa)
snd_pcm_hw_params_set_channels_near(alsa->out_handle, hw_params,
&alsa->actual_channels);
if (alsa->latency < 0)
frames = alsa->actual_rate * 4; /* Default to 4-second buffer */
frames = alsa->actual_rate * 4 / 10; /* Default to 400ms buffer */
else
frames = alsa->latency * alsa->actual_rate * 2 / 1000; /* Double of the latency */
if (frames < alsa->actual_rate / 2)
@ -137,6 +145,7 @@ static void rdpsnd_alsa_set_format(rdpsndDevicePlugin* device, rdpsndFormat* for
}
break;
case 2: /* MS ADPCM */
case 0x11: /* IMA ADPCM */
alsa->format = SND_PCM_FORMAT_S16_LE;
alsa->bytes_per_channel = 2;
@ -151,6 +160,42 @@ static void rdpsnd_alsa_set_format(rdpsndDevicePlugin* device, rdpsndFormat* for
rdpsnd_alsa_set_params(alsa);
}
static void rdpsnd_alsa_open_mixer(rdpsndAlsaPlugin* alsa)
{
int error;
snd_mixer_t* handle;
error = snd_mixer_open(&handle, 0);
if (error < 0)
{
DEBUG_WARN("snd_mixer_open failed");
return;
}
error = snd_mixer_attach(handle, alsa->device_name);
if (error < 0)
{
DEBUG_WARN("snd_mixer_attach failed");
snd_mixer_close(handle);
return;
}
error = snd_mixer_selem_register(handle, NULL, NULL);
if (error < 0)
{
DEBUG_WARN("snd_mixer_selem_register failed");
snd_mixer_close(handle);
return;
}
error = snd_mixer_load(handle);
if (error < 0)
{
DEBUG_WARN("snd_mixer_load failed");
snd_mixer_close(handle);
return;
}
alsa->mixer_handle = handle;
}
static void rdpsnd_alsa_open(rdpsndDevicePlugin* device, rdpsndFormat* format, int latency)
{
rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*)device;
@ -169,8 +214,9 @@ static void rdpsnd_alsa_open(rdpsndDevicePlugin* device, rdpsndFormat* format, i
}
else
{
memset(&alsa->adpcm, 0, sizeof(ADPCM));
freerdp_dsp_context_reset_adpcm(alsa->dsp_context);
rdpsnd_alsa_set_format(device, format, latency);
rdpsnd_alsa_open_mixer(alsa);
}
}
@ -185,6 +231,11 @@ static void rdpsnd_alsa_close(rdpsndDevicePlugin* device)
snd_pcm_close(alsa->out_handle);
alsa->out_handle = 0;
}
if (alsa->mixer_handle)
{
snd_mixer_close(alsa->mixer_handle);
alsa->mixer_handle = NULL;
}
}
static void rdpsnd_alsa_free(rdpsndDevicePlugin* device)
@ -193,6 +244,7 @@ static void rdpsnd_alsa_free(rdpsndDevicePlugin* device)
rdpsnd_alsa_close(device);
xfree(alsa->device_name);
freerdp_dsp_context_free(alsa->dsp_context);
xfree(alsa);
}
@ -210,6 +262,7 @@ static boolean rdpsnd_alsa_format_supported(rdpsndDevicePlugin* device, rdpsndFo
}
break;
case 2: /* MS ADPCM */
case 0x11: /* IMA ADPCM */
if (format->nSamplesPerSec <= 48000 &&
format->wBitsPerSample == 4 &&
@ -224,15 +277,38 @@ static boolean rdpsnd_alsa_format_supported(rdpsndDevicePlugin* device, rdpsndFo
static void rdpsnd_alsa_set_volume(rdpsndDevicePlugin* device, uint32 value)
{
rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*)device;
long left;
long right;
long volume_min;
long volume_max;
long volume_left;
long volume_right;
snd_mixer_elem_t* elem;
if (!alsa->mixer_handle)
return;
left = (value & 0xFFFF);
right = ((value >> 16) & 0xFFFF);
for (elem = snd_mixer_first_elem(alsa->mixer_handle); elem; elem = snd_mixer_elem_next(elem))
{
if (snd_mixer_selem_has_playback_volume(elem))
{
snd_mixer_selem_get_playback_volume_range(elem, &volume_min, &volume_max);
volume_left = volume_min + (left * (volume_max - volume_min)) / 0xFFFF;
volume_right = volume_min + (right * (volume_max - volume_min)) / 0xFFFF;
snd_mixer_selem_set_playback_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, volume_left);
snd_mixer_selem_set_playback_volume(elem, SND_MIXER_SCHN_FRONT_RIGHT, volume_right);
}
}
}
static void rdpsnd_alsa_play(rdpsndDevicePlugin* device, uint8* data, int size)
{
rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*)device;
uint8* decoded_data;
int decoded_size;
uint8* src;
uint8* resampled_data;
int len;
int error;
int frames;
@ -244,16 +320,22 @@ static void rdpsnd_alsa_play(rdpsndDevicePlugin* device, uint8* data, int size)
if (alsa->out_handle == 0)
return;
if (alsa->wformat == 0x11)
if (alsa->wformat == 2)
{
decoded_data = dsp_decode_ima_adpcm(&alsa->adpcm,
data, size, alsa->source_channels, alsa->block_size, &decoded_size);
size = decoded_size;
src = decoded_data;
alsa->dsp_context->decode_ms_adpcm(alsa->dsp_context,
data, size, alsa->source_channels, alsa->block_size);
size = alsa->dsp_context->adpcm_size;
src = alsa->dsp_context->adpcm_buffer;
}
else if (alsa->wformat == 0x11)
{
alsa->dsp_context->decode_ima_adpcm(alsa->dsp_context,
data, size, alsa->source_channels, alsa->block_size);
size = alsa->dsp_context->adpcm_size;
src = alsa->dsp_context->adpcm_buffer;
}
else
{
decoded_data = NULL;
src = data;
}
@ -268,17 +350,17 @@ static void rdpsnd_alsa_play(rdpsndDevicePlugin* device, uint8* data, int size)
if ((alsa->source_rate == alsa->actual_rate) &&
(alsa->source_channels == alsa->actual_channels))
{
resampled_data = NULL;
}
else
{
resampled_data = dsp_resample(src, alsa->bytes_per_channel,
alsa->dsp_context->resample(alsa->dsp_context, src, alsa->bytes_per_channel,
alsa->source_channels, alsa->source_rate, size / sbytes_per_frame,
alsa->actual_channels, alsa->actual_rate, &frames);
alsa->actual_channels, alsa->actual_rate);
frames = alsa->dsp_context->resampled_frames;
DEBUG_SVC("resampled %d frames at %d to %d frames at %d",
size / sbytes_per_frame, alsa->source_rate, frames, alsa->actual_rate);
size = frames * rbytes_per_frame;
src = resampled_data;
src = alsa->dsp_context->resampled_buffer;
}
pindex = src;
@ -303,11 +385,6 @@ static void rdpsnd_alsa_play(rdpsndDevicePlugin* device, uint8* data, int size)
}
pindex += error * rbytes_per_frame;
}
if (resampled_data)
xfree(resampled_data);
if (decoded_data)
xfree(decoded_data);
}
static void rdpsnd_alsa_start(rdpsndDevicePlugin* device)
@ -353,6 +430,8 @@ int FreeRDPRdpsndDeviceEntry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pEntryPoints)
alsa->actual_channels = 2;
alsa->bytes_per_channel = 2;
alsa->dsp_context = freerdp_dsp_context_new();
pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*)alsa);
return 0;

View File

@ -0,0 +1,40 @@
# FreeRDP: A Remote Desktop Protocol Client
# FreeRDP cmake build script
#
# Copyright 2012 Laxmikant Rashinkar <LK.Rashinkar@gmail.com>
# Copyright 2011 O.S. Systems Software Ltda.
# Copyright 2011 Otavio Salvador <otavio@ossystems.com.br>
# Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
#
# 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.
set(RDPSND_MACAUDIO_SRCS
rdpsnd_audio_q.c)
include_directories(..)
include_directories(${MACAUDIO_INCLUDE_DIRS})
add_library(rdpsnd_macaudio ${RDPSND_MACAUDIO_SRCS})
set_target_properties(rdpsnd_macaudio PROPERTIES PREFIX "")
if(WITH_MONOLITHIC_BUILD)
target_link_libraries(rdpsnd_macaudio freerdp)
else()
target_link_libraries(rdpsnd_macaudio freerdp-utils)
endif()
target_link_libraries(rdpsnd_macaudio ${MAC_AUDIOTOOLBOX_LIBRARY_PATH})
target_link_libraries(rdpsnd_macaudio ${MAC_COREFOUNDATION_LIBRARY_PATH})
install(TARGETS rdpsnd_macaudio DESTINATION ${FREERDP_PLUGIN_PATH})

View File

@ -0,0 +1,229 @@
/**
* FreeRDP: A Remote Desktop Protocol client.
* Audio Output Virtual Channel
*
* Copyright 2012 Laxmikant Rashinkar <LK.Rashinkar@gmail.com>
*
* 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.
*/
/**
* Use AudioQueue to implement audio redirection
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <freerdp/types.h>
#include <freerdp/utils/memory.h>
#include <freerdp/utils/dsp.h>
#include <freerdp/utils/svc_plugin.h>
#include <AudioToolbox/AudioToolbox.h>
#include <AudioToolbox/AudioQueue.h>
#include "rdpsnd_main.h"
#define AQ_NUM_BUFFERS 10
#define AQ_BUF_SIZE (32 * 1024)
static void aq_playback_cb(void *user_data,
AudioQueueRef aq_ref,
AudioQueueBufferRef aq_buf_ref
);
struct rdpsnd_audio_q_plugin
{
rdpsndDevicePlugin device;
/* audio queue player state */
int is_open; // true when audio_q has been inited
char * device_name;
int is_playing;
int buf_index;
AudioStreamBasicDescription data_format;
AudioQueueRef aq_ref;
AudioQueueBufferRef buffers[AQ_NUM_BUFFERS];
};
typedef struct rdpsnd_audio_q_plugin rdpsndAudioQPlugin;
static void rdpsnd_audio_close(rdpsndDevicePlugin* device)
{
rdpsndAudioQPlugin* aq_plugin_p = (rdpsndAudioQPlugin*) device;
AudioQueueStop(aq_plugin_p->aq_ref, 0);
aq_plugin_p->is_open = 0;
}
static void rdpsnd_audio_open(rdpsndDevicePlugin* device, rdpsndFormat* format, int latency)
{
int rv;
int i;
rdpsndAudioQPlugin* aq_plugin_p = (rdpsndAudioQPlugin *) device;
if (aq_plugin_p->is_open) {
return;
}
aq_plugin_p->buf_index = 0;
// setup AudioStreamBasicDescription
aq_plugin_p->data_format.mSampleRate = 44100;
aq_plugin_p->data_format.mFormatID = kAudioFormatLinearPCM;
aq_plugin_p->data_format.mFormatFlags = kAudioFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
// until we know better, assume that one packet = one frame
// one frame = bytes_per_sample x number_of_channels
aq_plugin_p->data_format.mBytesPerPacket = 4;
aq_plugin_p->data_format.mFramesPerPacket = 1;
aq_plugin_p->data_format.mBytesPerFrame = 4;
aq_plugin_p->data_format.mChannelsPerFrame = 2;
aq_plugin_p->data_format.mBitsPerChannel = 16;
rv = AudioQueueNewOutput(&aq_plugin_p->data_format, // audio stream basic desc
aq_playback_cb, // callback when more data is required
aq_plugin_p, // data to pass to callback
CFRunLoopGetCurrent(), // The current run loop, and the one on
// which the audio queue playback callback
// will be invoked
kCFRunLoopCommonModes, // run loop modes in which callbacks can
// be invoked
0, // flags - reserved
&aq_plugin_p->aq_ref
);
if (rv != 0) {
printf("rdpsnd_audio_open: AudioQueueNewOutput() failed with error %d\n", rv);
aq_plugin_p->is_open = 1;
return;
}
for (i = 0; i < AQ_NUM_BUFFERS; i++)
{
rv = AudioQueueAllocateBuffer(aq_plugin_p->aq_ref, AQ_BUF_SIZE, &aq_plugin_p->buffers[i]);
}
aq_plugin_p->is_open = 1;
}
static void rdpsnd_audio_free(rdpsndDevicePlugin* device)
{
}
static boolean rdpsnd_audio_format_supported(rdpsndDevicePlugin* device, rdpsndFormat* format)
{
switch (format->wFormatTag)
{
case 1: /* PCM */
if (format->cbSize == 0 &&
(format->nSamplesPerSec <= 48000) &&
(format->wBitsPerSample == 8 || format->wBitsPerSample == 16) &&
(format->nChannels == 1 || format->nChannels == 2))
{
return 1;
}
break;
}
return 0;
}
static void rdpsnd_audio_set_format(rdpsndDevicePlugin* device, rdpsndFormat* format, int latency)
{
}
static void rdpsnd_audio_set_volume(rdpsndDevicePlugin* device, uint32 value)
{
}
static void rdpsnd_audio_play(rdpsndDevicePlugin* device, uint8* data, int size)
{
rdpsndAudioQPlugin* aq_plugin_p = (rdpsndAudioQPlugin *) device;
AudioQueueBufferRef aq_buf_ref;
int len;
if (!aq_plugin_p->is_open) {
return;
}
/* get next empty buffer */
aq_buf_ref = aq_plugin_p->buffers[aq_plugin_p->buf_index];
// fill aq_buf_ref with audio data
len = size > AQ_BUF_SIZE ? AQ_BUF_SIZE : size;
memcpy(aq_buf_ref->mAudioData, (char *) data, len);
aq_buf_ref->mAudioDataByteSize = len;
// add buffer to audioqueue
AudioQueueEnqueueBuffer(aq_plugin_p->aq_ref, aq_buf_ref, 0, 0);
// update buf_index
aq_plugin_p->buf_index++;
if (aq_plugin_p->buf_index >= AQ_NUM_BUFFERS) {
aq_plugin_p->buf_index = 0;
}
}
static void rdpsnd_audio_start(rdpsndDevicePlugin* device)
{
rdpsndAudioQPlugin* aq_plugin_p = (rdpsndAudioQPlugin *) device;
AudioQueueStart(aq_plugin_p->aq_ref, NULL);
}
/**
* AudioQueue Playback callback
*
* our job here is to fill aq_buf_ref with audio data and enqueue it
*/
static void aq_playback_cb(void *user_data,
AudioQueueRef aq_ref,
AudioQueueBufferRef aq_buf_ref
)
{
}
int FreeRDPRdpsndDeviceEntry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pEntryPoints)
{
rdpsndAudioQPlugin* aqPlugin;
RDP_PLUGIN_DATA* data;
aqPlugin = xnew(rdpsndAudioQPlugin);
aqPlugin->device.Open = rdpsnd_audio_open;
aqPlugin->device.FormatSupported = rdpsnd_audio_format_supported;
aqPlugin->device.SetFormat = rdpsnd_audio_set_format;
aqPlugin->device.SetVolume = rdpsnd_audio_set_volume;
aqPlugin->device.Play = rdpsnd_audio_play;
aqPlugin->device.Start = rdpsnd_audio_start;
aqPlugin->device.Close = rdpsnd_audio_close;
aqPlugin->device.Free = rdpsnd_audio_free;
data = pEntryPoints->plugin_data;
if (data && strcmp((char *)data->data[0], "macaudio") == 0) {
if(strlen((char *)data->data[1]) > 0)
aqPlugin->device_name = strdup((char *)data->data[1]);
else
aqPlugin->device_name = NULL;
}
pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*)aqPlugin);
return 0;
}

View File

@ -18,16 +18,20 @@
# limitations under the License.
set(RDPSND_PULSE_SRCS
rdpsnd_pulse.c
)
rdpsnd_pulse.c)
include_directories(..)
include_directories(${PULSE_INCLUDE_DIRS})
include_directories(${PULSEAUDIO_INCLUDE_DIR})
add_library(rdpsnd_pulse ${RDPSND_PULSE_SRCS})
set_target_properties(rdpsnd_pulse PROPERTIES PREFIX "")
target_link_libraries(rdpsnd_pulse freerdp-utils)
if(WITH_MONOLITHIC_BUILD)
target_link_libraries(rdpsnd_pulse freerdp)
else()
target_link_libraries(rdpsnd_pulse freerdp-utils)
endif()
target_link_libraries(rdpsnd_pulse ${PULSEAUDIO_LIBRARY})
install(TARGETS rdpsnd_pulse DESTINATION ${FREERDP_PLUGIN_PATH})

View File

@ -17,9 +17,14 @@
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pulse/pulseaudio.h>
#include <freerdp/types.h>
#include <freerdp/utils/memory.h>
@ -41,7 +46,8 @@ struct rdpsnd_pulse_plugin
int format;
int block_size;
int latency;
ADPCM adpcm;
FREERDP_DSP_CONTEXT* dsp_context;
};
static void rdpsnd_pulse_context_state_callback(pa_context* context, void* userdata)
@ -211,6 +217,7 @@ static void rdpsnd_pulse_set_format_spec(rdpsndPulsePlugin* pulse, rdpsndFormat*
sample_spec.format = PA_SAMPLE_ULAW;
break;
case 2: /* MS ADPCM */
case 0x11: /* IMA ADPCM */
sample_spec.format = PA_SAMPLE_S16LE;
break;
@ -297,7 +304,7 @@ static void rdpsnd_pulse_open(rdpsndDevicePlugin* device, rdpsndFormat* format,
pa_threaded_mainloop_unlock(pulse->mainloop);
if (state == PA_STREAM_READY)
{
memset(&pulse->adpcm, 0, sizeof(ADPCM));
freerdp_dsp_context_reset_adpcm(pulse->dsp_context);
DEBUG_SVC("connected");
}
else
@ -329,6 +336,7 @@ static void rdpsnd_pulse_free(rdpsndDevicePlugin* device)
pulse->mainloop = NULL;
}
xfree(pulse->device_name);
freerdp_dsp_context_free(pulse->dsp_context);
xfree(pulse);
}
@ -362,6 +370,7 @@ static boolean rdpsnd_pulse_format_supported(rdpsndDevicePlugin* device, rdpsndF
}
break;
case 2: /* MS ADPCM */
case 0x11: /* IMA ADPCM */
if ((format->nSamplesPerSec <= PA_RATE_MAX) &&
(format->wBitsPerSample == 4) &&
@ -391,6 +400,28 @@ static void rdpsnd_pulse_set_format(rdpsndDevicePlugin* device, rdpsndFormat* fo
static void rdpsnd_pulse_set_volume(rdpsndDevicePlugin* device, uint32 value)
{
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device;
pa_cvolume cv;
pa_volume_t left;
pa_volume_t right;
pa_operation* operation;
if (!pulse->context || !pulse->stream)
return;
left = (pa_volume_t) (value & 0xFFFF);
right = (pa_volume_t) ((value >> 16) & 0xFFFF);
pa_cvolume_init(&cv);
cv.channels = 2;
cv.values[0] = PA_VOLUME_MUTED + (left * (PA_VOLUME_NORM - PA_VOLUME_MUTED)) / 0xFFFF;
cv.values[1] = PA_VOLUME_MUTED + (right * (PA_VOLUME_NORM - PA_VOLUME_MUTED)) / 0xFFFF;
pa_threaded_mainloop_lock(pulse->mainloop);
operation = pa_context_set_sink_input_volume(pulse->context, pa_stream_get_index(pulse->stream), &cv, NULL, NULL);
if(operation)
pa_operation_unref(operation);
pa_threaded_mainloop_unlock(pulse->mainloop);
}
static void rdpsnd_pulse_play(rdpsndDevicePlugin* device, uint8* data, int size)
@ -398,23 +429,27 @@ static void rdpsnd_pulse_play(rdpsndDevicePlugin* device, uint8* data, int size)
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device;
int len;
int ret;
uint8* decoded_data;
uint8* src;
int decoded_size;
if (!pulse->stream)
return;
if (pulse->format == 0x11)
if (pulse->format == 2)
{
decoded_data = dsp_decode_ima_adpcm(&pulse->adpcm,
data, size, pulse->sample_spec.channels, pulse->block_size, &decoded_size);
size = decoded_size;
src = decoded_data;
pulse->dsp_context->decode_ms_adpcm(pulse->dsp_context,
data, size, pulse->sample_spec.channels, pulse->block_size);
size = pulse->dsp_context->adpcm_size;
src = pulse->dsp_context->adpcm_buffer;
}
else if (pulse->format == 0x11)
{
pulse->dsp_context->decode_ima_adpcm(pulse->dsp_context,
data, size, pulse->sample_spec.channels, pulse->block_size);
size = pulse->dsp_context->adpcm_size;
src = pulse->dsp_context->adpcm_buffer;
}
else
{
decoded_data = NULL;
src = data;
}
@ -440,9 +475,6 @@ static void rdpsnd_pulse_play(rdpsndDevicePlugin* device, uint8* data, int size)
size -= len;
}
pa_threaded_mainloop_unlock(pulse->mainloop);
if (decoded_data)
xfree(decoded_data);
}
static void rdpsnd_pulse_start(rdpsndDevicePlugin* device)
@ -474,12 +506,14 @@ int FreeRDPRdpsndDeviceEntry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pEntryPoints)
data = pEntryPoints->plugin_data;
if (data && strcmp((char*)data->data[0], "pulse") == 0)
{
if(strlen((char*)data->data[1]) > 0)
if(data->data[1] && strlen((char*)data->data[1]) > 0)
pulse->device_name = xstrdup((char*)data->data[1]);
else
pulse->device_name = NULL;
}
pulse->dsp_context = freerdp_dsp_context_new();
pulse->mainloop = pa_threaded_mainloop_new();
if (!pulse->mainloop)
{

View File

@ -18,6 +18,10 @@
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifndef _WIN32
#include <sys/time.h>
#endif
@ -25,6 +29,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <freerdp/constants.h>
#include <freerdp/types.h>
#include <freerdp/utils/memory.h>
@ -35,27 +40,6 @@
#include "rdpsnd_main.h"
#define SNDC_CLOSE 1
#define SNDC_WAVE 2
#define SNDC_SETVOLUME 3
#define SNDC_SETPITCH 4
#define SNDC_WAVECONFIRM 5
#define SNDC_TRAINING 6
#define SNDC_FORMATS 7
#define SNDC_CRYPTKEY 8
#define SNDC_WAVEENCRYPT 9
#define SNDC_UDPWAVE 10
#define SNDC_UDPWAVELAST 11
#define SNDC_QUALITYMODE 12
#define TSSNDCAPS_ALIVE 1
#define TSSNDCAPS_VOLUME 2
#define TSSNDCAPS_PITCH 4
#define DYNAMIC_QUALITY 0x0000
#define MEDIUM_QUALITY 0x0001
#define HIGH_QUALITY 0x0002
struct rdpsnd_plugin
{
rdpSvcPlugin plugin;
@ -107,11 +91,11 @@ static void rdpsnd_process_interval(rdpSvcPlugin* plugin)
struct data_out_item* item;
uint32 cur_time;
while (rdpsnd->data_out_list->head)
while (list_size(rdpsnd->data_out_list) > 0)
{
item = (struct data_out_item*)rdpsnd->data_out_list->head->data;
item = (struct data_out_item*)list_peek(rdpsnd->data_out_list) ;
cur_time = get_mstime();
if (cur_time <= item->out_timestamp)
if (!item || cur_time <= item->out_timestamp)
break;
item = (struct data_out_item*)list_dequeue(rdpsnd->data_out_list);
@ -135,7 +119,7 @@ static void rdpsnd_process_interval(rdpSvcPlugin* plugin)
}
}
if (rdpsnd->data_out_list->head == NULL && !rdpsnd->is_open)
if (list_size(rdpsnd->data_out_list) == 0 && !rdpsnd->is_open)
{
rdpsnd->plugin.interval_ms = 0;
}
@ -193,8 +177,8 @@ static void rdpsnd_process_message_formats(rdpsndPlugin* rdpsnd, STREAM* data_in
stream_write_uint8(data_out, SNDC_FORMATS); /* msgType */
stream_write_uint8(data_out, 0); /* bPad */
stream_seek_uint16(data_out); /* BodySize */
stream_write_uint32(data_out, TSSNDCAPS_ALIVE); /* dwFlags */
stream_write_uint32(data_out, 0); /* dwVolume */
stream_write_uint32(data_out, TSSNDCAPS_ALIVE | TSSNDCAPS_VOLUME); /* dwFlags */
stream_write_uint32(data_out, 0xFFFFFFFF); /* dwVolume */
stream_write_uint32(data_out, 0); /* dwPitch */
stream_write_uint16_be(data_out, 0); /* wDGramPort */
stream_seek_uint16(data_out); /* wNumberOfFormats */
@ -498,7 +482,7 @@ static void rdpsnd_process_plugin_data(rdpsndPlugin* rdpsnd, RDP_PLUGIN_DATA* da
static void rdpsnd_process_connect(rdpSvcPlugin* plugin)
{
rdpsndPlugin* rdpsnd = (rdpsndPlugin*)plugin;
rdpsndPlugin* rdpsnd = (rdpsndPlugin*) plugin;
RDP_PLUGIN_DATA* data;
RDP_PLUGIN_DATA default_data[2] = { { 0 }, { 0 } };
@ -510,10 +494,11 @@ static void rdpsnd_process_connect(rdpSvcPlugin* plugin)
rdpsnd->latency = -1;
data = (RDP_PLUGIN_DATA*)plugin->channel_entry_points.pExtendedData;
while (data && data->size > 0)
{
rdpsnd_process_plugin_data(rdpsnd, data);
data = (RDP_PLUGIN_DATA*) (((void*) data) + data->size);
data = (RDP_PLUGIN_DATA*) (((uint8*) data) + data->size);
}
if (rdpsnd->device == NULL)
@ -525,7 +510,22 @@ static void rdpsnd_process_connect(rdpSvcPlugin* plugin)
{
default_data[0].data[0] = "alsa";
default_data[0].data[1] = "default";
rdpsnd_load_device_plugin(rdpsnd, "alsa", default_data);
if (!rdpsnd_load_device_plugin(rdpsnd, "alsa", default_data))
{
default_data[0].data[0] = "macaudio";
default_data[0].data[1] = "default";
rdpsnd_load_device_plugin(rdpsnd, "macaudio", default_data);
}
else
{
printf("rdpsnd: successfully loaded alsa plugin\n");
}
}
else
{
printf("rdpsnd: successfully loaded pulseaudio plugin\n");
}
}
if (rdpsnd->device == NULL)

View File

@ -20,19 +20,9 @@
#ifndef __RDPSND_MAIN_H
#define __RDPSND_MAIN_H
typedef struct rdpsnd_plugin rdpsndPlugin;
#include <freerdp/channels/rdpsnd.h>
typedef struct rdpsnd_format rdpsndFormat;
struct rdpsnd_format
{
uint16 wFormatTag;
uint16 nChannels;
uint32 nSamplesPerSec;
uint16 nBlockAlign;
uint16 wBitsPerSample;
uint16 cbSize;
uint8* data;
};
typedef struct rdpsnd_plugin rdpsndPlugin;
typedef struct rdpsnd_device_plugin rdpsndDevicePlugin;

View File

@ -0,0 +1,29 @@
# FreeRDP: A Remote Desktop Protocol Client
# FreeRDP cmake build script
#
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
#
# 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.
set(MODULE_PREFIX "CHANNEL_RDPSND_SERVER")
set(${MODULE_PREFIX}_SRCS
rdpsnd.c
PARENT_SCOPE)
if(WITH_MONOLITHIC_BUILD)
set(${MODULE_PREFIX}_LIBS freerdp PARENT_SCOPE)
else()
set(${MODULE_PREFIX}_LIBS freerdp-utils PARENT_SCOPE)
endif()

View File

@ -0,0 +1,480 @@
/**
* FreeRDP: A Remote Desktop Protocol client.
* Server Audio Virtual Channel
*
* Copyright 2012 Vic Lee
*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <freerdp/utils/stream.h>
#include <freerdp/utils/memory.h>
#include <freerdp/utils/dsp.h>
#include <freerdp/utils/thread.h>
#include <freerdp/utils/wait_obj.h>
#include <freerdp/channels/wtsvc.h>
#include <freerdp/server/rdpsnd.h>
typedef struct _rdpsnd_server
{
rdpsnd_server_context context;
void* rdpsnd_channel;
freerdp_thread* rdpsnd_channel_thread;
STREAM* rdpsnd_pdu;
FREERDP_DSP_CONTEXT* dsp_context;
uint8* out_buffer;
int out_buffer_size;
int out_frames;
int out_pending_frames;
uint32 src_bytes_per_sample;
uint32 src_bytes_per_frame;
} rdpsnd_server;
#define RDPSND_PDU_INIT(_s, _msgType) \
{ \
stream_write_uint8(_s, _msgType); \
stream_write_uint8(_s, 0); \
stream_seek_uint16(_s); \
}
#define RDPSND_PDU_FINISH(_s) \
{ \
boolean _r; \
int _pos; \
_pos = stream_get_pos(_s); \
stream_set_pos(_s, 2); \
stream_write_uint16(_s, _pos - 4); \
stream_set_pos(_s, _pos); \
_r = WTSVirtualChannelWrite(rdpsnd->rdpsnd_channel, stream_get_head(_s), stream_get_length(_s), NULL); \
stream_set_pos(_s, 0); \
return _r; \
}
static boolean rdpsnd_server_send_formats(rdpsnd_server* rdpsnd, STREAM* s)
{
uint16 i;
RDPSND_PDU_INIT(s, SNDC_FORMATS);
stream_write_uint32(s, 0); /* dwFlags */
stream_write_uint32(s, 0); /* dwVolume */
stream_write_uint32(s, 0); /* dwPitch */
stream_write_uint16(s, 0); /* wDGramPort */
stream_write_uint16(s, rdpsnd->context.num_server_formats); /* wNumberOfFormats */
stream_write_uint8(s, rdpsnd->context.block_no); /* cLastBlockConfirmed */
stream_write_uint16(s, 0x06); /* wVersion */
stream_write_uint8(s, 0); /* bPad */
for (i = 0; i < rdpsnd->context.num_server_formats; i++)
{
stream_write_uint16(s, rdpsnd->context.server_formats[i].wFormatTag); /* wFormatTag (WAVE_FORMAT_PCM) */
stream_write_uint16(s, rdpsnd->context.server_formats[i].nChannels); /* nChannels */
stream_write_uint32(s, rdpsnd->context.server_formats[i].nSamplesPerSec); /* nSamplesPerSec */
stream_write_uint32(s, rdpsnd->context.server_formats[i].nSamplesPerSec *
rdpsnd->context.server_formats[i].nChannels *
rdpsnd->context.server_formats[i].wBitsPerSample / 8); /* nAvgBytesPerSec */
stream_write_uint16(s, rdpsnd->context.server_formats[i].nBlockAlign); /* nBlockAlign */
stream_write_uint16(s, rdpsnd->context.server_formats[i].wBitsPerSample); /* wBitsPerSample */
stream_write_uint16(s, rdpsnd->context.server_formats[i].cbSize); /* cbSize */
if (rdpsnd->context.server_formats[i].cbSize > 0)
{
stream_write(s, rdpsnd->context.server_formats[i].data, rdpsnd->context.server_formats[i].cbSize);
}
}
RDPSND_PDU_FINISH(s);
}
static boolean rdpsnd_server_recv_formats(rdpsnd_server* rdpsnd, STREAM* s)
{
int i;
if (stream_get_left(s) < 20)
return false;
stream_seek_uint32(s); /* dwFlags */
stream_seek_uint32(s); /* dwVolume */
stream_seek_uint32(s); /* dwPitch */
stream_seek_uint16(s); /* wDGramPort */
stream_read_uint16(s, rdpsnd->context.num_client_formats); /* wNumberOfFormats */
stream_seek_uint8(s); /* cLastBlockConfirmed */
stream_seek_uint16(s); /* wVersion */
stream_seek_uint8(s); /* bPad */
if (rdpsnd->context.num_client_formats > 0)
{
rdpsnd->context.client_formats = xzalloc(rdpsnd->context.num_client_formats * sizeof(rdpsndFormat));
for (i = 0; i < rdpsnd->context.num_client_formats; i++)
{
if (stream_get_left(s) < 18)
{
xfree(rdpsnd->context.client_formats);
rdpsnd->context.client_formats = NULL;
return false;
}
stream_read_uint16(s, rdpsnd->context.client_formats[i].wFormatTag);
stream_read_uint16(s, rdpsnd->context.client_formats[i].nChannels);
stream_read_uint32(s, rdpsnd->context.client_formats[i].nSamplesPerSec);
stream_seek_uint32(s); /* nAvgBytesPerSec */
stream_read_uint16(s, rdpsnd->context.client_formats[i].nBlockAlign);
stream_read_uint16(s, rdpsnd->context.client_formats[i].wBitsPerSample);
stream_read_uint16(s, rdpsnd->context.client_formats[i].cbSize);
if (rdpsnd->context.client_formats[i].cbSize > 0)
{
stream_seek(s, rdpsnd->context.client_formats[i].cbSize);
}
}
}
return true;
}
static void* rdpsnd_server_thread_func(void* arg)
{
void* fd;
STREAM* s;
void* buffer;
uint8 msgType;
uint16 BodySize;
uint32 bytes_returned = 0;
rdpsnd_server* rdpsnd = (rdpsnd_server*) arg;
freerdp_thread* thread = rdpsnd->rdpsnd_channel_thread;
if (WTSVirtualChannelQuery(rdpsnd->rdpsnd_channel, WTSVirtualFileHandle, &buffer, &bytes_returned) == true)
{
fd = *((void**)buffer);
WTSFreeMemory(buffer);
thread->signals[thread->num_signals++] = wait_obj_new_with_fd(fd);
}
s = stream_new(4096);
rdpsnd_server_send_formats(rdpsnd, s);
while (1)
{
freerdp_thread_wait(thread);
if (freerdp_thread_is_stopped(thread))
break;
stream_set_pos(s, 0);
if (WTSVirtualChannelRead(rdpsnd->rdpsnd_channel, 0, stream_get_head(s),
stream_get_size(s), &bytes_returned) == false)
{
if (bytes_returned == 0)
break;
stream_check_size(s, (int) bytes_returned);
if (WTSVirtualChannelRead(rdpsnd->rdpsnd_channel, 0, stream_get_head(s),
stream_get_size(s), &bytes_returned) == false)
break;
}
stream_read_uint8(s, msgType);
stream_seek_uint8(s); /* bPad */
stream_read_uint16(s, BodySize);
if (BodySize + 4 > (int) bytes_returned)
continue;
switch (msgType)
{
case SNDC_FORMATS:
if (rdpsnd_server_recv_formats(rdpsnd, s))
{
IFCALL(rdpsnd->context.Activated, &rdpsnd->context);
}
break;
default:
break;
}
}
stream_free(s);
freerdp_thread_quit(thread);
return 0;
}
static boolean rdpsnd_server_initialize(rdpsnd_server_context* context)
{
rdpsnd_server* rdpsnd = (rdpsnd_server*) context;
rdpsnd->rdpsnd_channel = WTSVirtualChannelOpenEx(context->vcm, "rdpsnd", 0);
if (rdpsnd->rdpsnd_channel != NULL)
{
rdpsnd->rdpsnd_pdu = stream_new(4096);
rdpsnd->rdpsnd_channel_thread = freerdp_thread_new();
freerdp_thread_start(rdpsnd->rdpsnd_channel_thread, rdpsnd_server_thread_func, rdpsnd);
return true;
}
else
{
return false;
}
}
static void rdpsnd_server_select_format(rdpsnd_server_context* context, int client_format_index)
{
int bs;
int out_buffer_size;
rdpsndFormat *format;
rdpsnd_server* rdpsnd = (rdpsnd_server*) context;
if (client_format_index < 0 || client_format_index >= context->num_client_formats)
{
printf("rdpsnd_server_select_format: index %d is not correct.\n", client_format_index);
return;
}
rdpsnd->src_bytes_per_sample = context->src_format.wBitsPerSample / 8;
rdpsnd->src_bytes_per_frame = rdpsnd->src_bytes_per_sample * context->src_format.nChannels;
context->selected_client_format = client_format_index;
format = &context->client_formats[client_format_index];
if (format->wFormatTag == 0x11)
{
bs = (format->nBlockAlign - 4 * format->nChannels) * 4;
rdpsnd->out_frames = (format->nBlockAlign * 4 * format->nChannels * 2 / bs + 1) * bs / (format->nChannels * 2);
}
else if (format->wFormatTag == 0x02)
{
bs = (format->nBlockAlign - 7 * format->nChannels) * 2 / format->nChannels + 2;
rdpsnd->out_frames = bs * 4;
}
else
{
rdpsnd->out_frames = 0x4000 / rdpsnd->src_bytes_per_frame;
}
if (format->nSamplesPerSec != context->src_format.nSamplesPerSec)
{
rdpsnd->out_frames = (rdpsnd->out_frames * context->src_format.nSamplesPerSec + format->nSamplesPerSec - 100) / format->nSamplesPerSec;
}
rdpsnd->out_pending_frames = 0;
out_buffer_size = rdpsnd->out_frames * rdpsnd->src_bytes_per_frame;
if (rdpsnd->out_buffer_size < out_buffer_size)
{
rdpsnd->out_buffer = xrealloc(rdpsnd->out_buffer, out_buffer_size);
rdpsnd->out_buffer_size = out_buffer_size;
}
freerdp_dsp_context_reset_adpcm(rdpsnd->dsp_context);
}
static boolean rdpsnd_server_send_audio_pdu(rdpsnd_server* rdpsnd)
{
STREAM* s = rdpsnd->rdpsnd_pdu;
rdpsndFormat* format;
int tbytes_per_frame;
uint8* src;
int size;
int frames;
int fill_size;
boolean r;
format = &rdpsnd->context.client_formats[rdpsnd->context.selected_client_format];
tbytes_per_frame = format->nChannels * rdpsnd->src_bytes_per_sample;
if (format->nSamplesPerSec == rdpsnd->context.src_format.nSamplesPerSec && format->nChannels == rdpsnd->context.src_format.nChannels)
{
src = rdpsnd->out_buffer;
frames = rdpsnd->out_pending_frames;
}
else
{
rdpsnd->dsp_context->resample(rdpsnd->dsp_context, rdpsnd->out_buffer, rdpsnd->src_bytes_per_sample,
rdpsnd->context.src_format.nChannels, rdpsnd->context.src_format.nSamplesPerSec, rdpsnd->out_pending_frames,
format->nChannels, format->nSamplesPerSec);
frames = rdpsnd->dsp_context->resampled_frames;
src = rdpsnd->dsp_context->resampled_buffer;
}
size = frames * tbytes_per_frame;
if (format->wFormatTag == 0x11)
{
rdpsnd->dsp_context->encode_ima_adpcm(rdpsnd->dsp_context,
src, size, format->nChannels, format->nBlockAlign);
src = rdpsnd->dsp_context->adpcm_buffer;
size = rdpsnd->dsp_context->adpcm_size;
}
else if (format->wFormatTag == 0x02)
{
rdpsnd->dsp_context->encode_ms_adpcm(rdpsnd->dsp_context,
src, size, format->nChannels, format->nBlockAlign);
src = rdpsnd->dsp_context->adpcm_buffer;
size = rdpsnd->dsp_context->adpcm_size;
}
rdpsnd->context.block_no = (rdpsnd->context.block_no + 1) % 256;
/* Fill to nBlockAlign for the last audio packet */
if ((format->wFormatTag == 0x11 || format->wFormatTag == 0x02) &&
rdpsnd->out_pending_frames < rdpsnd->out_frames && (size % format->nBlockAlign) != 0)
fill_size = format->nBlockAlign - (size % format->nBlockAlign);
else
fill_size = 0;
/* WaveInfo PDU */
stream_set_pos(s, 0);
stream_write_uint8(s, SNDC_WAVE); /* msgType */
stream_write_uint8(s, 0); /* bPad */
stream_write_uint16(s, size + fill_size + 8); /* BodySize */
stream_write_uint16(s, 0); /* wTimeStamp */
stream_write_uint16(s, rdpsnd->context.selected_client_format); /* wFormatNo */
stream_write_uint8(s, rdpsnd->context.block_no); /* cBlockNo */
stream_seek(s, 3); /* bPad */
stream_write(s, src, 4);
WTSVirtualChannelWrite(rdpsnd->rdpsnd_channel, stream_get_head(s), stream_get_length(s), NULL);
stream_set_pos(s, 0);
/* Wave PDU */
stream_check_size(s, size + fill_size);
stream_write_uint32(s, 0); /* bPad */
stream_write(s, src + 4, size - 4);
if (fill_size > 0)
stream_write_zero(s, fill_size);
r = WTSVirtualChannelWrite(rdpsnd->rdpsnd_channel, stream_get_head(s), stream_get_length(s), NULL);
stream_set_pos(s, 0);
rdpsnd->out_pending_frames = 0;
return r;
}
static boolean rdpsnd_server_send_samples(rdpsnd_server_context* context, const void* buf, int nframes)
{
int cframes;
int cframesize;
rdpsnd_server* rdpsnd = (rdpsnd_server*) context;
if (rdpsnd->context.selected_client_format < 0)
return false;
while (nframes > 0)
{
cframes = MIN(nframes, rdpsnd->out_frames - rdpsnd->out_pending_frames);
cframesize = cframes * rdpsnd->src_bytes_per_frame;
memcpy(rdpsnd->out_buffer + (rdpsnd->out_pending_frames * rdpsnd->src_bytes_per_frame),
buf, cframesize);
buf = (uint8*)buf + cframesize;
nframes -= cframes;
rdpsnd->out_pending_frames += cframes;
if (rdpsnd->out_pending_frames >= rdpsnd->out_frames)
{
if (!rdpsnd_server_send_audio_pdu(rdpsnd))
return false;
}
}
return true;
}
static boolean rdpsnd_server_set_volume(rdpsnd_server_context* context, int left, int right)
{
rdpsnd_server* rdpsnd = (rdpsnd_server*) context;
STREAM* s = rdpsnd->rdpsnd_pdu;
RDPSND_PDU_INIT(s, SNDC_SETVOLUME);
stream_write_uint16(s, left);
stream_write_uint16(s, right);
RDPSND_PDU_FINISH(s);
}
static boolean rdpsnd_server_close(rdpsnd_server_context* context)
{
rdpsnd_server* rdpsnd = (rdpsnd_server*) context;
STREAM* s = rdpsnd->rdpsnd_pdu;
if (rdpsnd->context.selected_client_format < 0)
return false;
if (rdpsnd->out_pending_frames > 0)
{
if (!rdpsnd_server_send_audio_pdu(rdpsnd))
return false;
}
rdpsnd->context.selected_client_format = -1;
RDPSND_PDU_INIT(s, SNDC_CLOSE);
RDPSND_PDU_FINISH(s);
}
rdpsnd_server_context* rdpsnd_server_context_new(WTSVirtualChannelManager* vcm)
{
rdpsnd_server* rdpsnd;
rdpsnd = xnew(rdpsnd_server);
rdpsnd->context.vcm = vcm;
rdpsnd->context.selected_client_format = -1;
rdpsnd->context.Initialize = rdpsnd_server_initialize;
rdpsnd->context.SelectFormat = rdpsnd_server_select_format;
rdpsnd->context.SendSamples = rdpsnd_server_send_samples;
rdpsnd->context.SetVolume = rdpsnd_server_set_volume;
rdpsnd->context.Close = rdpsnd_server_close;
rdpsnd->dsp_context = freerdp_dsp_context_new();
return (rdpsnd_server_context*) rdpsnd;
}
void rdpsnd_server_context_free(rdpsnd_server_context* context)
{
rdpsnd_server* rdpsnd = (rdpsnd_server*) context;
if (rdpsnd->rdpsnd_channel_thread)
{
freerdp_thread_stop(rdpsnd->rdpsnd_channel_thread);
freerdp_thread_free(rdpsnd->rdpsnd_channel_thread);
}
if (rdpsnd->rdpsnd_channel)
WTSVirtualChannelClose(rdpsnd->rdpsnd_channel);
if (rdpsnd->rdpsnd_pdu)
stream_free(rdpsnd->rdpsnd_pdu);
if (rdpsnd->out_buffer)
xfree(rdpsnd->out_buffer);
if (rdpsnd->dsp_context)
freerdp_dsp_context_free(rdpsnd->dsp_context);
if (rdpsnd->context.client_formats)
xfree(rdpsnd->context.client_formats);
xfree(rdpsnd);
}

View File

@ -0,0 +1,21 @@
# FreeRDP: A Remote Desktop Protocol Client
# FreeRDP cmake build script
#
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
#
# 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.
if(WITH_CLIENT_CHANNELS)
add_subdirectory(client)
endif()

View File

@ -0,0 +1,9 @@
set(CHANNEL_TYPE "static")
set(CHANNEL_SHORT_NAME "sample")
set(CHANNEL_LONG_NAME "Sample Virtual Channel Extension")
set(CHANNEL_SPECIFICATIONS "")
string(TOUPPER "WITH_${CHANNEL_SHORT_NAME}" CHANNEL_OPTION)
option(${CHANNEL_OPTION} "Build ${CHANNEL_SHORT_NAME}" OFF)

View File

@ -17,17 +17,17 @@
# See the License for the specific language governing permissions and
# limitations under the License.
set(DISK_SRCS
disk_file.c
disk_file.h
disk_main.c
)
set(SKEL_SRCS
skel_main.c
skel_main.h)
include_directories(..)
add_library(skel ${SKEL_SRCS})
set_target_properties(skel PROPERTIES PREFIX "")
add_library(disk ${DISK_SRCS})
set_target_properties(disk PROPERTIES PREFIX "")
if(WITH_MONOLITHIC_BUILD)
target_link_libraries(skel freerdp)
else()
target_link_libraries(skel freerdp-utils)
endif()
target_link_libraries(disk freerdp-utils)
install(TARGETS disk DESTINATION ${FREERDP_PLUGIN_PATH})
install(TARGETS skel DESTINATION ${FREERDP_PLUGIN_PATH})

View File

@ -0,0 +1,11 @@
This is a skeleton virtual channel plugin for freerdp
To create your own virtual channel plugin, copy this directory
then change all references of "skel" to your plugin name
remember, plugin name are 7 chars or less, no spaces or funny chars
server_chan_test.cpp is an example of how to open a channel to the client
this code needs to be compiled and run on the server in an rdp session
when connect with a client that has the "skel" plugin loaded
Jay

View File

@ -0,0 +1,60 @@
// xrdp_chan_test.cpp : Basic test for virtual channel use.
// These headers are required for the windows terminal service calls.
#include "windows.h"
#include "wtsapi32.h"
#include <string>
#define DSIZE 1024
int main()
{
// Initialize the data for send/receive
char* data;
char* data1;
data = (char*)malloc(DSIZE);
data1 = (char*)malloc(DSIZE);
memset(data, 0xca, DSIZE);
memset(data1, 0, DSIZE);
// Open the skel channel in current session
void* channel = WTSVirtualChannelOpenEx(WTS_CURRENT_SESSION, "skel", 0);
unsigned long written = 0;
// Write the data to the channel
bool ret = WTSVirtualChannelWrite(channel, data, DSIZE, &written);
if (!ret)
{
long err = GetLastError();
printf("error 0x%8.8x\n", err);
return 1;
}
ret = WTSVirtualChannelRead(channel, 100, data1, DSIZE, &written);
if (!ret)
{
long err = GetLastError();
printf("error 0x%8.8x\n", err);
return 1;
}
if (written != DSIZE)
{
printf("error read %d\n", written);
return 1;
}
ret = WTSVirtualChannelClose(channel);
if (memcmp(data, data1, DSIZE) == 0)
{
}
else
{
printf("error data no match\n");
return 1;
}
printf("Success!\n");
Sleep(2000);
return 0;
}

View File

@ -0,0 +1,136 @@
/**
* FreeRDP: A Remote Desktop Protocol client.
* Audio Output Virtual Channel
*
* Copyright 2009-2012 Jay Sorg
* Copyright 2010-2012 Vic Lee
*
* 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
#ifndef _WIN32
#include <sys/time.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <freerdp/constants.h>
#include <freerdp/types.h>
#include <freerdp/utils/memory.h>
#include <freerdp/utils/stream.h>
#include <freerdp/utils/list.h>
#include <freerdp/utils/load_plugin.h>
#include <freerdp/utils/svc_plugin.h>
#include "skel_main.h"
struct skel_plugin
{
rdpSvcPlugin plugin;
/* put your private data here */
};
static void skel_process_interval(rdpSvcPlugin* plugin)
{
printf("skel_process_interval:\n");
}
static void skel_process_receive(rdpSvcPlugin* plugin, STREAM* data_in)
{
skelPlugin* skel = (skelPlugin*)plugin;
STREAM* data_out;
int bytes;
printf("skel_process_receive:\n");
if (skel == NULL)
{
printf("skel_process_receive: skel is nil\n");
return;
}
/* process data in(from server) here */
/* here we just send the same data back */
bytes = stream_get_size(data_in);
printf("skel_process_receive: got bytes %d\n", bytes);
if (bytes > 0)
{
data_out = stream_new(bytes);
stream_copy(data_out, data_in, bytes);
/* svc_plugin_send takes ownership of data_out, that is why
we do not free it */
bytes = stream_get_length(data_in);
printf("skel_process_receive: sending bytes %d\n", bytes);
svc_plugin_send(plugin, data_out);
}
stream_free(data_in);
}
static void skel_process_connect(rdpSvcPlugin* plugin)
{
skelPlugin* skel = (skelPlugin*)plugin;
DEBUG_SVC("connecting");
printf("skel_process_connect:\n");
if (skel == NULL)
{
return;
}
/* if you want a call from channel thread once is a while do this */
plugin->interval_ms = 1000;
plugin->interval_callback = skel_process_interval;
}
static void skel_process_event(rdpSvcPlugin* plugin, RDP_EVENT* event)
{
printf("skel_process_event:\n");
/* events comming from main freerdp window to plugin */
/* send them back with svc_plugin_send_event */
freerdp_event_free(event);
}
static void skel_process_terminate(rdpSvcPlugin* plugin)
{
skelPlugin* skel = (skelPlugin*)plugin;
printf("skel_process_terminate:\n");
if (skel == NULL)
{
return;
}
/* put your cleanup here */
xfree(plugin);
}
DEFINE_SVC_PLUGIN(skel, "skel",
CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP)

View File

@ -0,0 +1,26 @@
/**
* FreeRDP: A Remote Desktop Protocol client.
* Audio Output Virtual Channel
*
* Copyright 2012 Jay Sorg
* Copyright 2010-2012 Vic Lee
*
* 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 __SKEL_MAIN_H
#define __SKEL_MAIN_H
typedef struct skel_plugin skelPlugin;
#endif /* __SKEL_MAIN_H */

View File

@ -0,0 +1,37 @@
# FreeRDP: A Remote Desktop Protocol Client
# FreeRDP cmake build script
#
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
#
# 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.
set(MODULE_NAME "freerdp-server-channels")
set(MODULE_PREFIX "FREERDP_SERVER_CHANNELS")
foreach(_MODULE_NAME ${CHANNEL_BUILTIN_SERVER_MODULES})
string(TOUPPER "CHANNEL_${_MODULE_NAME}" _MODULE_PREFIX)
message(STATUS "Adding built-in channel server module: ${_MODULE_NAME}")
foreach(SRC ${${_MODULE_PREFIX}_SERVER_SRCS})
set(CHANNEL_SERVER_SRCS ${CHANNEL_SERVER_SRCS} "../${_MODULE_NAME}/server/${SRC}")
endforeach()
set(CHANNEL_SERVER_LIBS ${CHANNEL_SERVER_LIBS} ${${_MODULE_PREFIX}_SERVER_LIBS})
endforeach()
add_library(${MODULE_NAME} ${CHANNEL_SERVER_SRCS})
set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION_FULL} SOVERSION ${FREERDP_VERSION} PREFIX "lib")
target_link_libraries(${MODULE_NAME} ${CHANNEL_SERVER_LIBS})
install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR})

View File

@ -0,0 +1,22 @@
# FreeRDP: A Remote Desktop Protocol Client
# FreeRDP cmake build script
#
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
#
# 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.
if(WITH_CLIENT_CHANNELS)
add_subdirectory(client)
endif()

Some files were not shown because too many files have changed in this diff Show More