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