90f201595915ac24a20d6927453676a6c7278435
[openafs.git] / src / rx / rx_rdwr.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 #include <afsconfig.h>
11 #ifdef KERNEL
12 #include "afs/param.h"
13 #else
14 #include <afs/param.h>
15 #endif
16
17
18 #ifdef KERNEL
19 #ifndef UKERNEL
20 #ifdef RX_KERNEL_TRACE
21 #include "rx_kcommon.h"
22 #endif
23 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
24 #include "afs/sysincludes.h"
25 #else
26 #include "h/types.h"
27 #include "h/time.h"
28 #include "h/stat.h"
29 #if defined(AFS_AIX_ENV) || defined(AFS_AUX_ENV) || defined(AFS_SUN5_ENV)
30 #include "h/systm.h"
31 #endif
32 #ifdef  AFS_OSF_ENV
33 #include <net/net_globals.h>
34 #endif /* AFS_OSF_ENV */
35 #ifdef AFS_LINUX20_ENV
36 #include "h/socket.h"
37 #endif
38 #include "netinet/in.h"
39 #if defined(AFS_SGI_ENV)
40 #include "afs/sysincludes.h"
41 #endif
42 #endif
43 #include "afs/afs_args.h"
44 #include "afs/afs_osi.h"
45 #if     (defined(AFS_AUX_ENV) || defined(AFS_AIX_ENV))
46 #include "h/systm.h"
47 #endif
48 #else /* !UKERNEL */
49 #include "afs/sysincludes.h"
50 #endif /* !UKERNEL */
51 #ifdef RXDEBUG
52 #undef RXDEBUG                  /* turn off debugging */
53 #endif /* RXDEBUG */
54
55 #include "rx_kmutex.h"
56 #include "rx/rx_kernel.h"
57 #include "rx/rx_clock.h"
58 #include "rx/rx_queue.h"
59 #include "rx/rx.h"
60 #include "rx/rx_globals.h"
61 #include "afs/lock.h"
62 #include "afsint.h"
63 #ifdef  AFS_OSF_ENV
64 #undef kmem_alloc
65 #undef kmem_free
66 #undef mem_alloc
67 #undef mem_free
68 #endif /* AFS_OSF_ENV */
69 #else /* KERNEL */
70 # include <sys/types.h>
71 #ifdef AFS_NT40_ENV
72 # include <winsock2.h>
73 #else /* !AFS_NT40_ENV */
74 # include <sys/socket.h>
75 # include <sys/file.h>
76 # include <netdb.h>
77 # include <netinet/in.h>
78 # include <sys/stat.h>
79 # include <sys/time.h>
80 #endif /* !AFS_NT40_ENV */
81 #include <string.h>
82 #ifdef HAVE_UNISTD_H
83 #include <unistd.h>
84 #endif
85 # include "rx_user.h"
86 # include "rx_clock.h"
87 # include "rx_queue.h"
88 # include "rx.h"
89 # include "rx_globals.h"
90 #endif /* KERNEL */
91
92 #ifdef RX_LOCKS_DB
93 /* rxdb_fileID is used to identify the lock location, along with line#. */
94 static int rxdb_fileID = RXDB_FILE_RX_RDWR;
95 #endif /* RX_LOCKS_DB */
96 /* rxi_ReadProc -- internal version.
97  *
98  * LOCKS USED -- called at netpri
99  */
100 int
101 rxi_ReadProc(struct rx_call *call, char *buf,
102              int nbytes)
103 {
104     struct rx_packet *cp = call->currentPacket;
105     struct rx_packet *rp;
106     int requestCount;
107     unsigned int t;
108
109 /* XXXX took out clock_NewTime from here.  Was it needed? */
110     requestCount = nbytes;
111
112     /* Free any packets from the last call to ReadvProc/WritevProc */
113     if (queue_IsNotEmpty(&call->iovq)) {
114 #ifdef RXDEBUG_PACKET
115         call->iovqc -=
116 #endif /* RXDEBUG_PACKET */
117             rxi_FreePackets(0, &call->iovq);
118     }
119
120     do {
121         if (call->nLeft == 0) {
122             /* Get next packet */
123             MUTEX_ENTER(&call->lock);
124             for (;;) {
125                 if (call->error || (call->mode != RX_MODE_RECEIVING)) {
126                     if (call->error) {
127                         call->mode = RX_MODE_ERROR;
128                         MUTEX_EXIT(&call->lock);
129                         return 0;
130                     }
131                     if (call->mode == RX_MODE_SENDING) {
132                         MUTEX_EXIT(&call->lock);
133                         rxi_FlushWrite(call);
134                         MUTEX_ENTER(&call->lock);
135                         continue;
136                     }
137                 }
138                 if (queue_IsNotEmpty(&call->rq)) {
139                     /* Check that next packet available is next in sequence */
140                     rp = queue_First(&call->rq, rx_packet);
141                     if (rp->header.seq == call->rnext) {
142                         afs_int32 error;
143                         struct rx_connection *conn = call->conn;
144                         queue_Remove(rp);
145 #ifdef RX_TRACK_PACKETS
146                         rp->flags &= ~RX_PKTFLAG_RQ;
147 #endif
148 #ifdef RXDEBUG_PACKET
149                         call->rqc--;
150 #endif /* RXDEBUG_PACKET */
151
152                         /* RXS_CheckPacket called to undo RXS_PreparePacket's
153                          * work.  It may reduce the length of the packet by up
154                          * to conn->maxTrailerSize, to reflect the length of the
155                          * data + the header. */
156                         if ((error =
157                              RXS_CheckPacket(conn->securityObject, call,
158                                              rp))) {
159                             /* Used to merely shut down the call, but now we
160                              * shut down the whole connection since this may
161                              * indicate an attempt to hijack it */
162
163                             MUTEX_EXIT(&call->lock);
164                             rxi_ConnectionError(conn, error);
165                             MUTEX_ENTER(&conn->conn_data_lock);
166                             rp = rxi_SendConnectionAbort(conn, rp, 0, 0);
167                             MUTEX_EXIT(&conn->conn_data_lock);
168                             rxi_FreePacket(rp);
169
170                             return 0;
171                         }
172                         call->rnext++;
173                         cp = call->currentPacket = rp;
174 #ifdef RX_TRACK_PACKETS
175                         call->currentPacket->flags |= RX_PKTFLAG_CP;
176 #endif
177                         call->curvec = 1;       /* 0th vec is always header */
178                         /* begin at the beginning [ more or less ], continue
179                          * on until the end, then stop. */
180                         call->curpos =
181                             (char *)cp->wirevec[1].iov_base +
182                             call->conn->securityHeaderSize;
183                         call->curlen =
184                             cp->wirevec[1].iov_len -
185                             call->conn->securityHeaderSize;
186
187                         /* Notice that this code works correctly if the data
188                          * size is 0 (which it may be--no reply arguments from
189                          * server, for example).  This relies heavily on the
190                          * fact that the code below immediately frees the packet
191                          * (no yields, etc.).  If it didn't, this would be a
192                          * problem because a value of zero for call->nLeft
193                          * normally means that there is no read packet */
194                         call->nLeft = cp->length;
195                         hadd32(call->bytesRcvd, cp->length);
196
197                         /* Send a hard ack for every rxi_HardAckRate+1 packets
198                          * consumed. Otherwise schedule an event to send
199                          * the hard ack later on.
200                          */
201                         call->nHardAcks++;
202                         if (!(call->flags & RX_CALL_RECEIVE_DONE)) {
203                             if (call->nHardAcks > (u_short) rxi_HardAckRate) {
204                                 rxevent_Cancel(call->delayedAckEvent, call,
205                                                RX_CALL_REFCOUNT_DELAY);
206                                 rxi_SendAck(call, 0, 0, RX_ACK_DELAY, 0);
207                             } else {
208                                 struct clock when, now;
209                                 clock_GetTime(&now);
210                                 when = now;
211                                 /* Delay to consolidate ack packets */
212                                 clock_Add(&when, &rx_hardAckDelay);
213                                 if (!call->delayedAckEvent
214                                     || clock_Gt(&call->delayedAckEvent->
215                                                 eventTime, &when)) {
216                                     rxevent_Cancel(call->delayedAckEvent,
217                                                    call,
218                                                    RX_CALL_REFCOUNT_DELAY);
219                                     MUTEX_ENTER(&rx_refcnt_mutex);
220                                     CALL_HOLD(call, RX_CALL_REFCOUNT_DELAY);
221                                     MUTEX_EXIT(&rx_refcnt_mutex);
222                                     call->delayedAckEvent =
223                                       rxevent_PostNow(&when, &now,
224                                                      rxi_SendDelayedAck, call,
225                                                      0);
226                                 }
227                             }
228                         }
229                         break;
230                     }
231                 }
232
233                 /*
234                  * If we reach this point either we have no packets in the
235                  * receive queue or the next packet in the queue is not the
236                  * one we are looking for.  There is nothing else for us to
237                  * do but wait for another packet to arrive.
238                  */
239
240                 /* Are there ever going to be any more packets? */
241                 if (call->flags & RX_CALL_RECEIVE_DONE) {
242                     MUTEX_EXIT(&call->lock);
243                     return requestCount - nbytes;
244                 }
245                 /* Wait for in-sequence packet */
246                 call->flags |= RX_CALL_READER_WAIT;
247                 clock_NewTime();
248                 call->startWait = clock_Sec();
249                 while (call->flags & RX_CALL_READER_WAIT) {
250 #ifdef  RX_ENABLE_LOCKS
251                     CV_WAIT(&call->cv_rq, &call->lock);
252 #else
253                     osi_rxSleep(&call->rq);
254 #endif
255                 }
256                 cp = call->currentPacket;
257
258                 call->startWait = 0;
259 #ifdef RX_ENABLE_LOCKS
260                 if (call->error) {
261                     MUTEX_EXIT(&call->lock);
262                     return 0;
263                 }
264 #endif /* RX_ENABLE_LOCKS */
265             }
266             MUTEX_EXIT(&call->lock);
267         } else
268             /* osi_Assert(cp); */
269             /* MTUXXX  this should be replaced by some error-recovery code before shipping */
270             /* yes, the following block is allowed to be the ELSE clause (or not) */
271             /* It's possible for call->nLeft to be smaller than any particular
272              * iov_len.  Usually, recvmsg doesn't change the iov_len, since it
273              * reflects the size of the buffer.  We have to keep track of the
274              * number of bytes read in the length field of the packet struct.  On
275              * the final portion of a received packet, it's almost certain that
276              * call->nLeft will be smaller than the final buffer. */
277             while (nbytes && cp) {
278                 t = MIN((int)call->curlen, nbytes);
279                 t = MIN(t, (int)call->nLeft);
280                 memcpy(buf, call->curpos, t);
281                 buf += t;
282                 nbytes -= t;
283                 call->curpos += t;
284                 call->curlen -= t;
285                 call->nLeft -= t;
286
287                 if (!call->nLeft) {
288                     /* out of packet.  Get another one. */
289 #ifdef RX_TRACK_PACKETS
290                     call->currentPacket->flags &= ~RX_PKTFLAG_CP;
291 #endif
292                     rxi_FreePacket(cp);
293                     cp = call->currentPacket = (struct rx_packet *)0;
294                 } else if (!call->curlen) {
295                     /* need to get another struct iov */
296                     if (++call->curvec >= cp->niovecs) {
297                         /* current packet is exhausted, get ready for another */
298                         /* don't worry about curvec and stuff, they get set somewhere else */
299 #ifdef RX_TRACK_PACKETS
300                         call->currentPacket->flags &= ~RX_PKTFLAG_CP;
301 #endif
302                         rxi_FreePacket(cp);
303                         cp = call->currentPacket = (struct rx_packet *)0;
304                         call->nLeft = 0;
305                     } else {
306                         call->curpos =
307                             (char *)cp->wirevec[call->curvec].iov_base;
308                         call->curlen = cp->wirevec[call->curvec].iov_len;
309                     }
310                 }
311             }
312         if (!nbytes) {
313             /* user buffer is full, return */
314             return requestCount;
315         }
316
317     } while (nbytes);
318
319     return requestCount;
320 }
321
322 int
323 rx_ReadProc(struct rx_call *call, char *buf, int nbytes)
324 {
325     int bytes;
326     int tcurlen;
327     int tnLeft;
328     char *tcurpos;
329     SPLVAR;
330
331     /* Free any packets from the last call to ReadvProc/WritevProc */
332     if (!queue_IsEmpty(&call->iovq)) {
333 #ifdef RXDEBUG_PACKET
334         call->iovqc -=
335 #endif /* RXDEBUG_PACKET */
336             rxi_FreePackets(0, &call->iovq);
337     }
338
339     /*
340      * Most common case, all of the data is in the current iovec.
341      * We are relying on nLeft being zero unless the call is in receive mode.
342      */
343     tcurlen = call->curlen;
344     tnLeft = call->nLeft;
345     if (!call->error && tcurlen > nbytes && tnLeft > nbytes) {
346         tcurpos = call->curpos;
347         memcpy(buf, tcurpos, nbytes);
348
349         call->curpos = tcurpos + nbytes;
350         call->curlen = tcurlen - nbytes;
351         call->nLeft = tnLeft - nbytes;
352
353         if (!call->nLeft && call->currentPacket != NULL) {
354             /* out of packet.  Get another one. */
355             rxi_FreePacket(call->currentPacket);
356             call->currentPacket = (struct rx_packet *)0;
357         }
358         return nbytes;
359     }
360
361     NETPRI;
362     bytes = rxi_ReadProc(call, buf, nbytes);
363     USERPRI;
364     return bytes;
365 }
366
367 /* Optimization for unmarshalling 32 bit integers */
368 int
369 rx_ReadProc32(struct rx_call *call, afs_int32 * value)
370 {
371     int bytes;
372     int tcurlen;
373     int tnLeft;
374     char *tcurpos;
375     SPLVAR;
376
377     /* Free any packets from the last call to ReadvProc/WritevProc */
378     if (!queue_IsEmpty(&call->iovq)) {
379 #ifdef RXDEBUG_PACKET
380         call->iovqc -=
381 #endif /* RXDEBUG_PACKET */
382             rxi_FreePackets(0, &call->iovq);
383     }
384
385     /*
386      * Most common case, all of the data is in the current iovec.
387      * We are relying on nLeft being zero unless the call is in receive mode.
388      */
389     tcurlen = call->curlen;
390     tnLeft = call->nLeft;
391     if (!call->error && tcurlen >= sizeof(afs_int32)
392         && tnLeft >= sizeof(afs_int32)) {
393         tcurpos = call->curpos;
394
395         memcpy((char *)value, tcurpos, sizeof(afs_int32));
396
397         call->curpos = tcurpos + sizeof(afs_int32);
398         call->curlen = (u_short)(tcurlen - sizeof(afs_int32));
399         call->nLeft = (u_short)(tnLeft - sizeof(afs_int32));
400         if (!call->nLeft && call->currentPacket != NULL) {
401             /* out of packet.  Get another one. */
402             rxi_FreePacket(call->currentPacket);
403             call->currentPacket = (struct rx_packet *)0;
404         }
405         return sizeof(afs_int32);
406     }
407
408     NETPRI;
409     bytes = rxi_ReadProc(call, (char *)value, sizeof(afs_int32));
410     USERPRI;
411
412     return bytes;
413 }
414
415 /* rxi_FillReadVec
416  *
417  * Uses packets in the receive queue to fill in as much of the
418  * current iovec as possible. Does not block if it runs out
419  * of packets to complete the iovec. Return true if an ack packet
420  * was sent, otherwise return false */
421 int
422 rxi_FillReadVec(struct rx_call *call, afs_uint32 serial)
423 {
424     int didConsume = 0;
425     int didHardAck = 0;
426     unsigned int t;
427     struct rx_packet *rp;
428     struct rx_packet *curp;
429     struct iovec *call_iov;
430     struct iovec *cur_iov = NULL;
431
432     curp = call->currentPacket;
433     if (curp) {
434         cur_iov = &curp->wirevec[call->curvec];
435     }
436     call_iov = &call->iov[call->iovNext];
437
438     while (!call->error && call->iovNBytes && call->iovNext < call->iovMax) {
439         if (call->nLeft == 0) {
440             /* Get next packet */
441             if (queue_IsNotEmpty(&call->rq)) {
442                 /* Check that next packet available is next in sequence */
443                 rp = queue_First(&call->rq, rx_packet);
444                 if (rp->header.seq == call->rnext) {
445                     afs_int32 error;
446                     struct rx_connection *conn = call->conn;
447                     queue_Remove(rp);
448 #ifdef RX_TRACK_PACKETS
449                     rp->flags &= ~RX_PKTFLAG_RQ;
450 #endif
451 #ifdef RXDEBUG_PACKET
452                     call->rqc--;
453 #endif /* RXDEBUG_PACKET */
454
455                     /* RXS_CheckPacket called to undo RXS_PreparePacket's
456                      * work.  It may reduce the length of the packet by up
457                      * to conn->maxTrailerSize, to reflect the length of the
458                      * data + the header. */
459                     if ((error =
460                          RXS_CheckPacket(conn->securityObject, call, rp))) {
461                         /* Used to merely shut down the call, but now we
462                          * shut down the whole connection since this may
463                          * indicate an attempt to hijack it */
464
465                         MUTEX_EXIT(&call->lock);
466                         rxi_ConnectionError(conn, error);
467                         MUTEX_ENTER(&conn->conn_data_lock);
468                         rp = rxi_SendConnectionAbort(conn, rp, 0, 0);
469                         MUTEX_EXIT(&conn->conn_data_lock);
470                         rxi_FreePacket(rp);
471                         MUTEX_ENTER(&call->lock);
472
473                         return 1;
474                     }
475                     call->rnext++;
476                     curp = call->currentPacket = rp;
477 #ifdef RX_TRACK_PACKETS
478                     call->currentPacket->flags |= RX_PKTFLAG_CP;
479 #endif
480                     call->curvec = 1;   /* 0th vec is always header */
481                     cur_iov = &curp->wirevec[1];
482                     /* begin at the beginning [ more or less ], continue
483                      * on until the end, then stop. */
484                     call->curpos =
485                         (char *)curp->wirevec[1].iov_base +
486                         call->conn->securityHeaderSize;
487                     call->curlen =
488                         curp->wirevec[1].iov_len -
489                         call->conn->securityHeaderSize;
490
491                     /* Notice that this code works correctly if the data
492                      * size is 0 (which it may be--no reply arguments from
493                      * server, for example).  This relies heavily on the
494                      * fact that the code below immediately frees the packet
495                      * (no yields, etc.).  If it didn't, this would be a
496                      * problem because a value of zero for call->nLeft
497                      * normally means that there is no read packet */
498                     call->nLeft = curp->length;
499                     hadd32(call->bytesRcvd, curp->length);
500
501                     /* Send a hard ack for every rxi_HardAckRate+1 packets
502                      * consumed. Otherwise schedule an event to send
503                      * the hard ack later on.
504                      */
505                     call->nHardAcks++;
506                     didConsume = 1;
507                     continue;
508                 }
509             }
510             break;
511         }
512
513         /* It's possible for call->nLeft to be smaller than any particular
514          * iov_len.  Usually, recvmsg doesn't change the iov_len, since it
515          * reflects the size of the buffer.  We have to keep track of the
516          * number of bytes read in the length field of the packet struct.  On
517          * the final portion of a received packet, it's almost certain that
518          * call->nLeft will be smaller than the final buffer. */
519         while (call->iovNBytes && call->iovNext < call->iovMax && curp) {
520
521             t = MIN((int)call->curlen, call->iovNBytes);
522             t = MIN(t, (int)call->nLeft);
523             call_iov->iov_base = call->curpos;
524             call_iov->iov_len = t;
525             call_iov++;
526             call->iovNext++;
527             call->iovNBytes -= t;
528             call->curpos += t;
529             call->curlen -= t;
530             call->nLeft -= t;
531
532             if (!call->nLeft) {
533                 /* out of packet.  Get another one. */
534 #ifdef RX_TRACK_PACKETS
535                 curp->flags &= ~RX_PKTFLAG_CP;
536                 curp->flags |= RX_PKTFLAG_IOVQ;
537 #endif
538                 queue_Append(&call->iovq, curp);
539 #ifdef RXDEBUG_PACKET
540                 call->iovqc++;
541 #endif /* RXDEBUG_PACKET */
542                 curp = call->currentPacket = (struct rx_packet *)0;
543             } else if (!call->curlen) {
544                 /* need to get another struct iov */
545                 if (++call->curvec >= curp->niovecs) {
546                     /* current packet is exhausted, get ready for another */
547                     /* don't worry about curvec and stuff, they get set somewhere else */
548 #ifdef RX_TRACK_PACKETS
549                     curp->flags &= ~RX_PKTFLAG_CP;
550                     curp->flags |= RX_PKTFLAG_IOVQ;
551 #endif
552                     queue_Append(&call->iovq, curp);
553 #ifdef RXDEBUG_PACKET
554                     call->iovqc++;
555 #endif /* RXDEBUG_PACKET */
556                     curp = call->currentPacket = (struct rx_packet *)0;
557                     call->nLeft = 0;
558                 } else {
559                     cur_iov++;
560                     call->curpos = (char *)cur_iov->iov_base;
561                     call->curlen = cur_iov->iov_len;
562                 }
563             }
564         }
565     }
566
567     /* If we consumed any packets then check whether we need to
568      * send a hard ack. */
569     if (didConsume && (!(call->flags & RX_CALL_RECEIVE_DONE))) {
570         if (call->nHardAcks > (u_short) rxi_HardAckRate) {
571             rxevent_Cancel(call->delayedAckEvent, call,
572                            RX_CALL_REFCOUNT_DELAY);
573             rxi_SendAck(call, 0, serial, RX_ACK_DELAY, 0);
574             didHardAck = 1;
575         } else {
576             struct clock when, now;
577             clock_GetTime(&now);
578             when = now;
579             /* Delay to consolidate ack packets */
580             clock_Add(&when, &rx_hardAckDelay);
581             if (!call->delayedAckEvent
582                 || clock_Gt(&call->delayedAckEvent->eventTime, &when)) {
583                 rxevent_Cancel(call->delayedAckEvent, call,
584                                RX_CALL_REFCOUNT_DELAY);
585                 MUTEX_ENTER(&rx_refcnt_mutex);
586                 CALL_HOLD(call, RX_CALL_REFCOUNT_DELAY);
587                 MUTEX_EXIT(&rx_refcnt_mutex);
588                 call->delayedAckEvent =
589                     rxevent_PostNow(&when, &now, rxi_SendDelayedAck, call, 0);
590             }
591         }
592     }
593     return didHardAck;
594 }
595
596
597 /* rxi_ReadvProc -- internal version.
598  *
599  * Fills in an iovec with pointers to the packet buffers. All packets
600  * except the last packet (new current packet) are moved to the iovq
601  * while the application is processing the data.
602  *
603  * LOCKS USED -- called at netpri.
604  */
605 int
606 rxi_ReadvProc(struct rx_call *call, struct iovec *iov, int *nio, int maxio,
607               int nbytes)
608 {
609     int bytes;
610
611     /* Free any packets from the last call to ReadvProc/WritevProc */
612     if (queue_IsNotEmpty(&call->iovq)) {
613 #ifdef RXDEBUG_PACKET
614         call->iovqc -=
615 #endif /* RXDEBUG_PACKET */
616             rxi_FreePackets(0, &call->iovq);
617     }
618
619     if (call->mode == RX_MODE_SENDING) {
620         rxi_FlushWrite(call);
621     }
622
623     MUTEX_ENTER(&call->lock);
624     if (call->error)
625         goto error;
626
627     /* Get whatever data is currently available in the receive queue.
628      * If rxi_FillReadVec sends an ack packet then it is possible
629      * that we will receive more data while we drop the call lock
630      * to send the packet. Set the RX_CALL_IOVEC_WAIT flag
631      * here to avoid a race with the receive thread if we send
632      * hard acks in rxi_FillReadVec. */
633     call->flags |= RX_CALL_IOVEC_WAIT;
634     call->iovNBytes = nbytes;
635     call->iovMax = maxio;
636     call->iovNext = 0;
637     call->iov = iov;
638     rxi_FillReadVec(call, 0);
639
640     /* if we need more data then sleep until the receive thread has
641      * filled in the rest. */
642     if (!call->error && call->iovNBytes && call->iovNext < call->iovMax
643         && !(call->flags & RX_CALL_RECEIVE_DONE)) {
644         call->flags |= RX_CALL_READER_WAIT;
645         clock_NewTime();
646         call->startWait = clock_Sec();
647         while (call->flags & RX_CALL_READER_WAIT) {
648 #ifdef  RX_ENABLE_LOCKS
649             CV_WAIT(&call->cv_rq, &call->lock);
650 #else
651             osi_rxSleep(&call->rq);
652 #endif
653         }
654         call->startWait = 0;
655     }
656     call->flags &= ~RX_CALL_IOVEC_WAIT;
657
658     if (call->error)
659         goto error;
660
661     call->iov = NULL;
662     *nio = call->iovNext;
663     bytes = nbytes - call->iovNBytes;
664     MUTEX_EXIT(&call->lock);
665     return bytes;
666
667   error:
668     MUTEX_EXIT(&call->lock);
669     call->mode = RX_MODE_ERROR;
670     return 0;
671 }
672
673 int
674 rx_ReadvProc(struct rx_call *call, struct iovec *iov, int *nio, int maxio,
675              int nbytes)
676 {
677     int bytes;
678     SPLVAR;
679
680     NETPRI;
681     bytes = rxi_ReadvProc(call, iov, nio, maxio, nbytes);
682     USERPRI;
683     return bytes;
684 }
685
686 /* rxi_WriteProc -- internal version.
687  *
688  * LOCKS USED -- called at netpri
689  */
690
691 int
692 rxi_WriteProc(struct rx_call *call, char *buf,
693               int nbytes)
694 {
695     struct rx_connection *conn = call->conn;
696     struct rx_packet *cp = call->currentPacket;
697     unsigned int t;
698     int requestCount = nbytes;
699
700     /* Free any packets from the last call to ReadvProc/WritevProc */
701     if (queue_IsNotEmpty(&call->iovq)) {
702 #ifdef RXDEBUG_PACKET
703         call->iovqc -=
704 #endif /* RXDEBUG_PACKET */
705             rxi_FreePackets(0, &call->iovq);
706     }
707
708     if (call->mode != RX_MODE_SENDING) {
709         if ((conn->type == RX_SERVER_CONNECTION)
710             && (call->mode == RX_MODE_RECEIVING)) {
711             call->mode = RX_MODE_SENDING;
712             if (cp) {
713 #ifdef RX_TRACK_PACKETS
714                 cp->flags &= ~RX_PKTFLAG_CP;
715 #endif
716                 rxi_FreePacket(cp);
717                 cp = call->currentPacket = (struct rx_packet *)0;
718                 call->nLeft = 0;
719                 call->nFree = 0;
720             }
721         } else {
722             return 0;
723         }
724     }
725
726     /* Loop condition is checked at end, so that a write of 0 bytes
727      * will force a packet to be created--specially for the case where
728      * there are 0 bytes on the stream, but we must send a packet
729      * anyway. */
730     do {
731         if (call->nFree == 0) {
732             MUTEX_ENTER(&call->lock);
733 #ifdef AFS_GLOBAL_RXLOCK_KERNEL
734             rxi_WaitforTQBusy(call);
735 #endif /* AFS_GLOBAL_RXLOCK_KERNEL */
736             cp = call->currentPacket;
737             if (call->error)
738                 call->mode = RX_MODE_ERROR;
739             if (!call->error && cp) {
740                 /* Clear the current packet now so that if
741                  * we are forced to wait and drop the lock
742                  * the packet we are planning on using
743                  * cannot be freed.
744                  */
745 #ifdef RX_TRACK_PACKETS
746                 cp->flags &= ~RX_PKTFLAG_CP;
747 #endif
748                 call->currentPacket = (struct rx_packet *)0;
749                 clock_NewTime();        /* Bogus:  need new time package */
750                 /* The 0, below, specifies that it is not the last packet:
751                  * there will be others. PrepareSendPacket may
752                  * alter the packet length by up to
753                  * conn->securityMaxTrailerSize */
754                 hadd32(call->bytesSent, cp->length);
755                 rxi_PrepareSendPacket(call, cp, 0);
756 #ifdef RX_TRACK_PACKETS
757                 cp->flags |= RX_PKTFLAG_TQ;
758 #endif
759                 queue_Append(&call->tq, cp);
760 #ifdef RXDEBUG_PACKET
761                 call->tqc++;
762 #endif /* RXDEBUG_PACKET */
763                 cp = (struct rx_packet *)0;
764                 if (!
765                     (call->
766                      flags & (RX_CALL_FAST_RECOVER |
767                               RX_CALL_FAST_RECOVER_WAIT))) {
768                     rxi_Start(0, call, 0, 0);
769                 }
770             } else if (cp) {
771 #ifdef RX_TRACK_PACKETS
772                 cp->flags &= ~RX_PKTFLAG_CP;
773 #endif
774                 rxi_FreePacket(cp);
775                 cp = call->currentPacket = (struct rx_packet *)0;
776             }
777             /* Wait for transmit window to open up */
778             while (!call->error
779                    && call->tnext + 1 > call->tfirst + (2 * call->twind)) {
780                 clock_NewTime();
781                 call->startWait = clock_Sec();
782
783 #ifdef  RX_ENABLE_LOCKS
784                 CV_WAIT(&call->cv_twind, &call->lock);
785 #else
786                 call->flags |= RX_CALL_WAIT_WINDOW_ALLOC;
787                 osi_rxSleep(&call->twind);
788 #endif
789
790                 call->startWait = 0;
791 #ifdef RX_ENABLE_LOCKS
792                 if (call->error) {
793                     call->mode = RX_MODE_ERROR;
794                     MUTEX_EXIT(&call->lock);
795                     return 0;
796                 }
797 #endif /* RX_ENABLE_LOCKS */
798             }
799             if ((cp = rxi_AllocSendPacket(call, nbytes))) {
800 #ifdef RX_TRACK_PACKETS
801                 cp->flags |= RX_PKTFLAG_CP;
802 #endif
803                 call->currentPacket = cp;
804                 call->nFree = cp->length;
805                 call->curvec = 1;       /* 0th vec is always header */
806                 /* begin at the beginning [ more or less ], continue
807                  * on until the end, then stop. */
808                 call->curpos =
809                     (char *)cp->wirevec[1].iov_base +
810                     call->conn->securityHeaderSize;
811                 call->curlen =
812                     cp->wirevec[1].iov_len - call->conn->securityHeaderSize;
813             }
814             if (call->error) {
815                 call->mode = RX_MODE_ERROR;
816                 if (cp) {
817 #ifdef RX_TRACK_PACKETS
818                     cp->flags &= ~RX_PKTFLAG_CP;
819 #endif
820                     rxi_FreePacket(cp);
821                     call->currentPacket = NULL;
822                 }
823                 MUTEX_EXIT(&call->lock);
824                 return 0;
825             }
826             MUTEX_EXIT(&call->lock);
827         }
828
829         if (cp && (int)call->nFree < nbytes) {
830             /* Try to extend the current buffer */
831             int len, mud;
832             len = cp->length;
833             mud = rx_MaxUserDataSize(call);
834             if (mud > len) {
835                 int want;
836                 want = MIN(nbytes - (int)call->nFree, mud - len);
837                 rxi_AllocDataBuf(cp, want, RX_PACKET_CLASS_SEND_CBUF);
838                 if (cp->length > (unsigned)mud)
839                     cp->length = mud;
840                 call->nFree += (cp->length - len);
841             }
842         }
843
844         /* If the remaining bytes fit in the buffer, then store them
845          * and return.  Don't ship a buffer that's full immediately to
846          * the peer--we don't know if it's the last buffer yet */
847
848         if (!cp) {
849             call->nFree = 0;
850         }
851
852         while (nbytes && call->nFree) {
853
854             t = MIN((int)call->curlen, nbytes);
855             t = MIN((int)call->nFree, t);
856             memcpy(call->curpos, buf, t);
857             buf += t;
858             nbytes -= t;
859             call->curpos += t;
860             call->curlen -= (u_short)t;
861             call->nFree -= (u_short)t;
862
863             if (!call->curlen) {
864                 /* need to get another struct iov */
865                 if (++call->curvec >= cp->niovecs) {
866                     /* current packet is full, extend or send it */
867                     call->nFree = 0;
868                 } else {
869                     call->curpos = (char *)cp->wirevec[call->curvec].iov_base;
870                     call->curlen = cp->wirevec[call->curvec].iov_len;
871                 }
872             }
873         }                       /* while bytes to send and room to send them */
874
875         /* might be out of space now */
876         if (!nbytes) {
877             return requestCount;
878         } else;                 /* more data to send, so get another packet and keep going */
879     } while (nbytes);
880
881     return requestCount - nbytes;
882 }
883
884 int
885 rx_WriteProc(struct rx_call *call, char *buf, int nbytes)
886 {
887     int bytes;
888     int tcurlen;
889     int tnFree;
890     char *tcurpos;
891     SPLVAR;
892
893     /* Free any packets from the last call to ReadvProc/WritevProc */
894     if (queue_IsNotEmpty(&call->iovq)) {
895 #ifdef RXDEBUG_PACKET
896         call->iovqc -=
897 #endif /* RXDEBUG_PACKET */
898             rxi_FreePackets(0, &call->iovq);
899     }
900
901     /*
902      * Most common case: all of the data fits in the current iovec.
903      * We are relying on nFree being zero unless the call is in send mode.
904      */
905     tcurlen = (int)call->curlen;
906     tnFree = (int)call->nFree;
907     if (!call->error && tcurlen >= nbytes && tnFree >= nbytes) {
908         tcurpos = call->curpos;
909
910         memcpy(tcurpos, buf, nbytes);
911         call->curpos = tcurpos + nbytes;
912         call->curlen = (u_short)(tcurlen - nbytes);
913         call->nFree = (u_short)(tnFree - nbytes);
914         return nbytes;
915     }
916
917     NETPRI;
918     bytes = rxi_WriteProc(call, buf, nbytes);
919     USERPRI;
920     return bytes;
921 }
922
923 /* Optimization for marshalling 32 bit arguments */
924 int
925 rx_WriteProc32(struct rx_call *call, afs_int32 * value)
926 {
927     int bytes;
928     int tcurlen;
929     int tnFree;
930     char *tcurpos;
931     SPLVAR;
932
933     if (queue_IsNotEmpty(&call->iovq)) {
934 #ifdef RXDEBUG_PACKET
935         call->iovqc -=
936 #endif /* RXDEBUG_PACKET */
937             rxi_FreePackets(0, &call->iovq);
938     }
939
940     /*
941      * Most common case: all of the data fits in the current iovec.
942      * We are relying on nFree being zero unless the call is in send mode.
943      */
944     tcurlen = call->curlen;
945     tnFree = call->nFree;
946     if (!call->error && tcurlen >= sizeof(afs_int32)
947         && tnFree >= sizeof(afs_int32)) {
948         tcurpos = call->curpos;
949
950         if (!((size_t)tcurpos & (sizeof(afs_int32) - 1))) {
951             *((afs_int32 *) (tcurpos)) = *value;
952         } else {
953             memcpy(tcurpos, (char *)value, sizeof(afs_int32));
954         }
955         call->curpos = tcurpos + sizeof(afs_int32);
956         call->curlen = (u_short)(tcurlen - sizeof(afs_int32));
957         call->nFree = (u_short)(tnFree - sizeof(afs_int32));
958         return sizeof(afs_int32);
959     }
960
961     NETPRI;
962     bytes = rxi_WriteProc(call, (char *)value, sizeof(afs_int32));
963     USERPRI;
964     return bytes;
965 }
966
967 /* rxi_WritevAlloc -- internal version.
968  *
969  * Fill in an iovec to point to data in packet buffers. The application
970  * calls rxi_WritevProc when the buffers are full.
971  *
972  * LOCKS USED -- called at netpri.
973  */
974
975 int
976 rxi_WritevAlloc(struct rx_call *call, struct iovec *iov, int *nio, int maxio,
977                 int nbytes)
978 {
979     struct rx_connection *conn = call->conn;
980     struct rx_packet *cp = call->currentPacket;
981     int requestCount;
982     int nextio;
983     /* Temporary values, real work is done in rxi_WritevProc */
984     int tnFree;
985     unsigned int tcurvec;
986     char *tcurpos;
987     int tcurlen;
988
989     requestCount = nbytes;
990     nextio = 0;
991
992     /* Free any packets from the last call to ReadvProc/WritevProc */
993     if (queue_IsNotEmpty(&call->iovq)) {
994 #ifdef RXDEBUG_PACKET
995         call->iovqc -=
996 #endif /* RXDEBUG_PACKET */
997             rxi_FreePackets(0, &call->iovq);
998     }
999
1000     if (call->mode != RX_MODE_SENDING) {
1001         if ((conn->type == RX_SERVER_CONNECTION)
1002             && (call->mode == RX_MODE_RECEIVING)) {
1003             call->mode = RX_MODE_SENDING;
1004             if (cp) {
1005 #ifdef RX_TRACK_PACKETS
1006                 cp->flags &= ~RX_PKTFLAG_CP;
1007 #endif
1008                 rxi_FreePacket(cp);
1009                 cp = call->currentPacket = (struct rx_packet *)0;
1010                 call->nLeft = 0;
1011                 call->nFree = 0;
1012             }
1013         } else {
1014             return 0;
1015         }
1016     }
1017
1018     /* Set up the iovec to point to data in packet buffers. */
1019     tnFree = call->nFree;
1020     tcurvec = call->curvec;
1021     tcurpos = call->curpos;
1022     tcurlen = call->curlen;
1023     do {
1024         int t;
1025
1026         if (tnFree == 0) {
1027             /* current packet is full, allocate a new one */
1028             MUTEX_ENTER(&call->lock);
1029             cp = rxi_AllocSendPacket(call, nbytes);
1030             MUTEX_EXIT(&call->lock);
1031             if (cp == NULL) {
1032                 /* out of space, return what we have */
1033                 *nio = nextio;
1034                 return requestCount - nbytes;
1035             }
1036 #ifdef RX_TRACK_PACKETS
1037             cp->flags |= RX_PKTFLAG_IOVQ;
1038 #endif
1039             queue_Append(&call->iovq, cp);
1040 #ifdef RXDEBUG_PACKET
1041             call->iovqc++;
1042 #endif /* RXDEBUG_PACKET */
1043             tnFree = cp->length;
1044             tcurvec = 1;
1045             tcurpos =
1046                 (char *)cp->wirevec[1].iov_base +
1047                 call->conn->securityHeaderSize;
1048             tcurlen = cp->wirevec[1].iov_len - call->conn->securityHeaderSize;
1049         }
1050
1051         if (tnFree < nbytes) {
1052             /* try to extend the current packet */
1053             int len, mud;
1054             len = cp->length;
1055             mud = rx_MaxUserDataSize(call);
1056             if (mud > len) {
1057                 int want;
1058                 want = MIN(nbytes - tnFree, mud - len);
1059                 rxi_AllocDataBuf(cp, want, RX_PACKET_CLASS_SEND_CBUF);
1060                 if (cp->length > (unsigned)mud)
1061                     cp->length = mud;
1062                 tnFree += (cp->length - len);
1063                 if (cp == call->currentPacket) {
1064                     call->nFree += (cp->length - len);
1065                 }
1066             }
1067         }
1068
1069         /* fill in the next entry in the iovec */
1070         t = MIN(tcurlen, nbytes);
1071         t = MIN(tnFree, t);
1072         iov[nextio].iov_base = tcurpos;
1073         iov[nextio].iov_len = t;
1074         nbytes -= t;
1075         tcurpos += t;
1076         tcurlen -= t;
1077         tnFree -= t;
1078         nextio++;
1079
1080         if (!tcurlen) {
1081             /* need to get another struct iov */
1082             if (++tcurvec >= cp->niovecs) {
1083                 /* current packet is full, extend it or move on to next packet */
1084                 tnFree = 0;
1085             } else {
1086                 tcurpos = (char *)cp->wirevec[tcurvec].iov_base;
1087                 tcurlen = cp->wirevec[tcurvec].iov_len;
1088             }
1089         }
1090     } while (nbytes && nextio < maxio);
1091     *nio = nextio;
1092     return requestCount - nbytes;
1093 }
1094
1095 int
1096 rx_WritevAlloc(struct rx_call *call, struct iovec *iov, int *nio, int maxio,
1097                int nbytes)
1098 {
1099     int bytes;
1100     SPLVAR;
1101
1102     NETPRI;
1103     bytes = rxi_WritevAlloc(call, iov, nio, maxio, nbytes);
1104     USERPRI;
1105     return bytes;
1106 }
1107
1108 /* rxi_WritevProc -- internal version.
1109  *
1110  * Send buffers allocated in rxi_WritevAlloc.
1111  *
1112  * LOCKS USED -- called at netpri.
1113  */
1114 int
1115 rxi_WritevProc(struct rx_call *call, struct iovec *iov, int nio, int nbytes)
1116 {
1117     struct rx_packet *cp = NULL;
1118 #ifdef RX_TRACK_PACKETS
1119     struct rx_packet *p, *np;
1120 #endif
1121     int nextio;
1122     int requestCount;
1123     struct rx_queue tmpq;
1124 #ifdef RXDEBUG_PACKET
1125     u_short tmpqc;
1126 #endif
1127
1128     requestCount = nbytes;
1129     nextio = 0;
1130
1131     MUTEX_ENTER(&call->lock);
1132     if (call->error) {
1133         call->mode = RX_MODE_ERROR;
1134     } else if (call->mode != RX_MODE_SENDING) {
1135         call->error = RX_PROTOCOL_ERROR;
1136     }
1137 #ifdef AFS_GLOBAL_RXLOCK_KERNEL
1138     rxi_WaitforTQBusy(call);
1139 #endif /* AFS_GLOBAL_RXLOCK_KERNEL */
1140     cp = call->currentPacket;
1141
1142     if (call->error) {
1143         call->mode = RX_MODE_ERROR;
1144         MUTEX_EXIT(&call->lock);
1145         if (cp) {
1146 #ifdef RX_TRACK_PACKETS
1147             cp->flags &= ~RX_PKTFLAG_CP;
1148             cp->flags |= RX_PKTFLAG_IOVQ;
1149 #endif
1150             queue_Prepend(&call->iovq, cp);
1151 #ifdef RXDEBUG_PACKET
1152             call->iovqc++;
1153 #endif /* RXDEBUG_PACKET */
1154             call->currentPacket = (struct rx_packet *)0;
1155         }
1156 #ifdef RXDEBUG_PACKET
1157         call->iovqc -=
1158 #endif /* RXDEBUG_PACKET */
1159             rxi_FreePackets(0, &call->iovq);
1160         return 0;
1161     }
1162
1163     /* Loop through the I/O vector adjusting packet pointers.
1164      * Place full packets back onto the iovq once they are ready
1165      * to send. Set RX_PROTOCOL_ERROR if any problems are found in
1166      * the iovec. We put the loop condition at the end to ensure that
1167      * a zero length write will push a short packet. */
1168     nextio = 0;
1169     queue_Init(&tmpq);
1170 #ifdef RXDEBUG_PACKET
1171     tmpqc = 0;
1172 #endif /* RXDEBUG_PACKET */
1173     do {
1174         if (call->nFree == 0 && cp) {
1175             clock_NewTime();    /* Bogus:  need new time package */
1176             /* The 0, below, specifies that it is not the last packet:
1177              * there will be others. PrepareSendPacket may
1178              * alter the packet length by up to
1179              * conn->securityMaxTrailerSize */
1180             hadd32(call->bytesSent, cp->length);
1181             rxi_PrepareSendPacket(call, cp, 0);
1182             queue_Append(&tmpq, cp);
1183 #ifdef RXDEBUG_PACKET
1184             tmpqc++;
1185 #endif /* RXDEBUG_PACKET */
1186             cp = call->currentPacket = (struct rx_packet *)0;
1187
1188             /* The head of the iovq is now the current packet */
1189             if (nbytes) {
1190                 if (queue_IsEmpty(&call->iovq)) {
1191                     MUTEX_EXIT(&call->lock);
1192                     call->error = RX_PROTOCOL_ERROR;
1193 #ifdef RXDEBUG_PACKET
1194                     tmpqc -=
1195 #endif /* RXDEBUG_PACKET */
1196                         rxi_FreePackets(0, &tmpq);
1197                     return 0;
1198                 }
1199                 cp = queue_First(&call->iovq, rx_packet);
1200                 queue_Remove(cp);
1201 #ifdef RX_TRACK_PACKETS
1202                 cp->flags &= ~RX_PKTFLAG_IOVQ;
1203 #endif
1204 #ifdef RXDEBUG_PACKET
1205                 call->iovqc--;
1206 #endif /* RXDEBUG_PACKET */
1207 #ifdef RX_TRACK_PACKETS
1208                 cp->flags |= RX_PKTFLAG_CP;
1209 #endif
1210                 call->currentPacket = cp;
1211                 call->nFree = cp->length;
1212                 call->curvec = 1;
1213                 call->curpos =
1214                     (char *)cp->wirevec[1].iov_base +
1215                     call->conn->securityHeaderSize;
1216                 call->curlen =
1217                     cp->wirevec[1].iov_len - call->conn->securityHeaderSize;
1218             }
1219         }
1220
1221         if (nbytes) {
1222             /* The next iovec should point to the current position */
1223             if (iov[nextio].iov_base != call->curpos
1224                 || iov[nextio].iov_len > (int)call->curlen) {
1225                 call->error = RX_PROTOCOL_ERROR;
1226                 MUTEX_EXIT(&call->lock);
1227                 if (cp) {
1228 #ifdef RX_TRACK_PACKETS
1229                     cp->flags &= ~RX_PKTFLAG_CP;
1230 #endif
1231                     queue_Prepend(&tmpq, cp);
1232 #ifdef RXDEBUG_PACKET
1233                     tmpqc++;
1234 #endif /* RXDEBUG_PACKET */
1235                     cp = call->currentPacket = (struct rx_packet *)0;
1236                 }
1237 #ifdef RXDEBUG_PACKET
1238                 tmpqc -=
1239 #endif /* RXDEBUG_PACKET */
1240                     rxi_FreePackets(0, &tmpq);
1241                 return 0;
1242             }
1243             nbytes -= iov[nextio].iov_len;
1244             call->curpos += iov[nextio].iov_len;
1245             call->curlen -= iov[nextio].iov_len;
1246             call->nFree -= iov[nextio].iov_len;
1247             nextio++;
1248             if (call->curlen == 0) {
1249                 if (++call->curvec > cp->niovecs) {
1250                     call->nFree = 0;
1251                 } else {
1252                     call->curpos = (char *)cp->wirevec[call->curvec].iov_base;
1253                     call->curlen = cp->wirevec[call->curvec].iov_len;
1254                 }
1255             }
1256         }
1257     } while (nbytes && nextio < nio);
1258
1259     /* Move the packets from the temporary queue onto the transmit queue.
1260      * We may end up with more than call->twind packets on the queue. */
1261
1262 #ifdef RX_TRACK_PACKETS
1263     for (queue_Scan(&tmpq, p, np, rx_packet))
1264     {
1265         p->flags |= RX_PKTFLAG_TQ;
1266     }
1267 #endif
1268
1269     if (call->error)
1270         call->mode = RX_MODE_ERROR;
1271
1272     queue_SpliceAppend(&call->tq, &tmpq);
1273
1274     if (!(call->flags & (RX_CALL_FAST_RECOVER | RX_CALL_FAST_RECOVER_WAIT))) {
1275         rxi_Start(0, call, 0, 0);
1276     }
1277
1278     /* Wait for the length of the transmit queue to fall below call->twind */
1279     while (!call->error && call->tnext + 1 > call->tfirst + (2 * call->twind)) {
1280         clock_NewTime();
1281         call->startWait = clock_Sec();
1282 #ifdef  RX_ENABLE_LOCKS
1283         CV_WAIT(&call->cv_twind, &call->lock);
1284 #else
1285         call->flags |= RX_CALL_WAIT_WINDOW_ALLOC;
1286         osi_rxSleep(&call->twind);
1287 #endif
1288         call->startWait = 0;
1289     }
1290
1291     /* cp is no longer valid since we may have given up the lock */
1292     cp = call->currentPacket;
1293
1294     if (call->error) {
1295         call->mode = RX_MODE_ERROR;
1296         call->currentPacket = NULL;
1297         MUTEX_EXIT(&call->lock);
1298         if (cp) {
1299 #ifdef RX_TRACK_PACKETS
1300             cp->flags &= ~RX_PKTFLAG_CP;
1301 #endif
1302             rxi_FreePacket(cp);
1303         }
1304         return 0;
1305     }
1306     MUTEX_EXIT(&call->lock);
1307
1308     return requestCount - nbytes;
1309 }
1310
1311 int
1312 rx_WritevProc(struct rx_call *call, struct iovec *iov, int nio, int nbytes)
1313 {
1314     int bytes;
1315     SPLVAR;
1316
1317     NETPRI;
1318     bytes = rxi_WritevProc(call, iov, nio, nbytes);
1319     USERPRI;
1320     return bytes;
1321 }
1322
1323 /* Flush any buffered data to the stream, switch to read mode
1324  * (clients) or to EOF mode (servers)
1325  *
1326  * LOCKS HELD: called at netpri.
1327  */
1328 void
1329 rxi_FlushWrite(struct rx_call *call)
1330 {
1331     struct rx_packet *cp = NULL;
1332
1333     /* Free any packets from the last call to ReadvProc/WritevProc */
1334     if (queue_IsNotEmpty(&call->iovq)) {
1335 #ifdef RXDEBUG_PACKET
1336         call->iovqc -=
1337 #endif /* RXDEBUG_PACKET */
1338             rxi_FreePackets(0, &call->iovq);
1339     }
1340
1341     if (call->mode == RX_MODE_SENDING) {
1342
1343         call->mode =
1344             (call->conn->type ==
1345              RX_CLIENT_CONNECTION ? RX_MODE_RECEIVING : RX_MODE_EOF);
1346
1347 #ifdef RX_KERNEL_TRACE
1348         {
1349             int glockOwner = ISAFS_GLOCK();
1350             if (!glockOwner)
1351                 AFS_GLOCK();
1352             afs_Trace3(afs_iclSetp, CM_TRACE_WASHERE, ICL_TYPE_STRING,
1353                        __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER,
1354                        call);
1355             if (!glockOwner)
1356                 AFS_GUNLOCK();
1357         }
1358 #endif
1359
1360         MUTEX_ENTER(&call->lock);
1361 #ifdef AFS_GLOBAL_RXLOCK_KERNEL
1362         rxi_WaitforTQBusy(call);
1363 #endif /* AFS_GLOBAL_RXLOCK_KERNEL */
1364         if (call->error)
1365             call->mode = RX_MODE_ERROR;
1366
1367         cp = call->currentPacket;
1368
1369         if (cp) {
1370             /* cp->length is only supposed to be the user's data */
1371             /* cp->length was already set to (then-current)
1372              * MaxUserDataSize or less. */
1373 #ifdef RX_TRACK_PACKETS
1374             cp->flags &= ~RX_PKTFLAG_CP;
1375 #endif
1376             cp->length -= call->nFree;
1377             call->currentPacket = (struct rx_packet *)0;
1378             call->nFree = 0;
1379         } else {
1380             cp = rxi_AllocSendPacket(call, 0);
1381             if (!cp) {
1382                 /* Mode can no longer be MODE_SENDING */
1383                 return;
1384             }
1385             cp->length = 0;
1386             cp->niovecs = 2;    /* header + space for rxkad stuff */
1387             call->nFree = 0;
1388         }
1389
1390         /* The 1 specifies that this is the last packet */
1391         hadd32(call->bytesSent, cp->length);
1392         rxi_PrepareSendPacket(call, cp, 1);
1393 #ifdef RX_TRACK_PACKETS
1394         cp->flags |= RX_PKTFLAG_TQ;
1395 #endif
1396         queue_Append(&call->tq, cp);
1397 #ifdef RXDEBUG_PACKET
1398         call->tqc++;
1399 #endif /* RXDEBUG_PACKET */
1400         if (!
1401             (call->
1402              flags & (RX_CALL_FAST_RECOVER | RX_CALL_FAST_RECOVER_WAIT))) {
1403             rxi_Start(0, call, 0, 0);
1404         }
1405         MUTEX_EXIT(&call->lock);
1406     }
1407 }
1408
1409 /* Flush any buffered data to the stream, switch to read mode
1410  * (clients) or to EOF mode (servers) */
1411 void
1412 rx_FlushWrite(struct rx_call *call)
1413 {
1414     SPLVAR;
1415     NETPRI;
1416     rxi_FlushWrite(call);
1417     USERPRI;
1418 }