1 /*
2  * A type which wraps a pipe handle in message oriented mode
3  *
4  * pipe_connection.c
5  *
6  * Copyright (c) 2006-2008, R Oudkerk --- see COPYING.txt
7  */
8 
9 #include "processing.h"
10 
11 #define CLOSE(h) CloseHandle(h)
12 #define DUPLICATE(h) duplicate_handle(h)
13 
14 /*
15  * Connection struct
16  */
17 
18 #define BUFFER_SIZE 1024
19 
20 typedef struct {
21     PyObject_HEAD
22     HANDLE handle;
23     PyObject *weakreflist;
24     char buffer[BUFFER_SIZE];
25 } Connection;
26 
27 /*
28  * Send string to the pipe; assumes in message oriented mode
29  */
30 
31 static Py_ssize_t
conn_send_string(Connection * conn,char * string,size_t length)32 conn_send_string(Connection *conn, char *string, size_t length)
33 {
34     DWORD amount_written;
35 
36     if (!WriteFile(conn->handle, string, length, &amount_written, NULL))
37         return STANDARD_ERROR;
38 
39     /* assert(length == amount_written); */
40     return SUCCESS;
41 }
42 
43 /*
44  * Attempts to read into buffer, or if buffer too small into *newbuffer.
45  *
46  * Returns number of bytes read.  Assumes in message oriented mode.
47  */
48 
49 static Py_ssize_t
conn_recv_string(Connection * conn,char * buffer,size_t buflength,char ** newbuffer)50 conn_recv_string(Connection *conn, char *buffer,
51                  size_t buflength, char **newbuffer)
52 {
53     DWORD left, length, full_length, err;
54 
55     *newbuffer = NULL;
56 
57     if (ReadFile(conn->handle, buffer, buflength, &length, NULL))
58         return length;
59 
60     err = GetLastError();
61     if (err != ERROR_MORE_DATA) {
62         if (err == ERROR_BROKEN_PIPE)
63             return END_OF_FILE;
64         return STANDARD_ERROR;
65     }
66 
67     if (!PeekNamedPipe(conn->handle, NULL, 0, NULL, NULL, &left))
68         return STANDARD_ERROR;
69 
70     full_length = length + left;
71     if (TOO_LONG(full_length))
72         return BAD_MESSAGE_LENGTH;
73 
74     *newbuffer = PyMem_Malloc(full_length);
75     if (*newbuffer == NULL)
76         return MEMORY_ERROR;
77 
78     memcpy(*newbuffer, buffer, length);
79 
80     if (ReadFile(conn->handle, *newbuffer+length, left, &length, NULL)) {
81         assert(length == left);
82         return full_length;
83     } else {
84         PyMem_Free(*newbuffer);
85         return STANDARD_ERROR;
86     }
87 }
88 
89 /*
90  * Check whether any data is available for reading
91  */
92 
93 #define conn_poll(conn, timeout) conn_poll_save(conn, timeout, _save)
94 
95 static int
conn_poll_save(Connection * conn,double timeout,PyThreadState * _save)96 conn_poll_save(Connection *conn, double timeout, PyThreadState *_save)
97 {
98     DWORD bytes, deadline, delay;
99     int difference, res;
100     BOOL block = FALSE;
101 
102     if (!PeekNamedPipe(conn->handle, NULL, 0, NULL, &bytes, NULL))
103         return STANDARD_ERROR;
104 
105     if (timeout == 0.0)
106         return bytes > 0;
107 
108     if (timeout < 0.0)
109         block = TRUE;
110     else
111         /* XXX does not check for overflow */
112         deadline = GetTickCount() + (DWORD)(1000 * timeout + 0.5);
113 
114     Sleep(0);
115 
116     for (delay = 1 ; ; delay += 1) {
117         if (!PeekNamedPipe(conn->handle, NULL, 0, NULL, &bytes, NULL))
118             return STANDARD_ERROR;
119         else if (bytes > 0)
120             return TRUE;
121 
122         if (!block) {
123             difference = deadline - GetTickCount();
124             if (difference < 0)
125                 return FALSE;
126             if ((int)delay > difference)
127                 delay = difference;
128         }
129 
130         if (delay > 20)
131             delay = 20;
132 
133         Sleep(delay);
134 
135         /* check for signals */
136         Py_BLOCK_THREADS
137         res = PyErr_CheckSignals();
138         Py_UNBLOCK_THREADS
139 
140         if (res)
141             return EXCEPTION_HAS_BEEN_SET;
142     }
143 }
144 
145 /*
146  * "connection.h" defines the PipeConnection type using the definitions above
147  */
148 
149 #define CONNECTION_NAME "PipeConnection"
150 #define CONNECTION_TYPE PipeConnectionType
151 
152 #include "connection.h"
153