rx_identity: Add a super user value
[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 */