Skip to content

Commit

Permalink
Fix folder redirection according to [MS-RDPEFS] spec
Browse files Browse the repository at this point in the history
  • Loading branch information
Denis Loginov committed Sep 3, 2013
1 parent 27613dc commit be94c5c
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 185 deletions.
2 changes: 2 additions & 0 deletions Cord.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
98E972620BD9D9DF0041110D /* cache.c in Sources */ = {isa = PBXBuildFile; fileRef = 98E972270BD9D9DF0041110D /* cache.c */; };
98E972630BD9D9DF0041110D /* channels.c in Sources */ = {isa = PBXBuildFile; fileRef = 98E972280BD9D9DF0041110D /* channels.c */; };
98E972640BD9D9DF0041110D /* cliprdr.c in Sources */ = {isa = PBXBuildFile; fileRef = 98E972290BD9D9DF0041110D /* cliprdr.c */; };
98E972660BD9D9DF0041110D /* rdpsnd.c in Sources */ = {isa = PBXBuildFile; fileRef = 98E972570BD9D9DF0041110D /* rdpsnd.c */; };
98E972680BD9D9DF0041110D /* CRDApplication.m in Sources */ = {isa = PBXBuildFile; fileRef = 98E9722D0BD9D9DF0041110D /* CRDApplication.m */; };
98E9726C0BD9D9DF0041110D /* CRDLabelCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 98E972310BD9D9DF0041110D /* CRDLabelCell.m */; };
98E9726E0BD9D9DF0041110D /* CRDServerCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 98E972330BD9D9DF0041110D /* CRDServerCell.m */; };
Expand Down Expand Up @@ -664,6 +665,7 @@
98E972620BD9D9DF0041110D /* cache.c in Sources */,
98E972630BD9D9DF0041110D /* channels.c in Sources */,
98E972640BD9D9DF0041110D /* cliprdr.c in Sources */,
98E972660BD9D9DF0041110D /* rdpsnd.c in Sources */,
98E972680BD9D9DF0041110D /* CRDApplication.m in Sources */,
98E9726C0BD9D9DF0041110D /* CRDLabelCell.m in Sources */,
98E9726E0BD9D9DF0041110D /* CRDServerCell.m in Sources */,
Expand Down
5 changes: 5 additions & 0 deletions Source/CRDSession.m
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,11 @@ - (BOOL)connect

rdpdr_init(conn);
cliprdr_init(conn);

if (forwardDisks) {
conn->forwardAudio = forwardAudio;
rdpsnd_init(conn); // Required per official [MS-RDPEFS] specification
}

// Make the connection
BOOL connected = rdp_connect(conn,
Expand Down
4 changes: 2 additions & 2 deletions Source/proto.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,8 +183,8 @@ RD_BOOL rdpdr_abort_io(RDConnectionRef conn, uint32 fd, uint32 major, NTStatus s

#pragma mark -
#pragma mark rdpsnd.c
void rdpsnd_send_completion(uint16 tick, uint8 packet_index);
RD_BOOL rdpsnd_init(void);
void rdpsnd_send_completion(RDConnectionRef conn, uint16 tick, uint8 packet_index);
RD_BOOL rdpsnd_init(RDConnectionRef conn);

#pragma mark -
#pragma mark rdpsnd_oss.c
Expand Down
227 changes: 44 additions & 183 deletions Source/rdpsnd.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
#define RDPSND_SERVERTICK 6
#define RDPSND_NEGOTIATE 7

#define RDPSND_DISABLE 2

#define MAX_QUEUE 10

RD_BOOL g_dsp_busy = False;
Expand All @@ -47,48 +49,47 @@ static unsigned int current_format;
unsigned int queue_hi, queue_lo;
struct audio_packet packet_queue[MAX_QUEUE];

void (*wave_out_play) (void);

static RDStreamRef
rdpsnd_init_packet(uint16 type, uint16 size)
rdpsnd_init_packet(RDConnectionRef conn, uint16 type, uint16 size)
{
RDStreamRef s;

s = channel_init(rdpsnd_channel, size + 4);
s = channel_init(conn, rdpsnd_channel, size + 4);
out_uint16_le(s, type);
out_uint16_le(s, size);
return s;
}

static void
rdpsnd_send(RDStreamRef s)
rdpsnd_send(RDConnectionRef conn, RDStreamRef s)
{
#ifdef RDPSND_DEBUG
printf("RDPSND send:\n");
hexdump(s->channel_hdr + 8, s->end - s->channel_hdr - 8);
#endif

channel_send(s, rdpsnd_channel);
channel_send(conn, s, rdpsnd_channel);
}

void
rdpsnd_send_completion(uint16 tick, uint8 packet_index)
rdpsnd_send_completion(RDConnectionRef conn, uint16 tick, uint8 packet_index)
{
RDStreamRef s;

s = rdpsnd_init_packet(RDPSND_COMPLETION, 4);
s = rdpsnd_init_packet(conn, RDPSND_COMPLETION, 4);
out_uint16_le(s, tick);
out_uint8(s, packet_index);
out_uint8(s, 0);
s_mark_end(s);
rdpsnd_send(s);
rdpsnd_send(conn, s);
}

static void
rdpsnd_process_negotiate(RDStreamRef in)
rdpsnd_process_negotiate(RDConnectionRef conn, RDStreamRef in)
{
unsigned int in_format_count, i;
RDWaveFormat *format;
RDStreamRef out;
RDStreamRef outStream;
RD_BOOL device_available = False;
int readcnt;
Expand All @@ -98,12 +99,6 @@ rdpsnd_process_negotiate(RDStreamRef in)
in_uint16_le(in, in_format_count);
in_uint8s(in, 4); /* pad, status, pad */

if (current_driver->wave_out_open())
{
current_driver->wave_out_close();
device_available = True;
}

format_count = 0;
if (s_check_rem(in, 18 * in_format_count))
{
Expand All @@ -130,7 +125,7 @@ rdpsnd_process_negotiate(RDStreamRef in)
in_uint8a(in, format->cb, readcnt);
in_uint8s(in, discardcnt);

if (device_available && current_driver->wave_out_format_supported(format))
if (device_available)
{
format_count++;
if (format_count == MAX_SOUND_FORMATS)
Expand All @@ -139,35 +134,36 @@ rdpsnd_process_negotiate(RDStreamRef in)
}
}

out = rdpsnd_init_packet(RDPSND_NEGOTIATE | 0x200, 20 + 18 * format_count);
out_uint32_le(outStream, 3); /* flags */
out_uint32(outStream, 0xffffffff); /* volume */
out_uint32(outStream, 0); /* pitch */
out_uint16(outStream, 0); /* UDP port */

out_uint16_le(outStream, format_count);
out_uint8(outStream, 0x95); /* pad? */
out_uint16_le(outStream, 2); /* status */
out_uint8(outStream, 0x77); /* pad? */
out = rdpsnd_init_packet(conn, RDPSND_NEGOTIATE | 0x200, 20 + 18 * format_count);
if (conn->forwardAudio != RDPSND_DISABLE) {
out_uint32_le(outStream, 3); /* flags */
out_uint32(outStream, 0xffffffff); /* volume */
out_uint32(outStream, 0); /* pitch */
out_uint16(outStream, 0); /* UDP port */

for (i = 0; i < format_count; i++)
{
format = &formats[i];
out_uint16_le(outStream, format->wFormatTag);
out_uint16_le(outStream, format->nChannels);
out_uint32_le(outStream, format->nSamplesPerSec);
out_uint32_le(outStream, format->nAvgBytesPerSec);
out_uint16_le(outStream, format->nBlockAlign);
out_uint16_le(outStream, format->wBitsPerSample);
out_uint16(out, 0); /* cbSize */
}
out_uint16_le(outStream, format_count);
out_uint8(outStream, 0x95); /* pad? */
out_uint16_le(outStream, 2); /* status */
out_uint8(outStream, 0x77); /* pad? */

for (i = 0; i < format_count; i++)
{
format = &formats[i];
out_uint16_le(outStream, format->wFormatTag);
out_uint16_le(outStream, format->nChannels);
out_uint32_le(outStream, format->nSamplesPerSec);
out_uint32_le(outStream, format->nAvgBytesPerSec);
out_uint16_le(outStream, format->nBlockAlign);
out_uint16_le(outStream, format->wBitsPerSample);
out_uint16(out, 0); /* cbSize */
}
}
s_mark_end(out);
rdpsnd_send(out);
rdpsnd_send(conn, out);
}

static void
rdpsnd_process_servertick(RDStreamRef in)
rdpsnd_process_servertick(RDConnectionRef conn, RDStreamRef in)
{
uint16 tick1, tick2;
RDStreamRef out;
Expand All @@ -176,15 +172,15 @@ rdpsnd_process_servertick(RDStreamRef in)
in_uint16_le(in, tick1);
in_uint16_le(in, tick2);

out = rdpsnd_init_packet(RDPSND_SERVERTICK | 0x2300, 4);
out = rdpsnd_init_packet(conn, RDPSND_SERVERTICK | 0x2300, 4);
out_uint16_le(out, tick1);
out_uint16_le(out, tick2);
s_mark_end(out);
rdpsnd_send(out);
rdpsnd_send(conn, out);
}

static void
rdpsnd_process(RDStreamRef s)
rdpsnd_process(RDConnectionRef conn, RDStreamRef s)
{
uint8 type;
uint16 datalen;
Expand All @@ -210,21 +206,13 @@ rdpsnd_process(RDStreamRef s)
{
if (!device_open && !current_driver->wave_out_open())
{
rdpsnd_send_completion(tick, packet_index);
return;
}
if (!current_driver->wave_out_set_format(&formats[format]))
{
rdpsnd_send_completion(tick, packet_index);
current_driver->wave_out_close();
device_open = False;
rdpsnd_send_completion(conn, tick, packet_index);
return;
}
device_open = True;
current_format = format;
}

current_driver->wave_out_write(s, tick, packet_index);
awaiting_data_packet = False;
return;
}
Expand All @@ -246,10 +234,10 @@ rdpsnd_process(RDStreamRef s)
device_open = False;
break;
case RDPSND_NEGOTIATE:
rdpsnd_process_negotiate(s);
rdpsnd_process_negotiate(conn, s);
break;
case RDPSND_SERVERTICK:
rdpsnd_process_servertick(s);
rdpsnd_process_servertick(conn, s);
break;
case RDPSND_SET_VOLUME:
in_uint32(s, volume);
Expand All @@ -265,141 +253,14 @@ rdpsnd_process(RDStreamRef s)
}

RD_BOOL
rdpsnd_init(void)
rdpsnd_init(RDConnectionRef conn)
{
rdpsnd_channel =
channel_register("rdpsnd", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP,
channel_register(conn, "rdpsnd", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP,
rdpsnd_process);
return (rdpsnd_channel != NULL);
}

RD_BOOL
rdpsnd_auto_open(void)
{
current_driver = drivers;
while (current_driver != NULL)
{
DEBUG(("trying %s...\n", current_driver->name));
if (current_driver->wave_out_open())
{
DEBUG(("selected %s\n", current_driver->name));
return True;
}
g_dsp_fd = 0;
current_driver = current_driver->next;
}

warning("no working audio-driver found\n");

return False;
}

void
rdpsnd_register_drivers(char *options)
{
struct audio_driver **reg;

/* The order of registrations define the probe-order
when opening the device for the first time */
reg = &drivers;
#if defined(RDPSND_ALSA)
*reg = alsa_register(options);
reg = &((*reg)->next);
#endif
#if defined(RDPSND_OSS)
*reg = oss_register(options);
reg = &((*reg)->next);
#endif
#if defined(RDPSND_SUN)
*reg = sun_register(options);
reg = &((*reg)->next);
#endif
#if defined(RDPSND_SGI)
*reg = sgi_register(options);
reg = &((*reg)->next);
#endif
#if defined(RDPSND_LIBAO)
*reg = libao_register(options);
reg = &((*reg)->next);
#endif
}

RD_BOOL
rdpsnd_select_driver(char *driver, char *options)
{
static struct audio_driver auto_driver;
struct audio_driver *pos;

drivers = NULL;
rdpsnd_register_drivers(options);

if (!driver)
{
auto_driver.wave_out_open = &rdpsnd_auto_open;
current_driver = &auto_driver;
return True;
}

pos = drivers;
while (pos != NULL)
{
if (!strcmp(pos->name, driver))
{
DEBUG(("selected %s\n", pos->name));
current_driver = pos;
return True;
}
pos = pos->next;
}
return False;
}

void
rdpsnd_show_help(void)
{
struct audio_driver *pos;

rdpsnd_register_drivers(NULL);

pos = drivers;
while (pos != NULL)
{
fprintf(stderr, " %s:\t%s\n", pos->name, pos->description);
pos = pos->next;
}
}

inline void
rdpsnd_play(void)
{
current_driver->wave_out_play();
}

rdpsnd_queue_write(STREAM s, uint16 tick, uint8 index)
{
struct audio_packet *packet = &packet_queue[queue_hi];
unsigned int next_hi = (queue_hi + 1) % MAX_QUEUE;

if (next_hi == queue_lo)
{
error("No space to queue audio packet\n");
return;
}

queue_hi = next_hi;

packet->s = *s;
packet->tick = tick;
packet->index = index;
packet->s.p += 4;

/* we steal the data buffer from s, give it a new one */
s->data = malloc(s->size);

if (!g_dsp_busy)
current_driver->wave_out_play();
}

inline struct audio_packet *
rdpsnd_queue_current_packet(void)
{
Expand Down
1 change: 1 addition & 0 deletions Source/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ struct _RDConnection

// State flags
int isConnected, useRdp5, useEncryption, useBitmapCompression, rdp5PerformanceFlags, consoleSession, bitmapCache, bitmapCachePersist, bitmapCachePrecache, desktopSave, polygonEllipseOrders, licenseIssued, notifyStamp, pstcacheEnumerated;
long forwardAudio;
RDP_ORDER_STATE orderState;

// Keyboard
Expand Down

1 comment on commit be94c5c

@peelman
Copy link
Collaborator

@peelman peelman commented on be94c5c Sep 9, 2013

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bravo dude. nice code!

Please sign in to comment.