summaryrefslogblamecommitdiff
path: root/nuttx/fs/nfs/rpc_clnt.c
blob: cdf16f56cd86be5e0a765bed19aa0950908f5f23 (plain) (tree)
1
2
3
4
5
6
7
8
9
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332





                                                                             
  
                          
  





                                                                  
























                                                                          


                                                                          
  

                                                                                
  












                                                                             
  










                                                                              








                                                                              










                       
                          

                     
                      
                
 



                                                                              
                                                                             






                                                                             
 











                                                                              
                                                                         








                                                                            
 

                                            

                                  







                                                                              







                                                         

                            



                                                

                                             







                                               



                                                                              
                                                                     


                                                   








                                
 
                  
                         

                             
 

                              
                            
                                             
 



                                                                              







                                                                               
                       





                                                                     
      
           
                                                   
                                                     
      






                                                                                   
 


                                                                              
 
                                                                           







                                                                                
 


                                                                     

                           
                 



                       
                 




                                       
                       
         
 


                                               
                    
         
 
                                       
                       
                                           
      
     
                       
      



                            
                                  


                     

      


                    

                                   


                      
      


                
 
                             
 






                                                                
     

                                                                 

         



                                                      
         

                                                           
 
                                                     
 
                                           
             




                                              
             
         
     

               

 
                                                                   
                                                           



                                                                  
 
                                                                       
                                                                              
                                                     

                    
                 
                       
                   
             
      
                

             

                                             


                                     
                                                                    




                                                                    
 



                                                             
         
                                                             


                       
             
 

                                                      



                                                               
 


                                                      
                       
         
 






                                                          
                           
             
 




                                            
                                                                               





                                                              
                               
                 
 






                                                  
                     

             
                                                                  
                                                         
                                                                           

                                                
                 
                                 

                                                                      
                                                     
                                                          
                     
                                   
                     
                 
             
                                        
 



                             
                                    
             
                                                               
                                                       
                                                                    
                                     

                            



                        
 

                                                     

                                                         


                                                               
 
                                           
             
                                                        
                                              
                                                                


                            

                    

             
                                                                   
                                                                
                                                                           

                                                



                                                                     
             
                                                                                 
 




                             
                                    
             
                                                               
                                                       
                                                                    
                                     

                            
              
             
                        
             


          
                                                               
                                                                  



                                                            
 
                     

             
                                                                   
                                                                   

                                                                         
                 

                                                                     

                                                   
                     



                                                       


                     
                                                       
 




                             
                                    
             


                                                                    
                                     

                            



                        





                                                            
             
                                                                  
                                                              

             

                                                                 



                                             
                         


                            


         
      
     

                                 
         
                        
         
 
                                                  
                                                                      
                     
         


                                                             
         
     
 

                                 

 
                                                                             



                                                                            
                                                                     
                                                     

                      
                                      

                                         

                
            
 

                                              
                                     
     
                                                                  



                                                                  
 


                                     


                       
      

                                                 
                                                                                 





                                       
                                                    

                        
 


                                                        
                 
                           

                 
                                                                          

                       
                       

         
                                                                   
 
                                                            
 

                                                


                                              
             
                       

             

                   

                                                                   

                                      
 
                                                               



                                                      
                                                          

                                         
 


                                               
                                                                                         
 
                                                 


                                                 




                                            
                                                        

                                                          
 

                                             
                                                  





                                                       
 



                                                  



                               


                                                   
 



                                   

                                                                

             
 

                   
                                          
                                   
                        


                            
                   
         
 
                                          
         
                   
         
     
 
                

 
                       

                                                                     
 

                      
 



                    
 



                                            
 
                                                  
     
                   
     

                                        
     
               
     

                 


               








                                                 
 


                                                              
                   
     
 
                 
           



















                                                                             



                       








                                        
           























                                                


                       
      


                  



                                                             



                       









                                                                           
           























                                                                   


                                   
 
           

 



















































































































































































































































































































































































































                                                                                           
     

               









                                                                              



                        



















                                                                      
                      
 
                                 
 
                             
 

  


                    
                    
                                                               











                                                                             
                         

                              
                                

                               
                    
                 


                        
 

                         
                       

                               
                                                        
 


                                                       
                                                           
                    
     
 
                                                                              
                
     

                                                     
                   

     

                       

                                



                                                                      
                 



                                                               
                
     

                                                           


               




                                                                 
                                
                                   
                             
 
             


              
                                  
                                                                           




                                                         
     
                                                   


            
                                                     


               













                                                                     









                                                                     

      
      
     
                                                               
                    
         

                                                                       
                   
         
 


                                                                          
 

                                                       



                                              
 
                                                                        

                                                                                      

                     
                                                             

                   
 
                                           
                                                                     

                                                               
                    
         

                                                                        




                             

                                                         
                                              
                                                        

                                                                          

                                                                                        

                     
                                                             


                   

                                                          
         
                                                           

                   
 
                                                                 
 



                                                                         

                                                       


                                                               
                    
         

                                                                      








                                                                        

                                                                                      

                     
                                                             



                                                                     
 


                                                               
                                                             

                   

     
                       
           


                          
               








                                                                      
                       






                                          
    
     

                                   
         




                                                             
         
     
                    




                                                         
                                                          


                                                


                                         
     
 
           
 
      







                                            



                            



                                       
                              
                              

                                


                       
                                       
 


                                                                      
 

                                                   




                                                           
                                                            


               




                                          
                                                                    

                                                                                  

                 
                                                         

               
 
                                                                 

                                                           

            
                                                            



                          
 

                                                     


                                                    

                                                                       

                                                                                    

                 
                                                        

               


                                                        
                                                           


               
           


                          
               

 












                                                
                                                                           

                                                                           
                                            
  
                                                              


                                                                          
 



                                                                    
 
                                   


                                      
                
 
                                                                      
 




                                   
                                   








                                    
 
                                     
 
                           
 
                                                      
 


                                                           
                                                              

                     
 

                                                                  

            
                                                  


                   
                        
                              
                            

                                  


                                    
      



                                                               


                                      


                                  
      


                        
 

                               

                         
                                                                       

                                               
 
                                         
 
                                                                      


                                                                     
 
                                                    


                                                         

                                            


                                                       
      

                     
                                                                       
                                                            


                                                


                                               

         
 










                                                               

                                         
                                   
     
                                                                    
                                                   
     
 

                                     
                                     
 

                                                






                                                      


                   
 

                                                 
                                         
                                                                  

                                                            
     

                                                                    

                          
                                           
                                                                        
                                            
                                                                           
                                                      

                             
 
                         
                                                                                    
                                                     

                         
 





                             
                                            






                         
                               
                                                                    

                                                             
 
                                     
     
                             
     
                                               
     
                                       
                                                                    

                                                                       
 
                                                        
                         
     
                               





                         
              
               

 

           
                                                                         


                                                                            
 






                                                    
                                                           



                                                  



                   



                                              


                                    
              



                                                                                  
                                   



                                                             
                                  



                       
                                   


                                 
         


                                           


                                                  
                                             

                                          
 





                                              
 


                                              


                                            

                   
 
                                    


                   
 
                                                                   

                                                        
 





                                                                            


                                                                        
              
             

                                                                            
             
 
                        
             
                                                       


                                                     
 



                                                      



                                                    

                                                   



                                                   






                                                
 






                                                                        
      
 
           




                                           
                                                     


                                                                    



                   




                             
                                                          


                                                        


                    
         
 
                       


                   

     
               
 
      
      
/****************************************************************************
 * fs/nfs/rpc_clnt.c
 *
 *   Copyright (C) 2012 Gregory Nutt. All rights reserved.
 *   Copyright (C) 2012 Jose Pablo Rojas Vargas. All rights reserved.
 *   Author: Jose Pablo Rojas Vargas <jrojas@nx-engineering.com>
 *
 * Leveraged from OpenBSD:
 *
 *   Copyright (c) 2004 The Regents of the University of Michigan.
 *   All rights reserved.
 *
 *   Copyright (c) 2004 Weston Andros Adamson <muzzle@umich.edu>.
 *   Copyright (c) 2004 Marius Aamodt Eriksen <marius@umich.edu>.
 *   All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *   Copyright (c) 1989, 1991, 1993, 1995 The Regents of the University of
 *   California.  All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by Rick Macklem at
 * The University of Guelph.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: 1. Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer. 2.
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution. 3. All advertising
 * materials mentioning features or use of this software must display the
 * following acknowledgement: This product includes software developed by the
 * University of California, Berkeley and its contributors. 4. Neither the
 * name of the University nor the names of its contributors may be used to
 * endorse or promote products derived from this software without specific
 * prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 ****************************************************************************/

#ifndef __FS_NFS_NFS_SOCKET_H
#define __FS_NFS_NFS_SOCKET_H

/****************************************************************************
 * Included Files
 ****************************************************************************/

#include <sys/socket.h>
#include <queue.h>
#include <time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <debug.h>
#include <nuttx/kmalloc.h>

#include "xdr_subs.h"
#include "nfs_proto.h"
#include "rpc.h"

/****************************************************************************
 * Pre-processor Definitions
 ****************************************************************************/

/* Estimate rto for an nfs rpc sent via. an unreliable datagram. Use the mean
 * and mean deviation of rtt for the appropriate type of rpc for the frequent
 * rpcs and a default for the others. The justification for doing "other"
 * this way is that these rpcs happen so infrequently that timer est. would
 * probably be stale. Also, since many of these rpcs are non-idempotent, a
 * conservative timeout is desired. getattr, lookup - A+2D read, write     -
 * A+4D other           - nm_timeo
 */

#define RPC_RTO(n, t) \
        ((t) == 0 ? (n)->rc_timeo : \
         ((t) < 3 ? \
          (((((n)->rc_srtt[t-1] + 3) >> 2) + (n)->rc_sdrtt[t-1] + 1) >> 1) : \
          ((((n)->rc_srtt[t-1] + 7) >> 3) + (n)->rc_sdrtt[t-1] + 1)))

#define RPC_SRTT(s,r)   (r)->r_rpcclnt->rc_srtt[rpcclnt_proct((s),\
                                (r)->r_procnum) - 1]

#define RPC_SDRTT(s,r)  (r)->r_rpcclnt->rc_sdrtt[rpcclnt_proct((s),\
                                (r)->r_procnum) - 1]

/* There is a congestion window for outstanding rpcs maintained per mount
 * point. The cwnd size is adjusted in roughly the way that: Van Jacobson,
 * Congestion avoidance and Control, In "Proceedings of SIGCOMM '88". ACM,
 * August 1988. describes for TCP. The cwnd size is chopped in half on a
 * retransmit timeout and incremented by 1/cwnd when each rpc reply is
 * received and a full cwnd of rpcs is in progress. (The sent count and cwnd
 * are scaled for integer arith.) Variants of "slow start" were tried and
 * were found to be too much of a performance hit (ave. rtt 3 times larger),
 * I suspect due to the large rtt that nfs rpcs have.
 */

#define RPC_CWNDSCALE   256
#define RPC_MAXCWND     (RPC_CWNDSCALE * 32)

#define RPC_ERRSTR_ACCEPTED_SIZE 6
#define RPC_ERRSTR_AUTH_SIZE 6

/****************************************************************************
 * Public Data
 ****************************************************************************/

char *rpc_errstr_accepted[RPC_ERRSTR_ACCEPTED_SIZE] =
{
  "",                           /* no good message... */
  "remote server hasn't exported program.",
  "remote server can't support version number.",
  "program can't support procedure.",
  "procedure can't decode params.",
  "remote error.  remote side memory allocation failure?"
};

char *rpc_errstr_denied[2] =
{
  "remote server doesnt support rpc version 2!",
  "remote server authentication error."
};

char *rpc_errstr_auth[RPC_ERRSTR_AUTH_SIZE] =
{
  "",
  "auth error: bad credential (seal broken).",
  "auth error: client must begin new session.",
  "auth error: bad verifier (seal broken).",
  "auth error: verifier expired or replayed.",
  "auth error: rejected for security reasons.",
};

/****************************************************************************
 * Private Data
 ****************************************************************************/

//static int rpcclnt_backoff[8] = { 2, 4, 8, 16, 32, 64, 128, 256, };

/* Static data, mostly RPC constants in XDR form */

static uint32_t rpc_reply;
static uint32_t rpc_call;
static uint32_t rpc_vers;
static uint32_t rpc_msgdenied;
static uint32_t rpc_mismatch;
static uint32_t rpc_auth_unix;
static uint32_t rpc_msgaccepted;
static uint32_t rpc_autherr;
static uint32_t rpc_auth_null;

int rpcclnt_ticks;
struct rpcstats rpcstats;
//struct rpc_call *callmgs;
//struct rpc_reply *replymsg;

/* Queue head for rpctask's */

static dq_queue_t rpctask_q;
//struct callout_handle rpcclnt_timer_handle;

/****************************************************************************
 * Private Function Prototypes
 ****************************************************************************/

static int rpcclnt_send(struct socket *so, struct sockaddr *nam,
                        int procid, int prog, void *call, int reqlen,
                        struct rpctask *rep);
static int rpcclnt_receive(struct rpctask *rep, struct sockaddr *aname,
                           int proc, int program, void *reply, size_t resplen);
                           //, struct rpc_call *);
static int rpcclnt_reply(struct rpctask *myrep, int procid, int prog,
                         void *reply, size_t resplen);
#ifdef CONFIG_NFS_TCPIP
static int rpcclnt_sndlock(int *flagp, struct rpctask *task);
static void rpcclnt_sndunlock(int *flagp);
static int rpcclnt_rcvlock(struct rpctask *task);
static void rpcclnt_rcvunlock(int *flagp);
static int rpcclnt_sigintr(struct rpcclnt *rpc, struct rpctask *task,
                           cthread_t *td);
#endif
#ifdef COMP
static void rpcclnt_softterm(struct rpctask *task);
void rpcclnt_timer(void *arg, struct rpc_call *call);
#endif
static uint32_t rpcclnt_proct(struct rpcclnt *rpc, uint32_t procid);
static uint32_t rpcclnt_newxid(void);
static void rpcclnt_fmtheader(FAR struct rpc_call_header *ch,
                              uint32_t xid, int procid, int prog, int vers);
static int rpcclnt_buildheader(struct rpcclnt *rpc, int procid, int prog, int vers,
                               struct xidr *value, FAR const void *request,
                               size_t *reqlen, FAR void *msgbuf);

/****************************************************************************
 * Private Functions
 ****************************************************************************/

/* This is the nfs send routine. For connection based socket types, it must
 * be called with an nfs_sndlock() on the socket. "rep == NULL" indicates
 * that it has been called from a server. For the client side: - return EINTR
 * if the RPC is terminated, 0 otherwise - set TASK_MUSTRESEND if the send fails
 * for any reason - do any cleanup required by recoverable socket errors
 * (???) For the server side: - return EINTR or ERESTART if interrupted by a
 * signal - return EPIPE if a connection is lost for connection based sockets
 * (TCP...) - do any cleanup required by recoverable socket errors (???)
 */

static int rpcclnt_send(struct socket *so, struct sockaddr *nam,
                        int procid, int prog, void *call, int reqlen,
                        struct rpctask *rep)
{
  struct sockaddr *sendnam;
  ssize_t nbytes;
#ifdef CONFIG_NFS_TCPIP
  int soflags;
#endif
  int flags;
  int error = OK;

  if (rep != NULL)
    {
      if (rep->r_flags & TASK_SOFTTERM)
        {
          return EINTR;
        }

      if ((so = rep->r_rpcclnt->rc_so) == NULL)
        {
          rep->r_flags |= TASK_MUSTRESEND;
          return OK;
        }

      rep->r_flags &= ~TASK_MUSTRESEND;
#ifdef CONFIG_NFS_TCPIP
      soflags = rep->r_rpcclnt->rc_soflags;
#endif
    }
#ifdef CONFIG_NFS_TCPIP
  else
    {
      soflags = so->s_flags;
    }

  if ((soflags & PR_CONNREQUIRED))
    {
      sendnam = NULL;
    {
  else
#endif
    {
      sendnam = nam;
    }

  if (so->s_type == SOCK_SEQPACKET)
    {
      flags = MSG_EOR;
    }
  else
    {
      flags = 0;
    }

  /* Send the call message */

  /* On success, psock_sendto returns the number of bytes sent;
   * On failure, it returns -1 with the specific error in errno.
   */

  nbytes = psock_sendto(so, call, reqlen, flags,
                        sendnam, sizeof(struct sockaddr));
  if (nbytes < 0)
    {
      /* psock_sendto failed,  Sample the error value (subsequent
       * calls can change the errno value!
       */

      error = errno;
      fdbg("ERROR: psock_sendto failed: %d\n", error);

      if (rep != NULL)
        {
          fdbg("rpc send error %d for service %s\n", error,
               rep->r_rpcclnt->rc_prog->prog_name);

          /* Deal with errors for the client side. */

          if (rep->r_flags & TASK_SOFTTERM)
            {
              error = EINTR;
            }
          else
            {
              rep->r_flags |= TASK_MUSTRESEND;
            }
        }
    }

  return error;
}

/* Receive a Sun RPC Request/Reply. For SOCK_DGRAM, the work is all
 * done by psock_recvfrom(). For SOCK_STREAM, first get the
 * Record Mark to find out how much more there is to get. We must
 * lock the socket against other receivers until we have an entire
 * rpc request/reply.
 */

static int rpcclnt_receive(struct rpctask *rep, struct sockaddr *aname,
                           int proc, int program, void *reply, size_t resplen)
                           //, struct rpc_call *call)
{
  struct socket *so;
  ssize_t nbytes;
#ifdef CONFIG_NFS_TCPIP
  uint32_t resplen;
  int sotype;
#endif
  int error = 0;
  int errval;

#ifdef CONFIG_NFS_TCPIP
  /* Set up arguments for psock_recvfrom() */

  sotype = rep->r_rpcclnt->rc_sotype;

  /* For reliable protocols, lock against other senders/receivers in
   * case a reconnect is necessary. For SOCK_STREAM, first get the
   * Record Mark to find out how much more there is to get. We must
   * lock the socket against other receivers until we have an entire
   * rpc request/reply.
   */

  if (sotype != SOCK_DGRAM)
    {
      error = rpcclnt_sndlock(&rep->r_rpcclnt->rc_flag, rep);
      if (error != 0)
        {
          fdbg("ERROR: rpcclnt_sndlock failed: %d\n", error);
          return error;
        }

    tryagain:

      /* Check for fatal errors and resending request.
       *
       * Ugh: If a reconnect attempt just happened, rc_so would
       * have changed. NULL indicates a failed attempt that has
       * essentially shut down this mount point.
       */

      if (rep->r_flags & TASK_SOFTTERM)
        {
          rpcclnt_sndunlock(&rep->r_rpcclnt->rc_flag);
          return EINTR;
        }

      so = rep->r_rpcclnt->rc_so;
      if (so == NULL)
        {
          error = rpcclnt_reconnect(rep);
          if (error)
            {
              rpcclnt_sndunlock(&rep->r_rpcclnt->rc_flag);
              return error;
            }

          goto tryagain;
        }
      while (rep->r_flags & TASK_MUSTRESEND)
        {
          rpcstats.rpcretries++;
          error = rpcclnt_send(so, rep->r_rpcclnt->rc_name, call, reqlen, rep);
          if (error)
            {
              if (error == EINTR || error == ERESTART ||
                  (error = rpcclnt_reconnect(rep)) != 0)
                {
                  rpcclnt_sndunlock(&rep->r_rpcclnt->rc_flag);
                  return error;
                }

              goto tryagain;
            }
        }

      rpcclnt_sndunlock(&rep->r_rpcclnt->rc_flag);
      if (sotype == SOCK_STREAM)
        {
          errval = 0;
          do
            {
              socklen_t fromlen = sizeof(*rep->r_rpcclnt->rc_name)
              nbytes = psock_recvfrom(so, reply, resplen,
                                      MSG_WAITALL, rep->r_rpcclnt->rc_name,
                                      &fromlen);
              if (nbytes < 0)
                {
                  errval = errno;
                  fdbg("ERROR: psock_recvfrom returned %d\n", errval);

                  if (errval == EWOULDBLOCK && rep &&
                      (rep->r_flags & TASK_SOFTTERM) != 0)
                    {
                      return EINTR;
                    }
                }
            }
          while (errval == EWOULDBLOCK);

          if (nbytes < 0)
            {
              error = errval;
            }
          else if (nbytes < resplen)
            {
              fdbg("ERROR: Short receive from rpc server %s\n",
                   rep->r_rpcclnt->rc_prog->prog_name);
              fvdbg("       Expected %d bytes, received %d bytes\n",
                    resplen, nbytes);
              error = EPIPE;
            }
          else
            {
              error = 0;
            }

#warning "What is resplen?  This logic is not right!"
          resplen = ntohl(resplen) & ~0x80000000;

          /* This is SERIOUS! We are out of sync with the
           * sender and forcing a disconnect/reconnect is all I
           * can do.
           */

          else if (resplen > RPC_MAXPACKET)
            {
              fdbg("ERROR %s (%d) from rpc server %s\n",
                   "impossible packet length",
                   resplen, rep->r_rpcclnt->rc_prog->prog_name);
              error = EFBIG;
              goto errout;
            }

          errval = 0
          do
            {
              socklen_t fromlen = sizeof(*rep->r_rpcclnt->rc_name);
              nbytes = psock_recvfrom(so, reply, sizeof(*reply),
                                      MSG_WAITALL, rep->r_rpcclnt->rc_name,
                                      &fromlen);
              if (nbytes < 0)
                {
                  errval = errno;
                  fdbg("ERROR: psock_recvfrom failed: %d\n", errval);
                }
            }
          while (errval == EWOULDBLOCK || errval == EINTR || errval == ERESTART);

          if (nbytes < 0)
            {
              error = errval;
              goto errout;
            }
          else if (nbytes < resplen)
            {
              fdbg("ERROR: Short receive from rpc server %s\n",
                   rep->r_rpcclnt->rc_prog->prog_name);
              fvdbg("       Expected %d bytes, received %d bytes\n",
                    resplen, nbytes);
              error = EPIPE;
            }
          else
            {
              error = 0;
            }
        }
      else
        {
          /* NB: Since uio_resid is big, MSG_WAITALL is ignored
           * and psock_recvfrom() will return when it has either a
           * control msg or a data msg. We have no use for
           * control msg., but must grab them and then throw
           * them away so we know what is going on.
           */

          errval = 0;
          do
            {
              socklen_t fromlen = sizeof(*rep->r_rpcclnt->rc_name);
              nbytes = psock_recvfrom(so, reply, sizeof(*reply), 0,
                                      rep->r_rpcclnt->rc_name, &fromlen);
              if (nbytes < 0)
                {
                  errval = errno;
                  fdbg("ERROR: psock_recvfrom failed: %d\n", errval);

                  if (errval == EWOULDBLOCK && rep)
                    {
                      if (rep->r_flags & TASK_SOFTTERM)
                        {
                          return EINTR;
                        }
                    }
                }
            }
          while (errval == EWOULDBLOCK || nbytes == 0);

          if (nbytes < 0)
            {
              error = errval;
              goto errout;
            }
          else if (nbytes < resplen)
            {
              fdbg("ERROR: Short receive from rpc server %s\n",
                   rep->r_rpcclnt->rc_prog->prog_name);
              fvdbg("       Expected %d bytes, received %d bytes\n",
                    resplen, nbytes);
              error = EPIPE;
            }
          else
            {
              error = 0;
            }
        }

    errout:
      if (error != 0 && error != EINTR && error != ERESTART)
        {
          if (error != EPIPE)
            {
              fdbg("ERROR: Receive error %d from rpc server %s\n",
                   error, rep->r_rpcclnt->rc_prog->prog_name);
            }

          error = rpcclnt_sndlock(&rep->r_rpcclnt->rc_flag, rep);
          if (error == 0)
            {
              error = rpcclnt_reconnect(rep);
            }

          if (error == 0)
            {
              goto tryagain;
            }
        }
    }
  else
#endif
    {
      so = rep->r_rpcclnt->rc_so;
      if (so == NULL)
        {
          return EACCES;
        }

      socklen_t fromlen = sizeof(struct sockaddr);
      nbytes = psock_recvfrom(so, reply, resplen, 0, aname, &fromlen);
      if (nbytes < 0)
        {
          errval = errno;
          fdbg("ERROR: psock_recvfrom failed: %d\n", errval);
          error = errval;
        }
    }

  fvdbg("Returning %d\n", error);
  return error;
}

/* Implement receipt of reply on a socket. We must search through the list of
 * received datagrams matching them with outstanding requests using the xid,
 * until ours is found.
 */

static int rpcclnt_reply(struct rpctask *myrep, int procid, int prog,
                         void *reply, size_t resplen)
{
  struct rpctask *rep;
  struct rpc_reply_header replyheader;
  struct rpcclnt *rpc = myrep->r_rpcclnt;
  int32_t t1;
  uint32_t rxid;
  int error;
  int count;

  /* Loop around until we get our own reply */

  for (count = 0; count < 9; count++)
    {
      /* Lock against other receivers so that I don't get stuck in
       * sbwait() after someone else has received my reply for me.
       * Also necessary for connection based protocols to avoid
       * race conditions during a reconnect.
       */

#ifdef CONFIG_NFS_TCPIP
      error = rpcclnt_rcvlock(myrep);
      if (error)
        {
          return error;
        }
#endif
      /* Get the next Rpc reply off the socket */

      error = rpcclnt_receive(myrep, rpc->rc_name, procid, prog, reply, resplen);
#ifdef CONFIG_NFS_TCPIP
      rpcclnt_rcvunlock(&rpc->rc_flag);
#endif

      if (error != 0)
        {
          /* Ignore routing errors on connectionless
           * protocols??
           */

          if (RPCIGNORE_SOERROR(rpc->rc_soflags, error))
            {
              if (myrep->r_flags & TASK_GETONEREP)
                {
                  return 0;
                }

              fdbg("ignoring routing error on connectionless protocol\n");
              continue;
            }
          return error;
        }

      memcpy(&replyheader, reply, sizeof(struct rpc_reply_header));

      /* Get the xid and check that it is an rpc replysvr */

      rxid = replyheader.rp_xid;
      if (replyheader.rp_direction != rpc_reply)
        {
          rpcstats.rpcinvalid++;
          if (myrep->r_flags & TASK_GETONEREP)
            {
              return 0;
            }

          continue;
        }

      /* Loop through the request list to match up the reply Iff no
       * match, just drop the datagram
       */

      for (rep = (struct rpctask *)rpctask_q.head; rep != NULL;
           rep = (struct rpctask *)rep->r_chain.flink)
        {
          if (rxid == rep->r_xid)
            {
              /* Update congestion window. Do the additive
               * increase of one rpc/rtt.
               */

              if (rpc->rc_cwnd <= rpc->rc_sent)
                {
                  rpc->rc_cwnd +=
                    (RPC_CWNDSCALE * RPC_CWNDSCALE + (rpc->rc_cwnd >> 1)) / rpc->rc_cwnd;

                  if (rpc->rc_cwnd > RPC_MAXCWND)
                    {
                      rpc->rc_cwnd = RPC_MAXCWND;
                    }
                }

              rep->r_flags &= ~TASK_SENT;
              rpc->rc_sent -= RPC_CWNDSCALE;

              /* Update rtt using a gain of 0.125 on the
               * mean and a gain of 0.25 on the deviation.
               */

              if (rep->r_flags & TASK_TIMING)
                {
                  /* Since the timer resolution of
                   * NFS_HZ is so course, it can often
                   * result in r_rtt == 0. Since r_rtt
                   * == N means that the actual rtt is
                   * between N+dt and N+2-dt ticks, add
                   * 1.
                   */

                  t1 = rep->r_rtt + 1;
                  t1 -= (RPC_SRTT(rpc, rep) >> 3);
                  RPC_SRTT(rpc, rep) += t1;
                  if (t1 < 0)
                    {
                      t1 = -t1;
                    }

                  t1 -= (RPC_SDRTT(rpc, rep) >> 2);
                  RPC_SDRTT(rpc, rep) += t1;
                }

              rpc->rc_timeouts = 0;
              break;
            }
        }

      /* If not matched to a request, drop it. If it's mine, get
       * out.
       */

      if (rep == 0)
        {
          fdbg("rpc reply not matched\n");
          rpcstats.rpcunexpected++;
          return ENOMSG;
        }
      else if (rep == myrep)
        {
          return 0;
        }

      if (myrep->r_flags & TASK_GETONEREP)
        {
          return 0;
        }
    }

  return ENONET;
}

#ifdef CONFIG_NFS_TCPIP
static int rpcclnt_sigintr(struct rpcclnt *rpc, struct rpctask *task,
                           cthread_t *td)
{
  struct proc *p;
  sigset_t     tmpset;

  if (rpc == NULL)
    {
      return EFAULT;
    }

  if (ISSET(rpc->rc_flag, RPCCLNT_REDIRECT))
    {
      return 0;
    }

  if (task && ISSET(task->r_flags, TASK_SOFTTERM))
    {
      return EINTR;
    }

  if (!ISSET(rpc->rc_flag, RPCCLNT_INT))
    {
      return 0;
    }

  if (td == NULL)
    {
      return 0;
    }

  p = cthread_proc(td);

  PROC_LOCK(p);
  tmpset = p->p_siglist;
  SIGSETNAND(tmpset, td->td_sigmask);
  mtx_lock(&p->p_sigacts->ps_mtx);
  SIGSETNAND(tmpset, p->p_sigacts->ps_sigignore);
  mtx_unlock(&p->p_sigacts->ps_mtx);

  if (SIGNOTEMPTY(p->p_siglist) && RPCCLNTINT_SIGMASK(tmpset))
    {
      PROC_UNLOCK(p);
      return EINTR;
    }

  PROC_UNLOCK(p);
  return 0;
}

/* Lock a socket against others. Necessary for STREAM sockets to ensure you
 * get an entire rpc request/reply and also to avoid race conditions between
 * the processes with nfs requests in progress when a reconnect is necessary.
 */

static int rpcclnt_sndlock(int *flagp, struct rpctask *task)
{
  int slpflag = 0, slptimeo = 0;

  if (task)
    {
      if (task->r_rpcclnt->rc_flag & RPCCLNT_INT)
        slpflag = PCATCH;
    }

  while (*flagp & RPCCLNT_SNDLOCK)
    {
      if (rpcclnt_sigintr(task->r_rpcclnt, task, p))
        {
          return EINTR;
        }

      *flagp |= RPCCLNT_WANTSND;
      if (slpflag == PCATCH)
        {
          slpflag = 0;
          slptimeo = 2 * CLOCKS_PER_SEC;
        }
    }

  *flagp |= RPCCLNT_SNDLOCK;
  return 0;
}

/* Unlock the stream socket for others. */

static void rpcclnt_sndunlock(int *flagp)
{
  if ((*flagp & RPCCLNT_SNDLOCK) == 0)
    {
      panic("rpc sndunlock");
    }

  *flagp &= ~RPCCLNT_SNDLOCK;
  if (*flagp & RPCCLNT_WANTSND)
    {
      *flagp &= ~RPCCLNT_WANTSND;
    }
}

static int rpcclnt_rcvlock(struct rpctask *task)
{
  int *flagp = &task->r_rpcclnt->rc_flag;
  int slpflag, slptimeo = 0;

  if (*flagp & RPCCLNT_INT)
    {
      slpflag = PCATCH;
    }
  else
    {
      slpflag = 0;
    }

  while (*flagp & RPCCLNT_RCVLOCK)
    {
      if (rpcclnt_sigintr(task->r_rpcclnt, task, task->r_td))
        {
          return EINTR;
        }

      *flagp |= RPCCLNT_WANTRCV;
      tsleep((caddr_t) flagp, slpflag | (PZERO - 1), "rpcrcvlk", slptimeo);
      if (slpflag == PCATCH)
        {
          slpflag = 0;
          slptimeo = 2 * CLOCKS_PER_SEC;
        }
    }

  *flagp |= RPCCLNT_RCVLOCK;
  return 0;
}

/* Unlock the stream socket for others. */

static void rpcclnt_rcvunlock(int *flagp)
{
  if ((*flagp & RPCCLNT_RCVLOCK) == 0)
    {
      panic("nfs rcvunlock");
    }

  *flagp &= ~RPCCLNT_RCVLOCK;
  if (*flagp & RPCCLNT_WANTRCV)
    {
      *flagp &= ~RPCCLNT_WANTRCV;
      wakeup((caddr_t) flagp);
    }
}
#endif

static uint32_t rpcclnt_proct(struct rpcclnt *rpc, uint32_t procid)
{
  if (rpc->rc_proctlen != 0 && rpc->rc_proct != NULL &&
      procid < rpc->rc_proctlen)
    {
      return rpc->rc_proct[procid];
    }

  return 0;
}

#ifdef COMP
static void rpcclnt_softterm(struct rpctask *task)
{
  task->r_flags |= TASK_SOFTTERM;
  if (task->r_flags & TASK_SENT)
    {
      task->r_rpcclnt->rc_sent -= RPC_CWNDSCALE;
      task->r_flags &= ~TASK_SENT;
    }
}
#endif

/* Get a new (non-zero) xid */

static uint32_t rpcclnt_newxid(void)
{
  static uint32_t rpcclnt_xid = 0;
  static uint32_t rpcclnt_xid_touched = 0;
  int xidp = 0;

  srand(time(NULL));
  if ((rpcclnt_xid == 0) && (rpcclnt_xid_touched == 0))
    {
      rpcclnt_xid = rand();
      rpcclnt_xid_touched = 1;
    }
  else
    {
      do
        {
          xidp = rand();
        }
      while ((xidp % 256) == 0);

      rpcclnt_xid += xidp;
    }

  return rpcclnt_xid;
}

/* Format the common part of the call header */

static void rpcclnt_fmtheader(FAR struct rpc_call_header *ch,
                              uint32_t xid, int prog, int vers, int procid)
{
  /* Format the call header */
 
  ch->rp_xid            = txdr_unsigned(xid);
  ch->rp_direction      = rpc_call;
  ch->rp_rpcvers        = rpc_vers;
  ch->rp_prog           = txdr_unsigned(prog);
  ch->rp_vers           = txdr_unsigned(vers);
  ch->rp_proc           = txdr_unsigned(procid);

  /* rpc_auth part (auth_unix as root) */

  ch->rpc_auth.authtype = rpc_auth_null;
//call->rpc_auth.authlen        = 0;
#ifdef CONFIG_NFS_UNIX_AUTH
  ch->rpc_unix.stamp    = txdr_unsigned(1);
  ch->rpc_unix.hostname = 0;
  ch->rpc_unix.uid      = setuid;
  ch->rpc_unix.gid      = setgid;
  ch->rpc_unix.gidlist  = 0;
#endif
  /* rpc_verf part (auth_null) */

  ch->rpc_verf.authtype  = rpc_auth_null;
//call->rpc_verf.authlen = 0;
}

/* Build the RPC header and fill in the authorization info. */

static int rpcclnt_buildheader(struct rpcclnt *rpc, int procid, int prog, int vers,
                               struct xidr *value, FAR const void *request,
                               size_t *reqlen, FAR void *msgbuf)
{
  uint32_t xid;

  /* The RPC header.*/

  /* Get a new (non-zero) xid */

  xid = rpcclnt_newxid();

  /* Perform the binding depending on the protocol type */

  if (prog == PMAPPROG)
    {
      if (procid == PMAPPROC_GETPORT)
        {
          /* Copy the variable, caller-provided data into the call message structure */

          struct rpc_call_pmap *callmsg = (struct rpc_call_pmap *)msgbuf;
          memcpy(&callmsg->pmap, request, *reqlen);

          /* Return the full size of the message (including messages headers) */

          DEBUGASSERT(*reqlen == sizeof(struct call_args_pmap));
          *reqlen = sizeof(struct rpc_call_pmap);

          /* Format the message header */

          rpcclnt_fmtheader(&callmsg->ch, xid, prog, vers, procid);
          value->xid = callmsg->ch.rp_xid;
          return 0;
        }
      else if (procid == PMAPPROC_UNSET)
        {
          /* Copy the variable, caller-provided data into the call message structure */

          struct rpc_call_pmap *callmsg = (struct rpc_call_pmap *)msgbuf;;
          memcpy(&callmsg->pmap, request, *reqlen);

          /* Return the full size of the message (including messages headers) */

          DEBUGASSERT(*reqlen == sizeof(struct call_args_pmap));
          *reqlen = sizeof(struct rpc_call_pmap);

          /* Format the message header */

          rpcclnt_fmtheader(&callmsg->ch, xid, prog, vers, procid);
          value->xid = callmsg->ch.rp_xid;
          return 0;
        }
    }
  else if (prog == RPCPROG_MNT)
    {
      if (procid == RPCMNT_UMOUNT)
        {
          /* Copy the variable, caller-provided data into the call message structure */

          struct rpc_call_mount *callmsg = (struct rpc_call_mount *)msgbuf;
          memcpy(&callmsg->mount, request, *reqlen);

          /* Return the full size of the message (including messages headers) */

          DEBUGASSERT(*reqlen == sizeof(struct call_args_mount));
          *reqlen = sizeof(struct rpc_call_mount);

          /* Format the message header */

          rpcclnt_fmtheader(&callmsg->ch, xid, prog, vers, procid);
          value->xid = callmsg->ch.rp_xid;
          return 0;
        }
      else if (procid == RPCMNT_MOUNT)
        {
          /* Copy the variable, caller-provided data into the call message structure */

          struct rpc_call_mount *callmsg = (struct rpc_call_mount *)msgbuf;
          memcpy(&callmsg->mount, request, *reqlen);

          /* Return the full size of the message (including messages headers) */

          DEBUGASSERT(*reqlen == sizeof(struct call_args_mount));
          *reqlen = sizeof(struct rpc_call_mount);

          /* Format the message header */

          rpcclnt_fmtheader(&callmsg->ch, xid, prog, vers, procid);
          value->xid = callmsg->ch.rp_xid;
          return 0;
        }
    }
  else if (prog == NFS_PROG)
    {
      switch (procid)
        {
        case NFSPROC_CREATE:
          {
            /* Copy the variable, caller-provided data into the call message structure */

            struct rpc_call_create *callmsg = (struct rpc_call_create *)msgbuf;
            memcpy(&callmsg->create, request, *reqlen);

            /* Return the full size of the message (including messages headers) */

            DEBUGASSERT(*reqlen == sizeof(struct CREATE3args));
            *reqlen = sizeof(struct rpc_call_create);

            /* Format the message header */

            rpcclnt_fmtheader(&callmsg->ch, xid, prog, vers, procid);
            value->xid = callmsg->ch.rp_xid;
            return 0;
          }

        case NFSPROC_LOOKUP:
          {
            struct rpc_call_lookup *callmsg = (struct rpc_call_lookup *)msgbuf;
            uint32_t namelen;

            /* Copy the variable, caller-provided data into the call message structure */

            memcpy(&callmsg->lookup, request, *reqlen);

            /* Return the full size of the message (including messages headers) */

            namelen = fxdr_unsigned(uint32_t, ((FAR struct LOOKUP3args*)request)->namelen);
            DEBUGASSERT(*reqlen <= SIZEOF_LOOKUP3args(namelen));
            *reqlen = SIZEOF_rpc_call_lookup(namelen);

            /* Format the message header */

            rpcclnt_fmtheader(&callmsg->ch, xid, prog, vers, procid);
            value->xid = callmsg->ch.rp_xid;
            return 0;
          }

        case NFSPROC_READ:
          {
            /* Copy the variable, caller-provided data into the call message structure */

            struct rpc_call_read *callmsg = (struct rpc_call_read *)msgbuf;
            memcpy(&callmsg->read, request, *reqlen);

            /* Return the full size of the message (including messages headers) */

            DEBUGASSERT(*reqlen == sizeof(struct READ3args));
            *reqlen = sizeof(struct rpc_call_read);

            /* Format the message header */

            rpcclnt_fmtheader(&callmsg->ch, xid, prog, vers, procid);
            value->xid = callmsg->ch.rp_xid;
            return 0;
          }

        case NFSPROC_WRITE:
          {
            /* Copy the variable, caller-provided data into the call message structure */

            struct rpc_call_write *callmsg = (struct rpc_call_write *)msgbuf;
            memcpy(&callmsg->write, request, *reqlen);

            /* Return the full size of the message (including messages headers) */

            DEBUGASSERT(*reqlen == sizeof(struct WRITE3args));
            *reqlen = sizeof(struct rpc_call_write);

            /* Format the message header */

            rpcclnt_fmtheader(&callmsg->ch, xid, prog, vers, procid);
            value->xid = callmsg->ch.rp_xid;
            return 0;
          }

        case NFSPROC_READDIR:
          {
            /* Copy the variable, caller-provided data into the call message structure */

            struct rpc_call_readdir *callmsg = (struct rpc_call_readdir *)msgbuf;
            memcpy(&callmsg->readdir, request, *reqlen);

            /* Return the full size of the message (including messages headers) */

            DEBUGASSERT(*reqlen == sizeof(struct READDIR3args));
            *reqlen = sizeof(struct rpc_call_readdir);

            /* Format the message header */

            rpcclnt_fmtheader(&callmsg->ch, xid, prog, vers, procid);
            value->xid = callmsg->ch.rp_xid;
            return 0;
          }

        case NFSPROC_FSSTAT:
          {
            /* Copy the variable, caller-provided data into the call message structure */

            struct rpc_call_fs *callmsg = (struct rpc_call_fs *)msgbuf;
            memcpy(&callmsg->fs, request, *reqlen);

            /* Return the full size of the message (including messages headers) */

            DEBUGASSERT(*reqlen == sizeof(struct FS3args));
            *reqlen = sizeof(struct rpc_call_fs);

            /* Format the message header */

            rpcclnt_fmtheader(&callmsg->ch, xid, prog, vers, procid);
            value->xid = callmsg->ch.rp_xid;
            return 0;
          }

        case NFSPROC_REMOVE:
          {
            /* Copy the variable, caller-provided data into the call message structure */

            struct rpc_call_remove *callmsg  = (struct rpc_call_remove *)msgbuf;
            memcpy(&callmsg->remove, request, *reqlen);

            /* Return the full size of the message (including messages headers) */

            DEBUGASSERT(*reqlen == sizeof(struct REMOVE3args));
            *reqlen = sizeof(struct rpc_call_remove);

            /* Format the message header */

            rpcclnt_fmtheader(&callmsg->ch, xid, prog, vers, procid);
            value->xid = callmsg->ch.rp_xid;
            return 0;
          }

         case NFSPROC_GETATTR:
          {
            /* Copy the variable, caller-provided data into the call message structure */

            struct rpc_call_fs *callmsg  = (struct rpc_call_fs *)msgbuf;
            memcpy(&callmsg->fs, request, *reqlen);

            /* Return the full size of the message (including messages headers) */

            DEBUGASSERT(*reqlen == sizeof(struct FS3args));
            *reqlen = sizeof(struct rpc_call_fs);

            /* Format the message header */

            rpcclnt_fmtheader(&callmsg->ch, xid, prog, vers, procid);
            value->xid = callmsg->ch.rp_xid;
            return 0;
          }

        case NFSPROC_MKDIR:
          {
            /* Copy the variable, caller-provided data into the call message structure */

            struct rpc_call_mkdir *callmsg = (struct rpc_call_mkdir *)msgbuf;
            memcpy(&callmsg->mkdir, request, *reqlen);

            /* Return the full size of the message (including messages headers) */

            DEBUGASSERT(*reqlen == sizeof(struct MKDIR3args));
            *reqlen = sizeof(struct rpc_call_mkdir);

            /* Format the message header */

            rpcclnt_fmtheader(&callmsg->ch, xid, prog, vers, procid);
            value->xid = callmsg->ch.rp_xid;
            return 0;
          }

        case NFSPROC_RMDIR:
          {
            /* Copy the variable, caller-provided data into the call message structure */

            struct rpc_call_rmdir *callmsg  = (struct rpc_call_rmdir *)msgbuf;
            memcpy(&callmsg->rmdir, request, *reqlen);

            /* Return the full size of the message (including messages headers) */

            DEBUGASSERT(*reqlen == sizeof(struct RMDIR3args));
            *reqlen = sizeof(struct rpc_call_rmdir);

            /* Format the message header */

            rpcclnt_fmtheader(&callmsg->ch, xid, prog, vers, procid);
            value->xid = callmsg->ch.rp_xid;
            return 0;
          }

        case NFSPROC_RENAME:
          {
            /* Copy the variable, caller-provided data into the call message structure */

            struct rpc_call_rename *callmsg  = (struct rpc_call_rename *)msgbuf;
            memcpy(&callmsg->rename, request, *reqlen);

            /* Return the full size of the message (including messages headers) */

            DEBUGASSERT(*reqlen == sizeof(struct RENAME3args));
            *reqlen = sizeof(struct rpc_call_rename);

            /* Format the message header */

            rpcclnt_fmtheader(&callmsg->ch, xid, prog, vers, procid);
            value->xid = callmsg->ch.rp_xid;
            return 0;
          }

        case NFSPROC_FSINFO:
          {
            /* Copy the variable, caller-provided data into the call message structure */

            struct rpc_call_fs *callmsg = (struct rpc_call_fs *)msgbuf;
            memcpy(&callmsg->fs, request, *reqlen);

            /* Return the full size of the message (including messages headers) */

            DEBUGASSERT(*reqlen == sizeof(struct FS3args));
            *reqlen = sizeof(struct rpc_call_fs);

            /* Format the message header */

            rpcclnt_fmtheader(&callmsg->ch, xid, prog, vers, procid);
            value->xid = callmsg->ch.rp_xid;
            return 0;
          }

        default:
          fdbg("No support for procid %d\n", procid);
          break;
        }
    }

  return ESRCH;
}

/****************************************************************************
 * Public Functions
 ****************************************************************************/

void rpcclnt_init(void)
{
  rpcclnt_ticks = (CLOCKS_PER_SEC * RPC_TICKINTVL + 500) / 1000;
  if (rpcclnt_ticks < 1)
    {
      rpcclnt_ticks = 1;
    }

  rpcstats.rpcretries = 0;
  rpcstats.rpcrequests = 0;
  rpcstats.rpctimeouts = 0;
  rpcstats.rpcunexpected = 0;
  rpcstats.rpcinvalid = 0;

  /* RPC constants how about actually using more than one of these! */

  rpc_reply = txdr_unsigned(RPC_REPLY);
  rpc_vers = txdr_unsigned(RPC_VER2);
  rpc_call = txdr_unsigned(RPC_CALL);
  rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
  rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
  rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
  rpc_autherr = txdr_unsigned(RPC_AUTHERR);
  rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
  rpc_auth_null = txdr_unsigned(RPCAUTH_NULL);

  /* Initialize rpctask queue */

  dq_init(&rpctask_q);

  //rpcclnt_timer(NULL, callmgs);

  fvdbg("rpc initialized\n");
}

/*
void
rpcclnt_uninit(void)
{
  fvdbg("uninit\n");
  untimeout(rpcclnt_timer, (void *)NULL, rpcclnt_timer_handle);
}
*/

/* Initialize sockets and congestion for a new RPC connection. We do not free
 * the sockaddr if error.
 */

int rpcclnt_connect(struct rpcclnt *rpc)
{
  struct socket *so;
  int error;
  struct sockaddr *saddr;
  struct sockaddr_in sin;
  struct sockaddr_in *sa;
  struct call_args_pmap sdata;
  struct call_args_mount mountd;
  struct rpc_reply_pmap rdata;
  struct rpc_reply_mount mdata;
  struct timeval tv;
  uint16_t tport;
  int errval;

  fvdbg("Connecting\n");

  /* Create the socket */

  saddr = rpc->rc_name;
  memset(&sin, 0, sizeof(sin));

  /* Create an instance of the socket state structure */

  so = (struct socket *)kzalloc(sizeof(struct socket));
  if (!so)
    {
      fdbg("ERROR: Failed to allocate socket structure\n");
      return ENOMEM;
    }

  error = psock_socket(saddr->sa_family, rpc->rc_sotype, rpc->rc_soproto, so);
  if (error < 0)
    {
      errval = errno;
      fdbg("ERROR: psock_socket failed: %d", errval);
      return error;
    }

  so->s_crefs     = 1;
  rpc->rc_so      = so;
  rpc->rc_soflags = so->s_flags;

   /* Always set receive timeout to detect server crash and reconnect.
    * Otherwise, we can get stuck in psock_receive forever.
    */

  tv.tv_sec  = 1;
  tv.tv_usec = 0;

  error = psock_setsockopt(rpc->rc_so, SOL_SOCKET, SO_RCVTIMEO,
                          (const void *)&tv, sizeof(tv));
  if (error < 0)
    {
      errval = errno;
      fdbg("ERROR: psock_setsockopt failed: %d\n", errval);
      goto bad;
    }

  /* Some servers require that the client port be a reserved port
   * number. We always allocate a reserved port, as this prevents
   * filehandle disclosure through UDP port capture.
   */

  sin.sin_family      = AF_INET;
  sin.sin_addr.s_addr = INADDR_ANY;
  tport               = 1024;

  errval = 0;
  do
    {
      tport--;
      sin.sin_port = htons(tport);
      error = psock_bind(rpc->rc_so, (struct sockaddr *)&sin, sizeof(sin));
      if (error < 0)
        {
          errval = errno;
          fdbg("ERROR: psock_bind failed: %d\n", errval);
        }
    }
  while (errval == EADDRINUSE && tport > 1024 / 2);

  if (error)
    {
      fdbg("ERROR: psock_bind failed: %d\n", errval);
      goto bad;
    }

  /* Initialize congestion variables */

  rpc->rc_srtt[0]  = (RPC_TIMEO << 3);
  rpc->rc_srtt[1]  = (RPC_TIMEO << 3);
  rpc->rc_srtt[2]  = (RPC_TIMEO << 3);
  rpc->rc_srtt[3]  = (RPC_TIMEO << 3);
  rpc->rc_sdrtt[0] = 0;
  rpc->rc_sdrtt[1] = 0;
  rpc->rc_sdrtt[2] = 0;
  rpc->rc_sdrtt[3] = 0;
  rpc->rc_cwnd     = RPC_MAXCWND / 2;       /* Initial send window */
  rpc->rc_sent     = 0;
  rpc->rc_timeouts = 0;

  /* Protocols that do not require connections may be optionally left
   * unconnected for servers that reply from a port other than
   * NFS_PORT.
   */

#ifdef CONFIG_NFS_TCPIP
  if (rpc->rc_soflags == PR_CONNREQUIRED)
    {
      error = ENOTCONN;
      goto bad;
    }
  else
#endif
    {
      error = psock_connect(rpc->rc_so, saddr, sizeof(*saddr));
      if (error < 0)
        {
          errval = errno;
          fdbg("ERROR: psock_connect to PMAP port failed: %d", errval);
          goto bad;
        }

      /* Do the RPC to get a dynamic bounding with the server using ppmap.
       * Get port number for MOUNTD.
       */

      memset(&sdata, 0, sizeof(struct call_args_pmap));
      memset(&rdata, 0, sizeof(struct rpc_reply_pmap));
      sdata.prog = txdr_unsigned(RPCPROG_MNT);
      sdata.vers = txdr_unsigned(RPCMNT_VER1);
      sdata.proc = txdr_unsigned(IPPROTO_UDP);
      sdata.port = 0;

      error = rpcclnt_request(rpc, PMAPPROC_GETPORT, PMAPPROG, PMAPVERS,
                              (FAR const void *)&sdata, sizeof(struct call_args_pmap),
                              (FAR void *)&rdata, sizeof(struct rpc_reply_pmap));
      if (error != 0)
        {
          fdbg("ERROR: rpcclnt_request failed: %d\n", error);
          goto bad;
        }

      sa = (FAR struct sockaddr_in *)saddr;
      sa->sin_port = htons(fxdr_unsigned(uint32_t, rdata.pmap.port));

      error = psock_connect(rpc->rc_so, saddr, sizeof(*saddr));
      if (error < 0)
        {
          errval = errno;
          fdbg("ERROR: psock_connect MOUNTD port failed: %d\n", errval);
          goto bad;
        }

      /* Do RPC to mountd. */

      memset(&mountd, 0, sizeof(struct call_args_mount));
      memset(&mdata, 0, sizeof(struct rpc_reply_mount));
      strncpy(mountd.rpath, rpc->rc_path, 90);
      mountd.len =  txdr_unsigned(sizeof(mountd.rpath));

      error = rpcclnt_request(rpc, RPCMNT_MOUNT, RPCPROG_MNT, RPCMNT_VER1,
                              (FAR const void *)&mountd, sizeof(struct call_args_mount),
                              (FAR void *)&mdata, sizeof(struct rpc_reply_mount));
      if (error != 0)
        {
          fdbg("ERROR: rpcclnt_request failed: %d\n", error);
          goto bad;
        }

      error = fxdr_unsigned(uint32_t, mdata.mount.status);
      if (error != 0)
        {
          fdbg("ERROR: fxdr_unsigned failed: %d\n", error);
          goto bad;
        }

      memcpy(&rpc->rc_fh, &mdata.mount.fhandle, sizeof(nfsfh_t));

      /* Do the RPC to get a dynamic bounding with the server using PMAP.
       * NFS port in the socket.
       */

      memset(&sdata, 0, sizeof(struct call_args_pmap));
      memset(&rdata, 0, sizeof(struct rpc_reply_pmap));
      sa->sin_port = htons(PMAPPORT);

      error = psock_connect(rpc->rc_so, saddr, sizeof(*saddr));
      if (error < 0)
        {
          errval = errno;
          fdbg("ERROR: psock_connect PMAP port failed: %d\n", errval);
          goto bad;
        }

      sdata.prog = txdr_unsigned(NFS_PROG);
      sdata.vers = txdr_unsigned(NFS_VER3);
      sdata.proc = txdr_unsigned(IPPROTO_UDP);
      sdata.port = 0;

      error = rpcclnt_request(rpc, PMAPPROC_GETPORT, PMAPPROG, PMAPVERS,
                              (FAR const void *)&sdata, sizeof(struct call_args_pmap),
                              (FAR void *)&rdata, sizeof(struct rpc_reply_pmap));
      if (error != 0)
        {
          fdbg("ERROR: rpcclnt_request failed: %d\n", error);
          goto bad;
        }

      sa->sin_port = htons(fxdr_unsigned(uint32_t, rdata.pmap.port));

      error = psock_connect(rpc->rc_so, saddr, sizeof(*saddr));
      if (error)
        {
          fdbg("psock_connect NFS port returns %d\n", error);
          goto bad;
        }
    }

  fvdbg("Succeeded\n");
  return 0;

bad:
  rpcclnt_disconnect(rpc);
  return error;
}

/* Reconnect routine: Called when a connection is broken on a reliable
 * protocol. - clean up the old socket - nfs_connect() again - set
 * TASK_MUSTRESEND for all outstanding requests on mount point If this
 * fails the mount point is DEAD! nb: Must be called with the
 * nfs_sndlock() set on the mount point.
 */

#ifdef CONFIG_NFS_TCPIP
int rpcclnt_reconnect(struct rpctask *rep)
{
  struct rpctask *rp;
  struct rpcclnt *rpc = rep->r_rpcclnt;
  int error;

  rpcclnt_disconnect(rpc);
  do
    {
      error = rpcclnt_connect(rpc);
      if (error != 0)
        {
          fdbg("ERROR: rpcclnt_connect failed: %d\n", error);
          if (error == EINTR || error == ERESTART)
            {
              return EINTR;
            }
        }
    }
  while (error != 0)

  /* Loop through outstanding request list and fix up all
   * requests on old socket.
   */

  for (rp = (struct rpctask *)rpctask_q->head; rp != NULL;
       rp = (struct rpctask *)rp->r_chain.blink)
    {
      if (rp->r_rpcclnt == rpc)
        {
          rp->r_flags |= TASK_MUSTRESEND;
        }
    }

  return 0;
}
#endif

void rpcclnt_disconnect(struct rpcclnt *rpc)
{
  struct socket *so;

  if (rpc->rc_so != NULL)
    {
      so = rpc->rc_so;
      (void)psock_close(so);
    }
}

int rpcclnt_umount(struct rpcclnt *rpc)
{
  struct sockaddr *saddr;
  struct sockaddr_in *sa;
  struct call_args_pmap sdata;
  struct rpc_reply_pmap rdata;
  struct call_args_mount mountd;
  struct rpc_reply_mount mdata;
  int error;

  saddr = rpc->rc_name;
  sa = (FAR struct sockaddr_in *)saddr;

  /* Do the RPC to get a dynamic bounding with the server using ppmap.
   * Get port number for MOUNTD.
   */

  memset(&sdata, 0, sizeof(struct call_args_pmap));
  memset(&rdata, 0, sizeof(struct rpc_reply_pmap));
  sa->sin_port = htons(PMAPPORT);

  error = psock_connect(rpc->rc_so, saddr, sizeof(*saddr));
  if (error)
    {
      fdbg("psock_connect MOUNTD port returns %d\n", error);
      goto bad;
    }

  sdata.prog = txdr_unsigned(RPCPROG_MNT);
  sdata.vers = txdr_unsigned(RPCMNT_VER1);
  sdata.proc = txdr_unsigned(IPPROTO_UDP);
  sdata.port = 0;

  error = rpcclnt_request(rpc, PMAPPROC_GETPORT, PMAPPROG, PMAPVERS,
                          (FAR const void *)&sdata, sizeof(struct call_args_pmap),
                          (FAR void *)&rdata, sizeof(struct rpc_reply_pmap));
  if (error != 0)
    {
      fdbg("ERROR: rpcclnt_request failed: %d\n", error);
      goto bad;
    }

  sa->sin_port = htons(fxdr_unsigned(uint32_t, rdata.pmap.port));

  error = psock_connect(rpc->rc_so, saddr, sizeof(*saddr));
  if (error)
    {
      fdbg("psock_connect MOUNTD port returns %d\n", error);
      goto bad;
    }

  /* Do RPC to umountd. */

  memset(&mountd, 0, sizeof(struct call_args_mount));
  memset(&mdata, 0, sizeof(struct rpc_reply_mount));

  strncpy(mountd.rpath, rpc->rc_path, 92);
  mountd.len =  txdr_unsigned(sizeof(mountd.rpath));

  error = rpcclnt_request(rpc, RPCMNT_UMOUNT, RPCPROG_MNT, RPCMNT_VER1,
                          (FAR const void *)&mountd, sizeof(struct call_args_mount),
                          (FAR void *)&mdata, sizeof(struct rpc_reply_mount));
  if (error != 0)
    {
     fdbg("ERROR: rpcclnt_request failed: %d\n", error);
      goto bad;
    }

 if ((fxdr_unsigned(uint32_t, mdata.mount.status)) != 0)
    {
      fdbg("error unmounting with the server %d\n", error);
      goto bad;
    }

  return 0;

bad:
  rpcclnt_disconnect(rpc);
  return error;
}

#ifdef CONFIG_NFS_TCPIP
void rpcclnt_safedisconnect(struct rpcclnt *rpc)
{
  struct rpctask dummytask;

  memset((void *)dummytask, 0, sizeof(*call));
  dummytask.r_rpcclnt = rpc;
  rpcclnt_rcvlock(&dummytask);
  rpcclnt_disconnect(rpc);
  rpcclnt_rcvunlock(&rpc->rc_flag);
}
#endif

/* Code from nfs_request - goes something like this - fill in task struct -
 * links task into list - calls nfs_send() for first transmit - calls
 * nfs_receive() to get reply - fills in reply (which should be initialized
 * prior to calling), which is valid when 0.
 *
 * Note that reply->result_* are invalid unless reply->type ==
 * RPC_MSGACCEPTED and reply->status == RPC_SUCCESS and that reply->verf_*
 * are invalid unless reply->type == RPC_MSGACCEPTED
 */

int  rpcclnt_request(FAR struct rpcclnt *rpc, int procnum, int prog,
                     int version,
                     FAR const void *request, size_t reqlen,
                     FAR void *response, size_t resplen)
{
  struct rpc_reply_header replymgs;
  struct rpc_reply_header replyheader;
  struct rpctask *task = NULL;
  struct xidr value;
  int error = 0;

  /* Set aside memory on the stack to hold the largest call message */

  union
  {
    struct rpc_call_pmap    pmap;
    struct rpc_call_mount   mountd;
    struct rpc_call_create  create;
    struct rpc_call_lookup  lookup;
    struct rpc_call_write   write;
    struct rpc_call_read    read;
    struct rpc_call_remove  removef;
    struct rpc_call_rename  renamef;
    struct rpc_call_mkdir   mkdir;
    struct rpc_call_rmdir   rmdir;
    struct rpc_call_readdir readdir;
    struct rpc_call_fs      fs;
  } u;

  /* Clear the call message memory */

  memset(&u, 0, sizeof(u));

  /* Create an instance of the task state structure */

  task = (struct rpctask *)kzalloc(sizeof(struct rpctask));
  if (!task)
    {
      fdbg("ERROR: Failed to allocate reply msg structure\n");
      return -ENOMEM;
    }

  error = rpcclnt_buildheader(rpc, procnum, prog, version, &value,
                              request, &reqlen, (FAR void*)&u);
  if (error)
    {
      fdbg("ERROR: Building call header error\n");
      goto rpcmout;
    }

  task->r_rpcclnt = rpc;
  task->r_xid     = value.xid;
  task->r_procnum = procnum;

  if (rpc->rc_flag & RPCCLNT_SOFT)
    {
      task->r_retry = rpc->rc_retry;
    }
  else
    {
      task->r_retry = RPC_MAXREXMIT + 1;  /* past clip limit */
    }

  task->r_rtt = task->r_rexmit = 0;

  if (rpcclnt_proct(rpc, procnum) > 0)
    {
      task->r_flags = TASK_TIMING;
    }
  else
    {
      task->r_flags = 0;
    }

  /* Do the client side RPC. */

  rpcstats.rpcrequests++;

  /* Chain request into list of outstanding requests. Be sure to put it
   * LAST so timer finds oldest requests first.
   */

  dq_addlast(&task->r_chain, &rpctask_q);

  /* If backing off another request or avoiding congestion, don't send
   * this one now but let timer do it. If not timing a request, do it
   * now.
   */

  if (rpc->rc_so && (rpc->rc_sotype == SOCK_DGRAM ||
                     (rpc->rc_flag & RPCCLNT_DUMBTIMR) ||
                     rpc->rc_sent < rpc->rc_cwnd))
    {
#ifdef CONFIG_NFS_TCPIP
      if (rpc->rc_soflags & PR_CONNREQUIRED)
        {
          error = rpcclnt_sndlock(&rpc->rc_flag, task);
        }
#endif
      if (error == 0)
        {
          error = rpcclnt_send(rpc->rc_so, rpc->rc_name, procnum, prog,
                               (FAR void*)&u, reqlen, task);

#ifdef CONFIG_NFS_TCPIP
          if (rpc->rc_soflags & PR_CONNREQUIRED)
            {
              rpcclnt_sndunlock(&rpc->rc_flag);
            }
#endif
        }

      if (error == 0 && (task->r_flags & TASK_MUSTRESEND) == 0)
        {
          rpc->rc_sent += RPC_CWNDSCALE;
          task->r_flags |= TASK_SENT;
        }
    }
  else
    {
      task->r_rtt = -1;
    }

  /* Wait for the reply from our send. */

  if (error == 0 || error == EPIPE)
    {
      error = rpcclnt_reply(task, procnum, prog, response, resplen);
      fvdbg("rpcclnt_reply returned: %d\n", error);
    }

  /* RPC done, unlink the request. */

  dq_rem(&task->r_chain, &rpctask_q);

  /* Decrement the outstanding request count. */

  if (task->r_flags & TASK_SENT)
    {
      task->r_flags &= ~TASK_SENT;      /* paranoia */
      rpc->rc_sent -= RPC_CWNDSCALE;
    }

  if (error != 0)
    {
      goto rpcmout;
    }

  /* Break down the rpc header and check if ok */

  memset(&replymgs, 0, sizeof(replymgs));
  memcpy(&replyheader, response, sizeof(struct rpc_reply_header));
  replymgs.type = fxdr_unsigned(uint32_t, replyheader.type);
  if (replymgs.type == RPC_MSGDENIED)
    {
      replymgs.status = fxdr_unsigned(uint32_t, replyheader.status);
      switch (replymgs.status)
        {
        case RPC_MISMATCH:
        /*replymgs.stat.mismatch_info.low =
            fxdr_unsigned(uint32_t, replyheader.stat.mismatch_info.low);
          replymgs.stat.mismatch_info.high =
            fxdr_unsigned(uint32_t, replyheader.stat.mismatch_info.high);*/
          fdbg("RPC_MSGDENIED: RPC_MISMATCH error\n");
          error = EOPNOTSUPP;
          break;

        case RPC_AUTHERR:
        //replymgs.stat.autherr = fxdr_unsigned(uint32_t, replyheader.stat.autherr);
          fdbg("RPC_MSGDENIED: RPC_AUTHERR error\n");
          error = EACCES;
          break;

        default:
          error = EOPNOTSUPP;
          break;
        }
      goto rpcmout;
    }
  else if (replymgs.type != RPC_MSGACCEPTED)
    {
      error = EOPNOTSUPP;
      goto rpcmout;
    }

  /* Verifier */

/*replymgs.rpc_verfi.authtype =
    fxdr_unsigned(enum auth_flavor, replyheader.rpc_verfi.authtype);
  replymgs.rpc_verfi.authlen =
    fxdr_unsigned(uint32_t, replyheader.rpc_verfi.authlen);*/

  if (replymgs.status == RPC_SUCCESS)
    {
      fvdbg("RPC_SUCCESS\n");
    }
  else if (replymgs.status == RPC_PROGMISMATCH)
    {
    /*replymgs.stat.mismatch_info.low =
        fxdr_unsigned(uint32_t, replyheader.stat.mismatch_info.low);
      replymgs.stat.mismatch_info.high =
        fxdr_unsigned(uint32_t, replyheader.stat.mismatch_info.high);*/

      fdbg("RPC_MSGACCEPTED: RPC_PROGMISMATCH error\n");
      error = EOPNOTSUPP;
    }
  else if (replymgs.status > 5)
    {
      error = EOPNOTSUPP;
      goto rpcmout;
    }

rpcmout:
  kfree(task);
  return error;
}

#undef COMP
#ifdef COMP
/* Nfs timer routine Scan the nfsreq list and retranmit any requests that
 * have timed out To avoid retransmission attempts on STREAM sockets (in the
 * future) make sure to set the r_retry field to 0 (implies nm_retry == 0).
 */

void rpcclnt_timer(void *arg, struct rpc_call *call)
{
  struct rpctask *rep;
  struct socket *so;
  struct rpcclnt *rpc;
  int timeo, error;

  for (rep = (struct rpctask *)rpctask_q.head; rep != NULL;
       rep = (struct rpctask *)rep->r_chain.flink)
    {
      rpc = rep->r_rpcclnt;
      if (rep->r_flags & TASK_SOFTTERM)
        {
          continue;
        }

      if (rep->r_rtt >= 0)
        {
          rep->r_rtt++;
          if (rpc->rc_flag & RPCCLNT_DUMBTIMR)
            {
              timeo = rpc->rc_timeo;
            }
          else
            {
              timeo = RPC_RTO(rpc, rpcclnt_proct(rep->r_rpcclnt, rep->r_procnum));
            }

          if (rpc->rc_timeouts > 0)
            {
              timeo *= rpcclnt_backoff[rpc->rc_timeouts - 1];
            }

          if (rep->r_rtt <= timeo)
            {
              continue;
            }

          if (rpc->rc_timeouts < 8)
            {
              rpc->rc_timeouts++;
            }
        }

      /* Check for server not responding */

      if ((rep->r_flags & TASK_TPRINTFMSG) == 0 &&
          rep->r_rexmit > rpc->rc_deadthresh)
        {
          fdbg("Server is not responding\n");
          rep->r_flags |= TASK_TPRINTFMSG;
        }

      if (rep->r_rexmit >= rep->r_retry)
        {                       /* too many */
          rpcstats.rpctimeouts++;
          rep->r_flags |= TASK_SOFTTERM;
          continue;
        }

      if (rpc->rc_sotype != SOCK_DGRAM)
        {
          if (++rep->r_rexmit > RPC_MAXREXMIT)
            {
              rep->r_rexmit = RPC_MAXREXMIT;
            }
          continue;
        }

      if ((so = rpc->rc_so) == NULL)
        {
          continue;
        }

      /* If there is enough space and the window allows.. Resend it
       * Set r_rtt to -1 in case we fail to send it now.
       */

      rep->r_rtt = -1;
      if ((rpc->rc_flag & RPCCLNT_DUMBTIMR) || (rep->r_flags & TASK_SENT) ||
          rpc->rc_sent < rpc->rc_cwnd)
        {

          if ((rpc->rc_flag & RPCCLNT_NOCONN) == 0)
            {
              error = psock_sendto(so, call, sizeof(*call), 0, NULL, 0);
            }
          else
            {
              error = psock_sendto(so, call, sizeof(*call), 0, rpc->rc_name,
                                   sizeof(*rpc->rc_name));
            }

          if (error < 0)
            {
              /* Iff first send, start timing else turn
               * timing off, backoff timer and divide
               * congestion window by 2.
               */

              if (rep->r_flags & TASK_SENT)
                {
                  rep->r_flags &= ~TASK_TIMING;
                  if (++rep->r_rexmit > RPC_MAXREXMIT)
                    {
                      rep->r_rexmit = RPC_MAXREXMIT;
                    }

                  rpc->rc_cwnd >>= 1;
                  if (rpc->rc_cwnd < RPC_CWNDSCALE)
                    {
                      rpc->rc_cwnd = RPC_CWNDSCALE;
                    }

                  rpcstats.rpcretries++;
                }
              else
                {
                  rep->r_flags |= TASK_SENT;
                  rpc->rc_sent += RPC_CWNDSCALE;
                }

              rep->r_rtt = 0;
            }
        }
    }

  // rpcclnt_timer_handle = timeout(rpcclnt_timer, NULL, rpcclnt_ticks);
}
#endif

#ifdef COMP
int rpcclnt_cancelreqs(struct rpcclnt *rpc)
{
  struct rpctask *task;
  int i;

  for (task = (struct rpctask *)rpctask_q.head; task;
       task = (struct rpctask *)task->r_chain.flink)
    {
      if (rpc != task->r_rpcclnt || (task->r_flags & TASK_SOFTTERM))
        {
          continue;
        }

      rpcclnt_softterm(task);
    }

  for (i = 0; i < 30; i++)
    {
      for (task = (struct rpctask *)&rpctask_q.head; task;
           task = (struct rpctask *)task->r_chain.flink)
        {
          if (rpc == task->r_rpcclnt)
            {
              break;
            }
        }

      if (task == NULL)
        {
          return 0;
        }
    }

  return EBUSY;
}
#endif
#endif