o added support for dynamic virtual channels

o added echo test routine in simple.c for testing DVC using Microsoft's ECHO protocol
This commit is contained in:
Laxmikant Rashinkar
2012-09-27 19:48:44 -07:00
parent 42a56cd33e
commit 5b0eaa4a9b
7 changed files with 1177 additions and 385 deletions
+141 -82
View File
@@ -1,7 +1,8 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
* Copyright (C) Jay Sorg 2004-2012
* Copyright (C) Jay Sorg 2012
* Copyright (C) Laxmikant Rashinkar 2012
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,13 +15,20 @@
* 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.
*
* sample program to demonstrate use of xrdpapi
*
*/
/*
* Basic test for virtual channel use
* build instructions:
* gcc simple.c -o simple -L./.libs -lxrdpapi
*/
// These headers are required for the windows terminal services calls.
#ifdef __WIN32__
#include <mstsapi.h>
#endif
#include "xrdpapi.h"
#include <stdlib.h>
#include <stdio.h>
@@ -28,92 +36,143 @@
#include <string.h>
#include <errno.h>
#define DSIZE (1024 * 4)
/* forward declarations */
int run_echo_test();
int run_tsmf_test();
int main()
int
main(int argc, char **argv)
{
// Initialize the data for send/receive
void *hFile;
char *data;
char *data1;
data = (char *)malloc(DSIZE);
data1 = (char *)malloc(DSIZE);
int ret;
void *vcFileHandlePtr = NULL;
memset(data, 0xca, DSIZE);
memset(data1, 0, DSIZE);
unsigned int written = 0;
// Open the skel channel in current session
//void* channel = WTSVirtualChannelOpenEx(WTS_CURRENT_SESSION, "skel", 0);
void *channel = WTSVirtualChannelOpenEx(WTS_CURRENT_SESSION, "TSMF", WTS_CHANNEL_OPTION_DYNAMIC);
ret = WTSVirtualChannelQuery(channel, WTSVirtualFileHandle, vcFileHandlePtr, &written);
// Write the data to the channel
ret = WTSVirtualChannelWrite(channel, data, DSIZE, &written);
if (!ret)
if (argc < 2)
{
long err = errno;
printf("error 1 0x%8.8x\n", err);
usleep(100000);
printf("usage: simple <echo|tsmf>\n");
return 1;
}
if (strcasecmp(argv[1], "echo") == 0)
{
return run_echo_test();
}
else if (strcasecmp(argv[1], "tsmf") == 0)
{
return run_tsmf_test();
}
else
{
printf("Sent bytes!\n");
}
if (written != DSIZE)
{
long err = errno;
printf("error 2 0x%8.8x\n", err);
usleep(100000);
printf("usage: simple <echo|tsmf>\n");
return 1;
}
else
{
printf("Read bytes!\n");
}
ret = WTSVirtualChannelRead(channel, 100, data1, DSIZE, &written);
if (!ret)
{
long err = errno;
printf("error 3 0x%8.8x\n", err);
usleep(100000);
return 1;
}
if (written != DSIZE)
{
long err = errno;
printf("error 4 0x%8.8x\n", err);
usleep(100000);
return 1;
}
else
{
printf("Read bytes!\n");
}
ret = WTSVirtualChannelClose(channel);
if (memcmp(data, data1, DSIZE) == 0)
{
}
else
{
printf("error data no match\n");
return 1;
}
printf("Done!\n");
usleep(100000);
return 0;
}
/**
* perform an ECHO test with a Microsoft Windows RDP client
*
* A Microsoft Windows RDP client echos data written
* to a dynamic virtual channel named ECHO
*
* NOTE: THIS TEST WILL FAIL IF CONNECTED FROM A NON
* WINDOWS RDP CLIENT
*
* @return 0 on success, -1 on failure
*/
int
run_echo_test()
{
char out_buf[8192];
char in_buf[1700];
void *channel;
int bytes_left;
int rv;
int count;
int pkt_count;
int i;
int bytes_written;
int bytes_read;
unsigned char c;
unsigned char *rd_ptr;
unsigned char *wr_ptr;
/* fill out_buf[] with incremental values */
for (i = 0, c = 0; i < 8192; i++, c++)
{
out_buf[i] = c;
}
/* open a virtual channel named ECHO */
channel = WTSVirtualChannelOpenEx(WTS_CURRENT_SESSION, "ECHO", WTS_CHANNEL_OPTION_DYNAMIC_PRI_LOW);
if (channel == NULL)
{
printf("### WTSVirtualChannelOpenEx() failed!\n");
return -1;
}
bytes_left = 8192;
wr_ptr = out_buf;
rd_ptr = out_buf;
pkt_count = 1;
while (bytes_left > 0)
{
/* write data to virtual channel */
count = (bytes_left > 1700) ? 1700 : bytes_left;
rv = WTSVirtualChannelWrite(channel, wr_ptr, count, &bytes_written);
if ((rv == 0) || (bytes_written == 0))
{
printf("### WTSVirtualChannelWrite() failed\n");
return -1;
}
count = bytes_written;
while (count)
{
/* read back the echo */
rv = WTSVirtualChannelRead(channel, 5000, in_buf, count, &bytes_read);
if ((rv == 0) || (bytes_read == 0))
{
printf("### WTSVirtualChannelRead() failed\n");
return -1;
}
/* validate the echo */
for (i = 0; i < bytes_read; i++, rd_ptr++)
{
if (*rd_ptr != (unsigned char) in_buf[i])
{
printf("### data mismatch: expected 0x%x got 0x%x\n",
(unsigned char) *rd_ptr, (unsigned char) in_buf[i]);
return -1;
}
}
count -= bytes_read;
}
bytes_left -= bytes_written;
wr_ptr += bytes_written;
printf("### pkt %d passed echo test\n", pkt_count++);
}
WTSVirtualChannelClose(channel);
return 0;
}
int
run_tsmf_test()
{
void *channel;
printf("this test not yet implemented!\n");
return 1;
/* open virtual channel */
channel = WTSVirtualChannelOpenEx(WTS_CURRENT_SESSION, "TSMF", WTS_CHANNEL_OPTION_DYNAMIC_PRI_LOW);
if (channel == NULL)
{
printf("### WTSVirtualChannelOpenEx() failed!\n");
return 1;
}
WTSVirtualChannelClose(channel);
return 0;
}
+225 -181
View File
@@ -1,8 +1,8 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
* Copyright (C) Thomas Goddard 2012
* Copyright (C) Jay Sorg 2012
* Copyright (C) Laxmikant Rashinkar 2012
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,8 +17,6 @@
* limitations under the License.
*/
/* do not use os_calls in here */
#define LOG_LEVEL 1
#define LLOG(_level, _args) \
do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0)
@@ -29,6 +27,7 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
@@ -40,69 +39,31 @@
struct wts_obj
{
int fd;
int status;
char name[8];
char dname[128];
int display_num;
int flags;
int fd;
int status;
char name[8];
char dname[128];
int display_num;
uint32_t flags;
};
/*****************************************************************************/
static int
get_display_num_from_display(char *display_text)
{
int index;
int mode;
int host_index;
int disp_index;
int scre_index;
char host[256];
char disp[256];
char scre[256];
/* helper functions used by WTSxxx API - do not invoke directly */
static int get_display_num_from_display(char *display_text);
static int send_init(struct wts_obj *wts);
static int can_send(int sck, int millis);
static int can_recv(int sck, int millis);
index = 0;
host_index = 0;
disp_index = 0;
scre_index = 0;
mode = 0;
while (display_text[index] != 0)
{
if (display_text[index] == ':')
{
mode = 1;
}
else if (display_text[index] == '.')
{
mode = 2;
}
else if (mode == 0)
{
host[host_index] = display_text[index];
host_index++;
}
else if (mode == 1)
{
disp[disp_index] = display_text[index];
disp_index++;
}
else if (mode == 2)
{
scre[scre_index] = display_text[index];
scre_index++;
}
index++;
}
host[host_index] = 0;
disp[disp_index] = 0;
scre[scre_index] = 0;
return atoi(disp);
}
/*****************************************************************************/
/*
* Opens a handle to the server end of a specified virtual channel - this
* call is deprecated - use WTSVirtualChannelOpenEx() instead
*
* @param hServer
* @param SessionId - current session ID; *must* be WTS_CURRENT_SERVER_HANDLE
* @param pVirtualName - virtual channel name when using SVC
* - name of endpoint listener when using DVC
*
* @return a valid pointer on success, NULL on error
******************************************************************************/
void *
WTSVirtualChannelOpen(void *hServer, unsigned int SessionId,
const char *pVirtualName)
@@ -115,98 +76,34 @@ WTSVirtualChannelOpen(void *hServer, unsigned int SessionId,
return WTSVirtualChannelOpenEx(SessionId, pVirtualName, 0);
}
/*****************************************************************************/
static int
can_send(int sck, int millis)
{
struct timeval time;
fd_set wfds;
int select_rv;
FD_ZERO(&wfds);
FD_SET(sck, &wfds);
time.tv_sec = millis / 1000;
time.tv_usec = (millis * 1000) % 1000000;
select_rv = select(sck + 1, 0, &wfds, 0, &time);
if (select_rv > 0)
{
return 1;
}
return 0;
}
/*****************************************************************************/
static int
can_recv(int sck, int millis)
{
struct timeval time;
fd_set rfds;
int select_rv;
FD_ZERO(&rfds);
FD_SET(sck, &rfds);
time.tv_sec = millis / 1000;
time.tv_usec = (millis * 1000) % 1000000;
select_rv = select(sck + 1, &rfds, 0, 0, &time);
if (select_rv > 0)
{
return 1;
}
return 0;
}
/*****************************************************************************/
static int
send_init(struct wts_obj *wts)
{
char initmsg[64];
memset(initmsg, 0, 64);
strncpy(initmsg, wts->name, 8);
initmsg[16] = (wts->flags >> 0) & 0xff;
initmsg[17] = (wts->flags >> 8) & 0xff;
initmsg[18] = (wts->flags >> 16) & 0xff;
initmsg[19] = (wts->flags >> 24) & 0xff;
LLOGLN(10, ("send_init: sending %s", initmsg));
if (!can_send(wts->fd, 500))
{
return 1;
}
if (send(wts->fd, initmsg, 64, 0) != 64)
{
return 1;
}
LLOGLN(10, ("send_init: send ok!"));
return 0;
}
/*****************************************************************************/
/*
* Opens a handle to the server end of a specified virtual channel
*
* @param SessionId - current session ID; *must* be WTS_CURRENT_SERVER_HANDLE
* @param pVirtualName - virtual channel name when using SVC
* - name of endpoint listener when using DVC
* @param flags - type of channel and channel priority if DVC
*
* @return a valid pointer on success, NULL on error
******************************************************************************/
void *
WTSVirtualChannelOpenEx(unsigned int SessionId,
const char *pVirtualName,
WTSVirtualChannelOpenEx(unsigned int SessionId, const char *pVirtualName,
unsigned int flags)
{
struct wts_obj *wts;
char *display_text;
struct sockaddr_un s;
int bytes;
unsigned long llong;
struct wts_obj *wts;
char *display_text;
int bytes;
unsigned long llong;
struct sockaddr_un s;
if (SessionId != WTS_CURRENT_SESSION)
{
LLOGLN(0, ("WTSVirtualChannelOpenEx: SessionId bad"));
LLOGLN(0, ("WTSVirtualChannelOpenEx: bad SessionId"));
return 0;
}
wts = (struct wts_obj *)malloc(sizeof(struct wts_obj));
memset(wts, 0, sizeof(struct wts_obj));
wts = (struct wts_obj *) calloc(1, sizeof(struct wts_obj));
wts->fd = -1;
wts->flags = flags;
display_text = getenv("DISPLAY");
@@ -216,37 +113,40 @@ WTSVirtualChannelOpenEx(unsigned int SessionId,
wts->display_num = get_display_num_from_display(display_text);
}
if (wts->display_num > 0)
if (wts->display_num <= 0)
{
wts->fd = socket(AF_UNIX, SOCK_STREAM, 0);
/* set non blocking */
llong = fcntl(wts->fd, F_GETFL);
llong = llong | O_NONBLOCK;
fcntl(wts->fd, F_SETFL, llong);
/* connect to session chansrv */
memset(&s, 0, sizeof(struct sockaddr_un));
s.sun_family = AF_UNIX;
bytes = sizeof(s.sun_path);
snprintf(s.sun_path, bytes - 1, "/tmp/.xrdp/xrdpapi_%d", wts->display_num);
s.sun_path[bytes - 1] = 0;
bytes = sizeof(struct sockaddr_un);
if (connect(wts->fd, (struct sockaddr *)&s, bytes) == 0)
{
LLOGLN(10, ("WTSVirtualChannelOpenEx: connected ok, name %s", pVirtualName));
strncpy(wts->name, pVirtualName, 8);
/* wait for connection to complete and send init */
if (send_init(wts) == 0)
{
/* all ok */
wts->status = 1;
}
}
LLOGLN(0, ("WTSVirtualChannelOpenEx: fatal errror; display is 0"));
free(wts);
return NULL;
}
else
/* we use unix domain socket to communicate with chansrv */
wts->fd = socket(AF_UNIX, SOCK_STREAM, 0);
/* set non blocking */
llong = fcntl(wts->fd, F_GETFL);
llong = llong | O_NONBLOCK;
fcntl(wts->fd, F_SETFL, llong);
/* connect to chansrv session */
memset(&s, 0, sizeof(struct sockaddr_un));
s.sun_family = AF_UNIX;
bytes = sizeof(s.sun_path);
snprintf(s.sun_path, bytes - 1, "/tmp/.xrdp/xrdpapi_%d", wts->display_num);
s.sun_path[bytes - 1] = 0;
bytes = sizeof(struct sockaddr_un);
if (connect(wts->fd, (struct sockaddr *) &s, bytes) == 0)
{
LLOGLN(0, ("WTSVirtualChannelOpenEx: display is 0"));
LLOGLN(10, ("WTSVirtualChannelOpenEx: connected ok, name %s", pVirtualName));
strncpy(wts->name, pVirtualName, 8);
/* wait for connection to complete and send init */
if (send_init(wts) == 0)
{
/* all ok */
wts->status = 1;
}
}
return wts;
@@ -312,7 +212,7 @@ WTSVirtualChannelRead(void *hChannelHandle, unsigned int TimeOut,
unsigned int *pBytesRead)
{
struct wts_obj *wts;
int error;
int rv;
int lerrno;
wts = (struct wts_obj *)hChannelHandle;
@@ -329,9 +229,9 @@ WTSVirtualChannelRead(void *hChannelHandle, unsigned int TimeOut,
if (can_recv(wts->fd, TimeOut))
{
error = recv(wts->fd, Buffer, BufferSize, 0);
rv = recv(wts->fd, Buffer, BufferSize, 0);
if (error == -1)
if (rv == -1)
{
lerrno = errno;
@@ -341,16 +241,15 @@ WTSVirtualChannelRead(void *hChannelHandle, unsigned int TimeOut,
*pBytesRead = 0;
return 1;
}
return 0;
}
else if (error == 0)
else if (rv == 0)
{
return 0;
}
else if (error > 0)
else if (rv > 0)
{
*pBytesRead = error;
*pBytesRead = rv;
return 1;
}
}
@@ -419,3 +318,148 @@ WTSFreeMemory(void *pMemory)
free(pMemory);
}
}
/*****************************************************************************
** **
** **
** Helper functions used by WTSxxx API - do not invoke directly **
** **
** **
*****************************************************************************/
/*
* check if socket is in a writable state - i.e will not block on write
*
* @param sck socket to check
* @param millis timeout value in milliseconds
*
* @return 0 if write will block
* @return 1 if write will not block
******************************************************************************/
static int
can_send(int sck, int millis)
{
struct timeval time;
fd_set wfds;
int select_rv;
/* setup for a select call */
FD_ZERO(&wfds);
FD_SET(sck, &wfds);
time.tv_sec = millis / 1000;
time.tv_usec = (millis * 1000) % 1000000;
/* check if it is ok to write to specified socket */
select_rv = select(sck + 1, 0, &wfds, 0, &time);
return (select_rv > 0) ? 1 : 0;
}
/*****************************************************************************/
static int
can_recv(int sck, int millis)
{
struct timeval time;
fd_set rfds;
int select_rv;
FD_ZERO(&rfds);
FD_SET(sck, &rfds);
time.tv_sec = millis / 1000;
time.tv_usec = (millis * 1000) % 1000000;
select_rv = select(sck + 1, &rfds, 0, 0, &time);
if (select_rv > 0)
{
return 1;
}
return 0;
}
/*****************************************************************************/
static int
send_init(struct wts_obj *wts)
{
char initmsg[64];
memset(initmsg, 0, 64);
/* insert channel name */
strncpy(initmsg, wts->name, 8);
/* insert open mode flags */
initmsg[16] = (wts->flags >> 0) & 0xff;
initmsg[17] = (wts->flags >> 8) & 0xff;
initmsg[18] = (wts->flags >> 16) & 0xff;
initmsg[19] = (wts->flags >> 24) & 0xff;
if (!can_send(wts->fd, 500))
{
LLOGLN(10, ("send_init: send() will block!"));
return 1;
}
if (send(wts->fd, initmsg, 64, 0) != 64)
{
LLOGLN(10, ("send_init: send() failed!"));
return 1;
}
LLOGLN(10, ("send_init: sent ok!"));
return 0;
}
/*****************************************************************************/
static int
get_display_num_from_display(char *display_text)
{
int index;
int mode;
int host_index;
int disp_index;
int scre_index;
char host[256];
char disp[256];
char scre[256];
index = 0;
host_index = 0;
disp_index = 0;
scre_index = 0;
mode = 0;
while (display_text[index] != 0)
{
if (display_text[index] == ':')
{
mode = 1;
}
else if (display_text[index] == '.')
{
mode = 2;
}
else if (mode == 0)
{
host[host_index] = display_text[index];
host_index++;
}
else if (mode == 1)
{
disp[disp_index] = display_text[index];
disp_index++;
}
else if (mode == 2)
{
scre[scre_index] = display_text[index];
scre_index++;
}
index++;
}
host[host_index] = 0;
disp[disp_index] = 0;
scre[scre_index] = 0;
return atoi(disp);
}
+37 -35
View File
@@ -1,8 +1,9 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
* Copyright (C) Thomas Goddard 2012
* Copyright (C) Jay Sorg 2012
* Copyright (C) Thomas Goddard 2012
* Copyright (C) Laxmikant Rashinkar 2012
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,46 +30,47 @@
extern "C" {
#endif
#define WTS_CURRENT_SERVER_HANDLE 0
#define WTS_CURRENT_SESSION 0xffffffff
#define WTS_CHANNEL_OPTION_DYNAMIC 0x00000001
#define WTS_CHANNEL_OPTION_DYNAMIC_PRI_LOW 0x00000000
#define WTS_CHANNEL_OPTION_DYNAMIC_PRI_MED 0x00000002
#define WTS_CHANNEL_OPTION_DYNAMIC_PRI_HIGH 0x00000004
#define WTS_CHANNEL_OPTION_DYNAMIC_PRI_REAL 0x00000006
#define WTS_CHANNEL_OPTION_DYNAMIC_PRI_COMPRESS 0x00000008
#define WTS_CURRENT_SERVER_HANDLE 0x00000000
#define WTS_CURRENT_SESSION 0xffffffff
#define WTS_CHANNEL_OPTION_STATIC 0x00000000
#define WTS_CHANNEL_OPTION_DYNAMIC 0x00000001
#define WTS_CHANNEL_OPTION_DYNAMIC_NO_COMPRESS 0x00000001
#define WTS_CHANNEL_OPTION_DYNAMIC_PRI_LOW 0x00000001
#define WTS_CHANNEL_OPTION_DYNAMIC_PRI_MED 0x00000002
#define WTS_CHANNEL_OPTION_DYNAMIC_PRI_HIGH 0x00000003
#define WTS_CHANNEL_OPTION_DYNAMIC_PRI_REAL 0x00000004
typedef enum _WTS_VIRTUAL_CLASS
{
WTSVirtualClientData,
WTSVirtualFileHandle
WTSVirtualClientData,
WTSVirtualFileHandle
} WTS_VIRTUAL_CLASS;
/*
Reference:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa383464(v=vs.85).aspx
*/
void*
WTSVirtualChannelOpen(void* hServer, unsigned int SessionId,
const char* pVirtualName);
void*
WTSVirtualChannelOpenEx(unsigned int SessionId,
const char* pVirtualName,
unsigned int flags);
int
WTSVirtualChannelWrite(void* hChannelHandle, const char* Buffer,
unsigned int Length, unsigned int* pBytesWritten);
int
WTSVirtualChannelRead(void* hChannelHandle, unsigned int TimeOut,
char* Buffer, unsigned int BufferSize,
unsigned int* pBytesRead);
int
WTSVirtualChannelClose(void* hChannelHandle);
int
WTSVirtualChannelQuery(void* hChannelHandle, WTS_VIRTUAL_CLASS WtsVirtualClass,
void** ppBuffer, unsigned int* pBytesReturned);
void
WTSFreeMemory(void* pMemory);
* Reference:
* http://msdn.microsoft.com/en-us/library/windows/desktop/aa383464(v=vs.85).aspx
*/
void* WTSVirtualChannelOpen(void* hServer, unsigned int SessionId,
const char* pVirtualName);
void* WTSVirtualChannelOpenEx(unsigned int SessionId,
const char* pVirtualName, unsigned int flags);
int WTSVirtualChannelWrite(void* hChannelHandle, const char* Buffer,
unsigned int Length, unsigned int* pBytesWritten);
int WTSVirtualChannelRead(void* hChannelHandle, unsigned int TimeOut,
char* Buffer, unsigned int BufferSize,
unsigned int* pBytesRead);
int WTSVirtualChannelClose(void* hChannelHandle);
int WTSVirtualChannelQuery(void* hChannelHandle, WTS_VIRTUAL_CLASS WtsVirtualClass,
void** ppBuffer, unsigned int* pBytesReturned);
void WTSFreeMemory(void* pMemory);
#ifdef __cplusplus
}