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