VirtualBox

source: vbox/trunk/src/VBox/RDP/client/rdpdr.c@ 8973

Last change on this file since 8973 was 7826, checked in by vboxsync, 17 years ago

Export modified rdesktop version including USB support to OSE. It's GPL anyway.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 26.2 KB
Line 
1/* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3 Copyright (C) Matthew Chapman 1999-2005
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18*/
19
20/*
21 Here are some resources, for your IRP hacking pleasure:
22
23 http://cvs.sourceforge.net/viewcvs.py/mingw/w32api/include/ddk/winddk.h?view=markup
24
25 http://win32.mvps.org/ntfs/streams.cpp
26
27 http://www.acc.umu.se/~bosse/ntifs.h
28
29 http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/NT%20Objects/File/
30
31 http://us1.samba.org/samba/ftp/specs/smb-nt01.txt
32
33 http://www.osronline.com/
34*/
35
36#include <unistd.h>
37#include <sys/types.h>
38#include <sys/time.h>
39#include <dirent.h> /* opendir, closedir, readdir */
40#include <time.h>
41#include <errno.h>
42#include "rdesktop.h"
43
44#define IRP_MJ_CREATE 0x00
45#define IRP_MJ_CLOSE 0x02
46#define IRP_MJ_READ 0x03
47#define IRP_MJ_WRITE 0x04
48#define IRP_MJ_QUERY_INFORMATION 0x05
49#define IRP_MJ_SET_INFORMATION 0x06
50#define IRP_MJ_QUERY_VOLUME_INFORMATION 0x0a
51#define IRP_MJ_DIRECTORY_CONTROL 0x0c
52#define IRP_MJ_DEVICE_CONTROL 0x0e
53#define IRP_MJ_LOCK_CONTROL 0x11
54
55#define IRP_MN_QUERY_DIRECTORY 0x01
56#define IRP_MN_NOTIFY_CHANGE_DIRECTORY 0x02
57
58extern char g_hostname[16];
59extern DEVICE_FNS serial_fns;
60extern DEVICE_FNS printer_fns;
61extern DEVICE_FNS parallel_fns;
62extern DEVICE_FNS disk_fns;
63extern FILEINFO g_fileinfo[];
64extern BOOL g_notify_stamp;
65
66static VCHANNEL *rdpdr_channel;
67
68/* If select() times out, the request for the device with handle g_min_timeout_fd is aborted */
69NTHANDLE g_min_timeout_fd;
70uint32 g_num_devices;
71
72/* Table with information about rdpdr devices */
73RDPDR_DEVICE g_rdpdr_device[RDPDR_MAX_DEVICES];
74char *g_rdpdr_clientname = NULL;
75
76/* Used to store incoming io request, until they are ready to be completed */
77/* using a linked list ensures that they are processed in the right order, */
78/* if multiple ios are being done on the same fd */
79struct async_iorequest
80{
81 uint32 fd, major, minor, offset, device, id, length, partial_len;
82 long timeout, /* Total timeout */
83 itv_timeout; /* Interval timeout (between serial characters) */
84 uint8 *buffer;
85 DEVICE_FNS *fns;
86
87 struct async_iorequest *next; /* next element in list */
88};
89
90struct async_iorequest *g_iorequest;
91
92/* Return device_id for a given handle */
93int
94get_device_index(NTHANDLE handle)
95{
96 int i;
97 for (i = 0; i < RDPDR_MAX_DEVICES; i++)
98 {
99 if (g_rdpdr_device[i].handle == handle)
100 return i;
101 }
102 return -1;
103}
104
105/* Converts a windows path to a unix path */
106void
107convert_to_unix_filename(char *filename)
108{
109 char *p;
110
111 while ((p = strchr(filename, '\\')))
112 {
113 *p = '/';
114 }
115}
116
117static BOOL
118rdpdr_handle_ok(int device, int handle)
119{
120 switch (g_rdpdr_device[device].device_type)
121 {
122 case DEVICE_TYPE_PARALLEL:
123 case DEVICE_TYPE_SERIAL:
124 case DEVICE_TYPE_PRINTER:
125 case DEVICE_TYPE_SCARD:
126 if (g_rdpdr_device[device].handle != handle)
127 return False;
128 break;
129 case DEVICE_TYPE_DISK:
130 if (g_fileinfo[handle].device_id != device)
131 return False;
132 break;
133 }
134 return True;
135}
136
137/* Add a new io request to the table containing pending io requests so it won't block rdesktop */
138static BOOL
139add_async_iorequest(uint32 device, uint32 file, uint32 id, uint32 major, uint32 length,
140 DEVICE_FNS * fns, uint32 total_timeout, uint32 interval_timeout, uint8 * buffer,
141 uint32 offset)
142{
143 struct async_iorequest *iorq;
144
145 if (g_iorequest == NULL)
146 {
147 g_iorequest = (struct async_iorequest *) xmalloc(sizeof(struct async_iorequest));
148 if (!g_iorequest)
149 return False;
150 g_iorequest->fd = 0;
151 g_iorequest->next = NULL;
152 }
153
154 iorq = g_iorequest;
155
156 while (iorq->fd != 0)
157 {
158 /* create new element if needed */
159 if (iorq->next == NULL)
160 {
161 iorq->next =
162 (struct async_iorequest *) xmalloc(sizeof(struct async_iorequest));
163 if (!iorq->next)
164 return False;
165 iorq->next->fd = 0;
166 iorq->next->next = NULL;
167 }
168 iorq = iorq->next;
169 }
170 iorq->device = device;
171 iorq->fd = file;
172 iorq->id = id;
173 iorq->major = major;
174 iorq->length = length;
175 iorq->partial_len = 0;
176 iorq->fns = fns;
177 iorq->timeout = total_timeout;
178 iorq->itv_timeout = interval_timeout;
179 iorq->buffer = buffer;
180 iorq->offset = offset;
181 return True;
182}
183
184static void
185rdpdr_send_connect(void)
186{
187 uint8 magic[4] = "rDCC";
188 STREAM s;
189
190 s = channel_init(rdpdr_channel, 12);
191 out_uint8a(s, magic, 4);
192 out_uint16_le(s, 1); /* unknown */
193 out_uint16_le(s, 5);
194 out_uint32_be(s, 0x815ed39d); /* IP address (use 127.0.0.1) 0x815ed39d */
195 s_mark_end(s);
196 channel_send(s, rdpdr_channel);
197}
198
199
200static void
201rdpdr_send_name(void)
202{
203 uint8 magic[4] = "rDNC";
204 STREAM s;
205 uint32 hostlen;
206
207 if (NULL == g_rdpdr_clientname)
208 {
209 g_rdpdr_clientname = g_hostname;
210 }
211 hostlen = (strlen(g_rdpdr_clientname) + 1) * 2;
212
213 s = channel_init(rdpdr_channel, 16 + hostlen);
214 out_uint8a(s, magic, 4);
215 out_uint16_le(s, 0x63); /* unknown */
216 out_uint16_le(s, 0x72);
217 out_uint32(s, 0);
218 out_uint32_le(s, hostlen);
219 rdp_out_unistr(s, g_rdpdr_clientname, hostlen - 2);
220 s_mark_end(s);
221 channel_send(s, rdpdr_channel);
222}
223
224/* Returns the size of the payload of the announce packet */
225static int
226announcedata_size()
227{
228 int size, i;
229 PRINTER *printerinfo;
230
231 size = 8; /* static announce size */
232 size += g_num_devices * 0x14;
233
234 for (i = 0; i < g_num_devices; i++)
235 {
236 if (g_rdpdr_device[i].device_type == DEVICE_TYPE_PRINTER)
237 {
238 printerinfo = (PRINTER *) g_rdpdr_device[i].pdevice_data;
239 printerinfo->bloblen =
240 printercache_load_blob(printerinfo->printer, &(printerinfo->blob));
241
242 size += 0x18;
243 size += 2 * strlen(printerinfo->driver) + 2;
244 size += 2 * strlen(printerinfo->printer) + 2;
245 size += printerinfo->bloblen;
246 }
247 }
248
249 return size;
250}
251
252static void
253rdpdr_send_available(void)
254{
255
256 uint8 magic[4] = "rDAD";
257 uint32 driverlen, printerlen, bloblen;
258 int i;
259 STREAM s;
260 PRINTER *printerinfo;
261
262 s = channel_init(rdpdr_channel, announcedata_size());
263 out_uint8a(s, magic, 4);
264 out_uint32_le(s, g_num_devices);
265
266 for (i = 0; i < g_num_devices; i++)
267 {
268 out_uint32_le(s, g_rdpdr_device[i].device_type);
269 out_uint32_le(s, i); /* RDP Device ID */
270 /* Is it possible to use share names longer than 8 chars?
271 /astrand */
272 out_uint8p(s, g_rdpdr_device[i].name, 8);
273
274 switch (g_rdpdr_device[i].device_type)
275 {
276 case DEVICE_TYPE_PRINTER:
277 printerinfo = (PRINTER *) g_rdpdr_device[i].pdevice_data;
278
279 driverlen = 2 * strlen(printerinfo->driver) + 2;
280 printerlen = 2 * strlen(printerinfo->printer) + 2;
281 bloblen = printerinfo->bloblen;
282
283 out_uint32_le(s, 24 + driverlen + printerlen + bloblen); /* length of extra info */
284 out_uint32_le(s, printerinfo->default_printer ? 2 : 0);
285 out_uint8s(s, 8); /* unknown */
286 out_uint32_le(s, driverlen);
287 out_uint32_le(s, printerlen);
288 out_uint32_le(s, bloblen);
289 rdp_out_unistr(s, printerinfo->driver, driverlen - 2);
290 rdp_out_unistr(s, printerinfo->printer, printerlen - 2);
291 out_uint8a(s, printerinfo->blob, bloblen);
292
293 if (printerinfo->blob)
294 xfree(printerinfo->blob); /* Blob is sent twice if reconnecting */
295 break;
296 default:
297 out_uint32(s, 0);
298 }
299 }
300#if 0
301 out_uint32_le(s, 0x20); /* Device type 0x20 - smart card */
302 out_uint32_le(s, 0);
303 out_uint8p(s, "SCARD", 5);
304 out_uint8s(s, 3);
305 out_uint32(s, 0);
306#endif
307
308 s_mark_end(s);
309 channel_send(s, rdpdr_channel);
310}
311
312static void
313rdpdr_send_completion(uint32 device, uint32 id, uint32 status, uint32 result, uint8 * buffer,
314 uint32 length)
315{
316 uint8 magic[4] = "rDCI";
317 STREAM s;
318
319 s = channel_init(rdpdr_channel, 20 + length);
320 out_uint8a(s, magic, 4);
321 out_uint32_le(s, device);
322 out_uint32_le(s, id);
323 out_uint32_le(s, status);
324 out_uint32_le(s, result);
325 out_uint8p(s, buffer, length);
326 s_mark_end(s);
327 /* JIF */
328#ifdef WITH_DEBUG_RDP5
329 printf("--> rdpdr_send_completion\n");
330 /* hexdump(s->channel_hdr + 8, s->end - s->channel_hdr - 8); */
331#endif
332 channel_send(s, rdpdr_channel);
333}
334
335static void
336rdpdr_process_irp(STREAM s)
337{
338 uint32 result = 0,
339 length = 0,
340 desired_access = 0,
341 request,
342 file,
343 info_level,
344 buffer_len,
345 id,
346 major,
347 minor,
348 device,
349 offset,
350 bytes_in,
351 bytes_out,
352 error_mode,
353 share_mode, disposition, total_timeout, interval_timeout, flags_and_attributes = 0;
354
355 char filename[PATH_MAX];
356 uint8 *buffer, *pst_buf;
357 struct stream out;
358 DEVICE_FNS *fns;
359 BOOL rw_blocking = True;
360 NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
361
362 in_uint32_le(s, device);
363 in_uint32_le(s, file);
364 in_uint32_le(s, id);
365 in_uint32_le(s, major);
366 in_uint32_le(s, minor);
367
368 buffer_len = 0;
369 buffer = (uint8 *) xmalloc(1024);
370 buffer[0] = 0;
371
372 switch (g_rdpdr_device[device].device_type)
373 {
374 case DEVICE_TYPE_SERIAL:
375
376 fns = &serial_fns;
377 rw_blocking = False;
378 break;
379
380 case DEVICE_TYPE_PARALLEL:
381
382 fns = &parallel_fns;
383 rw_blocking = False;
384 break;
385
386 case DEVICE_TYPE_PRINTER:
387
388 fns = &printer_fns;
389 break;
390
391 case DEVICE_TYPE_DISK:
392
393 fns = &disk_fns;
394 rw_blocking = False;
395 break;
396
397 case DEVICE_TYPE_SCARD:
398 default:
399
400 error("IRP for bad device %ld\n", device);
401 return;
402 }
403
404 switch (major)
405 {
406 case IRP_MJ_CREATE:
407
408 in_uint32_be(s, desired_access);
409 in_uint8s(s, 0x08); /* unknown */
410 in_uint32_le(s, error_mode);
411 in_uint32_le(s, share_mode);
412 in_uint32_le(s, disposition);
413 in_uint32_le(s, flags_and_attributes);
414 in_uint32_le(s, length);
415
416 if (length && (length / 2) < 256)
417 {
418 rdp_in_unistr(s, filename, length);
419 convert_to_unix_filename(filename);
420 }
421 else
422 {
423 filename[0] = 0;
424 }
425
426 if (!fns->create)
427 {
428 status = STATUS_NOT_SUPPORTED;
429 break;
430 }
431
432 status = fns->create(device, desired_access, share_mode, disposition,
433 flags_and_attributes, filename, &result);
434 buffer_len = 1;
435 break;
436
437 case IRP_MJ_CLOSE:
438 if (!fns->close)
439 {
440 status = STATUS_NOT_SUPPORTED;
441 break;
442 }
443
444 status = fns->close(file);
445 break;
446
447 case IRP_MJ_READ:
448
449 if (!fns->read)
450 {
451 status = STATUS_NOT_SUPPORTED;
452 break;
453 }
454
455 in_uint32_le(s, length);
456 in_uint32_le(s, offset);
457#if WITH_DEBUG_RDP5
458 DEBUG(("RDPDR IRP Read (length: %d, offset: %d)\n", length, offset));
459#endif
460 if (!rdpdr_handle_ok(device, file))
461 {
462 status = STATUS_INVALID_HANDLE;
463 break;
464 }
465
466 if (rw_blocking) /* Complete read immediately */
467 {
468 buffer = (uint8 *) xrealloc((void *) buffer, length);
469 if (!buffer)
470 {
471 status = STATUS_CANCELLED;
472 break;
473 }
474 status = fns->read(file, buffer, length, offset, &result);
475 buffer_len = result;
476 break;
477 }
478
479 /* Add request to table */
480 pst_buf = (uint8 *) xmalloc(length);
481 if (!pst_buf)
482 {
483 status = STATUS_CANCELLED;
484 break;
485 }
486 serial_get_timeout(file, length, &total_timeout, &interval_timeout);
487 if (add_async_iorequest
488 (device, file, id, major, length, fns, total_timeout, interval_timeout,
489 pst_buf, offset))
490 {
491 status = STATUS_PENDING;
492 break;
493 }
494
495 status = STATUS_CANCELLED;
496 break;
497 case IRP_MJ_WRITE:
498
499 buffer_len = 1;
500
501 if (!fns->write)
502 {
503 status = STATUS_NOT_SUPPORTED;
504 break;
505 }
506
507 in_uint32_le(s, length);
508 in_uint32_le(s, offset);
509 in_uint8s(s, 0x18);
510#if WITH_DEBUG_RDP5
511 DEBUG(("RDPDR IRP Write (length: %d)\n", result));
512#endif
513 if (!rdpdr_handle_ok(device, file))
514 {
515 status = STATUS_INVALID_HANDLE;
516 break;
517 }
518
519 if (rw_blocking) /* Complete immediately */
520 {
521 status = fns->write(file, s->p, length, offset, &result);
522 break;
523 }
524
525 /* Add to table */
526 pst_buf = (uint8 *) xmalloc(length);
527 if (!pst_buf)
528 {
529 status = STATUS_CANCELLED;
530 break;
531 }
532
533 in_uint8a(s, pst_buf, length);
534
535 if (add_async_iorequest
536 (device, file, id, major, length, fns, 0, 0, pst_buf, offset))
537 {
538 status = STATUS_PENDING;
539 break;
540 }
541
542 status = STATUS_CANCELLED;
543 break;
544
545 case IRP_MJ_QUERY_INFORMATION:
546
547 if (g_rdpdr_device[device].device_type != DEVICE_TYPE_DISK)
548 {
549 status = STATUS_INVALID_HANDLE;
550 break;
551 }
552 in_uint32_le(s, info_level);
553
554 out.data = out.p = buffer;
555 out.size = sizeof(buffer);
556 status = disk_query_information(file, info_level, &out);
557 result = buffer_len = out.p - out.data;
558
559 break;
560
561 case IRP_MJ_SET_INFORMATION:
562
563 if (g_rdpdr_device[device].device_type != DEVICE_TYPE_DISK)
564 {
565 status = STATUS_INVALID_HANDLE;
566 break;
567 }
568
569 in_uint32_le(s, info_level);
570
571 out.data = out.p = buffer;
572 out.size = sizeof(buffer);
573 status = disk_set_information(file, info_level, s, &out);
574 result = buffer_len = out.p - out.data;
575 break;
576
577 case IRP_MJ_QUERY_VOLUME_INFORMATION:
578
579 if (g_rdpdr_device[device].device_type != DEVICE_TYPE_DISK)
580 {
581 status = STATUS_INVALID_HANDLE;
582 break;
583 }
584
585 in_uint32_le(s, info_level);
586
587 out.data = out.p = buffer;
588 out.size = sizeof(buffer);
589 status = disk_query_volume_information(file, info_level, &out);
590 result = buffer_len = out.p - out.data;
591 break;
592
593 case IRP_MJ_DIRECTORY_CONTROL:
594
595 if (g_rdpdr_device[device].device_type != DEVICE_TYPE_DISK)
596 {
597 status = STATUS_INVALID_HANDLE;
598 break;
599 }
600
601 switch (minor)
602 {
603 case IRP_MN_QUERY_DIRECTORY:
604
605 in_uint32_le(s, info_level);
606 in_uint8s(s, 1);
607 in_uint32_le(s, length);
608 in_uint8s(s, 0x17);
609 if (length && length < 2 * 255)
610 {
611 rdp_in_unistr(s, filename, length);
612 convert_to_unix_filename(filename);
613 }
614 else
615 {
616 filename[0] = 0;
617 }
618 out.data = out.p = buffer;
619 out.size = sizeof(buffer);
620 status = disk_query_directory(file, info_level, filename,
621 &out);
622 result = buffer_len = out.p - out.data;
623 if (!buffer_len)
624 buffer_len++;
625 break;
626
627 case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
628
629 /* JIF
630 unimpl("IRP major=0x%x minor=0x%x: IRP_MN_NOTIFY_CHANGE_DIRECTORY\n", major, minor); */
631
632 in_uint32_le(s, info_level); /* notify mask */
633
634 g_notify_stamp = True;
635
636 status = disk_create_notify(file, info_level);
637 result = 0;
638
639 if (status == STATUS_PENDING)
640 add_async_iorequest(device, file, id, major, length,
641 fns, 0, 0, NULL, 0);
642 break;
643
644 default:
645
646 status = STATUS_INVALID_PARAMETER;
647 /* JIF */
648 unimpl("IRP major=0x%x minor=0x%x\n", major, minor);
649 }
650 break;
651
652 case IRP_MJ_DEVICE_CONTROL:
653
654 if (!fns->device_control)
655 {
656 status = STATUS_NOT_SUPPORTED;
657 break;
658 }
659
660 in_uint32_le(s, bytes_out);
661 in_uint32_le(s, bytes_in);
662 in_uint32_le(s, request);
663 in_uint8s(s, 0x14);
664
665 buffer = (uint8 *) xrealloc((void *) buffer, bytes_out + 0x14);
666 if (!buffer)
667 {
668 status = STATUS_CANCELLED;
669 break;
670 }
671
672 out.data = out.p = buffer;
673 out.size = sizeof(buffer);
674 status = fns->device_control(file, request, s, &out);
675 result = buffer_len = out.p - out.data;
676
677 /* Serial SERIAL_WAIT_ON_MASK */
678 if (status == STATUS_PENDING)
679 {
680 if (add_async_iorequest
681 (device, file, id, major, length, fns, 0, 0, NULL, 0))
682 {
683 status = STATUS_PENDING;
684 break;
685 }
686 }
687 break;
688
689
690 case IRP_MJ_LOCK_CONTROL:
691
692 if (g_rdpdr_device[device].device_type != DEVICE_TYPE_DISK)
693 {
694 status = STATUS_INVALID_HANDLE;
695 break;
696 }
697
698 in_uint32_le(s, info_level);
699
700 out.data = out.p = buffer;
701 out.size = sizeof(buffer);
702 /* FIXME: Perhaps consider actually *do*
703 something here :-) */
704 status = STATUS_SUCCESS;
705 result = buffer_len = out.p - out.data;
706 break;
707
708 default:
709 unimpl("IRP major=0x%x minor=0x%x\n", major, minor);
710 break;
711 }
712
713 if (status != STATUS_PENDING)
714 {
715 rdpdr_send_completion(device, id, status, result, buffer, buffer_len);
716 }
717 if (buffer)
718 xfree(buffer);
719 buffer = NULL;
720}
721
722static void
723rdpdr_send_clientcapabilty(void)
724{
725 uint8 magic[4] = "rDPC";
726 STREAM s;
727
728 s = channel_init(rdpdr_channel, 0x50);
729 out_uint8a(s, magic, 4);
730 out_uint32_le(s, 5); /* count */
731 out_uint16_le(s, 1); /* first */
732 out_uint16_le(s, 0x28); /* length */
733 out_uint32_le(s, 1);
734 out_uint32_le(s, 2);
735 out_uint16_le(s, 2);
736 out_uint16_le(s, 5);
737 out_uint16_le(s, 1);
738 out_uint16_le(s, 5);
739 out_uint16_le(s, 0xFFFF);
740 out_uint16_le(s, 0);
741 out_uint32_le(s, 0);
742 out_uint32_le(s, 3);
743 out_uint32_le(s, 0);
744 out_uint32_le(s, 0);
745 out_uint16_le(s, 2); /* second */
746 out_uint16_le(s, 8); /* length */
747 out_uint32_le(s, 1);
748 out_uint16_le(s, 3); /* third */
749 out_uint16_le(s, 8); /* length */
750 out_uint32_le(s, 1);
751 out_uint16_le(s, 4); /* fourth */
752 out_uint16_le(s, 8); /* length */
753 out_uint32_le(s, 1);
754 out_uint16_le(s, 5); /* fifth */
755 out_uint16_le(s, 8); /* length */
756 out_uint32_le(s, 1);
757
758 s_mark_end(s);
759 channel_send(s, rdpdr_channel);
760}
761
762static void
763rdpdr_process(STREAM s)
764{
765 uint32 handle;
766 uint8 *magic;
767
768#if WITH_DEBUG_RDP5
769 printf("--- rdpdr_process ---\n");
770 hexdump(s->p, s->end - s->p);
771#endif
772 in_uint8p(s, magic, 4);
773
774 if ((magic[0] == 'r') && (magic[1] == 'D'))
775 {
776 if ((magic[2] == 'R') && (magic[3] == 'I'))
777 {
778 rdpdr_process_irp(s);
779 return;
780 }
781 if ((magic[2] == 'n') && (magic[3] == 'I'))
782 {
783 rdpdr_send_connect();
784 rdpdr_send_name();
785 return;
786 }
787 if ((magic[2] == 'C') && (magic[3] == 'C'))
788 {
789 /* connect from server */
790 rdpdr_send_clientcapabilty();
791 rdpdr_send_available();
792 return;
793 }
794 if ((magic[2] == 'r') && (magic[3] == 'd'))
795 {
796 /* connect to a specific resource */
797 in_uint32(s, handle);
798#if WITH_DEBUG_RDP5
799 DEBUG(("RDPDR: Server connected to resource %d\n", handle));
800#endif
801 return;
802 }
803 if ((magic[2] == 'P') && (magic[3] == 'S'))
804 {
805 /* server capability */
806 return;
807 }
808 }
809 if ((magic[0] == 'R') && (magic[1] == 'P'))
810 {
811 if ((magic[2] == 'C') && (magic[3] == 'P'))
812 {
813 printercache_process(s);
814 return;
815 }
816 }
817 unimpl("RDPDR packet type %c%c%c%c\n", magic[0], magic[1], magic[2], magic[3]);
818}
819
820BOOL
821rdpdr_init()
822{
823 if (g_num_devices > 0)
824 {
825 rdpdr_channel =
826 channel_register("rdpdr",
827 CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_COMPRESS_RDP,
828 rdpdr_process);
829 }
830
831 return (rdpdr_channel != NULL);
832}
833
834/* Add file descriptors of pending io request to select() */
835void
836rdpdr_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv, BOOL * timeout)
837{
838 uint32 select_timeout = 0; /* Timeout value to be used for select() (in millisecons). */
839 struct async_iorequest *iorq;
840 char c;
841
842 iorq = g_iorequest;
843 while (iorq != NULL)
844 {
845 if (iorq->fd != 0)
846 {
847 switch (iorq->major)
848 {
849 case IRP_MJ_READ:
850 /* Is this FD valid? FDs will
851 be invalid when
852 reconnecting. FIXME: Real
853 support for reconnects. */
854
855 FD_SET(iorq->fd, rfds);
856 *n = MAX(*n, iorq->fd);
857
858 /* Check if io request timeout is smaller than current (but not 0). */
859 if (iorq->timeout
860 && (select_timeout == 0
861 || iorq->timeout < select_timeout))
862 {
863 /* Set new timeout */
864 select_timeout = iorq->timeout;
865 g_min_timeout_fd = iorq->fd; /* Remember fd */
866 tv->tv_sec = select_timeout / 1000;
867 tv->tv_usec = (select_timeout % 1000) * 1000;
868 *timeout = True;
869 break;
870 }
871 if (iorq->itv_timeout && iorq->partial_len > 0
872 && (select_timeout == 0
873 || iorq->itv_timeout < select_timeout))
874 {
875 /* Set new timeout */
876 select_timeout = iorq->itv_timeout;
877 g_min_timeout_fd = iorq->fd; /* Remember fd */
878 tv->tv_sec = select_timeout / 1000;
879 tv->tv_usec = (select_timeout % 1000) * 1000;
880 *timeout = True;
881 break;
882 }
883 break;
884
885 case IRP_MJ_WRITE:
886 /* FD still valid? See above. */
887 if ((write(iorq->fd, &c, 0) != 0) && (errno == EBADF))
888 break;
889
890 FD_SET(iorq->fd, wfds);
891 *n = MAX(*n, iorq->fd);
892 break;
893
894 case IRP_MJ_DEVICE_CONTROL:
895 if (select_timeout > 5)
896 select_timeout = 5; /* serial event queue */
897 break;
898
899 }
900
901 }
902
903 iorq = iorq->next;
904 }
905}
906
907struct async_iorequest *
908rdpdr_remove_iorequest(struct async_iorequest *prev, struct async_iorequest *iorq)
909{
910 if (!iorq)
911 return NULL;
912
913 if (iorq->buffer)
914 xfree(iorq->buffer);
915 if (prev)
916 {
917 prev->next = iorq->next;
918 xfree(iorq);
919 iorq = prev->next;
920 }
921 else
922 {
923 /* Even if NULL */
924 g_iorequest = iorq->next;
925 xfree(iorq);
926 iorq = NULL;
927 }
928 return iorq;
929}
930
931/* Check if select() returned with one of the rdpdr file descriptors, and complete io if it did */
932static void
933_rdpdr_check_fds(fd_set * rfds, fd_set * wfds, BOOL timed_out)
934{
935 NTSTATUS status;
936 uint32 result = 0;
937 DEVICE_FNS *fns;
938 struct async_iorequest *iorq;
939 struct async_iorequest *prev;
940 uint32 req_size = 0;
941 uint32 buffer_len;
942 struct stream out;
943 uint8 *buffer = NULL;
944
945
946 if (timed_out)
947 {
948 /* check serial iv_timeout */
949
950 iorq = g_iorequest;
951 prev = NULL;
952 while (iorq != NULL)
953 {
954 if (iorq->fd == g_min_timeout_fd)
955 {
956 if ((iorq->partial_len > 0) &&
957 (g_rdpdr_device[iorq->device].device_type ==
958 DEVICE_TYPE_SERIAL))
959 {
960
961 /* iv_timeout between 2 chars, send partial_len */
962 /*printf("RDPDR: IVT total %u bytes read of %u\n", iorq->partial_len, iorq->length); */
963 rdpdr_send_completion(iorq->device,
964 iorq->id, STATUS_SUCCESS,
965 iorq->partial_len,
966 iorq->buffer, iorq->partial_len);
967 iorq = rdpdr_remove_iorequest(prev, iorq);
968 return;
969 }
970 else
971 {
972 break;
973 }
974
975 }
976 else
977 {
978 break;
979 }
980
981
982 prev = iorq;
983 if (iorq)
984 iorq = iorq->next;
985
986 }
987
988 rdpdr_abort_io(g_min_timeout_fd, 0, STATUS_TIMEOUT);
989 return;
990 }
991
992 iorq = g_iorequest;
993 prev = NULL;
994 while (iorq != NULL)
995 {
996 if (iorq->fd != 0)
997 {
998 switch (iorq->major)
999 {
1000 case IRP_MJ_READ:
1001 if (FD_ISSET(iorq->fd, rfds))
1002 {
1003 /* Read the data */
1004 fns = iorq->fns;
1005
1006 req_size =
1007 (iorq->length - iorq->partial_len) >
1008 8192 ? 8192 : (iorq->length -
1009 iorq->partial_len);
1010 /* never read larger chunks than 8k - chances are that it will block */
1011 status = fns->read(iorq->fd,
1012 iorq->buffer + iorq->partial_len,
1013 req_size, iorq->offset, &result);
1014
1015 if ((long) result > 0)
1016 {
1017 iorq->partial_len += result;
1018 iorq->offset += result;
1019 }
1020#if WITH_DEBUG_RDP5
1021 DEBUG(("RDPDR: %d bytes of data read\n", result));
1022#endif
1023 /* only delete link if all data has been transfered */
1024 /* or if result was 0 and status success - EOF */
1025 if ((iorq->partial_len == iorq->length) ||
1026 (result == 0))
1027 {
1028#if WITH_DEBUG_RDP5
1029 DEBUG(("RDPDR: AIO total %u bytes read of %u\n", iorq->partial_len, iorq->length));
1030#endif
1031 rdpdr_send_completion(iorq->device,
1032 iorq->id, status,
1033 iorq->partial_len,
1034 iorq->buffer,
1035 iorq->partial_len);
1036 iorq = rdpdr_remove_iorequest(prev, iorq);
1037 }
1038 }
1039 break;
1040 case IRP_MJ_WRITE:
1041 if (FD_ISSET(iorq->fd, wfds))
1042 {
1043 /* Write data. */
1044 fns = iorq->fns;
1045
1046 req_size =
1047 (iorq->length - iorq->partial_len) >
1048 8192 ? 8192 : (iorq->length -
1049 iorq->partial_len);
1050
1051 /* never write larger chunks than 8k - chances are that it will block */
1052 status = fns->write(iorq->fd,
1053 iorq->buffer +
1054 iorq->partial_len, req_size,
1055 iorq->offset, &result);
1056
1057 if ((long) result > 0)
1058 {
1059 iorq->partial_len += result;
1060 iorq->offset += result;
1061 }
1062
1063#if WITH_DEBUG_RDP5
1064 DEBUG(("RDPDR: %d bytes of data written\n",
1065 result));
1066#endif
1067 /* only delete link if all data has been transfered */
1068 /* or we couldn't write */
1069 if ((iorq->partial_len == iorq->length)
1070 || (result == 0))
1071 {
1072#if WITH_DEBUG_RDP5
1073 DEBUG(("RDPDR: AIO total %u bytes written of %u\n", iorq->partial_len, iorq->length));
1074#endif
1075 rdpdr_send_completion(iorq->device,
1076 iorq->id, status,
1077 iorq->partial_len,
1078 (uint8 *) "", 1);
1079
1080 iorq = rdpdr_remove_iorequest(prev, iorq);
1081 }
1082 }
1083 break;
1084 case IRP_MJ_DEVICE_CONTROL:
1085 if (serial_get_event(iorq->fd, &result))
1086 {
1087 buffer = (uint8 *) xrealloc((void *) buffer, 0x14);
1088 out.data = out.p = buffer;
1089 out.size = sizeof(buffer);
1090 out_uint32_le(&out, result);
1091 result = buffer_len = out.p - out.data;
1092 status = STATUS_SUCCESS;
1093 rdpdr_send_completion(iorq->device, iorq->id,
1094 status, result, buffer,
1095 buffer_len);
1096 xfree(buffer);
1097 iorq = rdpdr_remove_iorequest(prev, iorq);
1098 }
1099
1100 break;
1101 }
1102
1103 }
1104 prev = iorq;
1105 if (iorq)
1106 iorq = iorq->next;
1107 }
1108
1109 /* Check notify */
1110 iorq = g_iorequest;
1111 prev = NULL;
1112 while (iorq != NULL)
1113 {
1114 if (iorq->fd != 0)
1115 {
1116 switch (iorq->major)
1117 {
1118
1119 case IRP_MJ_DIRECTORY_CONTROL:
1120 if (g_rdpdr_device[iorq->device].device_type ==
1121 DEVICE_TYPE_DISK)
1122 {
1123
1124 if (g_notify_stamp)
1125 {
1126 g_notify_stamp = False;
1127 status = disk_check_notify(iorq->fd);
1128 if (status != STATUS_PENDING)
1129 {
1130 rdpdr_send_completion(iorq->device,
1131 iorq->id,
1132 status, 0,
1133 NULL, 0);
1134 iorq = rdpdr_remove_iorequest(prev,
1135 iorq);
1136 }
1137 }
1138 }
1139 break;
1140
1141
1142
1143 }
1144 }
1145
1146 prev = iorq;
1147 if (iorq)
1148 iorq = iorq->next;
1149 }
1150
1151}
1152
1153void
1154rdpdr_check_fds(fd_set * rfds, fd_set * wfds, BOOL timed_out)
1155{
1156 fd_set dummy;
1157
1158
1159 FD_ZERO(&dummy);
1160
1161
1162 /* fist check event queue only,
1163 any serial wait event must be done before read block will be sent
1164 */
1165
1166 _rdpdr_check_fds(&dummy, &dummy, False);
1167 _rdpdr_check_fds(rfds, wfds, timed_out);
1168}
1169
1170
1171/* Abort a pending io request for a given handle and major */
1172BOOL
1173rdpdr_abort_io(uint32 fd, uint32 major, NTSTATUS status)
1174{
1175 uint32 result;
1176 struct async_iorequest *iorq;
1177 struct async_iorequest *prev;
1178
1179 iorq = g_iorequest;
1180 prev = NULL;
1181 while (iorq != NULL)
1182 {
1183 /* Only remove from table when major is not set, or when correct major is supplied.
1184 Abort read should not abort a write io request. */
1185 if ((iorq->fd == fd) && (major == 0 || iorq->major == major))
1186 {
1187 result = 0;
1188 rdpdr_send_completion(iorq->device, iorq->id, status, result, (uint8 *) "",
1189 1);
1190
1191 iorq = rdpdr_remove_iorequest(prev, iorq);
1192 return True;
1193 }
1194
1195 prev = iorq;
1196 iorq = iorq->next;
1197 }
1198
1199 return False;
1200}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette