Merge branch 'devel' into v0.9
This commit is contained in:
commit
21ff90a89b
@ -15,6 +15,7 @@ min_amd64_deps: &min_amd64_deps
|
||||
- libssl-dev
|
||||
- libx11-dev
|
||||
- libxrandr-dev
|
||||
- libxfixes-dev
|
||||
|
||||
min_amd64_conf: &min_amd64_conf
|
||||
env:
|
||||
|
20
NEWS.md
20
NEWS.md
@ -1,3 +1,21 @@
|
||||
# Release notes for xrdp v1.9.11 (2019/08/19)
|
||||
|
||||
## New features
|
||||
* Suppress output (do not draw screen when client window is minimized) #1330
|
||||
* Audio input (microphone) redirection compatible with [MS-RDPEAI](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpeai/d04ffa42-5a0f-4f80-abb1-cc26f71c9452) #1369
|
||||
* Now xrdp can listen on more than one port #1124 #1366
|
||||
|
||||
## Bug fixes
|
||||
* Fix the issue audio redirection sometimes sounds with long delay #1363
|
||||
* Check term event for more responsive shutdown #1372
|
||||
|
||||
## 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.10 (2019/04/18)
|
||||
|
||||
## Special thanks
|
||||
@ -11,7 +29,7 @@ Thank you for matt335672 contributing to lots of improvements in drive redirecti
|
||||
* Fix the issue reconnecting to session causes duplicate drive entries in fuse fs #1299
|
||||
* Fix default_wm and reconnect_sh refer wrong path after sesman caught SIGUP #1315 #1331
|
||||
* Shutdown xrdp more responsively #1325
|
||||
* Improve remote file lookup in drive redirection #996 #1327
|
||||
* Improve remote file lookup in drive redirection #996 #1327
|
||||
* Overwriting & appending to existing files is are now supported #1327
|
||||
|
||||
## Other changes
|
||||
|
@ -2,7 +2,7 @@
|
||||
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/neutrinolabs/xrdp)
|
||||
![Apache-License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)
|
||||
|
||||
*Current Version:* 0.9.10
|
||||
*Current Version:* 0.9.11
|
||||
|
||||
# xrdp - an open source RDP server
|
||||
|
||||
|
@ -1041,6 +1041,25 @@ g_sck_vsock_bind(int sck, const char *port)
|
||||
#endif
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
g_sck_vsock_bind_address(int sck, const char *port, const char *address)
|
||||
{
|
||||
#if defined(XRDP_ENABLE_VSOCK)
|
||||
struct sockaddr_vm s;
|
||||
|
||||
g_memset(&s, 0, sizeof(struct sockaddr_vm));
|
||||
s.svm_family = AF_VSOCK;
|
||||
s.svm_port = atoi(port);
|
||||
s.svm_cid = atoi(address);
|
||||
|
||||
return bind(sck, (struct sockaddr *)&s, sizeof(struct sockaddr_vm));
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if defined(XRDP_ENABLE_IPV6)
|
||||
/*****************************************************************************/
|
||||
/* Helper function for g_tcp_bind_address. */
|
||||
@ -3823,3 +3842,153 @@ g_mirror_memcpy(void *dst, const void *src, int len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
g_tcp4_socket(void)
|
||||
{
|
||||
#if defined(XRDP_ENABLE_IPV6ONLY)
|
||||
return -1;
|
||||
#else
|
||||
int rv;
|
||||
int option_value;
|
||||
socklen_t option_len;
|
||||
|
||||
rv = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (rv < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
option_len = sizeof(option_value);
|
||||
if (getsockopt(rv, SOL_SOCKET, SO_REUSEADDR,
|
||||
(char *) &option_value, &option_len) == 0)
|
||||
{
|
||||
if (option_value == 0)
|
||||
{
|
||||
option_value = 1;
|
||||
option_len = sizeof(option_value);
|
||||
if (setsockopt(rv, SOL_SOCKET, SO_REUSEADDR,
|
||||
(char *) &option_value, option_len) < 0)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
g_tcp4_bind_address(int sck, const char *port, const char *address)
|
||||
{
|
||||
#if defined(XRDP_ENABLE_IPV6ONLY)
|
||||
return -1;
|
||||
#else
|
||||
struct sockaddr_in s;
|
||||
|
||||
memset(&s, 0, sizeof(s));
|
||||
s.sin_family = AF_INET;
|
||||
s.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
s.sin_port = htons((uint16_t) atoi(port));
|
||||
if (inet_aton(address, &s.sin_addr) < 0)
|
||||
{
|
||||
return -1; /* bad address */
|
||||
}
|
||||
if (bind(sck, (struct sockaddr*) &s, sizeof(s)) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
g_tcp6_socket(void)
|
||||
{
|
||||
#if defined(XRDP_ENABLE_IPV6)
|
||||
int rv;
|
||||
int option_value;
|
||||
socklen_t option_len;
|
||||
|
||||
rv = socket(AF_INET6, SOCK_STREAM, 0);
|
||||
if (rv < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
option_len = sizeof(option_value);
|
||||
if (getsockopt(rv, IPPROTO_IPV6, IPV6_V6ONLY,
|
||||
(char *) &option_value, &option_len) == 0)
|
||||
{
|
||||
#if defined(XRDP_ENABLE_IPV6ONLY)
|
||||
if (option_value == 0)
|
||||
{
|
||||
option_value = 1;
|
||||
#else
|
||||
if (option_value != 0)
|
||||
{
|
||||
option_value = 0;
|
||||
#endif
|
||||
option_len = sizeof(option_value);
|
||||
if (setsockopt(rv, IPPROTO_IPV6, IPV6_V6ONLY,
|
||||
(char *) &option_value, option_len) < 0)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
option_len = sizeof(option_value);
|
||||
if (getsockopt(rv, SOL_SOCKET, SO_REUSEADDR,
|
||||
(char *) &option_value, &option_len) == 0)
|
||||
{
|
||||
if (option_value == 0)
|
||||
{
|
||||
option_value = 1;
|
||||
option_len = sizeof(option_value);
|
||||
if (setsockopt(rv, SOL_SOCKET, SO_REUSEADDR,
|
||||
(char *) &option_value, option_len) < 0)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
g_tcp6_bind_address(int sck, const char *port, const char *address)
|
||||
{
|
||||
#if defined(XRDP_ENABLE_IPV6)
|
||||
int rv;
|
||||
int error;
|
||||
struct addrinfo hints;
|
||||
struct addrinfo *list;
|
||||
struct addrinfo *i;
|
||||
|
||||
rv = -1;
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_flags = 0;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
error = getaddrinfo(address, port, &hints, &list);
|
||||
if (error == 0)
|
||||
{
|
||||
i = list;
|
||||
while ((i != NULL) && (rv < 0))
|
||||
{
|
||||
rv = bind(sck, i->ai_addr, i->ai_addrlen);
|
||||
i = i->ai_next;
|
||||
}
|
||||
freeaddrinfo(list);
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return rv;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
@ -71,6 +71,7 @@ int g_sck_set_non_blocking(int sck);
|
||||
int g_tcp_bind(int sck, const char *port);
|
||||
int g_sck_local_bind(int sck, const char* port);
|
||||
int g_sck_vsock_bind(int sck, const char* port);
|
||||
int g_sck_vsock_bind_address(int sck, const char *port, const char *address);
|
||||
int g_tcp_bind_address(int sck, const char* port, const char* address);
|
||||
int g_sck_listen(int sck);
|
||||
int g_tcp_accept(int sck);
|
||||
@ -183,6 +184,10 @@ void * g_shmat(int shmid);
|
||||
int g_shmdt(const void *shmaddr);
|
||||
int g_gethostname(char *name, int len);
|
||||
int g_mirror_memcpy(void *dst, const void *src, int len);
|
||||
int g_tcp4_socket(void);
|
||||
int g_tcp4_bind_address(int sck, const char *port, const char *address);
|
||||
int g_tcp6_socket(void);
|
||||
int g_tcp6_bind_address(int sck, const char *port, const char *address);
|
||||
|
||||
/* glib-style wrappers */
|
||||
#define g_new(struct_type, n_structs) \
|
||||
|
@ -875,7 +875,43 @@ trans_listen_address(struct trans *self, char *port, const char *address)
|
||||
|
||||
g_tcp_set_non_blocking(self->sck);
|
||||
|
||||
if (g_sck_vsock_bind(self->sck, port) == 0)
|
||||
if (g_sck_vsock_bind_address(self->sck, port, address) == 0)
|
||||
{
|
||||
if (g_tcp_listen(self->sck) == 0)
|
||||
{
|
||||
self->status = TRANS_STATUS_UP; /* ok */
|
||||
self->type1 = TRANS_TYPE_LISTENER; /* listener */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (self->mode == TRANS_MODE_TCP4) /* tcp4 */
|
||||
{
|
||||
self->sck = g_tcp4_socket();
|
||||
if (self->sck < 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
g_tcp_set_non_blocking(self->sck);
|
||||
if (g_tcp4_bind_address(self->sck, port, address) == 0)
|
||||
{
|
||||
if (g_tcp_listen(self->sck) == 0)
|
||||
{
|
||||
self->status = TRANS_STATUS_UP; /* ok */
|
||||
self->type1 = TRANS_TYPE_LISTENER; /* listener */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (self->mode == TRANS_MODE_TCP6) /* tcp6 */
|
||||
{
|
||||
self->sck = g_tcp6_socket();
|
||||
if (self->sck < 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
g_tcp_set_non_blocking(self->sck);
|
||||
if (g_tcp6_bind_address(self->sck, port, address) == 0)
|
||||
{
|
||||
if (g_tcp_listen(self->sck) == 0)
|
||||
{
|
||||
@ -885,7 +921,6 @@ trans_listen_address(struct trans *self, char *port, const char *address)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -24,9 +24,11 @@
|
||||
#include "arch.h"
|
||||
#include "parse.h"
|
||||
|
||||
#define TRANS_MODE_TCP 1
|
||||
#define TRANS_MODE_TCP 1 /* tcp6 if defined, else tcp4 */
|
||||
#define TRANS_MODE_UNIX 2
|
||||
#define TRANS_MODE_VSOCK 3
|
||||
#define TRANS_MODE_TCP4 4 /* tcp4 only */
|
||||
#define TRANS_MODE_TCP6 6 /* tcp6 only */
|
||||
|
||||
#define TRANS_TYPE_LISTENER 1
|
||||
#define TRANS_TYPE_SERVER 2
|
||||
|
@ -156,6 +156,7 @@ struct xrdp_client_info
|
||||
int no_orders_supported;
|
||||
int use_cache_glyph_v2;
|
||||
int rail_enable;
|
||||
int suppress_output;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1,7 +1,7 @@
|
||||
# Process this file with autoconf to produce a configure script
|
||||
|
||||
AC_PREREQ(2.65)
|
||||
AC_INIT([xrdp], [0.9.10], [xrdp-devel@googlegroups.com])
|
||||
AC_INIT([xrdp], [0.9.11], [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])
|
||||
|
@ -810,7 +810,8 @@ xrdp_caps_send_demand_active(struct xrdp_rdp *self)
|
||||
out_uint16_le(s, 0); /* Update capability */
|
||||
out_uint16_le(s, 0); /* Remote unshare capability */
|
||||
out_uint16_le(s, 0); /* Compression level */
|
||||
out_uint16_le(s, 0); /* Pad */
|
||||
out_uint8(s, 1); /* refreshRectSupport */
|
||||
out_uint8(s, 1); /* suppressOutputSupport */
|
||||
|
||||
/* Output bitmap capability set */
|
||||
caps_count++;
|
||||
|
@ -1209,21 +1209,91 @@ xrdp_rdp_process_frame_ack(struct xrdp_rdp *self, struct stream *s)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
xrdp_rdp_process_suppress(struct xrdp_rdp *self, struct stream *s)
|
||||
{
|
||||
int allowDisplayUpdates;
|
||||
int left;
|
||||
int top;
|
||||
int right;
|
||||
int bottom;
|
||||
|
||||
if (!s_check_rem(s, 1))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
in_uint8(s, allowDisplayUpdates);
|
||||
g_writeln("xrdp_rdp_process_suppress: allowDisplayUpdates %d bytes "
|
||||
"left %d", allowDisplayUpdates, (int) (s->end - s->p));
|
||||
switch (allowDisplayUpdates)
|
||||
{
|
||||
case 0: /* SUPPRESS_DISPLAY_UPDATES */
|
||||
self->client_info.suppress_output = 1;
|
||||
g_writeln("xrdp_rdp_process_suppress: suppress_output %d",
|
||||
self->client_info.suppress_output);
|
||||
if (self->session->callback != 0)
|
||||
{
|
||||
self->session->callback(self->session->id, 0x5559, 1,
|
||||
0, 0, 0);
|
||||
}
|
||||
break;
|
||||
case 1: /* ALLOW_DISPLAY_UPDATES */
|
||||
self->client_info.suppress_output = 0;
|
||||
if (!s_check_rem(s, 11))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
in_uint8s(s, 3); /* pad */
|
||||
in_uint16_le(s, left);
|
||||
in_uint16_le(s, top);
|
||||
in_uint16_le(s, right);
|
||||
in_uint16_le(s, bottom);
|
||||
g_writeln("xrdp_rdp_process_suppress: suppress_output %d "
|
||||
"left %d top %d right %d bottom %d",
|
||||
self->client_info.suppress_output,
|
||||
left, top, right, bottom);
|
||||
if (self->session->callback != 0)
|
||||
{
|
||||
self->session->callback(self->session->id, 0x5559, 0,
|
||||
MAKELONG(left, top),
|
||||
MAKELONG(right, bottom), 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* RDP_PDU_DATA */
|
||||
int
|
||||
xrdp_rdp_process_data(struct xrdp_rdp *self, struct stream *s)
|
||||
{
|
||||
int data_type;
|
||||
int uncompressedLength;
|
||||
int pduType2;
|
||||
int compressedType;
|
||||
int compressedLength;
|
||||
|
||||
if (!s_check_rem(s, 12))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
in_uint8s(s, 6);
|
||||
in_uint8s(s, 2); /* len */
|
||||
in_uint8(s, data_type);
|
||||
in_uint8s(s, 1); /* ctype */
|
||||
in_uint8s(s, 2); /* clen */
|
||||
DEBUG(("xrdp_rdp_process_data code %d", data_type));
|
||||
|
||||
switch (data_type)
|
||||
in_uint16_le(s, uncompressedLength);
|
||||
in_uint8(s, pduType2);
|
||||
in_uint8(s, compressedType);
|
||||
in_uint16_le(s, compressedLength);
|
||||
if (compressedType != 0)
|
||||
{
|
||||
/* don't support compression */
|
||||
return 1;
|
||||
}
|
||||
if (compressedLength > uncompressedLength)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
DEBUG(("xrdp_rdp_process_data pduType2 %d", pduType2));
|
||||
switch (pduType2)
|
||||
{
|
||||
case RDP_DATA_PDU_POINTER: /* 27(0x1b) */
|
||||
xrdp_rdp_process_data_pointer(self, s);
|
||||
@ -1240,11 +1310,8 @@ xrdp_rdp_process_data(struct xrdp_rdp *self, struct stream *s)
|
||||
case 33: /* 33(0x21) ?? Invalidate an area I think */
|
||||
xrdp_rdp_process_screen_update(self, s);
|
||||
break;
|
||||
case 35: /* 35(0x23) */
|
||||
/* 35 ?? this comes when minimizing a full screen mstsc.exe 2600 */
|
||||
/* I think this is saying the client no longer wants screen */
|
||||
/* updates and it will issue a 33 above to catch up */
|
||||
/* so minimized apps don't take bandwidth */
|
||||
case 35: /* 35(0x23) PDUTYPE2_SUPPRESS_OUTPUT */
|
||||
xrdp_rdp_process_suppress(self, s);
|
||||
break;
|
||||
case 36: /* 36(0x24) ?? disconnect query? */
|
||||
/* when this message comes, send a 37 back so the client */
|
||||
@ -1259,10 +1326,9 @@ xrdp_rdp_process_data(struct xrdp_rdp *self, struct stream *s)
|
||||
xrdp_rdp_process_frame_ack(self, s);
|
||||
break;
|
||||
default:
|
||||
g_writeln("unknown in xrdp_rdp_process_data %d", data_type);
|
||||
g_writeln("unknown in xrdp_rdp_process_data pduType2 %d", pduType2);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
@ -27,6 +27,12 @@
|
||||
#include "log.h"
|
||||
#include <freerdp/settings.h>
|
||||
|
||||
#if defined(VERSION_STRUCT_RDP_FREERDP)
|
||||
#if VERSION_STRUCT_RDP_FREERDP > 1
|
||||
#define NEUTRINORDP_HAS_SUPPRESS_OUTPUT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef XRDP_DEBUG
|
||||
#define LOG_LEVEL 99
|
||||
#else
|
||||
@ -541,6 +547,24 @@ lxrdp_check_wait_objs(struct mod *mod)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
static int
|
||||
lxrdp_frame_ack(struct mod* mod, int flags, int frame_id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
static int
|
||||
lxrdp_suppress_output(struct mod* mod, int suppress,
|
||||
int left, int top, int right, int bottom)
|
||||
{
|
||||
#if defined(NEUTRINORDP_HAS_SUPPRESS_OUTPUT)
|
||||
mod->inst->SendSuppressOutput(mod->inst, !suppress, left, top, right, bottom);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
static void
|
||||
lfreerdp_begin_paint(rdpContext *context)
|
||||
@ -2009,6 +2033,8 @@ mod_init(void)
|
||||
mod->mod_session_change = lxrdp_session_change;
|
||||
mod->mod_get_wait_objs = lxrdp_get_wait_objs;
|
||||
mod->mod_check_wait_objs = lxrdp_check_wait_objs;
|
||||
mod->mod_frame_ack = lxrdp_frame_ack;
|
||||
mod->mod_suppress_output = lxrdp_suppress_output;
|
||||
|
||||
mod->inst = freerdp_new();
|
||||
mod->inst->PreConnect = lfreerdp_pre_connect;
|
||||
|
@ -58,7 +58,7 @@ struct pointer_item
|
||||
int bpp;
|
||||
};
|
||||
|
||||
#define CURRENT_MOD_VER 3
|
||||
#define CURRENT_MOD_VER 4
|
||||
|
||||
struct mod
|
||||
{
|
||||
@ -76,8 +76,11 @@ struct mod
|
||||
int (*mod_get_wait_objs)(struct mod *v, tbus *read_objs, int *rcount,
|
||||
tbus *write_objs, int *wcount, int *timeout);
|
||||
int (*mod_check_wait_objs)(struct mod *v);
|
||||
tintptr mod_dumby[100 - 9]; /* align, 100 minus the number of mod
|
||||
functions above */
|
||||
int (*mod_frame_ack)(struct mod* mod, int flags, int frame_id);
|
||||
int (*mod_suppress_output)(struct mod* mod, int suppress,
|
||||
int left, int top, int right, int bottom);
|
||||
tintptr mod_dumby[100 - 11]; /* align, 100 minus the number of mod
|
||||
functions above */
|
||||
/* server functions */
|
||||
int (*server_begin_update)(struct mod *v);
|
||||
int (*server_end_update)(struct mod *v);
|
||||
|
@ -70,7 +70,9 @@ xrdp_chansrv_SOURCES = \
|
||||
sound.c \
|
||||
sound.h \
|
||||
xcommon.c \
|
||||
xcommon.h
|
||||
xcommon.h \
|
||||
audin.c \
|
||||
audin.h
|
||||
|
||||
xrdp_chansrv_LDFLAGS = \
|
||||
$(X_LIBS)
|
||||
|
518
sesman/chansrv/audin.c
Normal file
518
sesman/chansrv/audin.c
Normal file
@ -0,0 +1,518 @@
|
||||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) Jay Sorg 2019
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* MS-RDPEAI
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config_ac.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "os_calls.h"
|
||||
#include "chansrv.h"
|
||||
#include "log.h"
|
||||
#include "xrdp_constants.h"
|
||||
#include "fifo.h"
|
||||
|
||||
#define MSG_SNDIN_VERSION 1
|
||||
#define MSG_SNDIN_FORMATS 2
|
||||
#define MSG_SNDIN_OPEN 3
|
||||
#define MSG_SNDIN_OPEN_REPLY 4
|
||||
#define MSG_SNDIN_DATA_INCOMING 5
|
||||
#define MSG_SNDIN_DATA 6
|
||||
#define MSG_SNDIN_FORMATCHANGE 7
|
||||
|
||||
#define AUDIN_VERSION 0x00000001
|
||||
|
||||
#define AUDIN_NAME "AUDIO_INPUT"
|
||||
#define AUDIN_FLAGS 1 /* WTS_CHANNEL_OPTION_DYNAMIC */
|
||||
|
||||
extern FIFO g_in_fifo; /* in sound.c */
|
||||
extern int g_bytes_in_fifo; /* in sound.c */
|
||||
|
||||
struct xr_wave_format_ex
|
||||
{
|
||||
int wFormatTag;
|
||||
int nChannels;
|
||||
int nSamplesPerSec;
|
||||
int nAvgBytesPerSec;
|
||||
int nBlockAlign;
|
||||
int wBitsPerSample;
|
||||
int cbSize;
|
||||
uint8_t *data;
|
||||
};
|
||||
|
||||
static uint8_t g_pcm_44100_data[] = { 0 };
|
||||
static struct xr_wave_format_ex g_pcm_44100 =
|
||||
{
|
||||
WAVE_FORMAT_PCM, /* wFormatTag */
|
||||
2, /* num of channels */
|
||||
44100, /* samples per sec */
|
||||
176400, /* avg bytes per sec */
|
||||
4, /* block align */
|
||||
16, /* bits per sample */
|
||||
0, /* data size */
|
||||
g_pcm_44100_data /* data */
|
||||
};
|
||||
|
||||
static struct chansrv_drdynvc_procs g_audin_info;
|
||||
static int g_audin_chanid;
|
||||
static struct stream *g_in_s;
|
||||
|
||||
static struct xr_wave_format_ex *g_server_formats[] =
|
||||
{
|
||||
&g_pcm_44100,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct xr_wave_format_ex **g_client_formats = NULL;
|
||||
|
||||
static int g_current_format = 0; /* index in g_client_formats */
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
cleanup_client_formats(void)
|
||||
{
|
||||
int index;
|
||||
|
||||
if (g_client_formats == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
index = 0;
|
||||
while (g_client_formats[index] != NULL)
|
||||
{
|
||||
g_free(g_client_formats[index]->data);
|
||||
g_free(g_client_formats[index]);
|
||||
index++;
|
||||
}
|
||||
g_free(g_client_formats);
|
||||
g_client_formats = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
audin_send_version(int chan_id)
|
||||
{
|
||||
int error;
|
||||
int bytes;
|
||||
struct stream *s;
|
||||
|
||||
LOG(0, ("audin_send_version:"));
|
||||
make_stream(s);
|
||||
init_stream(s, 32);
|
||||
out_uint8(s, MSG_SNDIN_VERSION);
|
||||
out_uint32_le(s, AUDIN_VERSION);
|
||||
s_mark_end(s);
|
||||
bytes = (int) (s->end - s->data);
|
||||
error = chansrv_drdynvc_data(chan_id, s->data, bytes);
|
||||
free_stream(s);
|
||||
return error;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
audin_send_formats(int chan_id)
|
||||
{
|
||||
int error;
|
||||
int bytes;
|
||||
int num_formats;
|
||||
int index;
|
||||
struct stream *s;
|
||||
struct xr_wave_format_ex *wf;
|
||||
|
||||
LOG(0, ("audin_send_formats:"));
|
||||
num_formats = sizeof(g_server_formats) /
|
||||
sizeof(g_server_formats[0]) - 1;
|
||||
make_stream(s);
|
||||
init_stream(s, 8192 * num_formats);
|
||||
out_uint8(s, MSG_SNDIN_FORMATS);
|
||||
out_uint32_le(s, num_formats);
|
||||
out_uint32_le(s, 0); /* cbSizeFormatsPacket */
|
||||
for (index = 0; index < num_formats; index++)
|
||||
{
|
||||
wf = g_server_formats[index];
|
||||
LOG(0, ("audin_send_formats: sending format wFormatTag 0x%4.4x "
|
||||
"nChannels %d nSamplesPerSec %d",
|
||||
wf->wFormatTag, wf->nChannels, wf->nSamplesPerSec));
|
||||
out_uint16_le(s, wf->wFormatTag);
|
||||
out_uint16_le(s, wf->nChannels);
|
||||
out_uint32_le(s, wf->nSamplesPerSec);
|
||||
out_uint32_le(s, wf->nAvgBytesPerSec);
|
||||
out_uint16_le(s, wf->nBlockAlign);
|
||||
out_uint16_le(s, wf->wBitsPerSample);
|
||||
out_uint16_le(s, wf->cbSize);
|
||||
if (wf->cbSize > 0)
|
||||
{
|
||||
out_uint8p(s, wf->data, wf->cbSize);
|
||||
}
|
||||
}
|
||||
s_mark_end(s);
|
||||
bytes = (int) (s->end - s->data);
|
||||
error = chansrv_drdynvc_data(chan_id, s->data, bytes);
|
||||
free_stream(s);
|
||||
return error;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
audin_send_open(int chan_id)
|
||||
{
|
||||
int error;
|
||||
int bytes;
|
||||
struct stream *s;
|
||||
struct xr_wave_format_ex *wf;
|
||||
|
||||
LOG(0, ("audin_send_open:"));
|
||||
make_stream(s);
|
||||
init_stream(s, 8192);
|
||||
out_uint8(s, MSG_SNDIN_OPEN);
|
||||
out_uint32_le(s, 2048); /* FramesPerPacket */
|
||||
out_uint32_le(s, g_current_format); /* initialFormat */
|
||||
wf = g_client_formats[g_current_format];
|
||||
out_uint16_le(s, wf->wFormatTag);
|
||||
out_uint16_le(s, wf->nChannels);
|
||||
out_uint32_le(s, wf->nSamplesPerSec);
|
||||
out_uint32_le(s, wf->nAvgBytesPerSec);
|
||||
out_uint16_le(s, wf->nBlockAlign);
|
||||
out_uint16_le(s, wf->wBitsPerSample);
|
||||
bytes = wf->cbSize;
|
||||
out_uint16_le(s, bytes);
|
||||
if (bytes > 0)
|
||||
{
|
||||
out_uint8p(s, wf->data, bytes);
|
||||
}
|
||||
s_mark_end(s);
|
||||
bytes = (int) (s->end - s->data);
|
||||
error = chansrv_drdynvc_data(chan_id, s->data, bytes);
|
||||
free_stream(s);
|
||||
return error;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
audin_process_version(int chan_id, struct stream *s)
|
||||
{
|
||||
int version;
|
||||
|
||||
LOG(0, ("audin_process_version:"));
|
||||
if (!s_check_rem(s, 4))
|
||||
{
|
||||
LOG(0, ("audin_process_version: parse error"));
|
||||
return 1;
|
||||
}
|
||||
in_uint32_le(s, version);
|
||||
LOG(0, ("audin_process_version: version %d", version));
|
||||
return audin_send_formats(chan_id);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
audin_process_formats(int chan_id, struct stream *s)
|
||||
{
|
||||
int index;
|
||||
int num_formats;
|
||||
struct xr_wave_format_ex *wf;
|
||||
|
||||
LOG(0, ("audin_process_formats:"));
|
||||
cleanup_client_formats();
|
||||
if (!s_check_rem(s, 8))
|
||||
{
|
||||
LOG(0, ("audin_process_formats: parse error"));
|
||||
return 1;
|
||||
}
|
||||
in_uint32_le(s, num_formats);
|
||||
in_uint8s(s, 4); /* cbSizeFormatsPacket */
|
||||
g_client_formats = g_new0(struct xr_wave_format_ex *, num_formats + 1);
|
||||
for (index = 0; index < num_formats; index++)
|
||||
{
|
||||
if (!s_check_rem(s, 18))
|
||||
{
|
||||
LOG(0, ("audin_process_formats: parse error"));
|
||||
return 1;
|
||||
}
|
||||
wf = g_new0(struct xr_wave_format_ex, 1);
|
||||
g_client_formats[index] = wf;
|
||||
in_uint16_le(s, wf->wFormatTag);
|
||||
in_uint16_le(s, wf->nChannels);
|
||||
in_uint32_le(s, wf->nSamplesPerSec);
|
||||
in_uint32_le(s, wf->nAvgBytesPerSec);
|
||||
in_uint16_le(s, wf->nBlockAlign);
|
||||
in_uint16_le(s, wf->wBitsPerSample);
|
||||
in_uint16_le(s, wf->cbSize);
|
||||
LOG(0, ("audin_process_formats: recved format wFormatTag 0x%4.4x "
|
||||
"nChannels %d nSamplesPerSec %d",
|
||||
wf->wFormatTag, wf->nChannels, wf->nSamplesPerSec));
|
||||
if (wf->cbSize > 0)
|
||||
{
|
||||
if (!s_check_rem(s, wf->cbSize))
|
||||
{
|
||||
LOG(0, ("audin_process_formats: parse error"));
|
||||
return 1;
|
||||
}
|
||||
wf->data = g_new0(uint8_t, wf->cbSize);
|
||||
in_uint8a(s, wf->data, wf->cbSize);
|
||||
}
|
||||
}
|
||||
audin_send_open(chan_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
audin_process_open_reply(int chan_id, struct stream *s)
|
||||
{
|
||||
int result;
|
||||
|
||||
if (!s_check_rem(s, 4))
|
||||
{
|
||||
LOG(0, ("audin_process_open_reply: parse error"));
|
||||
return 1;
|
||||
}
|
||||
in_uint32_le(s, result);
|
||||
LOG(0, ("audin_process_open_reply: result 0x%8.8x", result));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
audin_process_incoming_data(int chan_id, struct stream *s)
|
||||
{
|
||||
LOG(10, ("audin_process_incoming_data:"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
audin_process_data(int chan_id, struct stream *s)
|
||||
{
|
||||
int data_bytes;
|
||||
struct stream *ls;
|
||||
|
||||
data_bytes = (int) (s->end - s->p);
|
||||
LOG(10, ("audin_process_data: data_bytes %d", data_bytes));
|
||||
|
||||
xstream_new(ls, data_bytes);
|
||||
g_memcpy(ls->data, s->p, data_bytes);
|
||||
ls->p += data_bytes;
|
||||
s_mark_end(ls);
|
||||
fifo_insert(&g_in_fifo, (void *) ls);
|
||||
g_bytes_in_fifo += data_bytes;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
audin_process_format_change(int chan_id, struct stream *s)
|
||||
{
|
||||
LOG(0, ("audin_process_format_change:"));
|
||||
if (!s_check_rem(s, 4))
|
||||
{
|
||||
LOG(0, ("audin_process_format_change: parse error"));
|
||||
return 1;
|
||||
}
|
||||
in_uint32_le(s, g_current_format);
|
||||
LOG(0, ("audin_process_format_change: g_current_format %d",
|
||||
g_current_format));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
audin_process_msg(int chan_id, struct stream *s)
|
||||
{
|
||||
int code;
|
||||
|
||||
LOG(10, ("audin_process_msg:"));
|
||||
if (!s_check_rem(s, 1))
|
||||
{
|
||||
LOG(0, ("audin_process_msg: parse error"));
|
||||
return 1;
|
||||
}
|
||||
in_uint8(s, code);
|
||||
LOG(10, ("audin_process_msg: code %d", code));
|
||||
switch (code)
|
||||
{
|
||||
case MSG_SNDIN_VERSION:
|
||||
return audin_process_version(chan_id, s);
|
||||
case MSG_SNDIN_FORMATS:
|
||||
return audin_process_formats(chan_id, s);
|
||||
case MSG_SNDIN_OPEN_REPLY:
|
||||
return audin_process_open_reply(chan_id, s);
|
||||
case MSG_SNDIN_DATA_INCOMING:
|
||||
return audin_process_incoming_data(chan_id, s);
|
||||
case MSG_SNDIN_DATA:
|
||||
return audin_process_data(chan_id, s);
|
||||
case MSG_SNDIN_FORMATCHANGE:
|
||||
return audin_process_format_change(chan_id, s);
|
||||
default:
|
||||
LOG(0, ("audin_process_msg: unprocessed code %d", code));
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
audin_open_response(int chan_id, int creation_status)
|
||||
{
|
||||
LOG(0, ("audin_open_response: creation_status 0x%8.8x", creation_status));
|
||||
if (creation_status == 0)
|
||||
{
|
||||
return audin_send_version(chan_id);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
audin_close_response(int chan_id)
|
||||
{
|
||||
LOG(0, ("audin_close_response:"));
|
||||
g_audin_chanid = 0;
|
||||
cleanup_client_formats();
|
||||
free_stream(g_in_s);
|
||||
g_in_s = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
audin_data_fragment(int chan_id, char *data, int bytes)
|
||||
{
|
||||
int rv;
|
||||
int left;
|
||||
|
||||
LOG(10, ("audin_data_fragment:"));
|
||||
if (!s_check_rem(g_in_s, bytes))
|
||||
{
|
||||
left = (int) (g_in_s->end - g_in_s->p);
|
||||
LOG(0, ("audin_data_fragment: error bytes %d left %d", bytes, left));
|
||||
return 1;
|
||||
}
|
||||
out_uint8a(g_in_s, data, bytes);
|
||||
if (g_in_s->p == g_in_s->end)
|
||||
{
|
||||
g_in_s->p = g_in_s->data;
|
||||
rv = audin_process_msg(chan_id, g_in_s);
|
||||
free_stream(g_in_s);
|
||||
g_in_s = NULL;
|
||||
return rv;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
audin_data_first(int chan_id, char *data, int bytes, int total_bytes)
|
||||
{
|
||||
LOG(10, ("audin_data_first:"));
|
||||
if (g_in_s != NULL)
|
||||
{
|
||||
LOG(0, ("audin_data_first: warning g_in_s is not nil"));
|
||||
free_stream(g_in_s);
|
||||
}
|
||||
make_stream(g_in_s);
|
||||
init_stream(g_in_s, total_bytes);
|
||||
g_in_s->end = g_in_s->data + total_bytes;
|
||||
return audin_data_fragment(chan_id, data, bytes);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
audin_data(int chan_id, char *data, int bytes)
|
||||
{
|
||||
struct stream ls;
|
||||
|
||||
LOG(10, ("audin_data:"));
|
||||
//g_hexdump(data, bytes);
|
||||
if (g_in_s == NULL)
|
||||
{
|
||||
g_memset(&ls, 0, sizeof(ls));
|
||||
ls.data = data;
|
||||
ls.p = ls.data;
|
||||
ls.end = ls.p + bytes;
|
||||
return audin_process_msg(chan_id, &ls);
|
||||
}
|
||||
return audin_data_fragment(chan_id, data, bytes);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
audin_init(void)
|
||||
{
|
||||
LOG(0, ("audin_init:"));
|
||||
g_memset(&g_audin_info, 0, sizeof(g_audin_info));
|
||||
g_audin_info.open_response = audin_open_response;
|
||||
g_audin_info.close_response = audin_close_response;
|
||||
g_audin_info.data_first = audin_data_first;
|
||||
g_audin_info.data = audin_data;
|
||||
g_audin_chanid = 0;
|
||||
g_in_s = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
audin_deinit(void)
|
||||
{
|
||||
LOG(0, ("audin_deinit:"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
audin_start(void)
|
||||
{
|
||||
int error;
|
||||
struct stream* s;
|
||||
|
||||
LOG(0, ("audin_start:"));
|
||||
if (g_audin_chanid != 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* if there is any data in FIFO, discard it */
|
||||
while ((s = (struct stream *) fifo_remove(&g_in_fifo)) != NULL)
|
||||
{
|
||||
xstream_free(s);
|
||||
}
|
||||
g_bytes_in_fifo = 0;
|
||||
|
||||
error = chansrv_drdynvc_open(AUDIN_NAME, AUDIN_FLAGS,
|
||||
&g_audin_info, /* callback functions */
|
||||
&g_audin_chanid); /* chansrv chan_id */
|
||||
LOG(0, ("audin_start: error %d g_audin_chanid %d", error, g_audin_chanid));
|
||||
return error;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
audin_stop(void)
|
||||
{
|
||||
LOG(0, ("audin_stop:"));
|
||||
chansrv_drdynvc_close(g_audin_chanid);
|
||||
return 0;
|
||||
}
|
34
sesman/chansrv/audin.h
Normal file
34
sesman/chansrv/audin.h
Normal file
@ -0,0 +1,34 @@
|
||||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) Jay Sorg 2019
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* MS-RDPEAI
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _AUDIN_H_
|
||||
#define _AUDIN_H_
|
||||
|
||||
int
|
||||
audin_init(void);
|
||||
int
|
||||
audin_deinit(void);
|
||||
int
|
||||
audin_start(void);
|
||||
int
|
||||
audin_stop(void);
|
||||
|
||||
#endif
|
@ -37,6 +37,7 @@
|
||||
#include "xcommon.h"
|
||||
#include "chansrv_fuse.h"
|
||||
#include "xrdp_sockets.h"
|
||||
#include "audin.h"
|
||||
|
||||
static struct trans *g_lis_trans = 0;
|
||||
static struct trans *g_con_trans = 0;
|
||||
@ -415,6 +416,8 @@ process_message_channel_setup(struct stream *s)
|
||||
rail_init();
|
||||
}
|
||||
|
||||
audin_init();
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,8 @@
|
||||
#include "xrdp_constants.h"
|
||||
#include "xrdp_sockets.h"
|
||||
#include "chansrv_common.h"
|
||||
#include "list.h"
|
||||
#include "audin.h"
|
||||
|
||||
#if defined(XRDP_FDK_AAC)
|
||||
#include <fdk-aac/aacenc_lib.h>
|
||||
@ -70,9 +72,11 @@ static struct trans *g_audio_c_trans_in = 0; /* connection */
|
||||
static int g_training_sent_time = 0;
|
||||
static int g_cBlockNo = 0;
|
||||
static int g_bytes_in_stream = 0;
|
||||
static FIFO g_in_fifo;
|
||||
static int g_bytes_in_fifo = 0;
|
||||
static int g_unacked_frames = 0;
|
||||
FIFO g_in_fifo;
|
||||
int g_bytes_in_fifo = 0;
|
||||
static int g_time_diff = 0;
|
||||
static int g_best_time_diff = 0;
|
||||
|
||||
|
||||
static struct stream *g_stream_inp = NULL;
|
||||
static struct stream *g_stream_incoming_packet = NULL;
|
||||
@ -81,10 +85,11 @@ static struct stream *g_stream_incoming_packet = NULL;
|
||||
static char g_buffer[MAX_BBUF_SIZE];
|
||||
static int g_buf_index = 0;
|
||||
static int g_sent_time[256];
|
||||
static int g_sent_flag[256];
|
||||
|
||||
static int g_bbuf_size = 1024 * 8; /* may change later */
|
||||
|
||||
static struct list *g_ack_time_diff = 0;
|
||||
|
||||
struct xr_wave_format_ex
|
||||
{
|
||||
int wFormatTag;
|
||||
@ -236,6 +241,8 @@ static struct xr_wave_format_ex *g_wave_inp_formats[] =
|
||||
0
|
||||
};
|
||||
|
||||
static int g_rdpsnd_can_rec = 0;
|
||||
|
||||
static int g_client_input_format_index = 0;
|
||||
static int g_server_input_format_index = 0;
|
||||
|
||||
@ -340,7 +347,7 @@ sound_send_training(void)
|
||||
out_uint16_le(s, SNDC_TRAINING);
|
||||
size_ptr = s->p;
|
||||
out_uint16_le(s, 0); /* size, set later */
|
||||
time = g_time2();
|
||||
time = g_time3();
|
||||
g_training_sent_time = time;
|
||||
out_uint16_le(s, time);
|
||||
out_uint16_le(s, 1024);
|
||||
@ -883,18 +890,6 @@ sound_send_wave_data_chunk(char *data, int data_bytes)
|
||||
return 1;
|
||||
}
|
||||
|
||||
LOG(20, ("sound_send_wave_data_chunk: g_sent_flag[%d] = %d",
|
||||
g_cBlockNo + 1, g_sent_flag[(g_cBlockNo + 1) & 0xff]));
|
||||
if (g_sent_flag[(g_cBlockNo + 1) & 0xff] & 1)
|
||||
{
|
||||
LOG(10, ("sound_send_wave_data_chunk: no room"));
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(10, ("sound_send_wave_data_chunk: got room"));
|
||||
}
|
||||
|
||||
/* compress, if available */
|
||||
format_index = g_current_client_format_index;
|
||||
data_bytes = sound_wave_compress(data, data_bytes, &format_index);
|
||||
@ -908,14 +903,12 @@ sound_send_wave_data_chunk(char *data, int data_bytes)
|
||||
out_uint16_le(s, SNDC_WAVE);
|
||||
size_ptr = s->p;
|
||||
out_uint16_le(s, 0); /* size, set later */
|
||||
time = g_time2();
|
||||
time = g_time3();
|
||||
out_uint16_le(s, time);
|
||||
out_uint16_le(s, format_index); /* wFormatNo */
|
||||
g_cBlockNo++;
|
||||
g_unacked_frames++;
|
||||
out_uint8(s, g_cBlockNo);
|
||||
g_sent_time[g_cBlockNo & 0xff] = time;
|
||||
g_sent_flag[g_cBlockNo & 0xff] = 1;
|
||||
|
||||
LOG(10, ("sound_send_wave_data_chunk: sending time %d, g_cBlockNo %d",
|
||||
time & 0xffff, g_cBlockNo & 0xff));
|
||||
@ -956,6 +949,13 @@ sound_send_wave_data(char *data, int data_bytes)
|
||||
int res;
|
||||
|
||||
LOG(10, ("sound_send_wave_data: sending %d bytes", data_bytes));
|
||||
if (g_time_diff > g_best_time_diff + 250)
|
||||
{
|
||||
data_bytes = data_bytes / 4;
|
||||
data_bytes = data_bytes & ~3;
|
||||
g_memset(data, 0, data_bytes);
|
||||
g_time_diff = 0;
|
||||
}
|
||||
data_index = 0;
|
||||
error = 0;
|
||||
while (data_bytes > 0)
|
||||
@ -1005,17 +1005,8 @@ sound_send_close(void)
|
||||
|
||||
LOG(10, ("sound_send_close:"));
|
||||
|
||||
/* send any left over data */
|
||||
if (g_buf_index)
|
||||
{
|
||||
if (sound_send_wave_data_chunk(g_buffer, g_buf_index) != 0)
|
||||
{
|
||||
LOG(10, ("sound_send_close: sound_send_wave_data_chunk failed"));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
g_best_time_diff = 0;
|
||||
g_buf_index = 0;
|
||||
g_memset(g_sent_flag, 0, sizeof(g_sent_flag));
|
||||
|
||||
/* send close msg */
|
||||
make_stream(s);
|
||||
@ -1040,7 +1031,7 @@ sound_process_training(struct stream *s, int size)
|
||||
{
|
||||
int time_diff;
|
||||
|
||||
time_diff = g_time2() - g_training_sent_time;
|
||||
time_diff = g_time3() - g_training_sent_time;
|
||||
LOG(0, ("sound_process_training: round trip time %u", time_diff));
|
||||
return 0;
|
||||
}
|
||||
@ -1052,42 +1043,39 @@ sound_process_wave_confirm(struct stream *s, int size)
|
||||
{
|
||||
int wTimeStamp;
|
||||
int cConfirmedBlockNo;
|
||||
int cleared_count;
|
||||
int time;
|
||||
int time_diff;
|
||||
int block_no;
|
||||
int block_no_clamped;
|
||||
int found;
|
||||
int index;
|
||||
int acc;
|
||||
|
||||
time = g_time2();
|
||||
time = g_time3();
|
||||
in_uint16_le(s, wTimeStamp);
|
||||
in_uint8(s, cConfirmedBlockNo);
|
||||
time_diff = time - g_sent_time[cConfirmedBlockNo & 0xff];
|
||||
cleared_count = 0;
|
||||
found = 0;
|
||||
block_no = g_cBlockNo;
|
||||
for (index = 0; index < g_unacked_frames; index++)
|
||||
{
|
||||
block_no_clamped = block_no & 0xff;
|
||||
if ((cConfirmedBlockNo == block_no_clamped) || found)
|
||||
{
|
||||
found = 1;
|
||||
if (g_sent_flag[block_no_clamped] & 1)
|
||||
{
|
||||
LOG(10, ("sound_process_wave_confirm: clearing %d",
|
||||
block_no_clamped));
|
||||
g_sent_flag[block_no_clamped] &= ~1;
|
||||
cleared_count++;
|
||||
}
|
||||
}
|
||||
block_no--;
|
||||
}
|
||||
|
||||
LOG(10, ("sound_process_wave_confirm: wTimeStamp %d, "
|
||||
"cConfirmedBlockNo %d time diff %d cleared_count %d "
|
||||
"g_unacked_frames %d", wTimeStamp, cConfirmedBlockNo, time_diff,
|
||||
cleared_count, g_unacked_frames));
|
||||
g_unacked_frames -= cleared_count;
|
||||
"cConfirmedBlockNo %d time diff %d",
|
||||
wTimeStamp, cConfirmedBlockNo, time_diff));
|
||||
|
||||
acc = 0;
|
||||
list_add_item(g_ack_time_diff, time_diff);
|
||||
if (g_ack_time_diff->count >= 50)
|
||||
{
|
||||
while (g_ack_time_diff->count > 50)
|
||||
{
|
||||
list_remove_item(g_ack_time_diff, 0);
|
||||
}
|
||||
for (index = 0; index < g_ack_time_diff->count; index++)
|
||||
{
|
||||
acc += list_get_item(g_ack_time_diff, index);
|
||||
}
|
||||
acc = acc / g_ack_time_diff->count;
|
||||
if ((g_best_time_diff < 1) || (g_best_time_diff > acc))
|
||||
{
|
||||
g_best_time_diff = acc;
|
||||
}
|
||||
}
|
||||
g_time_diff = acc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1219,7 +1207,6 @@ sound_init(void)
|
||||
{
|
||||
LOG(0, ("sound_init:"));
|
||||
|
||||
g_memset(g_sent_flag, 0, sizeof(g_sent_flag));
|
||||
g_stream_incoming_packet = NULL;
|
||||
|
||||
/* init sound output */
|
||||
@ -1242,6 +1229,12 @@ sound_init(void)
|
||||
g_client_does_mp3lame = 0;
|
||||
g_client_mp3lame_index = 0;
|
||||
|
||||
if (g_ack_time_diff == 0)
|
||||
{
|
||||
g_ack_time_diff = list_create();
|
||||
}
|
||||
list_clear(g_ack_time_diff);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1570,6 +1563,10 @@ sound_process_input_formats(struct stream *s, int size)
|
||||
|
||||
LOG(10, ("sound_process_input_formats: size=%d", size));
|
||||
|
||||
if (g_getenv("XRDP_NO_RDPSND_REC") == NULL)
|
||||
{
|
||||
g_rdpsnd_can_rec = 1;
|
||||
}
|
||||
in_uint8s(s, 8); /* skip 8 bytes */
|
||||
in_uint16_le(s, num_formats);
|
||||
in_uint8s(s, 2); /* skip version */
|
||||
@ -1782,11 +1779,25 @@ sound_sndsrvr_source_data_in(struct trans *trans)
|
||||
}
|
||||
else if (cmd == PA_CMD_START_REC)
|
||||
{
|
||||
sound_input_start_recording();
|
||||
if (g_rdpsnd_can_rec)
|
||||
{
|
||||
sound_input_start_recording();
|
||||
}
|
||||
else
|
||||
{
|
||||
audin_start();
|
||||
}
|
||||
}
|
||||
else if (cmd == PA_CMD_STOP_REC)
|
||||
{
|
||||
sound_input_stop_recording();
|
||||
if (g_rdpsnd_can_rec)
|
||||
{
|
||||
sound_input_stop_recording();
|
||||
}
|
||||
else
|
||||
{
|
||||
audin_stop();
|
||||
}
|
||||
}
|
||||
|
||||
xstream_free(s);
|
||||
|
120
vnc/vnc.c
120
vnc/vnc.c
@ -380,20 +380,23 @@ lib_mod_event(struct vnc *v, int msg, long param1, long param2,
|
||||
}
|
||||
else if (msg == 200) /* invalidate */
|
||||
{
|
||||
/* FramebufferUpdateRequest */
|
||||
init_stream(s, 8192);
|
||||
out_uint8(s, 3);
|
||||
out_uint8(s, 0);
|
||||
x = (param1 >> 16) & 0xffff;
|
||||
out_uint16_be(s, x);
|
||||
y = param1 & 0xffff;
|
||||
out_uint16_be(s, y);
|
||||
cx = (param2 >> 16) & 0xffff;
|
||||
out_uint16_be(s, cx);
|
||||
cy = param2 & 0xffff;
|
||||
out_uint16_be(s, cy);
|
||||
s_mark_end(s);
|
||||
error = lib_send_copy(v, s);
|
||||
if (v->suppress_output == 0)
|
||||
{
|
||||
/* FramebufferUpdateRequest */
|
||||
init_stream(s, 8192);
|
||||
out_uint8(s, 3);
|
||||
out_uint8(s, 0);
|
||||
x = (param1 >> 16) & 0xffff;
|
||||
out_uint16_be(s, x);
|
||||
y = param1 & 0xffff;
|
||||
out_uint16_be(s, y);
|
||||
cx = (param2 >> 16) & 0xffff;
|
||||
out_uint16_be(s, cx);
|
||||
cy = param2 & 0xffff;
|
||||
out_uint16_be(s, cy);
|
||||
s_mark_end(s);
|
||||
error = lib_send_copy(v, s);
|
||||
}
|
||||
}
|
||||
|
||||
free_stream(s);
|
||||
@ -742,16 +745,19 @@ lib_framebuffer_update(struct vnc *v)
|
||||
|
||||
if (error == 0)
|
||||
{
|
||||
/* FramebufferUpdateRequest */
|
||||
init_stream(s, 8192);
|
||||
out_uint8(s, 3);
|
||||
out_uint8(s, 1);
|
||||
out_uint16_be(s, 0);
|
||||
out_uint16_be(s, 0);
|
||||
out_uint16_be(s, v->mod_width);
|
||||
out_uint16_be(s, v->mod_height);
|
||||
s_mark_end(s);
|
||||
error = lib_send_copy(v, s);
|
||||
if (v->suppress_output == 0)
|
||||
{
|
||||
/* FramebufferUpdateRequest */
|
||||
init_stream(s, 8192);
|
||||
out_uint8(s, 3);
|
||||
out_uint8(s, 1);
|
||||
out_uint16_be(s, 0);
|
||||
out_uint16_be(s, 0);
|
||||
out_uint16_be(s, v->mod_width);
|
||||
out_uint16_be(s, v->mod_height);
|
||||
s_mark_end(s);
|
||||
error = lib_send_copy(v, s);
|
||||
}
|
||||
}
|
||||
|
||||
free_stream(s);
|
||||
@ -916,7 +922,7 @@ lib_mod_process_message(struct vnc *v, struct stream *s)
|
||||
}
|
||||
else
|
||||
{
|
||||
g_sprintf(text, "VNC unknown in lib_mod_signal %d", type);
|
||||
g_sprintf(text, "VNC unknown in lib_mod_process_message %d", type);
|
||||
v->server_msg(v, text, 1);
|
||||
}
|
||||
}
|
||||
@ -1340,17 +1346,20 @@ lib_mod_connect(struct vnc *v)
|
||||
|
||||
if (error == 0)
|
||||
{
|
||||
/* FramebufferUpdateRequest */
|
||||
init_stream(s, 8192);
|
||||
out_uint8(s, 3);
|
||||
out_uint8(s, 0);
|
||||
out_uint16_be(s, 0);
|
||||
out_uint16_be(s, 0);
|
||||
out_uint16_be(s, v->mod_width);
|
||||
out_uint16_be(s, v->mod_height);
|
||||
v->server_msg(v, "VNC sending framebuffer update request", 0);
|
||||
s_mark_end(s);
|
||||
error = trans_force_write_s(v->trans, s);
|
||||
if (v->suppress_output == 0)
|
||||
{
|
||||
/* FramebufferUpdateRequest */
|
||||
init_stream(s, 8192);
|
||||
out_uint8(s, 3);
|
||||
out_uint8(s, 0);
|
||||
out_uint16_be(s, 0);
|
||||
out_uint16_be(s, 0);
|
||||
out_uint16_be(s, v->mod_width);
|
||||
out_uint16_be(s, v->mod_height);
|
||||
v->server_msg(v, "VNC sending framebuffer update request", 0);
|
||||
s_mark_end(s);
|
||||
error = trans_force_write_s(v->trans, s);
|
||||
}
|
||||
}
|
||||
|
||||
if (error == 0)
|
||||
@ -1492,6 +1501,43 @@ lib_mod_check_wait_objs(struct vnc *v)
|
||||
return rv;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* return error */
|
||||
int
|
||||
lib_mod_frame_ack(struct vnc* v, int flags, int frame_id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* return error */
|
||||
int
|
||||
lib_mod_suppress_output(struct vnc* v, int suppress,
|
||||
int left, int top, int right, int bottom)
|
||||
{
|
||||
int error;
|
||||
struct stream *s;
|
||||
|
||||
error = 0;
|
||||
v->suppress_output = suppress;
|
||||
if (suppress == 0)
|
||||
{
|
||||
/* FramebufferUpdateRequest */
|
||||
make_stream(s);
|
||||
init_stream(s, 8192);
|
||||
out_uint8(s, 3);
|
||||
out_uint8(s, 0);
|
||||
out_uint16_be(s, 0);
|
||||
out_uint16_be(s, 0);
|
||||
out_uint16_be(s, v->mod_width);
|
||||
out_uint16_be(s, v->mod_height);
|
||||
s_mark_end(s);
|
||||
error = lib_send_copy(v, s);
|
||||
free_stream(s);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
tintptr EXPORT_CC
|
||||
mod_init(void)
|
||||
@ -1511,6 +1557,8 @@ mod_init(void)
|
||||
v->mod_set_param = lib_mod_set_param;
|
||||
v->mod_get_wait_objs = lib_mod_get_wait_objs;
|
||||
v->mod_check_wait_objs = lib_mod_check_wait_objs;
|
||||
v->mod_frame_ack = lib_mod_frame_ack;
|
||||
v->mod_suppress_output = lib_mod_suppress_output;
|
||||
return (tintptr) v;
|
||||
}
|
||||
|
||||
|
10
vnc/vnc.h
10
vnc/vnc.h
@ -24,7 +24,7 @@
|
||||
#include "os_calls.h"
|
||||
#include "defines.h"
|
||||
|
||||
#define CURRENT_MOD_VER 3
|
||||
#define CURRENT_MOD_VER 4
|
||||
|
||||
struct vnc
|
||||
{
|
||||
@ -42,8 +42,11 @@ struct vnc
|
||||
int (*mod_get_wait_objs)(struct vnc* v, tbus* read_objs, int* rcount,
|
||||
tbus* write_objs, int* wcount, int* timeout);
|
||||
int (*mod_check_wait_objs)(struct vnc* v);
|
||||
tintptr mod_dumby[100 - 9]; /* align, 100 minus the number of mod
|
||||
functions above */
|
||||
int (*mod_frame_ack)(struct vnc* v, int flags, int frame_id);
|
||||
int (*mod_suppress_output)(struct vnc* v, int suppress,
|
||||
int left, int top, int right, int bottom);
|
||||
tintptr mod_dumby[100 - 11]; /* align, 100 minus the number of mod
|
||||
functions above */
|
||||
/* server functions */
|
||||
int (*server_begin_update)(struct vnc* v);
|
||||
int (*server_end_update)(struct vnc* v);
|
||||
@ -116,4 +119,5 @@ struct vnc
|
||||
struct trans *trans;
|
||||
int got_guid;
|
||||
tui8 guid[16];
|
||||
int suppress_output;
|
||||
};
|
||||
|
20
xrdp/xrdp.c
20
xrdp/xrdp.c
@ -575,6 +575,16 @@ main(int argc, char **argv)
|
||||
|
||||
if (!no_daemon)
|
||||
{
|
||||
/* if can't listen, exit with failure status */
|
||||
if (xrdp_listen_test(startup_params) != 0)
|
||||
{
|
||||
log_message(LOG_LEVEL_ERROR, "Failed to start xrdp daemon, "
|
||||
"possibly address already in use.");
|
||||
g_deinit();
|
||||
/* must exit with failure status,
|
||||
or systemd cannot detect xrdp daemon couldn't start properly */
|
||||
g_exit(1);
|
||||
}
|
||||
/* start of daemonizing code */
|
||||
pid = g_fork();
|
||||
|
||||
@ -587,16 +597,6 @@ main(int argc, char **argv)
|
||||
|
||||
if (0 != pid)
|
||||
{
|
||||
/* if can't listen, exit with failure status */
|
||||
if (xrdp_listen_test() != 0)
|
||||
{
|
||||
log_message(LOG_LEVEL_ERROR, "Failed to start xrdp daemon, "
|
||||
"possibly address already in use.");
|
||||
g_deinit();
|
||||
/* must exit with failure status,
|
||||
or systemd cannot detect xrdp daemon couldn't start properly */
|
||||
g_exit(1);
|
||||
}
|
||||
g_writeln("daemon process %d started ok", pid);
|
||||
/* exit, this is the main process */
|
||||
g_deinit();
|
||||
|
@ -170,7 +170,7 @@ xrdp_listen_delete(struct xrdp_listen* self);
|
||||
int
|
||||
xrdp_listen_main_loop(struct xrdp_listen* self);
|
||||
int
|
||||
xrdp_listen_test(void);
|
||||
xrdp_listen_test(struct xrdp_startup_params *startup_params);
|
||||
|
||||
/* xrdp_region.c */
|
||||
struct xrdp_region*
|
||||
@ -371,6 +371,9 @@ xrdp_bitmap_compress(char* in_data, int width, int height,
|
||||
/* xrdp_mm.c */
|
||||
int
|
||||
xrdp_mm_drdynvc_up(struct xrdp_mm* self);
|
||||
int
|
||||
xrdp_mm_suppress_output(struct xrdp_mm* self, int suppress,
|
||||
int left, int top, int right, int bottom);
|
||||
struct xrdp_mm*
|
||||
xrdp_mm_create(struct xrdp_wm* owner);
|
||||
void
|
||||
|
@ -4,29 +4,54 @@ ini_version=1
|
||||
|
||||
; fork a new process for each incoming connection
|
||||
fork=true
|
||||
; tcp port to listen
|
||||
|
||||
; ports to listen on, number alone means listen on all interfaces
|
||||
; 0.0.0.0 or :: if ipv6 is configured
|
||||
; space between multiple occurrences
|
||||
;
|
||||
; Examples:
|
||||
; port=3389
|
||||
; port=unix://./tmp/xrdp.socket
|
||||
; port=tcp://.:3389 127.0.0.1:3389
|
||||
; port=tcp://:3389 *:3389
|
||||
; port=tcp://<any ipv4 format addr>:3389 192.168.1.1:3389
|
||||
; port=tcp6://.:3389 ::1:3389
|
||||
; port=tcp6://:3389 *:3389
|
||||
; port=tcp6://{<any ipv6 format addr>}:3389 {FC00:0:0:0:0:0:0:1}:3389
|
||||
; port=vsock://<cid>:<port>
|
||||
port=3389
|
||||
|
||||
; 'port' above should be connected to with vsock instead of tcp
|
||||
; use this only with number alone in port above
|
||||
; prefer use vsock://<cid>:<port> above
|
||||
use_vsock=false
|
||||
|
||||
; regulate if the listening socket use socket option tcp_nodelay
|
||||
; no buffering will be performed in the TCP stack
|
||||
tcp_nodelay=true
|
||||
|
||||
; regulate if the listening socket use socket option keepalive
|
||||
; if the network connection disappear without close messages the connection will be closed
|
||||
tcp_keepalive=true
|
||||
|
||||
; set tcp send/recv buffer (for experts)
|
||||
#tcp_send_buffer_bytes=32768
|
||||
#tcp_recv_buffer_bytes=32768
|
||||
|
||||
; security layer can be 'tls', 'rdp' or 'negotiate'
|
||||
; for client compatible layer
|
||||
security_layer=negotiate
|
||||
; minimum security level allowed for client
|
||||
|
||||
; minimum security level allowed for client for classic RDP encryption
|
||||
; use tls_ciphers to configure TLS encryption
|
||||
; can be 'none', 'low', 'medium', 'high', 'fips'
|
||||
crypt_level=high
|
||||
|
||||
; X.509 certificate and private key
|
||||
; openssl req -x509 -newkey rsa:2048 -nodes -keyout key.pem -out cert.pem -days 365
|
||||
certificate=
|
||||
key_file=
|
||||
|
||||
; set SSL protocols
|
||||
; can be comma separated list of 'SSLv3', 'TLSv1', 'TLSv1.1', 'TLSv1.2', 'TLSv1.3'
|
||||
ssl_protocols=TLSv1.2, TLSv1.3
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -999,6 +999,25 @@ xrdp_mm_drdynvc_up(struct xrdp_mm* self)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
int
|
||||
xrdp_mm_suppress_output(struct xrdp_mm* self, int suppress,
|
||||
int left, int top, int right, int bottom)
|
||||
{
|
||||
LLOGLN(0, ("xrdp_mm_suppress_output: suppress %d "
|
||||
"left %d top %d right %d bottom %d",
|
||||
suppress, left, top, right, bottom));
|
||||
if (self->mod != NULL)
|
||||
{
|
||||
if (self->mod->mod_suppress_output != NULL)
|
||||
{
|
||||
self->mod->mod_suppress_output(self->mod, suppress,
|
||||
left, top, right, bottom);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* open response from client going to channel server */
|
||||
static int
|
||||
|
@ -48,7 +48,9 @@ struct xrdp_mod
|
||||
tbus* write_objs, int* wcount, int* timeout);
|
||||
int (*mod_check_wait_objs)(struct xrdp_mod* v);
|
||||
int (*mod_frame_ack)(struct xrdp_mod* v, int flags, int frame_id);
|
||||
tintptr mod_dumby[100 - 10]; /* align, 100 minus the number of mod
|
||||
int (*mod_suppress_output)(struct xrdp_mod* v, int suppress,
|
||||
int left, int top, int right, int bottom);
|
||||
tintptr mod_dumby[100 - 11]; /* align, 100 minus the number of mod
|
||||
functions above */
|
||||
/* server functions */
|
||||
int (*server_begin_update)(struct xrdp_mod* v);
|
||||
@ -403,8 +405,9 @@ struct xrdp_process
|
||||
struct xrdp_listen
|
||||
{
|
||||
int status;
|
||||
struct trans* listen_trans; /* in tcp listen mode */
|
||||
struct list* process_list;
|
||||
struct list *trans_list; /* list of struct trans* */
|
||||
struct list *process_list;
|
||||
struct list *fork_list;
|
||||
tbus pro_done_event;
|
||||
struct xrdp_startup_params* startup_params;
|
||||
};
|
||||
@ -525,14 +528,17 @@ struct xrdp_mod_data
|
||||
|
||||
struct xrdp_startup_params
|
||||
{
|
||||
char port[128];
|
||||
char port[1024];
|
||||
int kill;
|
||||
int no_daemon;
|
||||
int help;
|
||||
int version;
|
||||
int fork;
|
||||
int send_buffer_bytes;
|
||||
int recv_buffer_bytes;
|
||||
int tcp_send_buffer_bytes;
|
||||
int tcp_recv_buffer_bytes;
|
||||
int tcp_nodelay;
|
||||
int tcp_keepalive;
|
||||
int use_vsock;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -1916,6 +1916,11 @@ callback(intptr_t id, int msg, intptr_t param1, intptr_t param2,
|
||||
case 0x5558:
|
||||
xrdp_mm_drdynvc_up(wm->mm);
|
||||
break;
|
||||
case 0x5559:
|
||||
xrdp_mm_suppress_output(wm->mm, param1,
|
||||
LOWORD(param2), HIWORD(param2),
|
||||
LOWORD(param3), HIWORD(param3));
|
||||
break;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
45
xup/xup.c
45
xup/xup.c
@ -226,6 +226,11 @@ lib_mod_connect(struct mod *mod)
|
||||
break;
|
||||
}
|
||||
|
||||
if (mod->server_is_term(mod))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
i++;
|
||||
|
||||
if (i >= 60)
|
||||
@ -1143,6 +1148,33 @@ send_paint_rect_ex_ack(struct mod *mod, int flags, int frame_id)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* return error */
|
||||
static int
|
||||
send_suppress_output(struct mod *mod, int suppress,
|
||||
int left, int top, int right, int bottom)
|
||||
{
|
||||
int len;
|
||||
struct stream *s;
|
||||
|
||||
make_stream(s);
|
||||
init_stream(s, 8192);
|
||||
s_push_layer(s, iso_hdr, 4);
|
||||
out_uint16_le(s, 108);
|
||||
out_uint32_le(s, suppress);
|
||||
out_uint32_le(s, left);
|
||||
out_uint32_le(s, top);
|
||||
out_uint32_le(s, right);
|
||||
out_uint32_le(s, bottom);
|
||||
s_mark_end(s);
|
||||
len = (int)(s->end - s->data);
|
||||
s_pop_layer(s, iso_hdr);
|
||||
out_uint32_le(s, len);
|
||||
lib_send_copy(mod, s);
|
||||
free_stream(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* return error */
|
||||
static int
|
||||
@ -1556,6 +1588,18 @@ lib_mod_frame_ack(struct mod *amod, int flags, int frame_id)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* return error */
|
||||
int
|
||||
lib_mod_suppress_output(struct mod *amod, int suppress,
|
||||
int left, int top, int right, int bottom)
|
||||
{
|
||||
LLOGLN(10, ("lib_mod_suppress_output: suppress 0x%8.8x left %d top %d "
|
||||
"right %d bottom %d", suppress, left, top, right, bottom));
|
||||
send_suppress_output(amod, suppress, left, top, right, bottom);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
tintptr EXPORT_CC
|
||||
mod_init(void)
|
||||
@ -1575,6 +1619,7 @@ mod_init(void)
|
||||
mod->mod_get_wait_objs = lib_mod_get_wait_objs;
|
||||
mod->mod_check_wait_objs = lib_mod_check_wait_objs;
|
||||
mod->mod_frame_ack = lib_mod_frame_ack;
|
||||
mod->mod_suppress_output = lib_mod_suppress_output;
|
||||
return (tintptr) mod;
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@
|
||||
#include "xrdp_client_info.h"
|
||||
#include "xrdp_rail.h"
|
||||
|
||||
#define CURRENT_MOD_VER 3
|
||||
#define CURRENT_MOD_VER 4
|
||||
|
||||
struct mod
|
||||
{
|
||||
@ -45,7 +45,9 @@ struct mod
|
||||
tbus* write_objs, int* wcount, int* timeout);
|
||||
int (*mod_check_wait_objs)(struct mod* v);
|
||||
int (*mod_frame_ack)(struct mod* v, int flags, int frame_id);
|
||||
tintptr mod_dumby[100 - 10]; /* align, 100 minus the number of mod
|
||||
int (*mod_suppress_output)(struct mod* v, int suppress,
|
||||
int left, int top, int right, int bottom);
|
||||
tintptr mod_dumby[100 - 11]; /* align, 100 minus the number of mod
|
||||
functions above */
|
||||
/* server functions */
|
||||
int (*server_begin_update)(struct mod* v);
|
||||
|
Loading…
Reference in New Issue
Block a user