/[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 662 - (show annotations)
Fri Apr 16 14:04:02 2004 UTC (20 years ago) by astrand
File MIME type: text/plain
File size: 22946 byte(s)
Make sure iorq->fd is a valid FD before adding it to the FD_SET.
Prevents endless loops with "select: Bad file descriptor" error
messages.

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

  ViewVC Help
Powered by ViewVC 1.1.26