Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / rx / rx_xmit_nt.c
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
4 *
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
8 */
9
10 /* NT does not have uio structs, so we roll our own sendmsg and recvmsg.
11 *
12 * The dangerous part of this code is that it assumes that iovecs 0 and 1
13 * are contiguous and that all of 0 is used before any of 1.
14 * This is true if rx_packets are being sent, so we should be ok.
15 */
16
17 #include <afsconfig.h>
18 #include <afs/param.h>
19
20 #if defined(AFS_NT40_ENV)
21 # include <roken.h>
22 # if (_WIN32_WINNT < 0x0501)
23 # undef _WIN32_WINNT
24 # define _WIN32_WINNT 0x0501
25 # endif
26 # include <mswsock.h>
27
28 # if (_WIN32_WINNT < 0x0600)
29 /*
30 * WSASendMsg -- send data to a specific destination, with options, using
31 * overlapped I/O where applicable.
32 *
33 * Valid flags for dwFlags parameter:
34 * MSG_DONTROUTE
35 * MSG_PARTIAL (a.k.a. MSG_EOR) (only for non-stream sockets)
36 * MSG_OOB (only for stream style sockets) (NYI)
37 *
38 * Caller must provide either lpOverlapped or lpCompletionRoutine
39 * or neither (both NULL).
40 */
41 typedef
42 INT
43 (PASCAL FAR * LPFN_WSASENDMSG) (
44 IN SOCKET s,
45 IN LPWSAMSG lpMsg,
46 IN DWORD dwFlags,
47 __out_opt LPDWORD lpNumberOfBytesSent,
48 IN LPWSAOVERLAPPED lpOverlapped OPTIONAL,
49 IN LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine OPTIONAL
50 );
51
52 # define WSAID_WSASENDMSG /* a441e712-754f-43ca-84a7-0dee44cf606d */ \
53 {0xa441e712,0x754f,0x43ca,{0x84,0xa7,0x0d,0xee,0x44,0xcf,0x60,0x6d}}
54 #endif /* AFS_NT40_ENV */
55
56 #include "rx.h"
57 #include "rx_globals.h"
58 #include "rx_packet.h"
59 #include "rx_xmit_nt.h"
60 #include <malloc.h>
61
62
63 /*
64 * WSASendMsg is only supported on Vista and above
65 * Neither function is part of the public WinSock API
66 * and therefore the function pointers must be
67 * obtained via WSAIoctl()
68 */
69 static LPFN_WSARECVMSG pWSARecvMsg = NULL;
70 static LPFN_WSASENDMSG pWSASendMsg = NULL;
71
72 void
73 rxi_xmit_init(osi_socket s)
74 {
75 int rc;
76 GUID WSARecvMsg_GUID = WSAID_WSARECVMSG;
77 GUID WSASendMsg_GUID = WSAID_WSASENDMSG;
78 DWORD dwIn, dwOut, NumberOfBytes;
79
80 rc = WSAIoctl( s, SIO_GET_EXTENSION_FUNCTION_POINTER,
81 &WSARecvMsg_GUID, sizeof(WSARecvMsg_GUID),
82 &pWSARecvMsg, sizeof(pWSARecvMsg),
83 &NumberOfBytes, NULL, NULL);
84
85 rc = WSAIoctl( s, SIO_GET_EXTENSION_FUNCTION_POINTER,
86 &WSASendMsg_GUID, sizeof(WSASendMsg_GUID),
87 &pWSASendMsg, sizeof(pWSASendMsg),
88 &NumberOfBytes, NULL, NULL);
89
90 /* Turn on UDP PORT_UNREACHABLE messages */
91 dwIn = 1;
92 rc = WSAIoctl( s, SIO_UDP_CONNRESET,
93 &dwIn, sizeof(dwIn),
94 &dwOut, sizeof(dwOut),
95 &NumberOfBytes, NULL, NULL);
96
97 /* Turn on UDP CIRCULAR QUEUEING messages */
98 dwIn = 1;
99 rc = WSAIoctl( s, SIO_ENABLE_CIRCULAR_QUEUEING,
100 &dwIn, sizeof(dwIn),
101 &dwOut, sizeof(dwOut),
102 &NumberOfBytes, NULL, NULL);
103 }
104
105 int
106 recvmsg(osi_socket socket, struct msghdr *msgP, int flags)
107 {
108 int code;
109
110 if (pWSARecvMsg) {
111 WSAMSG wsaMsg;
112 DWORD dwBytes;
113
114 wsaMsg.name = (LPSOCKADDR)(msgP->msg_name);
115 wsaMsg.namelen = (INT)(msgP->msg_namelen);
116
117 wsaMsg.lpBuffers = (LPWSABUF) msgP->msg_iov;
118 wsaMsg.dwBufferCount = msgP->msg_iovlen;
119 wsaMsg.Control.len = 0;
120 wsaMsg.Control.buf = NULL;
121 wsaMsg.dwFlags = flags;
122
123 code = pWSARecvMsg(socket, &wsaMsg, &dwBytes, NULL, NULL);
124 if (code == 0) {
125 /* success - return the number of bytes read */
126 code = (int)dwBytes;
127 } else {
128 /* error - set errno and return -1 */
129 if (code == SOCKET_ERROR)
130 code = WSAGetLastError();
131 if (code == WSAEWOULDBLOCK || code == WSAECONNRESET)
132 errno = WSAEWOULDBLOCK;
133 else
134 errno = EIO;
135 code = -1;
136 }
137 } else {
138 char rbuf[RX_MAX_PACKET_SIZE];
139 int size;
140 int off, i, n;
141 int allocd = 0;
142
143 size = rx_maxJumboRecvSize;
144 code =
145 recvfrom((SOCKET) socket, rbuf, size, flags,
146 (struct sockaddr *)(msgP->msg_name), &(msgP->msg_namelen));
147
148 if (code > 0) {
149 size = code;
150
151 for (off = i = 0; size > 0 && i < msgP->msg_iovlen; i++) {
152 if (msgP->msg_iov[i].iov_len) {
153 if (msgP->msg_iov[i].iov_len < size) {
154 n = msgP->msg_iov[i].iov_len;
155 } else {
156 n = size;
157 }
158 memcpy(msgP->msg_iov[i].iov_base, &rbuf[off], n);
159 off += n;
160 size -= n;
161 }
162 }
163
164 /* Accounts for any we didn't copy in to iovecs. */
165 code -= size;
166 } else {
167 if (code == SOCKET_ERROR)
168 code = WSAGetLastError();
169 if (code == WSAEWOULDBLOCK || code == WSAECONNRESET)
170 errno = WSAEWOULDBLOCK;
171 else
172 errno = EIO;
173 code = -1;
174 }
175 }
176
177 return code;
178 }
179
180 int
181 sendmsg(osi_socket socket, struct msghdr *msgP, int flags)
182 {
183 int code;
184
185 if (pWSASendMsg) {
186 WSAMSG wsaMsg;
187 DWORD dwBytes;
188
189 wsaMsg.name = (LPSOCKADDR)(msgP->msg_name);
190 wsaMsg.namelen = (INT)(msgP->msg_namelen);
191
192 wsaMsg.lpBuffers = (LPWSABUF) msgP->msg_iov;
193 wsaMsg.dwBufferCount = msgP->msg_iovlen;
194 wsaMsg.Control.len = 0;
195 wsaMsg.Control.buf = NULL;
196 wsaMsg.dwFlags = 0;
197
198 code = pWSASendMsg(socket, &wsaMsg, flags, &dwBytes, NULL, NULL);
199 if (code == 0) {
200 /* success - return the number of bytes read */
201 code = (int)dwBytes;
202 } else {
203 /* error - set errno and return -1 */
204 if (code == SOCKET_ERROR)
205 code = WSAGetLastError();
206 switch (code) {
207 case WSAEINPROGRESS:
208 case WSAENETRESET:
209 case WSAENOBUFS:
210 errno = 0;
211 break;
212 case WSAEWOULDBLOCK:
213 case WSAECONNRESET:
214 errno = WSAEWOULDBLOCK;
215 break;
216 case WSAEHOSTUNREACH:
217 errno = WSAEHOSTUNREACH;
218 break;
219 default:
220 errno = EIO;
221 break;
222 }
223 code = -1;
224 }
225 } else {
226 char buf[RX_MAX_PACKET_SIZE];
227 char *sbuf = buf;
228 int size, tmp;
229 int off, i, n;
230 int allocd = 0;
231
232 for (size = i = 0; i < msgP->msg_iovlen; i++)
233 size += msgP->msg_iov[i].iov_len;
234
235 if (msgP->msg_iovlen <= 2) {
236 sbuf = msgP->msg_iov[0].iov_base;
237 } else {
238 /* Pack data into array from iovecs */
239 tmp = size;
240 for (off = i = 0; tmp > 0 && i < msgP->msg_iovlen; i++) {
241 if (msgP->msg_iov[i].iov_len > 0) {
242 if (tmp > msgP->msg_iov[i].iov_len)
243 n = msgP->msg_iov[i].iov_len;
244 else
245 n = tmp;
246 memcpy(&sbuf[off], msgP->msg_iov[i].iov_base, n);
247 off += n;
248 tmp -= n;
249 }
250 }
251 }
252
253 code =
254 sendto((SOCKET) socket, sbuf, size, flags,
255 (struct sockaddr *)(msgP->msg_name), msgP->msg_namelen);
256 if (code == SOCKET_ERROR) {
257 code = WSAGetLastError();
258 switch (code) {
259 case WSAEINPROGRESS:
260 case WSAENETRESET:
261 case WSAENOBUFS:
262 errno = 0;
263 break;
264 case WSAEWOULDBLOCK:
265 case WSAECONNRESET:
266 errno = WSAEWOULDBLOCK;
267 break;
268 case WSAEHOSTUNREACH:
269 errno = WSAEHOSTUNREACH;
270 break;
271 default:
272 errno = EIO;
273 break;
274 }
275 code = -1;
276 } else {
277 if (code < size) {
278 errno = EIO;
279 code = -1;
280 }
281 }
282 }
283 return code;
284
285 }
286 #endif /* AFS_NT40_ENV */