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