Initial commit - from Precise source
[freerdp-ubuntu-pcb-backport.git] / channels / rdpdr / serial / serial_main.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol client.
3  * Serial Port Device Service Virtual Channel
4  *
5  * Copyright 2011 O.S. Systems Software Ltda.
6  * Copyright 2011 Eduardo Fiss Beloni <beloni@ossystems.com.br>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *     http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <errno.h>
25
26 #include "config.h"
27
28 #ifdef HAVE_SYS_MODEM_H
29 #include <sys/modem.h>
30 #endif
31 #ifdef HAVE_SYS_FILIO_H
32 #include <sys/filio.h>
33 #endif
34 #ifdef HAVE_SYS_STRTIO_H
35 #include <sys/strtio.h>
36 #endif
37 #ifdef HAVE_UNISTD_H
38 #include <unistd.h>
39 #endif
40
41 #include "rdpdr_types.h"
42 #include "rdpdr_constants.h"
43 #include "devman.h"
44 #include "serial_tty.h"
45 #include "serial_constants.h"
46
47 #include <freerdp/utils/stream.h>
48 #include <freerdp/utils/thread.h>
49 #include <freerdp/utils/unicode.h>
50 #include <freerdp/utils/wait_obj.h>
51
52 typedef struct _SERIAL_DEVICE SERIAL_DEVICE;
53 struct _SERIAL_DEVICE
54 {
55         DEVICE device;
56
57         char* path;
58         SERIAL_TTY* tty;
59
60         LIST* irp_list;
61         LIST* pending_irps;
62         freerdp_thread* thread;
63         struct wait_obj* in_event;
64
65         fd_set read_fds;
66         fd_set write_fds;
67         uint32 nfds;
68         struct timeval tv;
69         uint32 select_timeout;
70         uint32 timeout_id;
71 };
72
73 static void serial_abort_single_io(SERIAL_DEVICE* serial, uint32 file_id, uint32 abort_io, uint32 io_status);
74 static void serial_check_for_events(SERIAL_DEVICE* serial);
75 static void serial_handle_async_irp(SERIAL_DEVICE* serial, IRP* irp);
76 static boolean serial_check_fds(SERIAL_DEVICE* serial);
77
78 static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp)
79 {
80         SERIAL_TTY* tty;
81         uint32 PathLength;
82         uint32 FileId;
83         char* path;
84         UNICONV* uniconv;
85
86         stream_seek(irp->input, 28); /* DesiredAccess(4) AllocationSize(8), FileAttributes(4) */
87                                                                  /* SharedAccess(4) CreateDisposition(4), CreateOptions(4) */
88         stream_read_uint32(irp->input, PathLength);
89
90         uniconv = freerdp_uniconv_new();
91         path = freerdp_uniconv_in(uniconv, stream_get_tail(irp->input), PathLength);
92         freerdp_uniconv_free(uniconv);
93
94         FileId = irp->devman->id_sequence++;
95
96         tty = serial_tty_new(serial->path, FileId);
97         if (tty == NULL)
98         {
99                 irp->IoStatus = STATUS_UNSUCCESSFUL;
100                 FileId = 0;
101
102                 DEBUG_WARN("failed to create %s", path);
103         }
104         else
105         {
106                 serial->tty = tty;
107                 DEBUG_SVC("%s(%d) created.", serial->path, FileId);
108         }
109
110         stream_write_uint32(irp->output, FileId);
111         stream_write_uint8(irp->output, 0);
112
113         xfree(path);
114
115         irp->Complete(irp);
116 }
117
118 static void serial_process_irp_close(SERIAL_DEVICE* serial, IRP* irp)
119 {
120         SERIAL_TTY* tty;
121
122         tty = serial->tty;
123         if (tty == NULL)
124         {
125                 irp->IoStatus = STATUS_UNSUCCESSFUL;
126                 DEBUG_WARN("tty not valid.");
127         }
128         else
129         {
130                 DEBUG_SVC("%s(%d) closed.", serial->path, tty->id);
131
132                 serial_tty_free(tty);
133                 serial->tty = NULL;
134         }
135
136         stream_write_zero(irp->output, 5); /* Padding(5) */
137
138         irp->Complete(irp);
139 }
140
141 static void serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp)
142 {
143         SERIAL_TTY* tty;
144         uint32 Length;
145         uint64 Offset;
146         uint8* buffer = NULL;
147
148         stream_read_uint32(irp->input, Length);
149         stream_read_uint64(irp->input, Offset);
150
151         DEBUG_SVC("length %u offset %llu", Length, Offset);
152
153         tty = serial->tty;
154         if (tty == NULL)
155         {
156                 irp->IoStatus = STATUS_UNSUCCESSFUL;
157                 Length = 0;
158
159                 DEBUG_WARN("tty not valid.");
160         }
161         else
162         {
163                 buffer = (uint8*)xmalloc(Length);
164                 if (!serial_tty_read(tty, buffer, &Length))
165                 {
166                         irp->IoStatus = STATUS_UNSUCCESSFUL;
167                         xfree(buffer);
168                         buffer = NULL;
169                         Length = 0;
170
171                         DEBUG_WARN("read %s(%d) failed.", serial->path, tty->id);
172                 }
173                 else
174                 {
175                         DEBUG_SVC("read %llu-%llu from %d", Offset, Offset + Length, tty->id);
176                 }
177         }
178
179         stream_write_uint32(irp->output, Length);
180         if (Length > 0)
181         {
182                 stream_check_size(irp->output, Length);
183                 stream_write(irp->output, buffer, Length);
184         }
185         xfree(buffer);
186
187         irp->Complete(irp);
188 }
189
190 static void serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp)
191 {
192         SERIAL_TTY* tty;
193         uint32 Length;
194         uint64 Offset;
195
196         stream_read_uint32(irp->input, Length);
197         stream_read_uint64(irp->input, Offset);
198         stream_seek(irp->input, 20); /* Padding */
199
200         DEBUG_SVC("length %u offset %llu", Length, Offset);
201
202         tty = serial->tty;
203         if (tty == NULL)
204         {
205                 irp->IoStatus = STATUS_UNSUCCESSFUL;
206                 Length = 0;
207
208                 DEBUG_WARN("tty not valid.");
209         }
210         else if (!serial_tty_write(tty, stream_get_tail(irp->input), Length))
211         {
212                 irp->IoStatus = STATUS_UNSUCCESSFUL;
213                 Length = 0;
214
215                 DEBUG_WARN("write %s(%d) failed.", serial->path, tty->id);
216         }
217         else
218         {
219                 DEBUG_SVC("write %llu-%llu to %s(%d).", Offset, Offset + Length, serial->path, tty->id);
220         }
221
222         stream_write_uint32(irp->output, Length);
223         stream_write_uint8(irp->output, 0); /* Padding */
224
225         irp->Complete(irp);
226 }
227
228 static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp)
229 {
230         SERIAL_TTY* tty;
231         uint32 IoControlCode;
232         uint32 InputBufferLength;
233         uint32 OutputBufferLength;
234         uint32 abort_io = SERIAL_ABORT_IO_NONE;
235
236         DEBUG_SVC("[in] pending size %d", list_size(serial->pending_irps));
237
238         stream_read_uint32(irp->input, InputBufferLength);
239         stream_read_uint32(irp->input, OutputBufferLength);
240         stream_read_uint32(irp->input, IoControlCode);
241         stream_seek(irp->input, 20); /* Padding */
242
243         tty = serial->tty;
244         if (tty == NULL)
245         {
246                 irp->IoStatus = STATUS_UNSUCCESSFUL;
247                 OutputBufferLength = 0;
248
249                 DEBUG_WARN("tty not valid.");
250         }
251         else
252         {
253                 irp->IoStatus = serial_tty_control(tty, IoControlCode, irp->input, irp->output, &abort_io);
254         }
255
256         if (abort_io & SERIAL_ABORT_IO_WRITE)
257                 serial_abort_single_io(serial, tty->id, SERIAL_ABORT_IO_WRITE, STATUS_CANCELLED);
258         if (abort_io & SERIAL_ABORT_IO_READ)
259                 serial_abort_single_io(serial, tty->id, SERIAL_ABORT_IO_READ, STATUS_CANCELLED);
260
261         if (irp->IoStatus == STATUS_PENDING)
262                 list_enqueue(serial->pending_irps, irp);
263         else
264                 irp->Complete(irp);
265 }
266
267 static void serial_process_irp(SERIAL_DEVICE* serial, IRP* irp)
268 {
269         DEBUG_SVC("MajorFunction %u", irp->MajorFunction);
270
271         switch (irp->MajorFunction)
272         {
273                 case IRP_MJ_CREATE:
274                         serial_process_irp_create(serial, irp);
275                         break;
276
277                 case IRP_MJ_CLOSE:
278                         serial_process_irp_close(serial, irp);
279                         break;
280
281                 case IRP_MJ_READ:
282                         serial_handle_async_irp(serial, irp);
283                         //serial_process_irp_read(serial, irp);
284                         break;
285
286                 case IRP_MJ_WRITE:
287                         serial_handle_async_irp(serial, irp);
288                         //serial_process_irp_write(serial, irp);
289                         break;
290
291                 case IRP_MJ_DEVICE_CONTROL:
292                         serial_process_irp_device_control(serial, irp);
293                         break;
294
295                 default:
296                         DEBUG_WARN("MajorFunction 0x%X not supported", irp->MajorFunction);
297                         irp->IoStatus = STATUS_NOT_SUPPORTED;
298                         irp->Complete(irp);
299                         break;
300         }
301
302         serial_check_for_events(serial);
303 }
304
305 static void serial_process_irp_list(SERIAL_DEVICE* serial)
306 {
307         IRP* irp;
308
309         while (1)
310         {
311                 if (freerdp_thread_is_stopped(serial->thread))
312                         break;
313
314                 freerdp_thread_lock(serial->thread);
315                 irp = (IRP*)list_dequeue(serial->irp_list);
316                 freerdp_thread_unlock(serial->thread);
317
318                 if (irp == NULL)
319                         break;
320
321                 serial_process_irp(serial, irp);
322         }
323 }
324
325 static void* serial_thread_func(void* arg)
326 {
327         SERIAL_DEVICE* serial = (SERIAL_DEVICE*)arg;
328
329         while (1)
330         {
331                 freerdp_thread_wait(serial->thread);
332
333                 serial->nfds = 1;
334                 FD_ZERO(&serial->read_fds);
335                 FD_ZERO(&serial->write_fds);
336
337                 serial->tv.tv_sec = 20;
338                 serial->tv.tv_usec = 0;
339                 serial->select_timeout = 0;
340
341                 if (freerdp_thread_is_stopped(serial->thread))
342                         break;
343
344                 freerdp_thread_reset(serial->thread);
345                 serial_process_irp_list(serial);
346
347                 if (wait_obj_is_set(serial->in_event))
348                 {
349                         if (serial_check_fds(serial))
350                                 wait_obj_clear(serial->in_event);
351                 }
352         }
353
354         freerdp_thread_quit(serial->thread);
355
356         return NULL;
357 }
358
359 static void serial_irp_request(DEVICE* device, IRP* irp)
360 {
361         SERIAL_DEVICE* serial = (SERIAL_DEVICE*)device;
362
363         freerdp_thread_lock(serial->thread);
364         list_enqueue(serial->irp_list, irp);
365         freerdp_thread_unlock(serial->thread);
366
367         freerdp_thread_signal(serial->thread);
368 }
369
370 static void serial_free(DEVICE* device)
371 {
372         SERIAL_DEVICE* serial = (SERIAL_DEVICE*)device;
373         IRP* irp;
374
375         DEBUG_SVC("freeing device");
376
377         freerdp_thread_stop(serial->thread);
378         freerdp_thread_free(serial->thread);
379
380         while ((irp = (IRP*)list_dequeue(serial->irp_list)) != NULL)
381                 irp->Discard(irp);
382         list_free(serial->irp_list);
383
384         while ((irp = (IRP*)list_dequeue(serial->pending_irps)) != NULL)
385                 irp->Discard(irp);
386         list_free(serial->pending_irps);
387
388         xfree(serial);
389 }
390
391 int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
392 {
393         SERIAL_DEVICE* serial;
394         char* name;
395         char* path;
396         int i, len;
397
398         name = (char*)pEntryPoints->plugin_data->data[1];
399         path = (char*)pEntryPoints->plugin_data->data[2];
400
401         if (name[0] && path[0])
402         {
403                 serial = xnew(SERIAL_DEVICE);
404
405                 serial->device.type = RDPDR_DTYP_SERIAL;
406                 serial->device.name = name;
407                 serial->device.IRPRequest = serial_irp_request;
408                 serial->device.Free = serial_free;
409
410                 len = strlen(name);
411                 serial->device.data = stream_new(len + 1);
412                 for (i = 0; i <= len; i++)
413                         stream_write_uint8(serial->device.data, name[i] < 0 ? '_' : name[i]);
414
415                 serial->path = path;
416                 serial->irp_list = list_new();
417                 serial->pending_irps = list_new();
418                 serial->thread = freerdp_thread_new();
419                 serial->in_event = wait_obj_new();
420
421                 pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*)serial);
422
423                 freerdp_thread_start(serial->thread, serial_thread_func, serial);
424         }
425
426         return 0;
427 }
428
429 static void serial_abort_single_io(SERIAL_DEVICE* serial, uint32 file_id, uint32 abort_io, uint32 io_status)
430 {
431         IRP* irp = NULL;
432         uint32 major;
433         SERIAL_TTY* tty;
434
435         DEBUG_SVC("[in] pending size %d", list_size(serial->pending_irps));
436
437         tty = serial->tty;
438
439         switch (abort_io)
440         {
441                 case SERIAL_ABORT_IO_NONE:
442                         major = 0;
443                         break;
444
445                 case SERIAL_ABORT_IO_READ:
446                         major = IRP_MJ_READ;
447                         break;
448
449                 case SERIAL_ABORT_IO_WRITE:
450                         major = IRP_MJ_WRITE;
451                         break;
452
453                 default:
454                         DEBUG_SVC("unexpected abort_io code %d", abort_io);
455                         return;
456         }
457
458         irp = (IRP*)list_peek(serial->pending_irps);
459         while (irp)
460         {
461                 if (irp->FileId != file_id || irp->MajorFunction != major)
462                 {
463                         irp = (IRP*)list_next(serial->pending_irps, irp);
464                         continue;
465                 }
466
467                 /* Process a SINGLE FileId and MajorFunction */
468                 list_remove(serial->pending_irps, irp);
469                 irp->IoStatus = io_status;
470                 stream_write_uint32(irp->output, 0);
471                 irp->Complete(irp);
472
473                 wait_obj_set(serial->in_event);
474                 break;
475         }
476
477         DEBUG_SVC("[out] pending size %d", list_size(serial->pending_irps));
478 }
479
480 static void serial_check_for_events(SERIAL_DEVICE* serial)
481 {
482         IRP* irp = NULL;
483         IRP* prev;
484         uint32 result = 0;
485         SERIAL_TTY* tty;
486
487         tty = serial->tty;
488
489         DEBUG_SVC("[in] pending size %d", list_size(serial->pending_irps));
490
491         irp = (IRP*)list_peek(serial->pending_irps);
492         while (irp)
493         {
494                 prev = NULL;
495
496                 if (irp->MajorFunction == IRP_MJ_DEVICE_CONTROL)
497                 {
498                         if (serial_tty_get_event(tty, &result))
499                         {
500                                 DEBUG_SVC("got event result %u", result);
501
502                                 irp->IoStatus = STATUS_SUCCESS;
503                                 stream_write_uint32(irp->output, result);
504                                 irp->Complete(irp);
505
506                                 prev = irp;
507                                 irp = (IRP*)list_next(serial->pending_irps, irp);
508                                 list_remove(serial->pending_irps, prev);
509
510                                 wait_obj_set(serial->in_event);
511                         }
512                 }
513
514                 if (!prev)
515                         irp = (IRP*)list_next(serial->pending_irps, irp);
516         }
517
518         DEBUG_SVC("[out] pending size %d", list_size(serial->pending_irps));
519 }
520
521 void serial_get_timeouts(SERIAL_DEVICE* serial, IRP* irp, uint32* timeout, uint32* interval_timeout)
522 {
523         SERIAL_TTY* tty;
524         uint32 Length;
525         uint32 pos;
526
527         pos = stream_get_pos(irp->input);
528         stream_read_uint32(irp->input, Length);
529         stream_set_pos(irp->input, pos);
530
531         DEBUG_SVC("length read %u", Length);
532
533         tty = serial->tty;
534         *timeout = (tty->read_total_timeout_multiplier * Length) +
535                 tty->read_total_timeout_constant;
536         *interval_timeout = tty->read_interval_timeout;
537
538         DEBUG_SVC("timeouts %u %u", *timeout, *interval_timeout);
539 }
540
541 static void serial_handle_async_irp(SERIAL_DEVICE* serial, IRP* irp)
542 {
543         uint32 timeout = 0;
544         uint32 itv_timeout = 0;
545         SERIAL_TTY* tty;
546
547         tty = serial->tty;
548
549         switch (irp->MajorFunction)
550         {
551         case IRP_MJ_WRITE:
552                 DEBUG_SVC("handling IRP_MJ_WRITE");
553                 break;
554
555         case IRP_MJ_READ:
556                 DEBUG_SVC("handling IRP_MJ_READ");
557
558                 serial_get_timeouts(serial, irp, &timeout, &itv_timeout);
559
560                 /* Check if io request timeout is smaller than current (but not 0). */
561                 if (timeout && (serial->select_timeout == 0 || timeout < serial->select_timeout))
562                 {
563                         serial->select_timeout = timeout;
564                         serial->tv.tv_sec = serial->select_timeout / 1000;
565                         serial->tv.tv_usec = (serial->select_timeout % 1000) * 1000;
566                         serial->timeout_id = tty->id;
567                 }
568                 if (itv_timeout && (serial->select_timeout == 0 || itv_timeout < serial->select_timeout))
569                 {
570                         serial->select_timeout = itv_timeout;
571                         serial->tv.tv_sec = serial->select_timeout / 1000;
572                         serial->tv.tv_usec = (serial->select_timeout % 1000) * 1000;
573                         serial->timeout_id = tty->id;
574                 }
575                 DEBUG_SVC("select_timeout %u, tv_sec %lu tv_usec %lu, timeout_id %u",
576                         serial->select_timeout, serial->tv.tv_sec, serial->tv.tv_usec, serial->timeout_id);
577                 break;
578
579         default:
580                 DEBUG_SVC("no need to handle %d", irp->MajorFunction);
581                 return;
582         }
583
584         irp->IoStatus = STATUS_PENDING;
585         list_enqueue(serial->pending_irps, irp);
586         wait_obj_set(serial->in_event);
587 }
588
589 static void __serial_check_fds(SERIAL_DEVICE* serial)
590 {
591         IRP* irp;
592         IRP* prev;
593         SERIAL_TTY* tty;
594         uint32 result = 0;
595
596         memset(&serial->tv, 0, sizeof(struct timeval));
597         tty = serial->tty;
598
599         /* scan every pending */
600         irp = list_peek(serial->pending_irps);
601         while (irp)
602         {
603                 DEBUG_SVC("MajorFunction %u", irp->MajorFunction);
604
605                 switch (irp->MajorFunction)
606                 {
607                         case IRP_MJ_READ:
608                                 if (FD_ISSET(tty->fd, &serial->read_fds))
609                                 {
610                                         irp->IoStatus = STATUS_SUCCESS;
611                                         serial_process_irp_read(serial, irp);
612                                 }
613                                 break;
614
615                         case IRP_MJ_WRITE:
616                                 if (FD_ISSET(tty->fd, &serial->write_fds))
617                                 {
618                                         irp->IoStatus = STATUS_SUCCESS;
619                                         serial_process_irp_write(serial, irp);
620                                 }
621                                 break;
622
623                         case IRP_MJ_DEVICE_CONTROL:
624                                 if (serial_tty_get_event(tty, &result))
625                                 {
626                                         DEBUG_SVC("got event result %u", result);
627
628                                         irp->IoStatus = STATUS_SUCCESS;
629                                         stream_write_uint32(irp->output, result);
630                                         irp->Complete(irp);
631                                 }
632                                 break;
633
634                         default:
635                                 DEBUG_SVC("no request found");
636                                 break;
637                 }
638
639                 prev = irp;
640                 irp = (IRP*)list_next(serial->pending_irps, irp);
641                 if (prev->IoStatus == STATUS_SUCCESS)
642                 {
643                         list_remove(serial->pending_irps, prev);
644                         wait_obj_set(serial->in_event);
645                 }
646         }
647 }
648
649 static void serial_set_fds(SERIAL_DEVICE* serial)
650 {
651         fd_set* fds;
652         IRP* irp;
653         SERIAL_TTY* tty;
654
655         DEBUG_SVC("[in] pending size %d", list_size(serial->pending_irps));
656
657         tty = serial->tty;
658         irp = (IRP*)list_peek(serial->pending_irps);
659         while (irp)
660         {
661                 fds = NULL;
662
663                 switch (irp->MajorFunction)
664                 {
665                         case IRP_MJ_WRITE:
666                                 fds = &serial->write_fds;
667                                 break;
668
669                         case IRP_MJ_READ:
670                                 fds = &serial->read_fds;
671                                 break;
672                 }
673
674                 if (fds && (tty->fd >= 0))
675                 {
676                         FD_SET(tty->fd, fds);
677                         serial->nfds = MAX(serial->nfds, tty->fd);
678                 }
679                 irp = (IRP*)list_next(serial->pending_irps, irp);
680         }
681 }
682
683 static boolean serial_check_fds(SERIAL_DEVICE* serial)
684 {
685         if (list_size(serial->pending_irps) == 0)
686                 return 1;
687
688         serial_set_fds(serial);
689         DEBUG_SVC("waiting %lu %lu", serial->tv.tv_sec, serial->tv.tv_usec);
690
691         switch (select(serial->nfds + 1, &serial->read_fds, &serial->write_fds, NULL, &serial->tv))
692         {
693                 case -1:
694                         DEBUG_SVC("select has returned -1 with error: %s", strerror(errno));
695                         return 0;
696
697                 case 0:
698                         if (serial->select_timeout)
699                         {
700                                 serial_abort_single_io(serial, serial->timeout_id, SERIAL_ABORT_IO_NONE, STATUS_TIMEOUT);
701                                 serial_abort_single_io(serial, serial->timeout_id, SERIAL_ABORT_IO_READ, STATUS_TIMEOUT);
702                                 serial_abort_single_io(serial, serial->timeout_id, SERIAL_ABORT_IO_WRITE, STATUS_TIMEOUT);
703                         }
704                         DEBUG_SVC("select has timed out");
705                         return 0;
706
707                 default:
708                         break;
709         }
710
711         __serial_check_fds(serial);
712
713         return 1;
714 }