/[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 647 - (show annotations)
Mon Apr 5 19:23:08 2004 UTC (20 years, 1 month ago) by astrand
File MIME type: text/plain
File size: 21329 byte(s)
Shouldn't use mid-function var decls

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

  ViewVC Help
Powered by ViewVC 1.1.26