/[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 674 - (show annotations)
Mon Apr 19 09:21:25 2004 UTC (20 years ago) by astrand
File MIME type: text/plain
File size: 23282 byte(s)
When checking for bad filedescriptors, need to explicitly check for EBADF

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 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 = 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 out_uint8p(s, g_rdpdr_device[i].name, 8);
270
271 switch (g_rdpdr_device[i].device_type)
272 {
273 case DEVICE_TYPE_PRINTER:
274 printerinfo = (PRINTER *) g_rdpdr_device[i].pdevice_data;
275
276 driverlen = 2 * strlen(printerinfo->driver) + 2;
277 printerlen = 2 * strlen(printerinfo->printer) + 2;
278 bloblen = printerinfo->bloblen;
279
280 out_uint32_le(s, 24 + driverlen + printerlen + bloblen); /* length of extra info */
281 out_uint32_le(s, printerinfo->default_printer ? 2 : 0);
282 out_uint8s(s, 8); /* unknown */
283 out_uint32_le(s, driverlen);
284 out_uint32_le(s, printerlen);
285 out_uint32_le(s, bloblen);
286 rdp_out_unistr(s, printerinfo->driver, driverlen - 2);
287 rdp_out_unistr(s, printerinfo->printer, printerlen - 2);
288 out_uint8a(s, printerinfo->blob, bloblen);
289
290 if (printerinfo->blob)
291 xfree(printerinfo->blob); /* Blob is sent twice if reconnecting */
292 break;
293 default:
294 out_uint32(s, 0);
295 }
296 }
297 #if 0
298 out_uint32_le(s, 0x20); /* Device type 0x20 - smart card */
299 out_uint32_le(s, 0);
300 out_uint8p(s, "SCARD", 5);
301 out_uint8s(s, 3);
302 out_uint32(s, 0);
303 #endif
304
305 s_mark_end(s);
306 channel_send(s, rdpdr_channel);
307 }
308
309 static void
310 rdpdr_send_completion(uint32 device, uint32 id, uint32 status, uint32 result, uint8 * buffer,
311 uint32 length)
312 {
313 uint8 magic[4] = "rDCI";
314 STREAM s;
315
316 s = channel_init(rdpdr_channel, 20 + length);
317 out_uint8a(s, magic, 4);
318 out_uint32_le(s, device);
319 out_uint32_le(s, id);
320 out_uint32_le(s, status);
321 out_uint32_le(s, result);
322 out_uint8p(s, buffer, length);
323 s_mark_end(s);
324 /* JIF
325 hexdump(s->channel_hdr + 8, s->end - s->channel_hdr - 8); */
326 channel_send(s, rdpdr_channel);
327 }
328
329 static void
330 rdpdr_process_irp(STREAM s)
331 {
332 uint32 result = 0,
333 length = 0,
334 desired_access = 0,
335 request,
336 file,
337 info_level,
338 buffer_len,
339 id,
340 major,
341 minor,
342 device,
343 offset,
344 bytes_in,
345 bytes_out,
346 error_mode,
347 share_mode, disposition, total_timeout, interval_timeout, flags_and_attributes = 0;
348
349 char filename[256];
350 uint8 *buffer, *pst_buf;
351 struct stream out;
352 DEVICE_FNS *fns;
353 BOOL rw_blocking = True;
354 NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
355
356 in_uint32_le(s, device);
357 in_uint32_le(s, file);
358 in_uint32_le(s, id);
359 in_uint32_le(s, major);
360 in_uint32_le(s, minor);
361
362 buffer_len = 0;
363 buffer = (uint8 *) xmalloc(1024);
364 buffer[0] = 0;
365
366 switch (g_rdpdr_device[device].device_type)
367 {
368 case DEVICE_TYPE_SERIAL:
369
370 fns = &serial_fns;
371 rw_blocking = False;
372 break;
373
374 case DEVICE_TYPE_PARALLEL:
375
376 fns = &parallel_fns;
377 rw_blocking = False;
378 break;
379
380 case DEVICE_TYPE_PRINTER:
381
382 fns = &printer_fns;
383 break;
384
385 case DEVICE_TYPE_DISK:
386
387 fns = &disk_fns;
388 rw_blocking = False;
389 break;
390
391 case DEVICE_TYPE_SCARD:
392 default:
393
394 error("IRP for bad device %ld\n", device);
395 return;
396 }
397
398 switch (major)
399 {
400 case IRP_MJ_CREATE:
401
402 in_uint32_be(s, desired_access);
403 in_uint8s(s, 0x08); // unknown
404 in_uint32_le(s, error_mode);
405 in_uint32_le(s, share_mode);
406 in_uint32_le(s, disposition);
407 in_uint32_le(s, flags_and_attributes);
408 in_uint32_le(s, length);
409
410 if (length && (length / 2) < 256)
411 {
412 rdp_in_unistr(s, filename, length);
413 convert_to_unix_filename(filename);
414 }
415 else
416 {
417 filename[0] = 0;
418 }
419
420 if (!fns->create)
421 {
422 status = STATUS_NOT_SUPPORTED;
423 break;
424 }
425
426 status = fns->create(device, desired_access, share_mode, disposition,
427 flags_and_attributes, filename, &result);
428 buffer_len = 1;
429 break;
430
431 case IRP_MJ_CLOSE:
432 if (!fns->close)
433 {
434 status = STATUS_NOT_SUPPORTED;
435 break;
436 }
437
438 status = fns->close(file);
439 break;
440
441 case IRP_MJ_READ:
442
443 if (!fns->read)
444 {
445 status = STATUS_NOT_SUPPORTED;
446 break;
447 }
448
449 in_uint32_le(s, length);
450 in_uint32_le(s, offset);
451 #if WITH_DEBUG_RDP5
452 DEBUG(("RDPDR IRP Read (length: %d, offset: %d)\n", length, offset));
453 #endif
454 if (!rdpdr_handle_ok(device, file))
455 {
456 status = STATUS_INVALID_HANDLE;
457 break;
458 }
459
460 if (rw_blocking) // Complete read immediately
461 {
462 buffer = (uint8 *) xrealloc((void *) buffer, length);
463 if (!buffer)
464 {
465 status = STATUS_CANCELLED;
466 break;
467 }
468 status = fns->read(file, buffer, length, offset, &result);
469 buffer_len = result;
470 break;
471 }
472
473 // Add request to table
474 pst_buf = (uint8 *) xmalloc(length);
475 if (!pst_buf)
476 {
477 status = STATUS_CANCELLED;
478 break;
479 }
480 serial_get_timeout(file, length, &total_timeout, &interval_timeout);
481 if (add_async_iorequest
482 (device, file, id, major, length, fns, total_timeout, interval_timeout,
483 pst_buf, offset))
484 {
485 status = STATUS_PENDING;
486 break;
487 }
488
489 status = STATUS_CANCELLED;
490 break;
491 case IRP_MJ_WRITE:
492
493 buffer_len = 1;
494
495 if (!fns->write)
496 {
497 status = STATUS_NOT_SUPPORTED;
498 break;
499 }
500
501 in_uint32_le(s, length);
502 in_uint32_le(s, offset);
503 in_uint8s(s, 0x18);
504 #if WITH_DEBUG_RDP5
505 DEBUG(("RDPDR IRP Write (length: %d)\n", result));
506 #endif
507 if (!rdpdr_handle_ok(device, file))
508 {
509 status = STATUS_INVALID_HANDLE;
510 break;
511 }
512
513 if (rw_blocking) // Complete immediately
514 {
515 status = fns->write(file, s->p, length, offset, &result);
516 break;
517 }
518
519 // Add to table
520 pst_buf = (uint8 *) xmalloc(length);
521 if (!pst_buf)
522 {
523 status = STATUS_CANCELLED;
524 break;
525 }
526
527 in_uint8a(s, pst_buf, length);
528
529 if (add_async_iorequest
530 (device, file, id, major, length, fns, 0, 0, pst_buf, offset))
531 {
532 status = STATUS_PENDING;
533 break;
534 }
535
536 status = STATUS_CANCELLED;
537 break;
538
539 case IRP_MJ_QUERY_INFORMATION:
540
541 if (g_rdpdr_device[device].device_type != DEVICE_TYPE_DISK)
542 {
543 status = STATUS_INVALID_HANDLE;
544 break;
545 }
546 in_uint32_le(s, info_level);
547
548 out.data = out.p = buffer;
549 out.size = sizeof(buffer);
550 status = disk_query_information(file, info_level, &out);
551 result = buffer_len = out.p - out.data;
552
553 break;
554
555 case IRP_MJ_SET_INFORMATION:
556
557 if (g_rdpdr_device[device].device_type != DEVICE_TYPE_DISK)
558 {
559 status = STATUS_INVALID_HANDLE;
560 break;
561 }
562
563 in_uint32_le(s, info_level);
564
565 out.data = out.p = buffer;
566 out.size = sizeof(buffer);
567 status = disk_set_information(file, info_level, s, &out);
568 result = buffer_len = out.p - out.data;
569 break;
570
571 case IRP_MJ_QUERY_VOLUME_INFORMATION:
572
573 if (g_rdpdr_device[device].device_type != DEVICE_TYPE_DISK)
574 {
575 status = STATUS_INVALID_HANDLE;
576 break;
577 }
578
579 in_uint32_le(s, info_level);
580
581 out.data = out.p = buffer;
582 out.size = sizeof(buffer);
583 status = disk_query_volume_information(file, info_level, &out);
584 result = buffer_len = out.p - out.data;
585 break;
586
587 case IRP_MJ_DIRECTORY_CONTROL:
588
589 if (g_rdpdr_device[device].device_type != DEVICE_TYPE_DISK)
590 {
591 status = STATUS_INVALID_HANDLE;
592 break;
593 }
594
595 switch (minor)
596 {
597 case IRP_MN_QUERY_DIRECTORY:
598
599 in_uint32_le(s, info_level);
600 in_uint8s(s, 1);
601 in_uint32_le(s, length);
602 in_uint8s(s, 0x17);
603 if (length && length < 2 * 255)
604 {
605 rdp_in_unistr(s, filename, length);
606 convert_to_unix_filename(filename);
607 }
608 else
609 {
610 filename[0] = 0;
611 }
612 out.data = out.p = buffer;
613 out.size = sizeof(buffer);
614 status = disk_query_directory(file, info_level, filename,
615 &out);
616 result = buffer_len = out.p - out.data;
617 if (!buffer_len)
618 buffer_len++;
619 break;
620
621 case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
622
623 /* JIF
624 unimpl("IRP major=0x%x minor=0x%x: IRP_MN_NOTIFY_CHANGE_DIRECTORY\n", major, minor); */
625 status = STATUS_PENDING; // Don't send completion packet
626 break;
627
628 default:
629
630 status = STATUS_INVALID_PARAMETER;
631 /* JIF
632 unimpl("IRP major=0x%x minor=0x%x\n", major, minor); */
633 }
634 break;
635
636 case IRP_MJ_DEVICE_CONTROL:
637
638 if (!fns->device_control)
639 {
640 status = STATUS_NOT_SUPPORTED;
641 break;
642 }
643
644 in_uint32_le(s, bytes_out);
645 in_uint32_le(s, bytes_in);
646 in_uint32_le(s, request);
647 in_uint8s(s, 0x14);
648
649 buffer = (uint8 *) xrealloc((void *) buffer, bytes_out + 0x14);
650 if (!buffer)
651 {
652 status = STATUS_CANCELLED;
653 break;
654 }
655
656 out.data = out.p = buffer;
657 out.size = sizeof(buffer);
658 status = fns->device_control(file, request, s, &out);
659 result = buffer_len = out.p - out.data;
660 break;
661
662
663 case IRP_MJ_LOCK_CONTROL:
664
665 if (g_rdpdr_device[device].device_type != DEVICE_TYPE_DISK)
666 {
667 status = STATUS_INVALID_HANDLE;
668 break;
669 }
670
671 in_uint32_le(s, info_level);
672
673 out.data = out.p = buffer;
674 out.size = sizeof(buffer);
675 /* FIXME: Perhaps consider actually *do*
676 something here :-) */
677 status = STATUS_SUCCESS;
678 result = buffer_len = out.p - out.data;
679 break;
680
681 default:
682 unimpl("IRP major=0x%x minor=0x%x\n", major, minor);
683 break;
684 }
685
686 if (status != STATUS_PENDING)
687 {
688 rdpdr_send_completion(device, id, status, result, buffer, buffer_len);
689 }
690 if (buffer)
691 xfree(buffer);
692 buffer = NULL;
693 }
694
695 static void
696 rdpdr_send_clientcapabilty(void)
697 {
698 uint8 magic[4] = "rDPC";
699 STREAM s;
700
701 s = channel_init(rdpdr_channel, 0x50);
702 out_uint8a(s, magic, 4);
703 out_uint32_le(s, 5); /* count */
704 out_uint16_le(s, 1); /* first */
705 out_uint16_le(s, 0x28); /* length */
706 out_uint32_le(s, 1);
707 out_uint32_le(s, 2);
708 out_uint16_le(s, 2);
709 out_uint16_le(s, 5);
710 out_uint16_le(s, 1);
711 out_uint16_le(s, 5);
712 out_uint16_le(s, 0xFFFF);
713 out_uint16_le(s, 0);
714 out_uint32_le(s, 0);
715 out_uint32_le(s, 3);
716 out_uint32_le(s, 0);
717 out_uint32_le(s, 0);
718 out_uint16_le(s, 2); /* second */
719 out_uint16_le(s, 8); /* length */
720 out_uint32_le(s, 1);
721 out_uint16_le(s, 3); /* third */
722 out_uint16_le(s, 8); /* length */
723 out_uint32_le(s, 1);
724 out_uint16_le(s, 4); /* fourth */
725 out_uint16_le(s, 8); /* length */
726 out_uint32_le(s, 1);
727 out_uint16_le(s, 5); /* fifth */
728 out_uint16_le(s, 8); /* length */
729 out_uint32_le(s, 1);
730
731 s_mark_end(s);
732 channel_send(s, rdpdr_channel);
733 }
734
735 static void
736 rdpdr_process(STREAM s)
737 {
738 uint32 handle;
739 uint8 *magic;
740
741 #if WITH_DEBUG_RDP5
742 printf("--- rdpdr_process ---\n");
743 hexdump(s->p, s->end - s->p);
744 #endif
745 in_uint8p(s, magic, 4);
746
747 if ((magic[0] == 'r') && (magic[1] == 'D'))
748 {
749 if ((magic[2] == 'R') && (magic[3] == 'I'))
750 {
751 rdpdr_process_irp(s);
752 return;
753 }
754 if ((magic[2] == 'n') && (magic[3] == 'I'))
755 {
756 rdpdr_send_connect();
757 rdpdr_send_name();
758 return;
759 }
760 if ((magic[2] == 'C') && (magic[3] == 'C'))
761 {
762 /* connect from server */
763 rdpdr_send_clientcapabilty();
764 rdpdr_send_available();
765 return;
766 }
767 if ((magic[2] == 'r') && (magic[3] == 'd'))
768 {
769 /* connect to a specific resource */
770 in_uint32(s, handle);
771 #if WITH_DEBUG_RDP5
772 DEBUG(("RDPDR: Server connected to resource %d\n", handle));
773 #endif
774 return;
775 }
776 if ((magic[2] == 'P') && (magic[3] == 'S'))
777 {
778 /* server capability */
779 return;
780 }
781 }
782 if ((magic[0] == 'R') && (magic[1] == 'P'))
783 {
784 if ((magic[2] == 'C') && (magic[3] == 'P'))
785 {
786 printercache_process(s);
787 return;
788 }
789 }
790 unimpl("RDPDR packet type %c%c%c%c\n", magic[0], magic[1], magic[2], magic[3]);
791 }
792
793 BOOL
794 rdpdr_init()
795 {
796 if (g_num_devices > 0)
797 {
798 rdpdr_channel =
799 channel_register("rdpdr",
800 CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_COMPRESS_RDP,
801 rdpdr_process);
802 }
803
804 return (rdpdr_channel != NULL);
805 }
806
807 /* Add file descriptors of pending io request to select() */
808 void
809 rdpdr_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv, BOOL * timeout)
810 {
811 uint32 select_timeout = 0; // Timeout value to be used for select() (in millisecons).
812 struct async_iorequest *iorq;
813 char c;
814
815 iorq = g_iorequest;
816 while (iorq != NULL)
817 {
818 if (iorq->fd != 0)
819 {
820 switch (iorq->major)
821 {
822 case IRP_MJ_READ:
823 /* Is this FD valid? FDs will
824 be invalid when
825 reconnecting. FIXME: Real
826 support for reconnects. */
827
828 if ((read(iorq->fd, &c, 0) != 0) && (errno == EBADF))
829 break;
830
831 FD_SET(iorq->fd, rfds);
832 *n = MAX(*n, iorq->fd);
833
834 // Check if io request timeout is smaller than current (but not 0).
835 if (iorq->timeout
836 && (select_timeout == 0
837 || iorq->timeout < select_timeout))
838 {
839 // Set new timeout
840 select_timeout = iorq->timeout;
841 g_min_timeout_fd = iorq->fd; /* Remember fd */
842 tv->tv_sec = select_timeout / 1000;
843 tv->tv_usec = (select_timeout % 1000) * 1000;
844 *timeout = True;
845 }
846
847 break;
848
849 case IRP_MJ_WRITE:
850 /* FD still valid? See above. */
851 if ((write(iorq->fd, &c, 0) != 0) && (errno == EBADF))
852 break;
853
854 FD_SET(iorq->fd, wfds);
855 *n = MAX(*n, iorq->fd);
856 break;
857
858 }
859
860 }
861
862 iorq = iorq->next;
863 }
864 }
865
866 struct async_iorequest *
867 rdpdr_remove_iorequest(struct async_iorequest *prev, struct async_iorequest *iorq)
868 {
869 if (!iorq)
870 return NULL;
871
872 if (iorq->buffer)
873 xfree(iorq->buffer);
874 if (prev)
875 {
876 prev->next = iorq->next;
877 xfree(iorq);
878 iorq = prev->next;
879 }
880 else
881 {
882 // Even if NULL
883 g_iorequest = iorq->next;
884 xfree(iorq);
885 iorq = NULL;
886 }
887 return iorq;
888 }
889
890 /* Check if select() returned with one of the rdpdr file descriptors, and complete io if it did */
891 void
892 rdpdr_check_fds(fd_set * rfds, fd_set * wfds, BOOL timed_out)
893 {
894 NTSTATUS status;
895 uint32 result = 0;
896 DEVICE_FNS *fns;
897 struct async_iorequest *iorq;
898 struct async_iorequest *prev;
899 uint32 req_size = 0;
900
901 if (timed_out)
902 {
903 rdpdr_abort_io(g_min_timeout_fd, 0, STATUS_TIMEOUT);
904 return;
905 }
906
907 iorq = g_iorequest;
908 prev = NULL;
909 while (iorq != NULL)
910 {
911 if (iorq->fd != 0)
912 {
913 switch (iorq->major)
914 {
915 case IRP_MJ_READ:
916 if (FD_ISSET(iorq->fd, rfds))
917 {
918 /* Read the data */
919 fns = iorq->fns;
920
921 req_size =
922 (iorq->length - iorq->partial_len) >
923 8192 ? 8192 : (iorq->length -
924 iorq->partial_len);
925 /* never read larger chunks than 8k - chances are that it will block */
926 status = fns->read(iorq->fd,
927 iorq->buffer + iorq->partial_len,
928 req_size, iorq->offset, &result);
929
930 if (result > 0)
931 {
932 iorq->partial_len += result;
933 iorq->offset += result;
934 }
935 #if WITH_DEBUG_RDP5
936 DEBUG(("RDPDR: %d bytes of data read\n", result));
937 #endif
938 /* only delete link if all data has been transfered */
939 /* or if result was 0 and status success - EOF */
940 if ((iorq->partial_len == iorq->length) ||
941 (result == 0))
942 {
943 #if WITH_DEBUG_RDP5
944 DEBUG(("RDPDR: AIO total %u bytes read of %u\n", iorq->partial_len, iorq->length));
945 #endif
946 rdpdr_send_completion(iorq->device,
947 iorq->id, status,
948 iorq->partial_len,
949 iorq->buffer,
950 iorq->partial_len);
951 iorq = rdpdr_remove_iorequest(prev, iorq);
952 }
953 }
954 break;
955 case IRP_MJ_WRITE:
956 if (FD_ISSET(iorq->fd, wfds))
957 {
958 /* Write data. */
959 fns = iorq->fns;
960
961 req_size =
962 (iorq->length - iorq->partial_len) >
963 8192 ? 8192 : (iorq->length -
964 iorq->partial_len);
965
966 /* never write larger chunks than 8k - chances are that it will block */
967 status = fns->write(iorq->fd,
968 iorq->buffer +
969 iorq->partial_len, req_size,
970 iorq->offset, &result);
971
972 if (result > 0)
973 {
974 iorq->partial_len += result;
975 iorq->offset += result;
976 }
977
978 #if WITH_DEBUG_RDP5
979 DEBUG(("RDPDR: %d bytes of data written\n",
980 result));
981 #endif
982 /* only delete link if all data has been transfered */
983 /* or we couldn't write */
984 if ((iorq->partial_len == iorq->length)
985 || (result == 0))
986 {
987 #if WITH_DEBUG_RDP5
988 DEBUG(("RDPDR: AIO total %u bytes written of %u\n", iorq->partial_len, iorq->length));
989 #endif
990 rdpdr_send_completion(iorq->device,
991 iorq->id, status,
992 iorq->partial_len,
993 (uint8 *) "", 1);
994
995 iorq = rdpdr_remove_iorequest(prev, iorq);
996 }
997 }
998 break;
999 }
1000
1001 }
1002 prev = iorq;
1003 if (iorq)
1004 iorq = iorq->next;
1005 }
1006
1007 }
1008
1009 /* Abort a pending io request for a given handle and major */
1010 BOOL
1011 rdpdr_abort_io(uint32 fd, uint32 major, NTSTATUS status)
1012 {
1013 uint32 result;
1014 struct async_iorequest *iorq;
1015 struct async_iorequest *prev;
1016
1017 iorq = g_iorequest;
1018 prev = NULL;
1019 while (iorq != NULL)
1020 {
1021 // Only remove from table when major is not set, or when correct major is supplied.
1022 // Abort read should not abort a write io request.
1023 if ((iorq->fd == fd) && (major == 0 || iorq->major == major))
1024 {
1025 result = 0;
1026 rdpdr_send_completion(iorq->device, iorq->id, status, result, (uint8 *) "",
1027 1);
1028
1029 iorq = rdpdr_remove_iorequest(prev, iorq);
1030 return True;
1031 }
1032
1033 prev = iorq;
1034 iorq = iorq->next;
1035 }
1036
1037 return False;
1038 }

  ViewVC Help
Powered by ViewVC 1.1.26