예제 #1
0
/**
*  get the arguments of the incoming request: it is mostly a rpc decode

 @param recv_buf : ruc buffer that contains the request
 @param xdr_argument : decoding procedure
 @param argument     : pointer to the array where decoded arguments will be stored
 
 @retval TRUE on success
 @retval FALSE decoding error
*/
int expgw_getargs (void *recv_buf,xdrproc_t xdr_argument, void *argument)
{
   XDR xdrs;
   uint32_t  msg_len;  /* length of the rpc messsage including the header length */
   uint32_t header_len;
   uint8_t  *pmsg;     /* pointer to the first available byte in the application message */
   int      len;       /* effective length of application message               */
   rozofs_rpc_call_hdr_with_sz_t *com_hdr_p;


   /*
   ** Get the full length of the message and adjust it the the length of the applicative part (RPC header+application msg)
   */
   msg_len = ruc_buf_getPayloadLen(recv_buf);
   msg_len -=sizeof(uint32_t);   

   com_hdr_p  = (rozofs_rpc_call_hdr_with_sz_t*) ruc_buf_getPayload(recv_buf);  
   pmsg = rozofs_rpc_set_ptr_on_first_byte_after_rpc_header((char*)&com_hdr_p->hdr,&header_len);
   if (pmsg == NULL)
   {
     errno = EFAULT;
     return FALSE;
   }
   /*
   ** map the memory on the first applicative RPC byte available and prepare to decode:
   ** notice that we will not call XDR_FREE since the application MUST
   ** provide a pointer for storing the file handle
   */
   len = msg_len - header_len;    
   xdrmem_create(&xdrs,(char*)pmsg,len,XDR_DECODE);
   return (*xdr_argument)(&xdrs,argument);
}
예제 #2
0
/**
* callback for the internal read request triggered by a truncate

 potential failure case:
  - socket_ref is out of range
  - connection is down
  
 @param buffer : pointer to the ruc_buffer that cointains the response
 @param socket_ref : non significant
 @param user_param_p : pointer to the root context
 
 
 @retval 0 : successfully submitted to the transport layer
 @retval < 0 error, the caller is intended to release the buffer
 */
int rozofs_storcli_internal_read_before_truncate_rsp_cbk(void *buffer,uint32_t socket_ref,void *user_param)
{

   int errcode = 0; 
   rozofs_storcli_ctx_t                *working_ctx_p = (rozofs_storcli_ctx_t*)user_param;
   storcli_truncate_arg_t * storcli_truncate_rq_p = (storcli_truncate_arg_t*)&working_ctx_p->storcli_truncate_arg;

   XDR       xdrs;       
   uint8_t  *payload;
   char     *data;
   int       position;
   int      bufsize;   
   struct rpc_msg  rpc_reply;
   storcli_status_ret_t rozofs_status;
   int  data_len; 
   int error;  
   rpc_reply.acpted_rply.ar_results.proc = NULL;

   /*
   ** decode the read internal read reply
   */
   payload  = (uint8_t*) ruc_buf_getPayload(buffer);
   payload += sizeof(uint32_t); /* skip length*/  
   
   /*
   ** OK now decode the received message
   */
   bufsize = ruc_buf_getPayloadLen(buffer);
   bufsize -= sizeof(uint32_t); /* skip length*/
   xdrmem_create(&xdrs,(char*)payload,bufsize,XDR_DECODE);   
   error = 0;
   while (1)
   {
     /*
     ** decode the rpc part
     */
     if (rozofs_xdr_replymsg(&xdrs,&rpc_reply) != TRUE)
     {
       errno = EPROTO;
       error = 1;
       break;
     }
     /*
     ** decode the status of the operation
     */
     if (xdr_storcli_status_ret_t(&xdrs,&rozofs_status)!= TRUE)
     {
       errno = EPROTO;
       error = 1;
       break;    
     }
     /*
     ** check th estatus of the operation
     */
     if ( rozofs_status.status != STORCLI_SUCCESS )
     {
       error = 0;
       break;    
     }
     {
       int alignment;
       /*
       ** skip the alignment
       */
       if (xdr_int(&xdrs, &alignment) != TRUE)
       {
         errno = EPROTO;
         STORCLI_ERR_PROF(read_prj_err);       
         error = 1;
         break;          
       }
      }
     /*
     ** Now get the length of the part that has been read
     */
     if (xdr_int(&xdrs, &data_len) != TRUE)
     {
       errno = EPROTO;
       error = 1;
       break;          
     }
     break;
   }
   if (error)
   {
     severe("error while decoding rpc reply");  
     goto failure;  
   }   

   position = XDR_GETPOS(&xdrs);
   data     = (char*)(payload+position);

   /*
   ** check the status of the read operation
   */
   if (rozofs_status.status != STORCLI_SUCCESS)
   {
     data = NULL;
   }
   else {
     /*, 
     ** No data returned
     */
     if (data_len == 0) {
       data = NULL;
     }
     else if (storcli_truncate_rq_p->last_seg <= data_len) {
       memset(data+storcli_truncate_rq_p->last_seg, 0, ROZOFS_BSIZE-storcli_truncate_rq_p->last_seg);       
     }
     else {
       memset(data+data_len, 0, ROZOFS_BSIZE-data_len);     
     }
   }
   rozofs_storcli_truncate_req_processing_exec(working_ctx_p, data);
   ruc_buf_freeBuffer(buffer);
   return 0 ;   


failure:
   ruc_buf_freeBuffer(buffer);
   /*
   ** check if the lock is asserted to prevent direct call to callback
   */
   if (working_ctx_p->write_ctx_lock == 1) return 0;
   /*
   ** write failure
   */
   rozofs_storcli_write_reply_error(working_ctx_p,errcode);

   /*
   ** release the transaction root context
   */
   working_ctx_p->xmitBuf = NULL;
   STORCLI_STOP_NORTH_PROF(working_ctx_p,truncate,0);  
   rozofs_storcli_release_context(working_ctx_p);
   return 0 ;

}
예제 #3
0
/**
  Initial truncate request
    
  @param socket_ctx_p: pointer to the af unix socket
  @param socketId: reference of the socket (not used)
  @param rozofs_storcli_remote_rsp_cbk: callback for sending out the response
 
   @retval : TRUE-> xmit ready event expected
  @retval : FALSE-> xmit  ready event not expected
*/
void rozofs_storcli_truncate_req_init(uint32_t  socket_ctx_idx, void *recv_buf,rozofs_storcli_resp_pf_t rozofs_storcli_remote_rsp_cbk)
{
   rozofs_rpc_call_hdr_with_sz_t    *com_hdr_p;
   rozofs_storcli_ctx_t *working_ctx_p = NULL;
   int i;
   uint32_t  msg_len;  /* length of the rpc messsage including the header length */
   storcli_truncate_arg_t *storcli_truncate_rq_p = NULL;
   rozofs_rpc_call_hdr_t   hdr;   /* structure that contains the rpc header in host format */
   int      len;       /* effective length of application message               */
   uint8_t  *pmsg;     /* pointer to the first available byte in the application message */
   uint32_t header_len;
   XDR xdrs;
   int errcode = EINVAL;
   /*
   ** allocate a context for the duration of the write
   */
   working_ctx_p = rozofs_storcli_alloc_context();
   if (working_ctx_p == NULL)
   {
     /*
     ** that situation MUST not occur since there the same number of receive buffer and working context!!
     */
     severe("out of working read/write saved context");
     goto failure;
   }
   storcli_truncate_rq_p = &working_ctx_p->storcli_truncate_arg;
   STORCLI_START_NORTH_PROF(working_ctx_p,truncate,0);

   
   /*
   ** Get the full length of the message and adjust it the the length of the applicative part (RPC header+application msg)
   */
   msg_len = ruc_buf_getPayloadLen(recv_buf);
   msg_len -=sizeof(uint32_t);

   /*
   ** save the reference of the received socket since it will be needed for sending back the
   ** response
   */
   working_ctx_p->socketRef    = socket_ctx_idx;
   working_ctx_p->user_param   = NULL;
   working_ctx_p->recv_buf     = recv_buf;
   working_ctx_p->response_cbk = rozofs_storcli_remote_rsp_cbk;
   /*
   ** Get the payload of the receive buffer and set the pointer to the array that describes the write request
   */
   com_hdr_p  = (rozofs_rpc_call_hdr_with_sz_t*) ruc_buf_getPayload(recv_buf);   
   memcpy(&hdr,&com_hdr_p->hdr,sizeof(rozofs_rpc_call_hdr_t));
   /*
   ** swap the rpc header
   */
   scv_call_hdr_ntoh(&hdr);
   pmsg = rozofs_storcli_set_ptr_on_nfs_call_msg((char*)&com_hdr_p->hdr,&header_len);
   if (pmsg == NULL)
   {
     errcode = EFAULT;
     goto failure;
   }
   /*
   ** map the memory on the first applicative RPC byte available and prepare to decode:
   ** notice that we will not call XDR_FREE since the application MUST
   ** provide a pointer for storing the file handle
   */
   len = msg_len - header_len;    
   xdrmem_create(&xdrs,(char*)pmsg,len,XDR_DECODE); 
   /*
   ** store the source transaction id needed for the reply
   */
   working_ctx_p->src_transaction_id =  hdr.hdr.xid;
   /*
   ** decode the RPC message of the truncate request
   */
   if (xdr_storcli_truncate_arg_t(&xdrs,storcli_truncate_rq_p) == FALSE)
   {
      /*
      ** decoding error
      */
      errcode = EFAULT;
      severe("rpc trucnate request decoding error");
      goto failure;
      
   }   
   /*
   ** init of the load balancing group/ projection association table:
   ** That table is ordered: the first corresponds to the storage associated with projection 0, second with 1, etc..
   ** When build that table, we MUST consider the value of the base which is associated with the distribution
   */

   
   uint8_t   rozofs_safe = rozofs_get_rozofs_safe(storcli_truncate_rq_p->layout);
   int lbg_in_distribution = 0;
   for (i = 0; i  <rozofs_safe ; i ++)
   {
    /*
    ** Get the load balancing group associated with the sid
    */
    int lbg_id = rozofs_storcli_get_lbg_for_sid(storcli_truncate_rq_p->cid,storcli_truncate_rq_p->dist_set[i]);
    if (lbg_id < 0)
    {
      /*
      ** there is no associated between the sid and the lbg. It is typically the case
      ** when a new cluster has been added to the configuration and the client does not
      ** know yet the configuration change
      */
      severe("sid is unknown !! %d\n",storcli_truncate_rq_p->dist_set[i]);
      continue;    
    }
     rozofs_storcli_lbg_prj_insert_lbg_and_sid(working_ctx_p->lbg_assoc_tb,lbg_in_distribution,
                                                lbg_id,
                                                storcli_truncate_rq_p->dist_set[i]);  

     rozofs_storcli_lbg_prj_insert_lbg_state(working_ctx_p->lbg_assoc_tb,
                                             lbg_in_distribution,
                                             NORTH_LBG_GET_STATE(working_ctx_p->lbg_assoc_tb[lbg_in_distribution].lbg_id));    
     lbg_in_distribution++;
     if (lbg_in_distribution == rozofs_safe) break;

   }
   /*
   ** allocate a small buffer that will be used for sending the response to the truncate request
   */
   working_ctx_p->xmitBuf = ruc_buf_getBuffer(ROZOFS_STORCLI_NORTH_SMALL_POOL);
   if (working_ctx_p == NULL)
   {
     /*
     ** that situation MUST not occur since there the same number of receive buffer and working context!!
     */
     errcode = ENOMEM;
     severe("out of small buffer");
     goto failure;
   }
   /*
   ** allocate a sequence number for the working context (same aas for read)
   */
   working_ctx_p->read_seqnum = rozofs_storcli_allocate_read_seqnum();
   /*
   ** set now the working variable specific for handling the truncate
   ** we re-use the structure used for writing even if nothing is written
   */
   uint8_t forward_projection = rozofs_get_rozofs_forward(storcli_truncate_rq_p->layout);
   for (i = 0; i < forward_projection; i++)
   {
     working_ctx_p->prj_ctx[i].prj_state = ROZOFS_PRJ_READ_IDLE;
     working_ctx_p->prj_ctx[i].prj_buf   = ruc_buf_getBuffer(ROZOFS_STORCLI_SOUTH_LARGE_POOL);
     if (working_ctx_p->prj_ctx[i].prj_buf == NULL)
     {
       /*
       ** that situation MUST not occur since there the same number of receive buffer and working context!!
       */
       errcode = ENOMEM;
       severe("out of large buffer");
       goto failure;
     }
     /*
     ** increment inuse counter on each buffer since we might need to re-use that packet in case
     ** of retransmission
     */
     working_ctx_p->prj_ctx[i].inuse_valid = 1;
     ruc_buf_inuse_increment(working_ctx_p->prj_ctx[i].prj_buf);
     /*
     ** set the pointer to the bins
     */
     int position = rozofs_storcli_get_position_of_first_byte2write_in_truncate();
     uint8_t *pbuf = (uint8_t*)ruc_buf_getPayload(working_ctx_p->prj_ctx[i].prj_buf); 

     working_ctx_p->prj_ctx[i].bins       = (bin_t*)(pbuf+position); 
   }
   		
   /*
   ** Prepare for request serialization
   */
   memcpy(working_ctx_p->fid_key, storcli_truncate_rq_p->fid, sizeof (sp_uuid_t));
   working_ctx_p->opcode_key = STORCLI_TRUNCATE;
   {
       /**
        * lock all the file for a truncate
        */
       uint64_t nb_blocks = 0;
       nb_blocks--;
       int ret;
       ret = stc_rng_insert((void*)working_ctx_p,
               STORCLI_READ,working_ctx_p->fid_key,
               0,nb_blocks,
               &working_ctx_p->sched_idx);
       if (ret == 0)
       {
           /*
            ** there is a current request that is processed with the same fid and there is a collision
            */
           return;
       }
       /*
        ** no request pending with that fid, so we can process it right away
        */
       return rozofs_storcli_truncate_req_processing(working_ctx_p);
   }

    /*
    **_____________________________________________
    **  Exception cases
    **_____________________________________________
    */      
       

    /*
    ** there was a failure while attempting to allocate a memory ressource.
    */
failure:
     /*
     ** send back the response with the appropriated error code. 
     ** note: The received buffer (rev_buf)  is
     ** intended to be released by this service in case of error or the TCP transmitter
     ** once it has been passed to the TCP stack.
     */
     rozofs_storcli_reply_error_with_recv_buf(socket_ctx_idx,recv_buf,NULL,rozofs_storcli_remote_rsp_cbk,errcode);
     /*
     ** check if the root context was allocated. Free it if is exist
     */
     if (working_ctx_p != NULL) 
     {
        /*
        ** remove the reference to the recvbuf to avoid releasing it twice
        */
       STORCLI_STOP_NORTH_PROF(working_ctx_p,truncate,0);
       working_ctx_p->recv_buf   = NULL;
       rozofs_storcli_release_context(working_ctx_p);
     }
     return;
}
 /*
**__________________________________________________________________________
*/
void af_unix_send_stream_fsm(af_unix_ctx_generic_t *socket_p,com_xmit_template_t *xmit_p)
{
  char *pbuf;
  int write_len;
  int ret;
  int inuse;

  while(1)
  {

    switch (xmit_p->state)
    {
      case XMIT_READY:
      /*
      ** the transmitter is ready to send however we need to double if there is a
      ** current buffer to send (because we just exit from congestion or if there
      ** some buffer in the xmit pending queue
      */
      /*
      ** Check if there is a current buffer to send
      */
      if (xmit_p->bufRefCurrent != NULL)
      {
         write_len  = (int)ruc_buf_getPayloadLen(xmit_p->bufRefCurrent);
         /*
         ** Get the reference of the destination socket (name) from the ruc_buffer)
         */
         xmit_p->nbWrite  = 0;
         xmit_p->nb2Write = write_len;
         xmit_p->state = XMIT_IN_PRG;
      }
      else
      {
        /*
        ** nothing to send !!
        */
        return;
      }
      break;

      case XMIT_IN_PRG:

        /*
        ** Check if there is a current buffer to send
        */
        socket_p->stats.totalXmitAttempts++;
        pbuf = (char *)ruc_buf_getPayload(xmit_p->bufRefCurrent);

        ret  = af_unix_send_stream_generic(socket_p->socketRef,pbuf+xmit_p->nbWrite,xmit_p->nb2Write - xmit_p->nbWrite, &write_len);

        switch (ret)
        {
          case RUC_OK:
          /*
          ** release the buffer that has been sent
          */
          xmit_p->xmit_credit++;
          inuse = ruc_buf_inuse_decrement(xmit_p->bufRefCurrent);
          if (inuse < 0)
          {
            /*
	    ** inuse MUST never be negative so EXIT !!!!!
	    */
            fatal("Inuse is negative %d",inuse);
          }
          if (socket_p->userXmitDoneCallBack != NULL)
          {
             /*
             ** caution: in that case it is up to the application that provides the callback to release
             ** the xmit buffer
             */
	         if (ruc_buf_get_opaque_ref(xmit_p->bufRefCurrent) == socket_p) 
             {
                   (socket_p->userXmitDoneCallBack)(socket_p->userRef,socket_p->index,xmit_p->bufRefCurrent);
	         }
	         else 
             {
                if (inuse == 1) 
                {
                  /*
                  ** need an obj remove since that buffer might still queue somewhere : typically
                  ** in the xmit list of a load balacner entry.
                  */
                  ruc_objRemove((ruc_obj_desc_t*)xmit_p->bufRefCurrent);
                  ruc_buf_freeBuffer(xmit_p->bufRefCurrent);	
                }        
	         }  
          }
          else
          {
            if (inuse == 1) 
            {
              ruc_objRemove((ruc_obj_desc_t*)xmit_p->bufRefCurrent);
              ruc_buf_freeBuffer(xmit_p->bufRefCurrent);
            }
          }
          xmit_p->bufRefCurrent = NULL;
          xmit_p->nbWrite  = 0;
          xmit_p->nb2Write = 0;
          socket_p->stats.totalXmitSuccess++;
          socket_p->stats.totalXmitBytes += write_len;
          xmit_p->state = XMIT_CHECK_XMITQ;
          break;

          case RUC_PARTIAL:
          /*
          ** need to re-attempt writing
          */
          xmit_p->nbWrite  += write_len;
          socket_p->stats.totalXmitBytes += write_len;
          break;

          case RUC_WOULDBLOCK:
          /*
          ** the socket is congested-> so exit
          */
          socket_p->stats.totalXmitCongested++;
          xmit_p->congested_flag = 1;
          xmit_p->eoc_flag       = 0;
          xmit_p->eoc_threshold  = AF_UNIX_CONGESTION_DEFAULT_THRESHOLD;
          xmit_p->state = XMIT_CONGESTED;
          return ;

          case RUC_DISC:
          /*
          ** something wrong on sending: if the user has a callback use it:
          ** the transmitter is no more the owner of the buffer
          */
          inuse = ruc_buf_inuse_decrement(xmit_p->bufRefCurrent);
          if (inuse < 0)
          {
            /*
	        * inuse MUST never be negative so EXIT !!!!!
	        */
            fatal("Inuse is negative %d",inuse);
          }
          socket_p->stats.totalXmitError++;
          if (socket_p->userDiscCallBack != NULL)
          {
            void *bufref = xmit_p->bufRefCurrent;
            xmit_p->bufRefCurrent = NULL;	     
            if (ruc_buf_get_opaque_ref(bufref) != socket_p) 
            {
              /*
              ** the buffer is affected to another socket, however it might possible
              ** that the real owner of the buffer has finished while the buffer is
              ** still used by that old connection. So it might be necessary to release
              ** the buffer.
              ** However in any case the application must not be inform that there was
              ** an issue while sendig that buffer since the connection is not considered
              ** anymore.
              */ 
              if (inuse == 1) 
              {
                ruc_objRemove((ruc_obj_desc_t*)bufref);
                ruc_buf_freeBuffer(bufref);
              }
              bufref = NULL;
            }
            /*
            ** it is up to the application to release the buffer if the error is fatal:
            ** caution the internal disconnection MUST be called before the application since
            ** the application might attempt to perform a direct re-connection
            */
            xmit_p->state = XMIT_DEAD;
            af_unix_sock_stream_disconnect_internal(socket_p);
            (socket_p->userDiscCallBack)(socket_p->userRef,socket_p->index,bufref,errno);
            return;
          }
          else
          {
              if (inuse == 1) 
              {
                ruc_objRemove((ruc_obj_desc_t*)xmit_p->bufRefCurrent);
                ruc_buf_freeBuffer(xmit_p->bufRefCurrent);
              }            
              xmit_p->bufRefCurrent = NULL;
          }
          /*
          ** general disconnection->need to clean the socket queue
          */
          xmit_p->state = XMIT_DEAD;
          af_unix_sock_stream_disconnect_internal(socket_p);
          return ;
          break;

        }
        break;

      case XMIT_CHECK_XMITQ:
        /*
        ** Check the xmit credit
        */
        if (xmit_p->xmit_credit >= xmit_p->xmit_credit_conf)
        {
          xmit_p->xmit_credit = 0;
          /*
          ** asser the flag to request a re-activation on the next run of the socket
          ** controller
          */
          xmit_p->xmit_req_flag = 1;
          return;
        }
        /*
        ** check if there is a pending buffer (case found if there was a previous congestion
        */
        if (xmit_p->bufRefCurrent != NULL)
        {
          /*
          * lest's go and send it
          */
          xmit_p->state =  XMIT_IN_PRG;
          break;
        }
        /*
        ** read the pending Xmit queue (only priority 0 is considered in the current implementation
        */
        xmit_p->bufRefCurrent = com_xmit_pendingQueue_get(xmit_p,0);
        if (xmit_p->bufRefCurrent == NULL)
        {
          /*
          ** queue is empty
          */
          xmit_p->xmit_credit = 0;
          xmit_p->state =  XMIT_READY;
          return;
        }
        /*
        ** OK, go back to send that new bufffer
        */
        ruc_buf_inuse_increment(xmit_p->bufRefCurrent);
        xmit_p->state =  XMIT_READY;
        break;


      case XMIT_CONGESTED:
        /*
        ** the transmitter is congested: check of the threshold has reached 0
        */
        xmit_p->eoc_threshold--;
        if (xmit_p->eoc_threshold == 0)
        {
           xmit_p->eoc_flag  = 1;
           xmit_p->congested_flag = 0;
           xmit_p->state = XMIT_IN_PRG;
           break;
        }
        return;

       case XMIT_DEAD:
        /*
        ** the transmitter is dead
        */
        return;

    }
  }
}
예제 #5
0
 /*
**__________________________________________________________________________
*/
void af_unix_send_fsm(af_unix_ctx_generic_t *socket_p,com_xmit_template_t *xmit_p)
{
  char *pbuf;
  int len;
  int ret;
  char *sockname_p;

  while(1)
  {

    switch (xmit_p->state)
    {
      case XMIT_READY:
      /*
      ** the transmitter is ready to send however we need to double if there is a
      ** current buffer to send (because we just exit from congestion or if there
      ** some buffer in the xmit pending queue
      */
      /*
      ** Check if there is a current buffer to send
      */
      if (xmit_p->bufRefCurrent != NULL)
      {
         pbuf = (char *)ruc_buf_getPayload(xmit_p->bufRefCurrent);
         len  = (int)ruc_buf_getPayloadLen(xmit_p->bufRefCurrent);
         /*
         ** Get the reference of the destination socket (name) from the ruc_buffer)
         */
         socket_p->stats.totalXmitAttempts++;
         sockname_p = ruc_buf_get_usrDestInfo(xmit_p->bufRefCurrent);
         ret  = af_unix_send_generic(socket_p->socketRef,pbuf,len, sockname_p);
         xmit_p->xmit_credit++;

        switch (ret)
        {
          case RUC_OK:
          /*
          ** release the buffer that has been sent
          */
          ruc_buf_freeBuffer(xmit_p->bufRefCurrent);
          xmit_p->bufRefCurrent = NULL;
          socket_p->stats.totalXmitSuccess++;
          socket_p->stats.totalXmitBytes += len;

          xmit_p->state = XMIT_CHECK_XMITQ;
          break;

          case RUC_WOULDBLOCK:
          /*
          ** the socket is congested-> so exit
          */
          socket_p->stats.totalXmitCongested++;
          xmit_p->congested_flag = 1;
          xmit_p->eoc_flag       = 0;
          xmit_p->eoc_threshold  = AF_UNIX_CONGESTION_DEFAULT_THRESHOLD;
          xmit_p->state = XMIT_CONGESTED;
          return ;

          case RUC_DISC:

          /*
          ** something wrong on sending: if the user has a callback use it
          */
          socket_p->stats.totalXmitError++;
          if (socket_p->userDiscCallBack != NULL)
          {
             void *bufref = xmit_p->bufRefCurrent;
             xmit_p->bufRefCurrent = NULL;
             /*
             ** it is up to the application to release the buffer if the error is fatal
             */
             (socket_p->userDiscCallBack)(socket_p->userRef,socket_p->index,bufref,errno);
          }
          else
          {
            ruc_buf_freeBuffer(xmit_p->bufRefCurrent);
            xmit_p->bufRefCurrent = NULL;

          }
          /*
          ** need to clean the socket queue
          */
          xmit_p->state = XMIT_CHECK_XMITQ;

          /*
          ** need to clean the socket queue
          */

//          xmit_p->state = XMIT_DEAD;
//          return ;
            break;
        }
      }
      else
      {
        /*
        ** nothing to send !!
        */
        return;
      }
      break;

      case XMIT_IN_PRG:

        /*
        ** Check if there is a current buffer to send
        */
        socket_p->stats.totalXmitAttempts++;
        pbuf = (char *)ruc_buf_getPayload(xmit_p->bufRefCurrent);
        len  = (int)ruc_buf_getPayloadLen(xmit_p->bufRefCurrent);
        /*
        ** Get the reference of the destination socket (name) from the ruc_buffer)
        */
        sockname_p = ruc_buf_get_usrDestInfo(xmit_p->bufRefCurrent);
        ret  = af_unix_send_generic(socket_p->socketRef,pbuf,len, sockname_p);
        xmit_p->xmit_credit++;
        switch (ret)
        {
          case RUC_OK:
          /*
          ** release the buffer that has been sent
          */
          ruc_buf_freeBuffer(xmit_p->bufRefCurrent);
          xmit_p->bufRefCurrent = NULL;
          socket_p->stats.totalXmitSuccess++;
          socket_p->stats.totalXmitBytes += len;
          xmit_p->state = XMIT_CHECK_XMITQ;
          break;

          case RUC_WOULDBLOCK:
          /*
          ** the socket is congested-> so exit
          */
          socket_p->stats.totalXmitCongested++;
          xmit_p->congested_flag = 1;
          xmit_p->eoc_flag       = 0;
          xmit_p->eoc_threshold  = AF_UNIX_CONGESTION_DEFAULT_THRESHOLD;
          xmit_p->state = XMIT_CONGESTED;
          return ;

          case RUC_DISC:
          /*
          ** something wrong on sending: if the user has a callback use it
          */
          socket_p->stats.totalXmitError++;
          if (socket_p->userDiscCallBack != NULL)
          {
             void *bufref = xmit_p->bufRefCurrent;
             xmit_p->bufRefCurrent = NULL;
             /*
             ** it is up to the application to release the buffer if the error is fatal
             */
             (socket_p->userDiscCallBack)(socket_p->userRef,socket_p->index,bufref,errno);
          }
          else
          {
            ruc_buf_freeBuffer(xmit_p->bufRefCurrent);
            xmit_p->bufRefCurrent = NULL;

          }
          /*
          ** need to clean the socket queue
          */
          xmit_p->state = XMIT_CHECK_XMITQ;

 //         xmit_p->state = XMIT_DEAD;
 //         return ;
          break;

        }
        break;

      case XMIT_CHECK_XMITQ:
#if 0
        /*
        ** Check the xmit credit
        */
        if (xmit_p->xmit_credit >= xmit_p->xmit_credit_conf)
        {
          xmit_p->xmit_credit = 0;
          /*
          ** asser the flag to request a re-activation on the next run of the socket
          ** controller
          */
          xmit_p->xmit_req_flag = 1;
          return;
        }
#endif
        /*
        ** check if there is a pending buffer (case found if there was a previous congestion
        */
        if (xmit_p->bufRefCurrent != NULL)
        {
          /*
          * lest's go and send it
          */
          xmit_p->state =  XMIT_IN_PRG;
          break;
        }
        /*
        ** read the pending Xmit queue (only priority 0 is considered in the current implementation
        */
        xmit_p->bufRefCurrent = com_xmit_pendingQueue_get(xmit_p,0);
        if (xmit_p->bufRefCurrent == NULL)
        {
          /*
          ** queue is empty
          */
          xmit_p->xmit_credit = 0;
          xmit_p->state =  XMIT_READY;
          return;
        }
        /*
        ** OK, go back to send that new bufffer
        */
        xmit_p->state =  XMIT_IN_PRG;
        break;


      case XMIT_CONGESTED:
        /*
        ** the transmitter is congested: check of the threshold has reached 0
        */
#if 0
        while(1)
	{
#warning loop on congestion
	  nanosleep(5);
	  printf("FDL congested\n");

	}
#endif
        xmit_p->eoc_threshold--;
        if (xmit_p->eoc_threshold == 0)
        {
           xmit_p->eoc_flag  = 1;
           xmit_p->congested_flag = 0;
           xmit_p->state = XMIT_CHECK_XMITQ;
           break;
        }
        return;

       case XMIT_DEAD:
        /*
        ** the transmitter is dead
        */
        return;

    }
  }
}
/**
* send a error read reply by using the receiver buffer
 
  @param socket_ctx_idx: index of the TCP connection
  @param recv_buf: pointer to the ruc_buffer that contains the message
  @param rozofs_storcli_remote_rsp_cbk: callback for sending out the response
  @param user_param : pointer to a user opaque parameter (non significant for a remote access)
  @param error : error code
  
  @retval none

*/
void rozofs_storcli_reply_error_with_recv_buf(uint32_t  socket_ctx_idx,
                                              void *recv_buf,
                                              void *user_param,
                                              rozofs_storcli_resp_pf_t rozofs_storcli_remote_rsp_cbk,
                                              int error)
{


   rozofs_rpc_call_hdr_with_sz_t    *com_hdr_p;
   uint32_t  msg_len;  /* length of the rpc messsage including the header length */
   rozofs_rpc_call_hdr_t   hdr;   /* structure that contains the rpc header in host format */
   
   int ret;
   uint8_t *pbuf;           /* pointer to the part that follows the header length */
   uint32_t *header_len_p;  /* pointer to the array that contains the length of the rpc message*/
   XDR xdrs;
   int len;
   storcli_status_ret_t status;

   status.status = STORCLI_FAILURE;
   status.storcli_status_ret_t_u.error = error;
   /*
   ** Get the full length of the message and adjust it the the length of the applicative part (RPC header+application msg)
   */
   msg_len = ruc_buf_getPayloadLen(recv_buf);
   msg_len -=sizeof(uint32_t);
   
   /*
   ** Get the payload of the receive buffer and set the pointer to array that describes the read request
   */
   com_hdr_p  = (rozofs_rpc_call_hdr_with_sz_t*) ruc_buf_getPayload(recv_buf);  
   memcpy(&hdr,&com_hdr_p->hdr,sizeof(rozofs_rpc_call_hdr_t));
   /*
   ** swap the rpc header
   */
   scv_call_hdr_ntoh(&hdr);   
    /*
    ** create xdr structure on top of the buffer that will be used for sending the response
    */
    header_len_p = (uint32_t*)ruc_buf_getPayload(recv_buf); 
    pbuf = (uint8_t*) (header_len_p+1);            
    len = (int)ruc_buf_getMaxPayloadLen(recv_buf);
    len -= sizeof(uint32_t);
    xdrmem_create(&xdrs,(char*)pbuf,len,XDR_ENCODE); 
    if (rozofs_encode_rpc_reply(&xdrs,(xdrproc_t)xdr_sp_status_ret_t,(caddr_t)&status,hdr.hdr.xid) != TRUE)
    {
      severe("rpc reply encoding error");
      goto error;     
    }       
    /*
    ** compute the total length of the message for the rpc header and add 4 bytes more bytes for
    ** the ruc buffer to take care of the header length of the rpc message.
    */
    int total_len = xdr_getpos(&xdrs) ;
    *header_len_p = htonl(0x80000000 | total_len);
    total_len +=sizeof(uint32_t);
    ruc_buf_setPayloadLen(recv_buf,total_len);
    /*
    ** Get the callback for sending back the response:
    ** A callback is needed since the request for read might be local or remote
    */
    ret = (*rozofs_storcli_remote_rsp_cbk)(recv_buf,socket_ctx_idx,user_param);
    if (ret == 0)
    {
      return;
    }
    
error:
    ruc_buf_freeBuffer(recv_buf);
    return;
}