Fix changelog email address
[freerdp-ubuntu-pcb-backport.git] / channels / rdpdr / parallel / parallel_main.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol client.
3  * Redirected Parallel Port Device Service
4  *
5  * Copyright 2010 O.S. Systems Software Ltda.
6  * Copyright 2010 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
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <termios.h>
28 #include <errno.h>
29 #include <strings.h>
30 #include <sys/ioctl.h>
31 #ifdef __LINUX__
32 #include <linux/ppdev.h>
33 #include <linux/parport.h>
34 #endif
35
36 #include <freerdp/types.h>
37 #include <freerdp/constants.h>
38 #include <freerdp/utils/list.h>
39 #include <freerdp/utils/thread.h>
40 #include <freerdp/utils/memory.h>
41 #include <freerdp/utils/stream.h>
42 #include <freerdp/utils/svc_plugin.h>
43
44 #include "rdpdr_constants.h"
45 #include "rdpdr_types.h"
46
47 struct _PARALLEL_DEVICE
48 {
49         DEVICE device;
50
51         int file;
52         char* path;
53         uint32 id;
54
55         LIST* irp_list;
56         freerdp_thread* thread;
57 };
58 typedef struct _PARALLEL_DEVICE PARALLEL_DEVICE;
59
60 static void parallel_process_irp_create(PARALLEL_DEVICE* parallel, IRP* irp)
61 {
62         uint32 PathLength;
63         char* path;
64         UNICONV* uniconv;
65
66         stream_seek(irp->input, 28);
67         /* DesiredAccess(4) AllocationSize(8), FileAttributes(4) */
68         /* SharedAccess(4) CreateDisposition(4), CreateOptions(4) */
69         stream_read_uint32(irp->input, PathLength);
70
71         uniconv = freerdp_uniconv_new();
72         path = freerdp_uniconv_in(uniconv, stream_get_tail(irp->input), PathLength);
73         freerdp_uniconv_free(uniconv);
74
75         parallel->id = irp->devman->id_sequence++;
76         parallel->file = open(parallel->path, O_RDWR);
77         if (parallel->file < 0)
78         {
79                 irp->IoStatus = STATUS_ACCESS_DENIED;
80                 parallel->id = 0;
81
82                 DEBUG_WARN("failed to create %s: %s", parallel->path, strerror(errno));
83         }
84         else
85         {
86                 /* all read and write operations should be non-blocking */
87                 if (fcntl(parallel->file, F_SETFL, O_NONBLOCK) == -1)
88                         DEBUG_WARN("%s fcntl %s", path, strerror(errno));
89
90                 DEBUG_SVC("%s(%d) created", parallel->path, parallel->file);
91         }
92
93         stream_write_uint32(irp->output, parallel->id);
94         stream_write_uint8(irp->output, 0);
95
96         xfree(path);
97
98         irp->Complete(irp);
99 }
100
101 static void parallel_process_irp_close(PARALLEL_DEVICE* parallel, IRP* irp)
102 {
103         if (close(parallel->file) < 0)
104                 DEBUG_SVC("failed to close %s(%d)", parallel->path, parallel->id);
105         else
106                 DEBUG_SVC("%s(%d) closed", parallel->path, parallel->id);
107
108         stream_write_zero(irp->output, 5); /* Padding(5) */
109
110         irp->Complete(irp);
111 }
112
113 static void parallel_process_irp_read(PARALLEL_DEVICE* parallel, IRP* irp)
114 {
115         uint32 Length;
116         uint64 Offset;
117         ssize_t status;
118         uint8* buffer = NULL;
119
120         stream_read_uint32(irp->input, Length);
121         stream_read_uint64(irp->input, Offset);
122
123         buffer = (uint8*) xmalloc(Length);
124
125         status = read(parallel->file, irp->output->p, Length);
126
127         if (status < 0)
128         {
129                 irp->IoStatus = STATUS_UNSUCCESSFUL;
130                 xfree(buffer);
131                 buffer = NULL;
132                 Length = 0;
133
134                 DEBUG_WARN("read %s(%d) failed", parallel->path, parallel->id);
135         }
136         else
137         {
138                 DEBUG_SVC("read %llu-%llu from %d", Offset, Offset + Length, parallel->id);
139         }
140
141         stream_write_uint32(irp->output, Length);
142         if (Length > 0)
143         {
144                 stream_check_size(irp->output, Length);
145                 stream_write(irp->output, buffer, Length);
146         }
147         xfree(buffer);
148
149         irp->Complete(irp);
150 }
151
152 static void parallel_process_irp_write(PARALLEL_DEVICE* parallel, IRP* irp)
153 {
154         uint32 Length;
155         uint64 Offset;
156         ssize_t status;
157         uint32 len;
158
159         stream_read_uint32(irp->input, Length);
160         stream_read_uint64(irp->input, Offset);
161         stream_seek(irp->input, 20); /* Padding */
162
163         DEBUG_SVC("Length %u Offset %llu", Length, Offset);
164
165         len = Length;
166         while (len > 0)
167         {
168                 status = write(parallel->file, stream_get_tail(irp->input), len);
169
170                 if (status < 0)
171                 {
172                         irp->IoStatus = STATUS_UNSUCCESSFUL;
173                         Length = 0;
174
175                         DEBUG_WARN("write %s(%d) failed.", parallel->path, parallel->id);
176                         break;
177                 }
178
179                 stream_seek(irp->input, status);
180                 len -= status;
181         }
182
183         stream_write_uint32(irp->output, Length);
184         stream_write_uint8(irp->output, 0); /* Padding */
185
186         irp->Complete(irp);
187 }
188
189 static void parallel_process_irp_device_control(PARALLEL_DEVICE* parallel, IRP* irp)
190 {
191         DEBUG_SVC("in");
192         stream_write_uint32(irp->output, 0); /* OutputBufferLength */
193         irp->Complete(irp);
194 }
195
196 static void parallel_process_irp(PARALLEL_DEVICE* parallel, IRP* irp)
197 {
198         DEBUG_SVC("MajorFunction %u", irp->MajorFunction);
199
200         switch (irp->MajorFunction)
201         {
202                 case IRP_MJ_CREATE:
203                         parallel_process_irp_create(parallel, irp);
204                         break;
205
206                 case IRP_MJ_CLOSE:
207                         parallel_process_irp_close(parallel, irp);
208                         break;
209
210                 case IRP_MJ_READ:
211                         parallel_process_irp_read(parallel, irp);
212                         break;
213
214                 case IRP_MJ_WRITE:
215                         parallel_process_irp_write(parallel, irp);
216                         break;
217
218                 case IRP_MJ_DEVICE_CONTROL:
219                         parallel_process_irp_device_control(parallel, irp);
220                         break;
221
222                 default:
223                         DEBUG_WARN("MajorFunction 0x%X not supported", irp->MajorFunction);
224                         irp->IoStatus = STATUS_NOT_SUPPORTED;
225                         irp->Complete(irp);
226                         break;
227         }
228 }
229
230 static void parallel_process_irp_list(PARALLEL_DEVICE* parallel)
231 {
232         IRP* irp;
233
234         while (1)
235         {
236                 if (freerdp_thread_is_stopped(parallel->thread))
237                         break;
238
239                 freerdp_thread_lock(parallel->thread);
240                 irp = (IRP*) list_dequeue(parallel->irp_list);
241                 freerdp_thread_unlock(parallel->thread);
242
243                 if (irp == NULL)
244                         break;
245
246                 parallel_process_irp(parallel, irp);
247         }
248 }
249
250 static void* parallel_thread_func(void* arg)
251 {
252         PARALLEL_DEVICE* parallel = (PARALLEL_DEVICE*) arg;
253
254         while (1)
255         {
256                 freerdp_thread_wait(parallel->thread);
257
258                 if (freerdp_thread_is_stopped(parallel->thread))
259                         break;
260
261                 freerdp_thread_reset(parallel->thread);
262                 parallel_process_irp_list(parallel);
263         }
264
265         freerdp_thread_quit(parallel->thread);
266
267         return NULL;
268 }
269
270 static void parallel_irp_request(DEVICE* device, IRP* irp)
271 {
272         PARALLEL_DEVICE* parallel = (PARALLEL_DEVICE*) device;
273
274         freerdp_thread_lock(parallel->thread);
275         list_enqueue(parallel->irp_list, irp);
276         freerdp_thread_unlock(parallel->thread);
277
278         freerdp_thread_signal(parallel->thread);
279 }
280
281 static void parallel_free(DEVICE* device)
282 {
283         IRP* irp;
284         PARALLEL_DEVICE* parallel = (PARALLEL_DEVICE*) device;
285
286         DEBUG_SVC("freeing device");
287
288         freerdp_thread_stop(parallel->thread);
289         freerdp_thread_free(parallel->thread);
290
291         while ((irp = (IRP*) list_dequeue(parallel->irp_list)) != NULL)
292                 irp->Discard(irp);
293
294         list_free(parallel->irp_list);
295
296         xfree(parallel);
297 }
298
299 int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
300 {
301         char* name;
302         char* path;
303         int i, length;
304         PARALLEL_DEVICE* parallel;
305
306         name = (char*) pEntryPoints->plugin_data->data[1];
307         path = (char*) pEntryPoints->plugin_data->data[2];
308
309         if (name[0] && path[0])
310         {
311                 parallel = xnew(PARALLEL_DEVICE);
312
313                 parallel->device.type = RDPDR_DTYP_PARALLEL;
314                 parallel->device.name = name;
315                 parallel->device.IRPRequest = parallel_irp_request;
316                 parallel->device.Free = parallel_free;
317
318                 length = strlen(name);
319                 parallel->device.data = stream_new(length + 1);
320
321                 for (i = 0; i <= length; i++)
322                         stream_write_uint8(parallel->device.data, name[i] < 0 ? '_' : name[i]);
323
324                 parallel->path = path;
325
326                 parallel->irp_list = list_new();
327                 parallel->thread = freerdp_thread_new();
328
329                 pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*) parallel);
330
331                 freerdp_thread_start(parallel->thread, parallel_thread_func, parallel);
332         }
333
334         return 0;
335 }