Merge branch 'devel' into v0.9

This commit is contained in:
Koichiro IWAO 2020-03-11 13:30:33 +09:00
commit 0a068311b1
No known key found for this signature in database
GPG Key ID: 9F72CDBC01BF10EB
18 changed files with 367 additions and 486 deletions

View File

@ -9,6 +9,12 @@ addons:
packages: &common_deps
- nasm
# This is required to use a version of cppcheck other than that
# suplied with the operating system
cppcheck_defs: &cppcheck_defs
- CPPCHECK_VER=1.90
- CPPCHECK_REPO=https://github.com/danmar/cppcheck.git
min_amd64_deps: &min_amd64_deps
- *common_deps
- libpam0g-dev
@ -81,6 +87,22 @@ max_x86_conf: &max_x86_conf
packages:
- *max_x86_deps
# For cppcheck, we've got a custom script
cppcheck_conf: &cppcheck_conf
env:
- *cppcheck_defs
# addons:
# apt:
# packages:
# - cppcheck
script:
- ./bootstrap
- scripts/install_cppcheck.sh $CPPCHECK_REPO $CPPCHECK_VER
- scripts/run_cppcheck.sh -v $CPPCHECK_VER
matrix:
include:
@ -108,6 +130,11 @@ matrix:
- compiler: clang
<< : *max_x86_conf
# cppcheck
- name: cppcheck
compiler: gcc
<< : *cppcheck_conf
script:
- ./bootstrap
- ./configure $CONF_FLAGS

27
NEWS.md
View File

@ -1,3 +1,30 @@
# Release notes for xrdp v0.9.13 (2020/03/11)
This release is an intermediate bugfix release. The previous version v0.9.12 has some regressions on drive redirection.
## Bug fixes (drive redirection related)
* Fix chansrv crashes with segmentation fault (regression in #1449) #1487
* Drive redirection now supports Guacamole client #1505 #1507
* Prevent a coredump in the event of a corrupted file system #1507
* Resolve double-free in `chansrv_fuse` #1469
## Bug fixes (other)
* Fix the issue `xrdp --version | less` will show empty output #1471 #1472
* Fix some warnings found by cppcheck #1479 #1481 #1484 #1485
## Other changes
* Add FreeBSD CI test #1466
* Move Microsoft-defined constants into separate includes #1470
* Perform cppcheck during CI test #1493
* Support mousex button 8/9 #1478
## Known issues
* FreeRDP 2.0.0-rc4 or later might not able to connect to xrdp due to
xrdp's bad-mannered behaviour, add `+glyph-cache` option to FreeRDP to connect #1266
* Audio redirection by MP3 codec doesn't sound with some client, use AAC instead #965
-----------------------
# Release notes for xrdp v0.9.12 (2019/12/28)
## Bug fixes

View File

@ -1,8 +1,8 @@
[![Build Status](https://travis-ci.org/neutrinolabs/xrdp.svg?branch=devel)](https://travis-ci.org/neutrinolabs/xrdp)
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/neutrinolabs/xrdp)
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/neutrinolabs/xrdp-questions)
![Apache-License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)
*Current Version:* 0.9.12
*Current Version:* 0.9.13
# xrdp - an open source RDP server

View File

@ -36,7 +36,8 @@ enum NTSTATUS
STATUS_ACCESS_DENIED = 0xc0000022,
STATUS_OBJECT_NAME_INVALID = 0xc0000033,
STATUS_OBJECT_NAME_NOT_FOUND = 0xc0000034,
STATUS_SHARING_VIOLATION = 0xc0000043
STATUS_SHARING_VIOLATION = 0xc0000043,
STATUS_NOT_SUPPORTED = 0xc00000bb
};
#endif /* MS_ERREF_H */

View File

@ -1,7 +1,7 @@
# Process this file with autoconf to produce a configure script
AC_PREREQ(2.65)
AC_INIT([xrdp], [0.9.12], [xrdp-devel@googlegroups.com])
AC_INIT([xrdp], [0.9.13], [xrdp-devel@googlegroups.com])
AC_CONFIG_HEADERS(config_ac.h:config_ac-h.in)
AM_INIT_AUTOMAKE([1.7.2 foreign])
AC_CONFIG_MACRO_DIR([m4])

105
scripts/install_cppcheck.sh Executable file
View File

@ -0,0 +1,105 @@
#!/bin/sh
# Script to install a version of cppcheck in ~/cppcheck.local/
#
# Used by Travis-CI builds, until Travis supports cppcheck natively
#
# Currently only supports git repos as sources
#
# Usage: /path/to/install_cppcheck.sh <cppcheck-git-repo> <version-tag>
INSTALL_ROOT=~/cppcheck.local
# ----------------------------------------------------------------------------
# U S A G E
# ----------------------------------------------------------------------------
usage()
{
echo "** Usage: $0 <git-repo URL> <version-tag>"
echo " e.g. $0 https://github.com/danmar/cppcheck.git 1.90"
} >&2
# ----------------------------------------------------------------------------
# C A L L _ M A K E
#
# Calls make with the specified parameters, but only displays the error
# log if it fails
# ----------------------------------------------------------------------------
call_make()
{
# Disable set -e, if active
set_entry_opts=`set +o`
set +e
status=1
log=`mktemp /tmp/cppcheck-log.XXXXXXXXXX`
if [ -n "$log" ]; then
make "$@" >$log 2>&1
status=$?
if [ $status -ne 0 ]; then
cat $log >&2
fi
rm $log
fi
# Re-enable `set -e` if active before
$set_entry_opts
return $status
}
# ----------------------------------------------------------------------------
# M A I N
# ----------------------------------------------------------------------------
if [ $# -ne 2 ]; then
usage
exit 1
fi
REPO_URL="$1"
CPPCHECK_VER="$2"
# Already installed?
exe=$INSTALL_ROOT/$CPPCHECK_VER/bin/cppcheck
if [ -x "$exe" ]; then
echo "cppcheck version $CPPCHECK_VER is already installed at $exe" >&2
exit 0
fi
workdir=`mktemp -d /tmp/cppcheck.XXXXXXXXXX`
if [ -z "$workdir" ]; then
echo "** Unable to create temporary working directory" 2>&1
exit 1
fi
# Use a sub-process for the next bit to restrict the scope of 'set -e'
(
set -e ; # Exit sub-process on first error
# Put everything in this directory
FILESDIR=$INSTALL_ROOT/$CPPCHECK_VER
# CFGDIR is needed for cppcheck before 1.86
make_args="FILESDIR=$FILESDIR PREFIX=$FILESDIR CFGDIR=$FILESDIR"
# See https://stackoverflow.com/questions/
# 791959/download-a-specific-tag-with-git
git clone -b $CPPCHECK_VER --depth 1 $REPO_URL $workdir
cd $workdir
echo "Making cppcheck..."
# CFGDIR is needed for cppcheck before 1.86
call_make $make_args
echo "Installing cppcheck..."
mkdir -p $FILESDIR
call_make install $make_args
)
status=$?
if [ $status -eq 0 ]; then
rm -rf $workdir
else
"** Script failed. Work dir is $workdir" >&2
fi
exit $status

58
scripts/run_cppcheck.sh Executable file
View File

@ -0,0 +1,58 @@
#!/bin/sh
# Script to run cppcheck
#
# Usage: /path/to/run_cppcheck.sh [ -v CPPCHECK_VER] [<extra_opts_and_dirs>]
#
# - If <extra_opts_and_dirs> is missing, '.' is assumed
# - If -v CPPCHECK_VER is specified, that version of cppcheck is run from
# ~/cppcheck.local (whether or not it's there!). Use install_cppcheck.sh
# to install a new version.
#
# Environment (all optional):-
#
# CPPCHECK : Override the default cppcheck command ('cppcheck').
# Ignored if -v is specified
# CPPCHECK_FLAGS : Override the default cppcheck flags
INSTALL_ROOT=~/cppcheck.local
# Figure out CPPCHECK setting, if any. Currently '-v' must be the first
# argument on the command line.
case "$1" in
-v) # Version is separate parameter
if [ $# -ge 2 ]; then
CPPCHECK="$INSTALL_ROOT/$2/bin/cppcheck"
shift 2
else
echo "** ignoring '-v' with no arg" >&2
shift 1
fi
;;
-v*) # Version is in same parameter
# ${parameter#word} is not supported by classic Bourne shell,
# but it is on bash, dash, etc. If it doesn't work on your shell,
# don't use this form!
CPPCHECK="$INSTALL_ROOT/${1#-v}/bin/cppcheck"
shift 1
esac
if [ -z "$CPPCHECK" ]; then
CPPCHECK=cppcheck
fi
# Supply default flags passed to cppcheck if necessary
if [ -z "$CPPCHECK_FLAGS" ]; then
CPPCHECK_FLAGS="--quiet --force --std=c11 --std=c++11 --inline-suppr \
--enable=warning --error-exitcode=1"
fi
# Any options/directories specified?
if [ $# -eq 0 ]; then
set -- .
fi
# Display the cppcheck version and command for debugging
"$CPPCHECK" --version && {
echo Command: $CPPCHECK $CPPCHECK_FLAGS "$@"
"$CPPCHECK" $CPPCHECK_FLAGS "$@"
}

View File

@ -78,6 +78,7 @@ void xfuse_devredir_cb_open_file(struct state_open *fip,
tui32 DeviceId, tui32 FileId)
{}
void xfuse_devredir_cb_read_file(struct state_read *fip,
enum NTSTATUS IoStatus,
const char *buf, size_t length)
{}
void xfuse_devredir_cb_write_file(
@ -637,6 +638,7 @@ int xfuse_create_share(tui32 device_id, const char *dirname)
}
else
{
xinode->is_redirected = 1;
xinode->device_id = device_id;
result = 0;
}
@ -653,7 +655,7 @@ int xfuse_create_share(tui32 device_id, const char *dirname)
void xfuse_delete_share(tui32 device_id)
{
xfs_delete_entries_with_device_id(g_xfs, device_id);
xfs_delete_redirected_entries_with_device_id(g_xfs, device_id);
}
/**
@ -1313,9 +1315,18 @@ void xfuse_devredir_cb_open_file(struct state_open *fip,
}
void xfuse_devredir_cb_read_file(struct state_read *fip,
enum NTSTATUS IoStatus,
const char *buf, size_t length)
{
fuse_reply_buf(fip->req, buf, length);
if (IoStatus != STATUS_SUCCESS)
{
log_error("Read NTSTATUS is %d", (int) IoStatus);
fuse_reply_err(fip->req, EIO);
}
else
{
fuse_reply_buf(fip->req, buf, length);
}
free(fip);
}
@ -1438,7 +1449,7 @@ static void xfuse_cb_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
}
else
{
if (parent_xinode->device_id == 0)
if (!parent_xinode->is_redirected)
{
/* File cannot be remote - we either know about it or we don't */
if ((xinode = xfs_lookup_in_dir(g_xfs, parent, name)) != NULL)
@ -1673,13 +1684,13 @@ static void xfuse_cb_unlink(fuse_req_t req, fuse_ino_t parent,
fuse_reply_err(req, ENOTEMPTY);
}
else if (xinode->device_id == 0)
else if (!xinode->is_redirected)
{
/* specified file is a local resource */
//XFUSE_HANDLE *fh;
log_debug("LK_TODO: this is still a TODO");
fuse_reply_err(req, EINVAL);
fuse_reply_err(req, EROFS);
}
else
{
@ -1744,26 +1755,27 @@ static void xfuse_cb_rename(fuse_req_t req,
else if (!(new_parent_xinode = xfs_get(g_xfs, new_parent)))
{
log_error("inode %ld is not valid", new_parent);
fuse_reply_err(req, EINVAL);
fuse_reply_err(req, ENOENT);
}
else if (!xfs_check_move_entry(g_xfs, old_xinode->inum,
new_parent, new_name))
{
/* Catchall -see rename(2). Fix when logging is improved */
fuse_reply_err(req, EINVAL);
}
else if (new_parent_xinode->device_id != old_xinode->device_id)
else if (new_parent_xinode->is_redirected != old_xinode->is_redirected ||
new_parent_xinode->device_id != old_xinode->device_id)
{
log_error("rename across file systems not supported");
fuse_reply_err(req, EINVAL);
fuse_reply_err(req, EXDEV);
}
else if (old_xinode->device_id == 0)
else if (!old_xinode->is_redirected)
{
/* specified file is a local resource */
log_debug("LK_TODO: this is still a TODO");
fuse_reply_err(req, EINVAL);
fuse_reply_err(req, EROFS);
}
else
@ -1853,20 +1865,25 @@ static void xfuse_create_dir_or_file(fuse_req_t req, fuse_ino_t parent,
}
/* is parent inode valid? */
if (parent == FUSE_ROOT_ID ||
(xinode = xfs_get(g_xfs, parent)) == NULL ||
(xinode->mode & S_IFDIR) == 0)
if (parent == FUSE_ROOT_ID)
{
fuse_reply_err(req, EROFS);
}
else if ((xinode = xfs_get(g_xfs, parent)) == NULL)
{
log_error("inode %ld is not valid", parent);
fuse_reply_err(req, ENOENT);
}
else if (xinode->device_id == 0)
else if ((xinode->mode & S_IFDIR) == 0)
{
fuse_reply_err(req, ENOTDIR);
}
else if (!xinode->is_redirected)
{
/* specified file is a local resource */
//XFUSE_HANDLE *fh;
log_debug("LK_TODO: this is still a TODO");
fuse_reply_err(req, EINVAL);
fuse_reply_err(req, EROFS);
}
else
{
@ -1945,13 +1962,20 @@ static void xfuse_cb_open(fuse_req_t req, fuse_ino_t ino,
log_debug("Invalid access mode specified");
fuse_reply_err(req, EINVAL);
}
else if (xinode->device_id == 0)
else if (!xinode->is_redirected)
{
/* specified file is a local resource */
XFUSE_HANDLE *fh = g_new0(XFUSE_HANDLE, 1);
fh->is_loc_resource = 1;
fi->fh = (tintptr) fh;
fuse_reply_open(req, fi);
if ((fi->flags & O_ACCMODE) != O_RDONLY)
{
fuse_reply_err(req, EROFS);
}
else
{
XFUSE_HANDLE *fh = g_new0(XFUSE_HANDLE, 1);
fh->is_loc_resource = 1;
fi->fh = (tintptr) fh;
fuse_reply_open(req, fi);
}
}
else
{
@ -2017,7 +2041,7 @@ static void xfuse_cb_release(fuse_req_t req, fuse_ino_t ino, struct
log_error("inode %ld is not valid", ino);
fuse_reply_err(req, ENOENT);
}
else if (xinode->device_id == 0)
else if (!xinode->is_redirected)
{
/* specified file is a local resource */
fuse_reply_err(req, 0);
@ -2153,7 +2177,7 @@ static void xfuse_cb_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
{
/* target file is in .clipboard dir */
log_debug("THIS IS STILL A TODO!");
fuse_reply_err(req, EINVAL);
fuse_reply_err(req, EROFS);
}
else
{
@ -2283,7 +2307,7 @@ static void xfuse_cb_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
/* No changes have been made */
make_fuse_attr_reply(req, xinode);
}
else if (xinode->device_id == 0)
else if (!xinode->is_redirected)
{
/* Update the local fs */
update_inode_file_attributes(&attrs, change_mask, xinode);
@ -2349,7 +2373,7 @@ static void xfuse_cb_opendir(fuse_req_t req, fuse_ino_t ino,
log_error("inode %ld is not valid", ino);
fuse_reply_err(req, ENOENT);
}
else if (xinode->device_id == 0)
else if (!xinode->is_redirected)
{
if ((fi->fh = (tintptr) xfs_opendir(g_xfs, ino)) == 0)
{
@ -2537,6 +2561,8 @@ static char *get_name_for_entry_in_parent(fuse_ino_t parent, const char *name)
strlen(result) + 1 + strlen(name) + 1);
if (p == NULL)
{
/* See cppcheck trac #9292 and #9437 */
/* cppcheck-suppress doubleFree symbolName=result */
free(result);
result = NULL;
}

View File

@ -98,6 +98,7 @@ void xfuse_devredir_cb_open_file(struct state_open *fip,
tui32 DeviceId, tui32 FileId);
void xfuse_devredir_cb_read_file(struct state_read *fip,
enum NTSTATUS IoStatus,
const char *buf, size_t length);
void xfuse_devredir_cb_write_file(
struct state_write *fip,

View File

@ -344,6 +344,7 @@ xfs_create_xfs_fs(mode_t umask, uid_t uid, gid_t gid)
xino1->pub.ctime = xino1->pub.atime;
strcpy(xino1->pub.name, ".");
xino1->pub.generation = xfs->generation;
xino1->pub.is_redirected = 0;
xino1->pub.device_id = 0;
/*
@ -365,6 +366,7 @@ xfs_create_xfs_fs(mode_t umask, uid_t uid, gid_t gid)
xino2->pub.ctime = xino2->pub.atime;
strcpy(xino2->pub.name, ".delete-pending");
xino2->pub.generation = xfs->generation;
xino2->pub.is_redirected = 0;
xino2->pub.device_id = 0;
xino2->parent = NULL;
@ -469,6 +471,7 @@ xfs_add_entry(struct xfs_fs *xfs, fuse_ino_t parent_inum,
xino->pub.ctime = xino->pub.atime;
strcpy(xino->pub.name, name);
xino->pub.generation = xfs->generation;
xino->pub.is_redirected = parent->pub.is_redirected;
xino->pub.device_id = parent->pub.device_id;
xino->pub.lindex = 0;
@ -565,7 +568,7 @@ xfs_get_full_path(struct xfs_fs *xfs, fuse_ino_t inum)
*/
size_t len = 0;
XFS_INODE_ALL *p;
for (p = xino ; p->pub.inum != FUSE_ROOT_ID ; p = p->parent)
for (p = xino ; p && p->pub.inum != FUSE_ROOT_ID ; p = p->parent)
{
len += strlen(p->pub.name);
++len; /* Allow for '/' prefix */
@ -578,7 +581,7 @@ xfs_get_full_path(struct xfs_fs *xfs, fuse_ino_t inum)
char *end = result + len;
*end = '\0';
for (p = xino ; p->pub.inum != FUSE_ROOT_ID ; p = p->parent)
for (p = xino ; p && p->pub.inum != FUSE_ROOT_ID ; p = p->parent)
{
len = strlen(p->pub.name);
end -= (len + 1);
@ -816,35 +819,35 @@ xfs_get_file_open_count(struct xfs_fs *xfs, fuse_ino_t inum)
/* ------------------------------------------------------------------------ */
void
xfs_delete_entries_with_device_id(struct xfs_fs *xfs, tui32 device_id)
xfs_delete_redirected_entries_with_device_id(struct xfs_fs *xfs,
tui32 device_id)
{
fuse_ino_t inum;
XFS_INODE_ALL *xino;
if (device_id != 0)
/* Using xfs_remove_entry() is convenient, but it recurses
* in to directories. To make sure all entries are removed, set the
* open_count of all affected files to 0 first
*/
for (inum = FUSE_ROOT_ID; inum < xfs->inode_count; ++inum)
{
/* Using xfs_remove_entry() is convenient, but it recurses
* in to directories. To make sure all entries are removed, set the
* open_count of all affected files to 0 first
*/
for (inum = FUSE_ROOT_ID; inum < xfs->inode_count; ++inum)
if ((xino = xfs->inode_table[inum]) != NULL &&
xino->pub.is_redirected != 0 &&
xino->pub.device_id == device_id &&
(xino->pub.mode & S_IFREG) != 0)
{
if ((xino = xfs->inode_table[inum]) != NULL &&
xino->pub.device_id == device_id &&
(xino->pub.mode & S_IFREG) != 0)
{
xino->open_count = 0;
}
xino->open_count = 0;
}
}
/* Now we can be sure everything will be deleted correctly */
for (inum = FUSE_ROOT_ID; inum < xfs->inode_count; ++inum)
/* Now we can be sure everything will be deleted correctly */
for (inum = FUSE_ROOT_ID; inum < xfs->inode_count; ++inum)
{
if ((xino = xfs->inode_table[inum]) != NULL &&
xino->pub.is_redirected != 0 &&
xino->pub.device_id == device_id)
{
if ((xino = xfs->inode_table[inum]) != NULL &&
xino->pub.device_id == device_id)
{
xfs_remove_entry(xfs, xino->pub.inum);
}
xfs_remove_entry(xfs, xino->pub.inum);
}
}
}

View File

@ -49,9 +49,8 @@ typedef struct xfs_inode
time_t ctime; /* Time of last status change. */
char name[XFS_MAXFILENAMELEN + 1]; /* Short name */
tui32 generation; /* Changes if inode is reused */
tui32 device_id; /* for file system redirection
* Non-redirected devices are guaranteed
* to have a device_id or zero */
char is_redirected; /* file is on redirected device */
tui32 device_id; /* device ID of redirected device */
int lindex; /* used in clipboard operations */
} XFS_INODE;
@ -271,17 +270,15 @@ unsigned int
xfs_get_file_open_count(struct xfs_fs *xfs, fuse_ino_t inum);
/*
* Deletes all entries with the matching device id
* Deletes all redirected entries with the matching device id
*
* Files are deleted even if they are open
*
* The specified device_id must be non-zero so that the root
* filesystem is not deleted!
*
* @param device_id Device ID
*/
void
xfs_delete_entries_with_device_id(struct xfs_fs *xfs, tui32 device_id);
xfs_delete_redirected_entries_with_device_id(struct xfs_fs *xfs,
tui32 device_id);
/*
* Check an entry move will be successful

View File

@ -185,28 +185,10 @@ devredir_init(void)
{
struct stream *s;
int bytes;
int fd;
union _u
{
tui32 clientID;
char buf[4];
} u;
tui32 clientID;
/* get a random number that will act as a unique clientID */
if ((fd = open("/dev/urandom", O_RDONLY)) != -1)
{
if (read(fd, u.buf, 4) != 4)
{
}
close(fd);
}
else
{
/* /dev/urandom did not work - use address of struct s */
tui64 u64 = (tui64) (tintptr) &s;
u.clientID = (tui32) u64;
}
g_random((char *) &clientID, sizeof(clientID));
/* setup stream */
xstream_new(s, 1024);
@ -216,7 +198,7 @@ devredir_init(void)
xstream_wr_u16_le(s, PAKID_CORE_SERVER_ANNOUNCE);
xstream_wr_u16_le(s, 0x0001); /* server major ver */
xstream_wr_u16_le(s, 0x000C); /* server minor ver - pretend 2 b Win 7 */
xstream_wr_u32_le(s, u.clientID); /* unique ClientID */
xstream_wr_u32_le(s, clientID); /* unique ClientID */
/* send data to client */
bytes = xstream_len(s);
@ -578,7 +560,8 @@ devredir_send_server_user_logged_on(void)
}
static void
devredir_send_server_device_announce_resp(tui32 device_id)
devredir_send_server_device_announce_resp(tui32 device_id,
enum NTSTATUS result_code)
{
struct stream *s;
int bytes;
@ -589,7 +572,7 @@ devredir_send_server_device_announce_resp(tui32 device_id)
xstream_wr_u16_le(s, RDPDR_CTYP_CORE);
xstream_wr_u16_le(s, PAKID_CORE_DEVICE_REPLY);
xstream_wr_u32_le(s, device_id);
xstream_wr_u32_le(s, 0); /* ResultCode */
xstream_wr_u32_le(s, (tui32)result_code);
/* send to client */
bytes = xstream_len(s);
@ -829,6 +812,7 @@ devredir_proc_client_devlist_announce_req(struct stream *s)
tui32 device_type;
tui32 device_data_len;
char preferred_dos_name[9];
enum NTSTATUS response_status;
/* get number of devices being announced */
xstream_rd_u32_le(s, device_count);
@ -839,19 +823,20 @@ devredir_proc_client_devlist_announce_req(struct stream *s)
{
xstream_rd_u32_le(s, device_type);
xstream_rd_u32_le(s, g_device_id);
/* get preferred DOS name
* DOS names that are 8 chars long are not NULL terminated */
for (j = 0; j < 8; j++)
{
preferred_dos_name[j] = *s->p++;
}
preferred_dos_name[8] = 0;
/* Assume this device isn't supported by us */
response_status = STATUS_NOT_SUPPORTED;
switch (device_type)
{
case RDPDR_DTYP_FILESYSTEM:
/* get preferred DOS name */
for (j = 0; j < 8; j++)
{
preferred_dos_name[j] = *s->p++;
}
/* DOS names that are 8 chars long are not NULL terminated */
preferred_dos_name[8] = 0;
/* get device data len */
xstream_rd_u32_le(s, device_data_len);
if (device_data_len)
@ -865,7 +850,7 @@ devredir_proc_client_devlist_announce_req(struct stream *s)
preferred_dos_name,
device_data_len, g_full_name_for_filesystem);
devredir_send_server_device_announce_resp(g_device_id);
response_status = STATUS_SUCCESS;
/* create share directory in xrdp file system; */
/* think of this as the mount point for this share */
@ -873,31 +858,44 @@ devredir_proc_client_devlist_announce_req(struct stream *s)
break;
case RDPDR_DTYP_SMARTCARD:
/* get preferred DOS name */
for (j = 0; j < 8; j++)
{
preferred_dos_name[j] = *s->p++;
}
/* DOS names that are 8 chars long are not NULL terminated */
preferred_dos_name[8] = 0;
/* for smart cards, device data len always 0 */
log_debug("device_type=SMARTCARD device_id=0x%x dosname=%s",
g_device_id, preferred_dos_name);
devredir_send_server_device_announce_resp(g_device_id);
response_status = STATUS_SUCCESS;
scard_device_announce(g_device_id);
break;
/* we don't yet support these devices */
case RDPDR_DTYP_SERIAL:
log_debug(
"device_type=SERIAL device_id=0x%x dosname=%s",
g_device_id, preferred_dos_name);
break;
case RDPDR_DTYP_PARALLEL:
log_debug(
"device_type=PARALLEL device_id=0x%x dosname=%s",
g_device_id, preferred_dos_name);
break;
case RDPDR_DTYP_PRINT:
log_debug("unsupported dev: 0x%x", device_type);
log_debug(
"device_type=PRINT device_id=0x%x dosname=%s",
g_device_id, preferred_dos_name);
break;
default:
log_debug(
"device_type=UNKNOWN device_id=0x%x dosname=%s",
g_device_id, preferred_dos_name);
break;
}
/* Tell the client wheth or not we're supporting this one */
devredir_send_server_device_announce_resp(g_device_id,
response_status);
}
}
@ -1011,6 +1009,7 @@ devredir_proc_device_iocompletion(struct stream *s)
case CID_READ:
xstream_rd_u32_le(s, Length);
xfuse_devredir_cb_read_file((struct state_read *) irp->fuse_info,
IoStatus,
s->p, Length);
devredir_irp_delete(irp);
break;
@ -1529,10 +1528,10 @@ devredir_rmdir_or_file(struct state_remove *fusep, tui32 device_id,
/**
* Read data from previously opened file
*
* @return 0 on success, -1 on failure
* Errors are reported via xfuse_devredir_cb_read_file()
*****************************************************************************/
int
void
devredir_file_read(struct state_read *fusep, tui32 DeviceId, tui32 FileId,
tui32 Length, tui64 Offset)
{
@ -1540,7 +1539,6 @@ devredir_file_read(struct state_read *fusep, tui32 DeviceId, tui32 FileId,
IRP *irp;
IRP *new_irp;
int bytes;
int rval = -1;
xstream_new(s, 1024);
@ -1548,14 +1546,14 @@ devredir_file_read(struct state_read *fusep, tui32 DeviceId, tui32 FileId,
if ((irp = devredir_irp_find_by_fileid(FileId)) == NULL)
{
log_error("no IRP found with FileId = %d", FileId);
xfuse_devredir_cb_read_file(fusep, NULL, 0);
xfuse_devredir_cb_read_file(fusep, STATUS_UNSUCCESSFUL, NULL, 0);
xstream_free(s);
}
/* create a new IRP for this request */
else if ((new_irp = devredir_irp_new()) == NULL)
{
/* system out of memory */
xfuse_devredir_cb_read_file(fusep, NULL, 0);
xfuse_devredir_cb_read_file(fusep, STATUS_UNSUCCESSFUL, NULL, 0);
xstream_free(s);
}
else
@ -1581,13 +1579,16 @@ devredir_file_read(struct state_read *fusep, tui32 DeviceId, tui32 FileId,
bytes = xstream_len(s);
send_channel_data(g_rdpdr_chan_id, s->data, bytes);
xstream_free(s);
rval = 0;
}
return rval;
}
int
/**
* Read data from previously opened file
*
* Errors are reported via xfuse_devredir_cb_write_file()
*****************************************************************************/
void
devredir_file_write(struct state_write *fusep, tui32 DeviceId, tui32 FileId,
const char *buf, int Length, tui64 Offset)
{
@ -1595,7 +1596,6 @@ devredir_file_write(struct state_write *fusep, tui32 DeviceId, tui32 FileId,
IRP *irp;
IRP *new_irp;
int bytes;
int rval = -1;
log_debug("DeviceId=%d FileId=%d Length=%d Offset=%lld",
DeviceId, FileId, Length, (long long)Offset);
@ -1643,10 +1643,7 @@ devredir_file_write(struct state_write *fusep, tui32 DeviceId, tui32 FileId,
bytes = xstream_len(s);
send_channel_data(g_rdpdr_chan_id, s->data, bytes);
xstream_free(s);
rval = 0;
}
return rval;
}

View File

@ -78,12 +78,13 @@ int devredir_file_open(struct state_open *fusep, tui32 device_id,
int devredir_file_close(struct state_close *fusep, tui32 device_id,
tui32 file_id);
int devredir_file_read(struct state_read *fusep, tui32 device_id, tui32 FileId,
tui32 Length, tui64 Offset);
void
devredir_file_read(struct state_read *fusep, tui32 device_id, tui32 FileId,
tui32 Length, tui64 Offset);
int
void
devredir_file_write(struct state_write *fusep, tui32 DeviceId, tui32 FileId,
const char *buf, int Length, tui64 Offset);
const char *buf, int Length, tui64 Offset);
int devredir_file_rename(
struct state_rename *fusep, tui32 device_id,

View File

@ -37,8 +37,6 @@ int g_rem_io_count = 0; // bytes read from remote port
static int g_terminated = 0;
static char g_buf[1024 * 32];
#define
#define
typedef unsigned short tui16;

View File

@ -1,266 +0,0 @@
// not used
#include "decoderthread.h"
/*
* TODO:
* o need to maintain aspect ratio while resizing
* o clicking in the middle of the slider bar should move the slider to the middle
* o need to be able to rewind the move when it is done playing
* o need to be able to load another move and play it w/o restarting player
* o pause button needs to work
* o need images for btns
*/
DecoderThread::DecoderThread()
{
channel = NULL;
geometry.setX(0);
geometry.setY(0);
geometry.setWidth(0);
geometry.setHeight(0);
stream_id = 101;
elapsedTime = 0;
la_seekPos = -1;
videoTimer = NULL;
audioTimer = NULL;
}
void DecoderThread::run()
{
/* need a media file */
if (filename.length() == 0)
{
emit on_decoderErrorMsg("No media file",
"Please select a media file to play");
return;
}
}
void DecoderThread::startMediaPlay()
{
MediaPacket *mediaPkt;
int is_video_frame;
int rv;
/* setup video timer; each time this timer fires, it sends */
/* one video pkt to the client then resets the callback duration */
videoTimer = new QTimer;
connect(videoTimer, SIGNAL(timeout()), this, SLOT(videoTimerCallback()));
//videoTimer->start(1500);
/* setup audio timer; does the same as above, but with audio pkts */
audioTimer = new QTimer;
connect(audioTimer, SIGNAL(timeout()), this, SLOT(audioTimerCallback()));
//audioTimer->start(500);
/* setup pktTimer; each time this timer fires, it reads AVPackets */
/* and puts them into audio/video Queues */
pktTimer = new QTimer;
connect(pktTimer, SIGNAL(timeout()), this, SLOT(pktTimerCallback()));
while (1)
{
/* fill the audio/video queues with initial data; thereafter */
/* data will be filled by pktTimerCallback() */
if ((audioQueue.count() >= 3000) || (videoQueue.count() >= 3000))
{
//pktTimer->start(50);
//videoTimer->start(1500);
//audioTimer->start(500);
playVideo = new PlayVideo(NULL, &videoQueue, channel, 101);
playVideoThread = new QThread(this);
connect(playVideoThread, SIGNAL(started()), playVideo, SLOT(play()));
playVideo->moveToThread(playVideoThread);
playVideoThread->start();
playAudio = new PlayAudio(NULL, &audioQueue, channel, 101);
playAudioThread = new QThread(this);
connect(playAudioThread, SIGNAL(started()), playAudio, SLOT(play()));
playAudio->moveToThread(playAudioThread);
playAudioThread->start();
return;
}
mediaPkt = new MediaPacket;
rv = xrdpvr_get_frame(&mediaPkt->av_pkt,
&is_video_frame,
&mediaPkt->delay_in_us);
if (rv < 0)
{
/* looks like we reached end of file */
break;
}
if (is_video_frame)
videoQueue.enqueue(mediaPkt);
else
audioQueue.enqueue(mediaPkt);
} /* end while (1) */
}
void DecoderThread::on_mediaSeek(int value)
{
mutex.lock();
la_seekPos = value;
mutex.unlock();
qDebug() << "media seek value=" << value;
/* pktTimer stops at end of media; need to restart it */
if (!pktTimer->isActive())
{
updateSlider();
pktTimer->start(100);
}
}
void DecoderThread::setFilename(QString filename)
{
this->filename = filename;
}
void DecoderThread::stopPlayer()
{
pktTimer->stop();
audioQueue.clear();
videoQueue.clear();
}
void DecoderThread::pausePlayer()
{
pktTimer->stop();
}
void DecoderThread::resumePlayer()
{
pktTimer->start(100);
}
void DecoderThread::close()
{
}
void DecoderThread::audioTimerCallback()
{
MediaPacket *pkt;
int delayInMs;
if (audioQueue.isEmpty())
{
qDebug() << "audioTimerCallback: got empty";
audioTimer->setInterval(100);
return;
}
pkt = audioQueue.dequeue();
delayInMs = (int) ((float) pkt->delay_in_us / 1000.0);
send_audio_pkt(channel, 101, pkt->av_pkt);
delete pkt;
//qDebug() << "audioTimerCallback: delay :" << delayInMs;
audioTimer->setInterval(delayInMs);
}
void DecoderThread::videoTimerCallback()
{
MediaPacket *pkt;
int delayInMs;
if (videoQueue.isEmpty())
{
qDebug() << "videoTimerCallback: GOT EMPTY";
videoTimer->setInterval(100);
return;
}
pkt = videoQueue.dequeue();
delayInMs = (int) 10; // ((float) pkt->delay_in_us / 1000.0);
send_video_pkt(channel, 101, pkt->av_pkt);
delete pkt;
updateSlider();
//qDebug() << "videoTimerCallback: delay :" << delayInMs;
videoTimer->setInterval(delayInMs);
}
void DecoderThread::pktTimerCallback()
{
MediaPacket *mediaPkt;
int is_video_frame;
int rv;
while (1)
{
qDebug() << "pktTimerCallback: audioCount=" << audioQueue.count() << "videoCount=" << videoQueue.count();
#if 1
if ((audioQueue.count() >= 20) || (videoQueue.count() >= 20))
return;
#else
if (videoQueue.count() >= 60)
return;
#endif
mediaPkt = new MediaPacket;
rv = xrdpvr_get_frame(&mediaPkt->av_pkt,
&is_video_frame,
&mediaPkt->delay_in_us);
if (rv < 0)
{
/* looks like we reached end of file */
qDebug() << "###### looks like we reached EOF";
pktTimer->stop();
// LK_TODO set some flag so audio/video timer also stop when q is empty
return;
}
if (is_video_frame)
videoQueue.enqueue(mediaPkt);
else
audioQueue.enqueue(mediaPkt);
}
}
void DecoderThread::updateSlider()
{
if (elapsedTime == 0)
elapsedTime = av_gettime();
/* time elapsed in 1/100th sec units since play started */
emit on_elapsedtime((av_gettime() - elapsedTime) / 10000);
mutex.lock();
if (la_seekPos >= 0)
{
qDebug() << "seeking to" << la_seekPos;
//audioTimer->stop();
//videoTimer->stop();
xrdpvr_seek_media(la_seekPos, 0);
elapsedTime = av_gettime() - la_seekPos * 1000000;
//audioTimer->start(10);
//videoTimer->start(10);
la_seekPos = -1;
}
mutex.unlock();
}

View File

@ -1,95 +0,0 @@
#ifndef DECODERTHREAD_H
#define DECODERTHREAD_H
#ifdef __cplusplus
#define __STDC_CONSTANT_MACROS
#ifdef _STDINT_H
#undef _STDINT_H
#endif
#include <stdint.h>
#endif
#include <QThread>
#include <QDebug>
#include <QString>
#include <QRect>
#include <QMutex>
#include <QTimer>
#include <QQueue>
#include <xrdpapi.h>
#include <xrdpvr.h>
#include <mediapacket.h>
#include <playvideo.h>
#include <playaudio.h>
/* ffmpeg related stuff */
extern "C"
{
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
}
class DecoderThread : public QObject
{
Q_OBJECT
public:
/* public methods */
DecoderThread();
void setFilename(QString filename);
void stopPlayer();
void pausePlayer();
void resumePlayer();
void oneTimeDeinit();
void close();
void run();
void startMediaPlay();
public slots:
void on_mediaSeek(int value);
private:
/* private variables */
QQueue<MediaPacket *> audioQueue;
QQueue<MediaPacket *> videoQueue;
QTimer *videoTimer;
QTimer *audioTimer;
QTimer *pktTimer;
QString filename;
void *channel;
int stream_id;
QRect geometry;
int64_t elapsedTime; /* elapsed time in usecs since play started */
QMutex mutex;
int64_t la_seekPos; /* locked access; must hold mutex */
PlayVideo *playVideo;
QThread *playVideoThread;
PlayAudio *playAudio;
QThread *playAudioThread;
/* private functions */
int sendMetadataFile();
int sendAudioFormat();
int sendVideoFormat();
int sendGeometry();
void updateSlider();
private slots:
/* private slots */
void audioTimerCallback();
void videoTimerCallback();
void pktTimerCallback();
signals:
/* private signals */
void on_progressUpdate(int percent);
void on_decoderErrorMsg(QString title, QString msg);
void on_mediaDurationInSeconds(int duration);
void on_elapsedtime(int val); /* in hundredth of a sec */
};
#endif // DECODERTHREAD_H

View File

@ -11,6 +11,7 @@ OurInterface::OurInterface(QObject *parent) :
savedGeometry.setHeight(0);
stream_id = 101;
demuxMedia = 0;
demuxMediaThread = NULL;
//elapsedTime = 0;
}

View File

@ -267,7 +267,7 @@ handle_connection(int client_fd)
}
if (retlen != sizeof(rdp_fd))
{
fprintf(stderr, "WTSVirtualChannelQuery() returned wrong length %d\n",
fprintf(stderr, "WTSVirtualChannelQuery() returned wrong length %u\n",
retlen);
}
rdp_fd = *retdata;