/[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 650 - (show annotations)
Thu Apr 15 20:11:19 2004 UTC (20 years, 1 month ago) by astrand
File MIME type: text/plain
File size: 21230 byte(s)
Removed duplicat IRP_MJ defs. Added def for IRP_MJ_LOCK_CONTROL

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

  ViewVC Help
Powered by ViewVC 1.1.26