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