mirror of
https://github.com/FreeRDP/FreeRDP.git
synced 2025-06-03 00:00:20 +00:00
freerdp: merging with master
This commit is contained in:
commit
164783904a
18
.gitignore
vendored
18
.gitignore
vendored
@ -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*
|
||||
|
146
CMakeLists.txt
146
CMakeLists.txt
@ -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")
|
||||
|
@ -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()
|
||||
|
31
channels/audin/CMakeLists.txt
Normal file
31
channels/audin/CMakeLists.txt
Normal 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()
|
||||
|
10
channels/audin/ChannelOptions.cmake
Normal file
10
channels/audin/ChannelOptions.cmake
Normal 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)
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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})
|
@ -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;
|
@ -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);
|
@ -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);
|
||||
|
@ -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})
|
@ -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)
|
||||
{
|
28
channels/audin/server/CMakeLists.txt
Normal file
28
channels/audin/server/CMakeLists.txt
Normal 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()
|
435
channels/audin/server/audin.c
Normal file
435
channels/audin/server/audin.c
Normal 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);
|
||||
}
|
@ -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})
|
||||
|
10
channels/cliprdr/ChannelOptions.cmake
Normal file
10
channels/cliprdr/ChannelOptions.cmake
Normal 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)
|
||||
|
||||
|
36
channels/cliprdr/client/CMakeLists.txt
Normal file
36
channels/cliprdr/client/CMakeLists.txt
Normal 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})
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
@ -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()
|
||||
|
||||
|
||||
|
9
channels/drdynvc/ChannelOptions.cmake
Normal file
9
channels/drdynvc/ChannelOptions.cmake
Normal 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)
|
||||
|
38
channels/drdynvc/client/CMakeLists.txt
Normal file
38
channels/drdynvc/client/CMakeLists.txt
Normal 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})
|
||||
|
@ -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>
|
@ -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>
|
@ -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);
|
@ -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()
|
||||
|
||||
|
9
channels/rail/ChannelOptions.cmake
Normal file
9
channels/rail/ChannelOptions.cmake
Normal 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)
|
||||
|
@ -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})
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,6 @@
|
||||
|
||||
struct rdp_rail_order
|
||||
{
|
||||
UNICONV* uniconv;
|
||||
RDP_PLUGIN_DATA* plugin_data;
|
||||
void* plugin;
|
||||
RAIL_HANDSHAKE_ORDER handshake;
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
@ -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)
|
@ -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()
|
||||
|
||||
|
14
channels/rdpdr/ChannelOptions.cmake
Normal file
14
channels/rdpdr/ChannelOptions.cmake
Normal 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()
|
||||
|
52
channels/rdpdr/client/CMakeLists.txt
Normal file
52
channels/rdpdr/client/CMakeLists.txt
Normal 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()
|
@ -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>
|
47
channels/rdpdr/client/disk/CMakeLists.txt
Normal file
47
channels/rdpdr/client/disk/CMakeLists.txt
Normal 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})
|
374
channels/rdpdr/client/disk/dirent.h
Normal file
374
channels/rdpdr/client/disk/dirent.h
Normal 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*/
|
@ -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:
|
@ -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
|
||||
{
|
@ -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;
|
||||
}
|
57
channels/rdpdr/client/disk/statvfs.c
Normal file
57
channels/rdpdr/client/disk/statvfs.c
Normal 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;
|
||||
}
|
50
channels/rdpdr/client/disk/statvfs.h
Normal file
50
channels/rdpdr/client/disk/statvfs.h
Normal 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 */
|
@ -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>
|
@ -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})
|
@ -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);
|
@ -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})
|
@ -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)
|
@ -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)
|
||||
{
|
283
channels/rdpdr/client/printer/printer_win.c
Normal file
283
channels/rdpdr/client/printer/printer_win.c
Normal 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;
|
||||
}
|
||||
|
37
channels/rdpdr/client/printer/printer_win.h
Normal file
37
channels/rdpdr/client/printer/printer_win.h
Normal 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
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
{
|
@ -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);
|
@ -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>
|
@ -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})
|
@ -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;
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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})
|
332
channels/rdpdr/client/smartcard/scard_main.c
Normal file
332
channels/rdpdr/client/smartcard/scard_main.c
Normal 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;
|
||||
}
|
125
channels/rdpdr/client/smartcard/scard_main.h
Normal file
125
channels/rdpdr/client/smartcard/scard_main.h
Normal 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
|
@ -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
|
@ -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;
|
||||
}
|
@ -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
|
@ -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()
|
||||
|
||||
|
||||
|
14
channels/rdpsnd/ChannelOptions.cmake
Normal file
14
channels/rdpsnd/ChannelOptions.cmake
Normal 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()
|
||||
|
46
channels/rdpsnd/client/CMakeLists.txt
Normal file
46
channels/rdpsnd/client/CMakeLists.txt
Normal 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()
|
||||
|
@ -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})
|
@ -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;
|
40
channels/rdpsnd/client/mac_audio/CMakeLists.txt
Normal file
40
channels/rdpsnd/client/mac_audio/CMakeLists.txt
Normal 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})
|
||||
|
229
channels/rdpsnd/client/mac_audio/rdpsnd_audio_q.c
Normal file
229
channels/rdpsnd/client/mac_audio/rdpsnd_audio_q.c
Normal 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;
|
||||
}
|
||||
|
@ -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})
|
@ -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)
|
||||
{
|
@ -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)
|
@ -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;
|
||||
|
29
channels/rdpsnd/server/CMakeLists.txt
Normal file
29
channels/rdpsnd/server/CMakeLists.txt
Normal 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()
|
||||
|
480
channels/rdpsnd/server/rdpsnd.c
Normal file
480
channels/rdpsnd/server/rdpsnd.c
Normal 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);
|
||||
}
|
21
channels/sample/CMakeLists.txt
Normal file
21
channels/sample/CMakeLists.txt
Normal 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()
|
||||
|
9
channels/sample/ChannelOptions.cmake
Normal file
9
channels/sample/ChannelOptions.cmake
Normal 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)
|
||||
|
@ -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})
|
11
channels/sample/client/readme.txt
Normal file
11
channels/sample/client/readme.txt
Normal 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
|
60
channels/sample/client/server_chan_test.cpp
Normal file
60
channels/sample/client/server_chan_test.cpp
Normal 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;
|
||||
}
|
136
channels/sample/client/skel_main.c
Normal file
136
channels/sample/client/skel_main.c
Normal 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)
|
26
channels/sample/client/skel_main.h
Normal file
26
channels/sample/client/skel_main.h
Normal 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 */
|
37
channels/server/CMakeLists.txt
Normal file
37
channels/server/CMakeLists.txt
Normal 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})
|
22
channels/tsmf/CMakeLists.txt
Normal file
22
channels/tsmf/CMakeLists.txt
Normal 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
Loading…
Reference in New Issue
Block a user