/[rdesktop]/sourceforge.net/trunk/rdesktop/rdpdr.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /sourceforge.net/trunk/rdesktop/rdpdr.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 747 - (show annotations)
Mon Aug 9 13:50:41 2004 UTC (19 years, 9 months ago) by astrand
File MIME type: text/plain
File size: 23363 byte(s)
Disk redirection actually uses share names; not drive letters.
Make sure we truncate share names longer than 8 chars.
Documentation updated.

1 /* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3 Copyright (C) Matthew Chapman 1999-2004
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
58 extern char g_hostname[16];
59 extern DEVICE_FNS serial_fns;
60 extern DEVICE_FNS printer_fns;
61 extern DEVICE_FNS parallel_fns;
62 extern DEVICE_FNS disk_fns;
63 extern FILEINFO g_fileinfo[];
64
65 static VCHANNEL *rdpdr_channel;
66
67 /* If select() times out, the request for the device with handle g_min_timeout_fd is aborted */
68 HANDLE g_min_timeout_fd;
69 uint32 g_num_devices;
70
71 /* Table with information about rdpdr devices */
72 RDPDR_DEVICE g_rdpdr_device[RDPDR_MAX_DEVICES];
73 char *g_rdpdr_clientname = NULL;
74
75 /* Used to store incoming io request, until they are ready to be completed */
76 /* using a linked list ensures that they are processed in the right order, */
77 /* if multiple ios are being done on the same fd */
78 struct async_iorequest
79 {
80 uint32 fd, major, minor, offset, device, id, length, partial_len;
81 long timeout, /* Total timeout */
82 itv_timeout; /* Interval timeout (between serial characters) */
83 uint8 *buffer;
84 DEVICE_FNS *fns;
85
86 struct async_iorequest *next; /* next element in list */
87 };
88
89 struct async_iorequest *g_iorequest;
90
91 /* Return device_id for a given handle */
92 int
93 get_device_index(HANDLE handle)
94 {
95 int i;
96 for (i = 0; i < RDPDR_MAX_DEVICES; i++)
97 {
98 if (g_rdpdr_device[i].handle == handle)
99 return i;
100 }
101 return -1;
102 }
103
104 /* Converts a windows path to a unix path */
105 void
106 convert_to_unix_filename(char *filename)
107 {
108 char *p;
109
110 while ((p = strchr(filename, '\\')))
111 {
112 *p = '/';
113 }
114 }
115
116 static BOOL
117 rdpdr_handle_ok(int device, int handle)
118 {
119 switch (g_rdpdr_device[device].device_type)
120 {
121 case DEVICE_TYPE_PARALLEL:
122 case DEVICE_TYPE_SERIAL:
123 case DEVICE_TYPE_PRINTER:
124 case DEVICE_TYPE_SCARD:
125 if (g_rdpdr_device[device].handle != handle)
126 return False;
127 break;
128 case DEVICE_TYPE_DISK:
129 if (g_fileinfo[handle].device_id != device)
130 return False;
131 break;
132 }
133 return True;
134 }
135
136 /* Add a new io request to the table containing pending io requests so it won't block rdesktop */
137 static BOOL
138 add_async_iorequest(uint32 device, uint32 file, uint32 id, uint32 major, uint32 length,
139 DEVICE_FNS * fns, uint32 total_timeout, uint32 interval_timeout, uint8 * buffer,
140 uint32 offset)
141 {
142 struct async_iorequest *iorq;
143
144 if (g_iorequest == NULL)
145 {
146 g_iorequest = (struct async_iorequest *) xmalloc(sizeof(struct async_iorequest));
147 if (!g_iorequest)
148 return False;
149 g_iorequest->fd = 0;
150 g_iorequest->next = NULL;
151 }
152
153 iorq = g_iorequest;
154
155 while (iorq->fd != 0)
156 {
157 // create new element if needed
158 if (iorq->next == NULL)
159 {
160 iorq->next =
161 (struct async_iorequest *) xmalloc(sizeof(struct async_iorequest));
162 if (!iorq->next)
163 return False;
164 iorq->next->fd = 0;
165 iorq->next->next = NULL;
166 }
167 iorq = iorq->next;
168 }
169 iorq->device = device;
170 iorq->fd = file;
171 iorq->id = id;
172 iorq->major = major;
173 iorq->length = length;
174 iorq->partial_len = 0;
175 iorq->fns = fns;
176 iorq->timeout = total_timeout;
177 iorq->itv_timeout = interval_timeout;
178 iorq->buffer = buffer;
179 iorq->offset = offset;
180 return True;
181 }
182
183 static void
184 rdpdr_send_connect(void)
185 {
186 uint8 magic[4] = "rDCC";
187 STREAM s;
188
189 s = channel_init(rdpdr_channel, 12);
190 out_uint8a(s, magic, 4);
191 out_uint16_le(s, 1); /* unknown */
192 out_uint16_le(s, 5);
193 out_uint32_be(s, 0x815ed39d); /* IP address (use 127.0.0.1) 0x815ed39d */
194 s_mark_end(s);
195 channel_send(s, rdpdr_channel);
196 }
197
198
199 static void
200 rdpdr_send_name(void)
201 {
202 uint8 magic[4] = "rDNC";
203 STREAM s;
204 uint32 hostlen;
205
206 if (NULL == g_rdpdr_clientname)
207 {
208 g_rdpdr_clientname = g_hostname;
209 }
210 hostlen = (strlen(g_rdpdr_clientname) + 1) * 2;
211
212 s = channel_init(rdpdr_channel, 16 + hostlen);
213 out_uint8a(s, magic, 4);
214 out_uint16_le(s, 0x63); /* unknown */
215 out_uint16_le(s, 0x72);
216 out_uint32(s, 0);
217 out_uint32_le(s, hostlen);
218 rdp_out_unistr(s, g_rdpdr_clientname, hostlen - 2);
219 s_mark_end(s);
220 channel_send(s, rdpdr_channel);
221 }
222
223 /* Returns the size of the payload of the announce packet */
224 static int
225 announcedata_size()
226 {
227 int size, i;
228 PRINTER *printerinfo;
229
230 size = 8; //static announce size
231 size += g_num_devices * 0x14;
232
233 for (i = 0; i < g_num_devices; i++)
234 {
235 if (g_rdpdr_device[i].device_type == DEVICE_TYPE_PRINTER)
236 {
237 printerinfo = (PRINTER *) g_rdpdr_device[i].pdevice_data;
238 printerinfo->bloblen =
239 printercache_load_blob(printerinfo->printer, &(printerinfo->blob));
240
241 size += 0x18;
242 size += 2 * strlen(printerinfo->driver) + 2;
243 size += 2 * strlen(printerinfo->printer) + 2;
244 size += printerinfo->bloblen;
245 }
246 }
247
248 return size;
249 }
250
251 static void
252 rdpdr_send_available(void)
253 {
254
255 uint8 magic[4] = "rDAD";
256 uint32 driverlen, printerlen, bloblen;
257 int i;
258 STREAM s;
259 PRINTER *printerinfo;
260
261 s = channel_init(rdpdr_channel, announcedata_size());
262 out_uint8a(s, magic, 4);
263 out_uint32_le(s, g_num_devices);
264
265 for (i = 0; i < g_num_devices; i++)
266 {
267 out_uint32_le(s, g_rdpdr_device[i].device_type);
268 out_uint32_le(s, i); /* RDP Device ID */
269 /* Is it possible to use share names longer than 8 chars?
270 /astrand */
271 out_uint8p(s, g_rdpdr_device[i].name, 8);
272
273 switch (g_rdpdr_device[i].device_type)
274 {
275 case DEVICE_TYPE_PRINTER:
276 printerinfo = (PRINTER *) g_rdpdr_device[i].pdevice_data;
277
278 driverlen = 2 * strlen(printerinfo->driver) + 2;
279 printerlen = 2 * strlen(printerinfo->printer) + 2;
280 bloblen = printerinfo->bloblen;
281
282 out_uint32_le(s, 24 + driverlen + printerlen + bloblen); /* length of extra info */
283 out_uint32_le(s, printerinfo->default_printer ? 2 : 0);
284 out_uint8s(s, 8); /* unknown */
285 out_uint32_le(s, driverlen);
286 out_uint32_le(s, printerlen);
287 out_uint32_le(s, bloblen);
288 rdp_out_unistr(s, printerinfo->driver, driverlen - 2);
289 rdp_out_unistr(s, printerinfo->printer, printerlen - 2);
290 out_uint8a(s, printerinfo->blob, bloblen);
291
292 if (printerinfo->blob)
293 xfree(printerinfo->blob); /* Blob is sent twice if reconnecting */
294 break;
295 default:
296 out_uint32(s, 0);
297 }
298 }
299 #if 0
300 out_uint32_le(s, 0x20); /* Device type 0x20 - smart card */
301 out_uint32_le(s, 0);
302 out_uint8p(s, "SCARD", 5);
303 out_uint8s(s, 3);
304 out_uint32(s, 0);
305 #endif
306
307 s_mark_end(s);
308 channel_send(s, rdpdr_channel);
309 }
310
311 static void
312 rdpdr_send_completion(uint32 device, uint32 id, uint32 status, uint32 result, uint8 * buffer,
313 uint32 length)
314 {
315 uint8 magic[4] = "rDCI";
316 STREAM s;
317
318 s = channel_init(rdpdr_channel, 20 + length);
319 out_uint8a(s, magic, 4);
320 out_uint32_le(s, device);
321 out_uint32_le(s, id);
322 out_uint32_le(s, status);
323 out_uint32_le(s, result);
324 out_uint8p(s, buffer, length);
325 s_mark_end(s);
326 /* JIF
327 hexdump(s->channel_hdr + 8, s->end - s->channel_hdr - 8); */
328 channel_send(s, rdpdr_channel);
329 }
330
331 static void
332 rdpdr_process_irp(STREAM s)
333 {
334 uint32 result = 0,
335 length = 0,
336 desired_access = 0,
337 request,
338 file,
339 info_level,
340 buffer_len,
341 id,
342 major,
343 minor,
344 device,
345 offset,
346 bytes_in,
347 bytes_out,
348 error_mode,
349 share_mode, disposition, total_timeout, interval_timeout, flags_and_attributes = 0;
350
351 char filename[256];
352 uint8 *buffer, *pst_buf;
353 struct stream out;
354 DEVICE_FNS *fns;
355 BOOL rw_blocking = True;
356 NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
357
358 in_uint32_le(s, device);
359 in_uint32_le(s, file);
360 in_uint32_le(s, id);
361 in_uint32_le(s, major);
362 in_uint32_le(s, minor);
363
364 buffer_len = 0;
365 buffer = (uint8 *) xmalloc(1024);
366 buffer[0] = 0;
367
368 switch (g_rdpdr_device[device].device_type)
369 {
370 case DEVICE_TYPE_SERIAL:
371
372 fns = &serial_fns;
373 rw_blocking = False;
374 break;
375
376 case DEVICE_TYPE_PARALLEL:
377
378 fns = &parallel_fns;
379 rw_blocking = False;
380 break;
381
382 case DEVICE_TYPE_PRINTER:
383
384 fns = &printer_fns;
385 break;
386
387 case DEVICE_TYPE_DISK:
388
389 fns = &disk_fns;
390 rw_blocking = False;
391 break;
392
393 case DEVICE_TYPE_SCARD:
394 default:
395
396 error("IRP for bad device %ld\n", device);
397 return;
398 }
399
400 switch (major)
401 {
402 case IRP_MJ_CREATE:
403
404 in_uint32_be(s, desired_access);
405 in_uint8s(s, 0x08); // unknown
406 in_uint32_le(s, error_mode);
407 in_uint32_le(s, share_mode);
408 in_uint32_le(s, disposition);
409 in_uint32_le(s, flags_and_attributes);
410 in_uint32_le(s, length);
411
412 if (length && (length / 2) < 256)
413 {
414 rdp_in_unistr(s, filename, length);
415 convert_to_unix_filename(filename);
416 }
417 else
418 {
419 filename[0] = 0;
420 }
421
422 if (!fns->create)
423 {
424 status = STATUS_NOT_SUPPORTED;
425 break;
426 }
427
428 status = fns->create(device, desired_access, share_mode, disposition,
429 flags_and_attributes, filename, &result);
430 buffer_len = 1;
431 break;
432
433 case IRP_MJ_CLOSE:
434 if (!fns->close)
435 {
436 status = STATUS_NOT_SUPPORTED;
437 break;
438 }
439
440 status = fns->close(file);
441 break;
442
443 case IRP_MJ_READ:
444
445 if (!fns->read)
446 {
447 status = STATUS_NOT_SUPPORTED;
448 break;
449 }
450
451 in_uint32_le(s, length);
452 in_uint32_le(s, offset);
453 #if WITH_DEBUG_RDP5
454 DEBUG(("RDPDR IRP Read (length: %d, offset: %d)\n", length, offset));
455 #endif
456 if (!rdpdr_handle_ok(device, file))
457 {
458 status = STATUS_INVALID_HANDLE;
459 break;
460 }
461
462 if (rw_blocking) // Complete read immediately
463 {
464 buffer = (uint8 *) xrealloc((void *) buffer, length);
465 if (!buffer)
466 {
467 status = STATUS_CANCELLED;
468 break;
469 }
470 status = fns->read(file, buffer, length, offset, &result);
471 buffer_len = result;
472 break;
473 }
474
475 // Add request to table
476 pst_buf = (uint8 *) xmalloc(length);
477 if (!pst_buf)
478 {
479 status = STATUS_CANCELLED;
480 break;
481 }
482 serial_get_timeout(file, length, &total_timeout, &interval_timeout);
483 if (add_async_iorequest
484 (device, file, id, major, length, fns, total_timeout, interval_timeout,
485 pst_buf, offset))
486 {
487 status = STATUS_PENDING;
488 break;
489 }
490
491 status = STATUS_CANCELLED;
492 break;
493 case IRP_MJ_WRITE:
494
495 buffer_len = 1;
496
497 if (!fns->write)
498 {
499 status = STATUS_NOT_SUPPORTED;
500 break;
501 }
502
503 in_uint32_le(s, length);
504 in_uint32_le(s, offset);
505 in_uint8s(s, 0x18);
506 #if WITH_DEBUG_RDP5
507 DEBUG(("RDPDR IRP Write (length: %d)\n", result));
508 #endif
509 if (!rdpdr_handle_ok(device, file))
510 {
511 status = STATUS_INVALID_HANDLE;
512 break;
513 }
514
515 if (rw_blocking) // Complete immediately
516 {
517 status = fns->write(file, s->p, length, offset, &result);
518 break;
519 }
520
521 // Add to table
522 pst_buf = (uint8 *) xmalloc(length);
523 if (!pst_buf)
524 {
525 status = STATUS_CANCELLED;
526 break;
527 }
528
529 in_uint8a(s, pst_buf, length);
530
531 if (add_async_iorequest
532 (device, file, id, major, length, fns, 0, 0, pst_buf, offset))
533 {
534 status = STATUS_PENDING;
535 break;
536 }
537
538 status = STATUS_CANCELLED;
539 break;
540
541 case IRP_MJ_QUERY_INFORMATION:
542
543 if (g_rdpdr_device[device].device_type != DEVICE_TYPE_DISK)
544 {
545 status = STATUS_INVALID_HANDLE;
546 break;
547 }
548 in_uint32_le(s, info_level);
549
550 out.data = out.p = buffer;
551 out.size = sizeof(buffer);
552 status = disk_query_information(file, info_level, &out);
553 result = buffer_len = out.p - out.data;
554
555 break;
556
557 case IRP_MJ_SET_INFORMATION:
558
559 if (g_rdpdr_device[device].device_type != DEVICE_TYPE_DISK)
560 {
561 status = STATUS_INVALID_HANDLE;
562 break;
563 }
564
565 in_uint32_le(s, info_level);
566
567 out.data = out.p = buffer;
568 out.size = sizeof(buffer);
569 status = disk_set_information(file, info_level, s, &out);
570 result = buffer_len = out.p - out.data;
571 break;
572
573 case IRP_MJ_QUERY_VOLUME_INFORMATION:
574
575 if (g_rdpdr_device[device].device_type != DEVICE_TYPE_DISK)
576 {
577 status = STATUS_INVALID_HANDLE;
578 break;
579 }
580
581 in_uint32_le(s, info_level);
582
583 out.data = out.p = buffer;
584 out.size = sizeof(buffer);
585 status = disk_query_volume_information(file, info_level, &out);
586 result = buffer_len = out.p - out.data;
587 break;
588
589 case IRP_MJ_DIRECTORY_CONTROL:
590
591 if (g_rdpdr_device[device].device_type != DEVICE_TYPE_DISK)
592 {
593 status = STATUS_INVALID_HANDLE;
594 break;
595 }
596
597 switch (minor)
598 {
599 case IRP_MN_QUERY_DIRECTORY:
600
601 in_uint32_le(s, info_level);
602 in_uint8s(s, 1);
603 in_uint32_le(s, length);
604 in_uint8s(s, 0x17);
605 if (length && length < 2 * 255)
606 {
607 rdp_in_unistr(s, filename, length);
608 convert_to_unix_filename(filename);
609 }
610 else
611 {
612 filename[0] = 0;
613 }
614 out.data = out.p = buffer;
615 out.size = sizeof(buffer);
616 status = disk_query_directory(file, info_level, filename,
617 &out);
618 result = buffer_len = out.p - out.data;
619 if (!buffer_len)
620 buffer_len++;
621 break;
622
623 case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
624
625 /* JIF
626 unimpl("IRP major=0x%x minor=0x%x: IRP_MN_NOTIFY_CHANGE_DIRECTORY\n", major, minor); */
627 status = STATUS_PENDING; // Don't send completion packet
628 break;
629
630 default:
631
632 status = STATUS_INVALID_PARAMETER;
633 /* JIF
634 unimpl("IRP major=0x%x minor=0x%x\n", major, minor); */
635 }
636 break;
637
638 case IRP_MJ_DEVICE_CONTROL:
639
640 if (!fns->device_control)
641 {
642 status = STATUS_NOT_SUPPORTED;
643 break;
644 }
645
646 in_uint32_le(s, bytes_out);
647 in_uint32_le(s, bytes_in);
648 in_uint32_le(s, request);
649 in_uint8s(s, 0x14);
650
651 buffer = (uint8 *) xrealloc((void *) buffer, bytes_out + 0x14);
652 if (!buffer)
653 {
654 status = STATUS_CANCELLED;
655 break;
656 }
657
658 out.data = out.p = buffer;
659 out.size = sizeof(buffer);
660 status = fns->device_control(file, request, s, &out);
661 result = buffer_len = out.p - out.data;
662 break;
663
664
665 case IRP_MJ_LOCK_CONTROL:
666
667 if (g_rdpdr_device[device].device_type != DEVICE_TYPE_DISK)
668 {
669 status = STATUS_INVALID_HANDLE;
670 break;
671 }
672
673 in_uint32_le(s, info_level);
674
675 out.data = out.p = buffer;
676 out.size = sizeof(buffer);
677 /* FIXME: Perhaps consider actually *do*
678 something here :-) */
679 status = STATUS_SUCCESS;
680 result = buffer_len = out.p - out.data;
681 break;
682
683 default:
684 unimpl("IRP major=0x%x minor=0x%x\n", major, minor);
685 break;
686 }
687
688 if (status != STATUS_PENDING)
689 {
690 rdpdr_send_completion(device, id, status, result, buffer, buffer_len);
691 }
692 if (buffer)
693 xfree(buffer);
694 buffer = NULL;
695 }
696
697 static void
698 rdpdr_send_clientcapabilty(void)
699 {
700 uint8 magic[4] = "rDPC";
701 STREAM s;
702
703 s = channel_init(rdpdr_channel, 0x50);
704 out_uint8a(s, magic, 4);
705 out_uint32_le(s, 5); /* count */
706 out_uint16_le(s, 1); /* first */
707 out_uint16_le(s, 0x28); /* length */
708 out_uint32_le(s, 1);
709 out_uint32_le(s, 2);
710 out_uint16_le(s, 2);
711 out_uint16_le(s, 5);
712 out_uint16_le(s, 1);
713 out_uint16_le(s, 5);
714 out_uint16_le(s, 0xFFFF);
715 out_uint16_le(s, 0);
716 out_uint32_le(s, 0);
717 out_uint32_le(s, 3);
718 out_uint32_le(s, 0);
719 out_uint32_le(s, 0);
720 out_uint16_le(s, 2); /* second */
721 out_uint16_le(s, 8); /* length */
722 out_uint32_le(s, 1);
723 out_uint16_le(s, 3); /* third */
724 out_uint16_le(s, 8); /* length */
725 out_uint32_le(s, 1);
726 out_uint16_le(s, 4); /* fourth */
727 out_uint16_le(s, 8); /* length */
728 out_uint32_le(s, 1);
729 out_uint16_le(s, 5); /* fifth */
730 out_uint16_le(s, 8); /* length */
731 out_uint32_le(s, 1);
732
733 s_mark_end(s);
734 channel_send(s, rdpdr_channel);
735 }
736
737 static void
738 rdpdr_process(STREAM s)
739 {
740 uint32 handle;
741 uint8 *magic;
742
743 #if WITH_DEBUG_RDP5
744 printf("--- rdpdr_process ---\n");
745 hexdump(s->p, s->end - s->p);
746 #endif
747 in_uint8p(s, magic, 4);
748
749 if ((magic[0] == 'r') && (magic[1] == 'D'))
750 {
751 if ((magic[2] == 'R') && (magic[3] == 'I'))
752 {
753 rdpdr_process_irp(s);
754 return;
755 }
756 if ((magic[2] == 'n') && (magic[3] == 'I'))
757 {
758 rdpdr_send_connect();
759 rdpdr_send_name();
760 return;
761 }
762 if ((magic[2] == 'C') && (magic[3] == 'C'))
763 {
764 /* connect from server */
765 rdpdr_send_clientcapabilty();
766 rdpdr_send_available();
767 return;
768 }
769 if ((magic[2] == 'r') && (magic[3] == 'd'))
770 {
771 /* connect to a specific resource */
772 in_uint32(s, handle);
773 #if WITH_DEBUG_RDP5
774 DEBUG(("RDPDR: Server connected to resource %d\n", handle));
775 #endif
776 return;
777 }
778 if ((magic[2] == 'P') && (magic[3] == 'S'))
779 {
780 /* server capability */
781 return;
782 }
783 }
784 if ((magic[0] == 'R') && (magic[1] == 'P'))
785 {
786 if ((magic[2] == 'C') && (magic[3] == 'P'))
787 {
788 printercache_process(s);
789 return;
790 }
791 }
792 unimpl("RDPDR packet type %c%c%c%c\n", magic[0], magic[1], magic[2], magic[3]);
793 }
794
795 BOOL
796 rdpdr_init()
797 {
798 if (g_num_devices > 0)
799 {
800 rdpdr_channel =
801 channel_register("rdpdr",
802 CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_COMPRESS_RDP,
803 rdpdr_process);
804 }
805
806 return (rdpdr_channel != NULL);
807 }
808
809 /* Add file descriptors of pending io request to select() */
810 void
811 rdpdr_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv, BOOL * timeout)
812 {
813 uint32 select_timeout = 0; // Timeout value to be used for select() (in millisecons).
814 struct async_iorequest *iorq;
815 char c;
816
817 iorq = g_iorequest;
818 while (iorq != NULL)
819 {
820 if (iorq->fd != 0)
821 {
822 switch (iorq->major)
823 {
824 case IRP_MJ_READ:
825 /* Is this FD valid? FDs will
826 be invalid when
827 reconnecting. FIXME: Real
828 support for reconnects. */
829
830 if ((read(iorq->fd, &c, 0) != 0) && (errno == EBADF))
831 break;
832
833 FD_SET(iorq->fd, rfds);
834 *n = MAX(*n, iorq->fd);
835
836 // Check if io request timeout is smaller than current (but not 0).
837 if (iorq->timeout
838 && (select_timeout == 0
839 || iorq->timeout < select_timeout))
840 {
841 // Set new timeout
842 select_timeout = iorq->timeout;
843 g_min_timeout_fd = iorq->fd; /* Remember fd */
844 tv->tv_sec = select_timeout / 1000;
845 tv->tv_usec = (select_timeout % 1000) * 1000;
846 *timeout = True;
847 }
848
849 break;
850
851 case IRP_MJ_WRITE:
852 /* FD still valid? See above. */
853 if ((write(iorq->fd, &c, 0) != 0) && (errno == EBADF))
854 break;
855
856 FD_SET(iorq->fd, wfds);
857 *n = MAX(*n, iorq->fd);
858 break;
859
860 }
861
862 }
863
864 iorq = iorq->next;
865 }
866 }
867
868 struct async_iorequest *
869 rdpdr_remove_iorequest(struct async_iorequest *prev, struct async_iorequest *iorq)
870 {
871 if (!iorq)
872 return NULL;
873
874 if (iorq->buffer)
875 xfree(iorq->buffer);
876 if (prev)
877 {
878 prev->next = iorq->next;
879 xfree(iorq);
880 iorq = prev->next;
881 }
882 else
883 {
884 // Even if NULL
885 g_iorequest = iorq->next;
886 xfree(iorq);
887 iorq = NULL;
888 }
889 return iorq;
890 }
891
892 /* Check if select() returned with one of the rdpdr file descriptors, and complete io if it did */
893 void
894 rdpdr_check_fds(fd_set * rfds, fd_set * wfds, BOOL timed_out)
895 {
896 NTSTATUS status;
897 uint32 result = 0;
898 DEVICE_FNS *fns;
899 struct async_iorequest *iorq;
900 struct async_iorequest *prev;
901 uint32 req_size = 0;
902
903 if (timed_out)
904 {
905 rdpdr_abort_io(g_min_timeout_fd, 0, STATUS_TIMEOUT);
906 return;
907 }
908
909 iorq = g_iorequest;
910 prev = NULL;
911 while (iorq != NULL)
912 {
913 if (iorq->fd != 0)
914 {
915 switch (iorq->major)
916 {
917 case IRP_MJ_READ:
918 if (FD_ISSET(iorq->fd, rfds))
919 {
920 /* Read the data */
921 fns = iorq->fns;
922
923 req_size =
924 (iorq->length - iorq->partial_len) >
925 8192 ? 8192 : (iorq->length -
926 iorq->partial_len);
927 /* never read larger chunks than 8k - chances are that it will block */
928 status = fns->read(iorq->fd,
929 iorq->buffer + iorq->partial_len,
930 req_size, iorq->offset, &result);
931
932 if (result > 0)
933 {
934 iorq->partial_len += result;
935 iorq->offset += result;
936 }
937 #if WITH_DEBUG_RDP5
938 DEBUG(("RDPDR: %d bytes of data read\n", result));
939 #endif
940 /* only delete link if all data has been transfered */
941 /* or if result was 0 and status success - EOF */
942 if ((iorq->partial_len == iorq->length) ||
943 (result == 0))
944 {
945 #if WITH_DEBUG_RDP5
946 DEBUG(("RDPDR: AIO total %u bytes read of %u\n", iorq->partial_len, iorq->length));
947 #endif
948 rdpdr_send_completion(iorq->device,
949 iorq->id, status,
950 iorq->partial_len,
951 iorq->buffer,
952 iorq->partial_len);
953 iorq = rdpdr_remove_iorequest(prev, iorq);
954 }
955 }
956 break;
957 case IRP_MJ_WRITE:
958 if (FD_ISSET(iorq->fd, wfds))
959 {
960 /* Write data. */
961 fns = iorq->fns;
962
963 req_size =
964 (iorq->length - iorq->partial_len) >
965 8192 ? 8192 : (iorq->length -
966 iorq->partial_len);
967
968 /* never write larger chunks than 8k - chances are that it will block */
969 status = fns->write(iorq->fd,
970 iorq->buffer +
971 iorq->partial_len, req_size,
972 iorq->offset, &result);
973
974 if (result > 0)
975 {
976 iorq->partial_len += result;
977 iorq->offset += result;
978 }
979
980 #if WITH_DEBUG_RDP5
981 DEBUG(("RDPDR: %d bytes of data written\n",
982 result));
983 #endif
984 /* only delete link if all data has been transfered */
985 /* or we couldn't write */
986 if ((iorq->partial_len == iorq->length)
987 || (result == 0))
988 {
989 #if WITH_DEBUG_RDP5
990 DEBUG(("RDPDR: AIO total %u bytes written of %u\n", iorq->partial_len, iorq->length));
991 #endif
992 rdpdr_send_completion(iorq->device,
993 iorq->id, status,
994 iorq->partial_len,
995 (uint8 *) "", 1);
996
997 iorq = rdpdr_remove_iorequest(prev, iorq);
998 }
999 }
1000 break;
1001 }
1002
1003 }
1004 prev = iorq;
1005 if (iorq)
1006 iorq = iorq->next;
1007 }
1008
1009 }
1010
1011 /* Abort a pending io request for a given handle and major */
1012 BOOL
1013 rdpdr_abort_io(uint32 fd, uint32 major, NTSTATUS status)
1014 {
1015 uint32 result;
1016 struct async_iorequest *iorq;
1017 struct async_iorequest *prev;
1018
1019 iorq = g_iorequest;
1020 prev = NULL;
1021 while (iorq != NULL)
1022 {
1023 // Only remove from table when major is not set, or when correct major is supplied.
1024 // Abort read should not abort a write io request.
1025 if ((iorq->fd == fd) && (major == 0 || iorq->major == major))
1026 {
1027 result = 0;
1028 rdpdr_send_completion(iorq->device, iorq->id, status, result, (uint8 *) "",
1029 1);
1030
1031 iorq = rdpdr_remove_iorequest(prev, iorq);
1032 return True;
1033 }
1034
1035 prev = iorq;
1036 iorq = iorq->next;
1037 }
1038
1039 return False;
1040 }

  ViewVC Help
Powered by ViewVC 1.1.26