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