/**
*   Encode the dirty message to invalidate some sections for a server

   @param ctx_p     : pointer to the dirty management context
   @param pool_ref  : poll ref to get the buffer from 
   @param srv_rank  : Server to build the message for
   
   @retval the buffer containing the encode message
*/
void * exp_cache_encode_invalidate_sections_msg(exp_cache_dirty_ctx_t * ctx_p,
                                                void                  * pool_ref,
						int                     srv_rank)
{
  gw_invalidate_sections_t * msg = NULL;
  void                     * xmit_buf = NULL;
  int                        ret;
  exp_invalidate_type_e      build_msg_ret;

  /*
  ** allocate an xmit buffer
  */  
  xmit_buf = ruc_buf_getBuffer(pool_ref);
  if (xmit_buf == NULL) {
    severe ("Out of buffer");
    return NULL;
  } 
      
  /*
  ** Build the structure to encode from the cache data
  */    
  build_msg_ret = exp_cache_build_invalidate_sections_msg(ctx_p,srv_rank);
  
  /*
  ** Nothing to send 
  */
  if ((build_msg_ret == exp_invalidate_nothing)||(build_msg_ret == exp_invalidate_error)) {
    ruc_buf_freeBuffer(xmit_buf);    
    return NULL;
  }
  
  if (build_msg_ret == exp_invalidate_too_big) {
    /*
    ** Well let's invalidate everything, since we can not encode the invalidate sections
    */
    ruc_buf_freeBuffer(xmit_buf);    
    return exp_cache_encode_invalidate_all_msg(ctx_p,pool_ref,srv_rank);
  }
  
  /*
  ** Encode the message in the buffer
  */
  ret = exp_cache_encode_common(GW_INVALIDATE_SECTIONS,(xdrproc_t) xdr_gw_invalidate_sections_t,msg, xmit_buf);
  if (ret != 0) {
    /*
    ** Well let's invalidate everything, since we can not encode the invalidate sections
    */
    ruc_buf_freeBuffer(xmit_buf);    
    return exp_cache_encode_invalidate_all_msg(ctx_p,pool_ref,srv_rank);
  }
  
  return xmit_buf;
}
Exemple #2
0
void storcli_lbg_cnx_polling(af_unix_ctx_generic_t  *sock_p)
{
  void *xmit_buf = NULL;
  int ret;
  int timeout = (int)ROZOFS_TMR_GET(TMR_RPC_NULL_PROC_TCP);

  af_inet_set_cnx_tmo(sock_p,timeout*10);
  /*
  ** attempt to poll
  */
//   xmit_buf = ruc_buf_getBuffer(ROZOFS_STORCLI_SOUTH_LARGE_POOL);
   xmit_buf = rozofs_storcli_any_south_buffer_allocate();
   if (xmit_buf == NULL)
   {
      return ; 
   }
   ret =  rozofs_sorcli_poll_tx(sock_p,STORAGE_PROGRAM,STORAGE_VERSION,SP_NULL,
                                       (xdrproc_t) xdr_void, (caddr_t) NULL,
                                        xmit_buf,
                                        0,
                                        timeout,   /** TMO in secs */
                                        rozofs_storcli_storage_poll_cbk,
                                        (void*)NULL);
  if (ret < 0)
  {
   if (errno == ENOMEM)
   {
     /*
     ** direct need to free the xmit buffer
     */
     ruc_buf_freeBuffer(xmit_buf);
   }    
  }
}
void rozofs_export_lbg_cnx_polling(af_unix_ctx_generic_t  *sock_p)
{
  void *xmit_buf = NULL;
  int ret;
  int timeout = (int)ROZOFS_TMR_GET(TMR_RPC_NULL_PROC_TCP);

  af_inet_set_cnx_tmo(sock_p,timeout*10*5);
  /*
  ** attempt to poll
  */
   xmit_buf = ruc_buf_getBuffer(ROZOFS_TX_SMALL_TX_POOL);
   if (xmit_buf == NULL)
   {
      return ; 
   }

   ret =  rozofs_export_poll_tx(sock_p,EXPORT_PROGRAM,EXPORT_VERSION,EP_NULL,
                                       (xdrproc_t) xdr_void, (caddr_t) NULL,
                                        xmit_buf,
                                        0,
                                        timeout,   /** TMO in secs */
                                        rozofs_export_poll_cbk,
                                        (void*)NULL);
  if (ret < 0)
  {
   /*
   ** direct need to free the xmit buffer
   */
   ruc_buf_freeBuffer(xmit_buf);    
  }
}
Exemple #4
0
/**
* that callback is called upon the successful transmission of a buffer
  Depending on the inuse value of the buffer, the application can
  either release the message or queue it in its local xmit queue.
  The main purpose of queueing the message is to address the case of
  a disconnection of the remote end in order to re-balance the buffer
  on another equivalent destinatio
 

 @param userRef : pointer to a load balancer entry
 @param socket_context_ref: socket context reference
 @param bufRef : pointer to the packet buffer on which the error has been encountered
  
 @retval none
*/
void  north_lbg_userXmiDoneCallBack(void *userRef,uint32_t socket_context_ref,void *bufRef)
{
    int8_t inuse;
    
   north_lbg_entry_ctx_t *entry_p = (north_lbg_entry_ctx_t*)userRef;

    /*
    ** check the inuse value of the buffer, if inuse is 1, then release it
    */
    inuse = ruc_buf_inuse_get(bufRef);
    if (inuse < 0)
    {
//#warning  inuse MUST never be negative so EXIT !!!!!
     fatal("fatal error on buffer management: inuse counter %d",inuse );          
    }
    if (inuse == 1) 
    {
       ruc_buf_freeBuffer(bufRef);  
    } 
    else
    {
      /*
      ** queue it to the local xmit list of the entry 
      */
      ruc_objInsertTail((ruc_obj_desc_t*)&entry_p->xmitList,(ruc_obj_desc_t*)bufRef);    
    } 
}
/**
*   Encode the message to invalidate the whole cache of a server

   @param ctx_p     : pointer to the dirty management context
   @param pool_ref  : poll ref to get the buffer from 
   @param srv_rank  : Server to build the message for
   
   @retval the buffer containing the encode message
*/
void * exp_cache_encode_invalidate_all_msg(exp_cache_dirty_ctx_t * ctx_p,
                                           void                  * pool_ref,
				           int                     srv_rank)
{
  gw_header_t              * msg = NULL;
  void                     * xmit_buf = NULL;
  int                        ret;

  /*
  ** allocate an xmit buffer
  */  
  xmit_buf = ruc_buf_getBuffer(pool_ref);
  if (xmit_buf == NULL) {
    severe ("Out of buffer");
    return NULL;
  } 
      
  /*
  ** Build the structure to encode from the cache data
  */    
  msg = exp_cache_build_invalidate_all_msg(ctx_p,srv_rank);
  if (msg == NULL) {
    ruc_buf_freeBuffer(xmit_buf);    
    return NULL;
  }
  
  /*
  ** Encode the message in the buffer
  */
  ret = exp_cache_encode_common(GW_INVALIDATE_ALL,(xdrproc_t) xdr_gw_header_t,msg, xmit_buf);
  if (ret != 0) {
    ruc_buf_freeBuffer(xmit_buf);    
    return NULL;    
  }
  
  /*
  ** Since everything has been invalidated, let's operate a flip flop on the cache
  */
  exp_dirty_active_switch(ctx_p, srv_rank);
  
  return xmit_buf;
}
/**
* test function that is called upon a failure on sending

 The application might use that callback if it has some other
 destination that can be used in case of failure of the current one
 If the application has no other destination to select, it is up to the
 application to release the buffer.
 

 @param userRef : pointer to a user reference: not used here
 @param socket_context_ref: socket context reference
 @param bufRef : pointer to the packet buffer on which the error has been encountered
 @param err_no : errno has reported by the sendto().
 
 @retval none
*/
void  storcli_lbg_north_userDiscCallBack(void *userRef,uint32_t socket_context_ref,void *bufRef,int err_no)
{

    /*
    ** release the current buffer if significant
    */
    if (bufRef != NULL) ruc_buf_freeBuffer(bufRef);
    
    severe("remote end disconnection");;
    /*
    ** release the context now and clean up all the attached buffer
    */
    af_unix_delete_socket(socket_context_ref);   
}
/**
* 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;
}
Exemple #8
0
/**
* Load Balncing group deletion API

  - delete all the TCP of AF_UNIX conections
  - stop the timer  assoicated with each connection
  - release all the xmit pending buffers associated with the load balancing group 

 @param lbg_id : user ereference of the load balancing group
 
 @retval 0 : success
 @retval < 0  errno (see errno for details)
*/
int  north_lbg_delete(int lbg_id)
{
    int ret;
   north_lbg_entry_ctx_t *entry_p ;
   ruc_obj_desc_t        *pnext = (ruc_obj_desc_t*)NULL;
   north_lbg_ctx_t       *lbg_p;
   int i;
   void *bufRef;
   
   lbg_p = north_lbg_getObjCtx_p(lbg_id);
   if (lbg_p == NULL) 
   {
     errno = EINVAL;
     return -1;
   }

    lbg_p->state = NORTH_LBG_SHUTTING_DOWN;
    /*
    **get the pointer to the destination stored in the buffer
    */

    /*
    ** OK, now go the buffer that might be queued on that entry and do the same
    */
    for (i = 0;  i < lbg_p->nb_entries_conf; i++)
    {
      entry_p = &lbg_p->entry_tb[i];

      /*
      ** stop the timer
      */
      north_lbg_entry_stop_timer(entry_p);      
      /*
      ** delete the TCP or AF_UNIX connection
      */
      ret = af_unix_delete_socket(entry_p->sock_ctx_ref);
      if (ret < 0) severe("failure on af_unix_delete_socket()entry  %d",i);
      entry_p->sock_ctx_ref = -1;
      /*
      ** Purge the buffer that are queued in the xmitlist done of the entry
      */
      while ((bufRef = (void*) ruc_objGetNext((ruc_obj_desc_t*)&entry_p->xmitList,
                                           &pnext))
                  !=NULL) 
      { 
        /*
        ** remove it from the list because it might be queued afterwards on a new queue
        */        
        ruc_objRemove((ruc_obj_desc_t*)bufRef);
        while (1) 
        {	 	 
             if (lbg_p->userDiscCallBack!= NULL)
             {
              (lbg_p->userDiscCallBack)(NULL,lbg_p->index,bufRef, EPIPE); 
              break;        
             }
             /*
             ** release the buffer
             */
             ruc_buf_freeBuffer(bufRef); 
             break;               
        }   
      }
    }
    /*
    ** Purge the pending xmit list of the load balancer
    */
    for (i = 0; i < NORTH_LBG_MAX_PRIO; i++)
    {
      pnext = (ruc_obj_desc_t*)NULL;
      while ((bufRef = (void*) ruc_objGetNext((ruc_obj_desc_t*)&lbg_p->xmitList[i],
                                           &pnext))
                  !=NULL) 
      { 
        /*
        ** remove it from the list because it might be queued afterwards on a new queue
        */        
        ruc_objRemove((ruc_obj_desc_t*)bufRef);
        while (1) 
        {	 	 
             if (lbg_p->userDiscCallBack!= NULL)
             {
              (lbg_p->userDiscCallBack)(NULL,lbg_p->index,bufRef, EPIPE); 
              break;        
             }
             /*
             ** release the buffer
             */
             ruc_buf_freeBuffer(bufRef); 
             break;               
        }   
      }
    }
    /*
    ** release the lbg context
    */
    north_lbg_free_from_ptr(lbg_p);
    return 0;

}
Exemple #9
0
void  north_lbg_userDiscCallBack(void *userRef,uint32_t socket_context_ref,void *bufRef,int err_no)
{
//    int len;
    int ret;
    int8_t retry_counter;
   north_lbg_entry_ctx_t *entry_p = (north_lbg_entry_ctx_t*)userRef;
   north_lbg_ctx_t       *lbg_p   = (north_lbg_ctx_t*)entry_p->parent;
   ruc_obj_desc_t        *pnext = (ruc_obj_desc_t*)NULL;
   int up2down_transition = 0;

    /*
    ** change the state to DOWN
    */
    if (entry_p->state != NORTH_LBG_DOWN) 
    { 
      north_lbg_entry_state_change(entry_p,NORTH_LBG_DOWN);
      warning("north_lbg_userDiscCallBack : LBG %s entry %d \n",lbg_p->name, entry_p->index);
      up2down_transition = 1;
    }
    /*
    **get the pointer to the destination stored in the buffer
    */
    while (bufRef != NULL) 
    {
       /*
       ** get the retry counter of the buffer
       */
       retry_counter = ruc_buf_get_retryCounter(bufRef);
       
       if ((lbg_p->state == NORTH_LBG_DOWN) && (lbg_p->rechain_when_lbg_gets_down == 1)) {
         /* 
	 ** The lbg is down but we re-send on it hoping it will comme back up soon 
	 */
	 if (retry_counter < lbg_p->nb_entries_conf) {
           retry_counter +=1;
           ruc_buf_set_retryCounter(bufRef,retry_counter);
           /*
           ** resend by selecting a new destination
           */
           lbg_p->stats.totalXmitRetries++;
	   //info("rechain on LBG %d",lbg_p->index);
           north_lbg_send(lbg_p->index,bufRef);	   
	   break;
	 }
       }
       
//       if ((retry_counter >= NORTH_LBG_MAX_RETRY) || (lbg_p->state == NORTH_LBG_DOWN))
       if ((retry_counter >= lbg_p->nb_entries_conf) || (lbg_p->state == NORTH_LBG_DOWN))
       {       
         /*
         ** inform the application or release the buffer
         */
         lbg_p->stats.totalXmitAborts++;
         if (lbg_p->userDiscCallBack!= NULL)
         {
         
          (lbg_p->userDiscCallBack)(NULL,lbg_p->index,bufRef, err_no); 
          break;        
         }
         /*
         ** release the buffer
         */
//#warning Need to check the in_use counter of the buffer before the release
         ruc_buf_freeBuffer(bufRef); 
         break;               
       }
       /*
       ** the lbg is still up and there the retry count is not exhausted
       */
       retry_counter +=1;
       ruc_buf_set_retryCounter(bufRef,retry_counter);
       /*
       ** resend by selecting a new destination
       */
       lbg_p->stats.totalXmitRetries++;
       north_lbg_send(lbg_p->index,bufRef);
       break;
    }
    /*
    ** OK, now go the buffer that might be queued on that entry and do the same
    */    
    while ((bufRef = (void*) ruc_objGetNext((ruc_obj_desc_t*)&entry_p->xmitList,
                                         &pnext))
                !=NULL) 
    { 
      /*
      ** remove it from the list because it might be queued afterwards on a new queue
      */        
      ruc_objRemove((ruc_obj_desc_t*)bufRef);
      while (1) 
      {
         /*
         ** get the retry counter of the buffer
         */
         retry_counter = ruc_buf_get_retryCounter(bufRef);
         if ((lbg_p->state == NORTH_LBG_DOWN) && (lbg_p->rechain_when_lbg_gets_down == 1)) {
           /* 
	   ** The lbg is down but we re-send on it hoping it will comme back up soon 
	   */
	   if (retry_counter < lbg_p->nb_entries_conf) {
             retry_counter +=1;
             ruc_buf_set_retryCounter(bufRef,retry_counter);
             /*
             ** resend by selecting a new destination
             */
             lbg_p->stats.totalXmitRetries++;
	     #
	    //info("rechain on LBG %d",lbg_p->index);
             north_lbg_send(lbg_p->index,bufRef);	   
	     break;
	   }
         }
	 	
	 //         if ((retry_counter >= NORTH_LBG_MAX_RETRY) || (lbg_p->state == NORTH_LBG_DOWN))
         if ((retry_counter >= lbg_p->nb_entries_conf) || (lbg_p->state == NORTH_LBG_DOWN))
         {
           /*
           ** inform the application or release the buffer
           */
           lbg_p->stats.totalXmitAborts++;
           if (lbg_p->userDiscCallBack!= NULL)
           {
            (lbg_p->userDiscCallBack)(NULL,lbg_p->index,bufRef, err_no); 
            break;        
           }
           /*
           ** release the buffer
           */
           ruc_buf_freeBuffer(bufRef); 
           break;               
         }
         /*
         ** the lbg is still up and there the retry count is not exhausted
         */
         retry_counter +=1;
         ruc_buf_set_retryCounter(bufRef,retry_counter);
         /*
         ** resend by selecting a new destination
         */
         lbg_p->stats.totalXmitRetries++;
         north_lbg_send(lbg_p->index,bufRef);
         break;
      }   
    }   
    /*
    ** do the reconnect on UP 2 DOWN transition only
    */
  if (up2down_transition) 
  {
    entry_p->stats.totalConnectAttempts++;
    ret = af_unix_sock_client_reconnect(socket_context_ref);
    if (ret < 0)
    {
 //  printf("north_lbg_userDiscCallBack->fatal error on reconnect\n");
      north_lbg_entry_start_timer(entry_p,ROZOFS_TMR_GET(TMR_TCP_FIRST_RECONNECT)); 
    }
  }
}
/**
*  Internal Read procedure
   That procedure is used when it is required to read the last block before
   performing the truncate
   
   @param working_ctx_p: pointer to the root transaction
   
   @retval 0 on success
   retval < 0 on error (see errno for error details)
   
*/
int rozofs_storcli_internal_read_before_truncate_req(rozofs_storcli_ctx_t *working_ctx_p)
{
   storcli_truncate_arg_t *storcli_truncate_rq_p;
   void *xmit_buf = NULL;
   storcli_read_arg_t storcli_read_args;
   storcli_read_arg_t *request   = &storcli_read_args;
   struct rpc_msg   call_msg;
   int               bufsize;
   uint32_t          *header_size_p;
   XDR               xdrs;    
   uint8_t           *arg_p;
      
   storcli_truncate_rq_p = (storcli_truncate_arg_t*)&working_ctx_p->storcli_truncate_arg;
   
   /*
   ** allocated a buffer from sending the request
   */   
   xmit_buf = ruc_buf_getBuffer(ROZOFS_STORCLI_NORTH_SMALL_POOL);
   if (xmit_buf == NULL)
   {
     severe(" out of small buffer on north interface ");
     errno = ENOMEM;
     goto failure;
   }
   /*
   ** build the RPC message
   */
   request->sid = 0;  /* not significant */
   request->layout = storcli_truncate_rq_p->layout;
   request->cid    = storcli_truncate_rq_p->cid;
   request->spare = 0;  /* not significant */
   memcpy(request->dist_set, storcli_truncate_rq_p->dist_set, ROZOFS_SAFE_MAX*sizeof (uint8_t));
   memcpy(request->fid, storcli_truncate_rq_p->fid, sizeof (sp_uuid_t));
   request->proj_id = 0;  /* not significant */
   request->bid     = storcli_truncate_rq_p->bid;  
   request->nb_proj = 1;  
   
   /*
   ** get the pointer to the payload of the buffer
   */
   header_size_p  = (uint32_t*) ruc_buf_getPayload(xmit_buf);
   arg_p = (uint8_t*)(header_size_p+1);  
   /*
   ** create the xdr_mem structure for encoding the message
   */
   bufsize = (int)ruc_buf_getMaxPayloadLen(xmit_buf);
   xdrmem_create(&xdrs,(char*)arg_p,bufsize,XDR_ENCODE);
   /*
   ** fill in the rpc header
   */
   call_msg.rm_direction = CALL;
   /*
   ** allocate a xid for the transaction 
   */
   call_msg.rm_xid             = rozofs_tx_get_transaction_id(); 
   call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
   /* XXX: prog and vers have been long historically :-( */
   call_msg.rm_call.cb_prog = (uint32_t)STORCLI_PROGRAM;
   call_msg.rm_call.cb_vers = (uint32_t)STORCLI_VERSION;
   if (! xdr_callhdr(&xdrs, &call_msg))
   {
      /*
      ** THIS MUST NOT HAPPEN
      */
     errno = EFAULT;
     severe(" rpc header encode error ");
     goto failure;
   }
   /*
   ** insert the procedure number, NULL credential and verifier
   */
   uint32_t opcode = STORCLI_READ;
   uint32_t null_val = 0;
   XDR_PUTINT32(&xdrs, (int32_t *)&opcode);
   XDR_PUTINT32(&xdrs, (int32_t *)&null_val);
   XDR_PUTINT32(&xdrs, (int32_t *)&null_val);
   XDR_PUTINT32(&xdrs, (int32_t *)&null_val);
   XDR_PUTINT32(&xdrs, (int32_t *)&null_val);        
   /*
   ** ok now call the procedure to encode the message
   */
   if (xdr_storcli_read_arg_t(&xdrs,request) == FALSE)
   {
     severe(" internal read request encoding error ");
     errno = EFAULT;
     goto failure;
   }
   /*
   ** Now get the current length and fill the header of the message
   */
   int position = XDR_GETPOS(&xdrs);
   /*
   ** update the length of the message : must be in network order
   */
   *header_size_p = htonl(0x80000000 | position);
   /*
   ** set the payload length in the xmit buffer
   */
   int total_len = sizeof(*header_size_p)+ position;
   ruc_buf_setPayloadLen(xmit_buf,total_len);
   /*
   ** Submit the pseudo request
   */
   rozofs_storcli_read_req_init(0,xmit_buf,rozofs_storcli_internal_read_before_truncate_rsp_cbk,(void*)working_ctx_p,STORCLI_DO_NOT_QUEUE);
   return 0;
   
failure:
  if (xmit_buf != NULL) ruc_buf_freeBuffer(xmit_buf); 
  return -1; 
   
}
/**
* 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 ;

}
/**
*  callback associated with the socket controller for receiving a
   message on a AF_UNIX socket operating of datagram mode

  @param socket_pointer: pointer to the socket context
  @param socketId: reference of the socket--> not used

*/
uint32_t af_unix_recv_stream_generic_cbk(void * socket_pointer,int socketId)
{

  af_unix_ctx_generic_t  *sock_p = (af_unix_ctx_generic_t*)socket_pointer;
  com_recv_template_t    *recv_p;
  uint16_t               recv_credit;
  void                  *buf_recv_p = NULL;
  int                    full_msg_len;
  uint32_t               payloadLen;
  uint8_t               *payload_p;
  uint32_t               status;
  int                    len_read;
  void *bufref = NULL;
  /*
  ** set the credit, notice that the credit is decremented upon reception
  ** of a full message
  */
  recv_p = &sock_p->recv;
  recv_credit = recv_p->recv_credit_conf;

  while(recv_credit != 0)
  {
    switch (recv_p->state)
    {
      /*
      ** There is no recepition in progress
      */
      case RECV_IDLE:
        recv_p->nbread = 0;
        recv_p->nb2read = recv_p->headerSize;
        recv_p->bufRefCurrent = NULL;
        recv_p->state = RECV_WAIT_HDR;
        break;
      /*
      **_________________________________________________________________
      ** Waiting for the header before allocating the receive buffer
      **_________________________________________________________________
      */
      case RECV_WAIT_HDR:
        /*
        ** attempt to receive the full header to figure out what kind of receive buffer
        ** Must be allocated
        */
        status = af_unix_recv_stream_sock_recv(sock_p,recv_p->buffer_header+recv_p->nbread,
                                               recv_p->nb2read- recv_p->nbread ,0,&len_read);
        switch(status)
        {
          case RUC_OK:
           /*
           ** that's fine : go to the next step to figure out what kind of buffer can be allocated
           */
           sock_p->stats.totalRecvBytes += len_read;
           recv_p->state = RECV_ALLOC_BUF;
           break;

          case RUC_WOULDBLOCK:
           /*
           ** we don't get the full header so no change, wait for the next receiver event
           */
	   sock_p->stats.emptyRecv++;
           return TRUE;

          case RUC_PARTIAL:
          /*
          ** update the count and re-attempt until getting a EAGAIN or a full header
          */
	  sock_p->stats.partialRecv++;
          sock_p->stats.totalRecvBytes += len_read;
          recv_p->nbread += len_read;
          break;

          default:
          case RUC_DISC:
          /*
          ** general disconnection
          */
          af_unix_sock_stream_disconnect_internal(sock_p);
          /*
          ** socket is dead call the user callback
          */
          recv_p->state = RECV_DEAD;
//          warning("af_unix_recv_stream_generic_cbk: %s",strerror(errno));
          (sock_p->userDiscCallBack)(sock_p->userRef,sock_p->index,NULL,errno);

          return TRUE;
        }
      break;

      /*
      **_________________________________________________________________
      ** allocate a receive buffer according to the length of the message
      **_________________________________________________________________
      */
      case RECV_ALLOC_BUF:
        if (sock_p->userHdrAnalyzerCallBack != NULL)
        {
           /*
           ** The applicaton has provide a callback for parsing its header and to extract the
           ** length of the payload-> Typically, it is mandatory for the case of the RPC since
           ** the field that contains the length has the bit 31 asserted
           */
           payloadLen = (sock_p->userHdrAnalyzerCallBack)((char*)recv_p->buffer_header);         

        }
        else
        {
          payloadLen = com_sock_extract_length_from_header_host_format((char*)recv_p->buffer_header,
                                                                       recv_p->msgLenOffset,
                                                                       recv_p->msgLenSize);
        }
        if (payloadLen == 0)
        {
           /*
           ** general disconnection
           */
           af_unix_sock_stream_disconnect_internal(sock_p);
           recv_p->state = RECV_DEAD;
           sock_p->stats.totalRecvBadHeader++;
           /*
           ** the length is wrong, we have no choice we need to close the connection
           */
           (sock_p->userDiscCallBack)(sock_p->userRef,sock_p->index,NULL,errno);


           return TRUE;
        }
        /*
        ** check if the message does not exceed the max buffer size
        */
        full_msg_len = payloadLen + recv_p->headerSize;
        if (full_msg_len > recv_p->bufSize)
        {
          /*
           ** general disconnection
           */
           af_unix_sock_stream_disconnect_internal(sock_p);
           recv_p->state = RECV_DEAD;
           sock_p->stats.totalRecvBadHeader++;           /*
           ** the length is wrong, we have no choice we need to close the connection
           */
           (sock_p->userDiscCallBack)(sock_p->userRef,sock_p->index,NULL,errno);
 
 
           return TRUE;
        }
        /*
        ** Ok now call the application for receive buffer allocation
        */
        if (sock_p->userRcvAllocBufCallBack != NULL)
        {
           buf_recv_p = (sock_p->userRcvAllocBufCallBack)(sock_p->userRef,sock_p->index,full_msg_len);
        }
        else
        {
          buf_recv_p = af_unix_alloc_recv_buf();
        }
        if (buf_recv_p == NULL)
        {
          /*
          ** the receiver is out of buffer-> leave the message in the receiver queue and exit
          */
          sock_p->stats.totalRecvOutoFBuf++;
          recv_p->state = RECV_ALLOC_BUF;
          return TRUE;
        }
        /*
        ** set the payload length in the buffer
        */
        ruc_buf_setPayloadLen(buf_recv_p,(uint32_t)(payloadLen + recv_p->headerSize));
        /*
        ** Ok now start receiving the payload
        */
        recv_p->nbread = recv_p->headerSize;
        recv_p->nb2read = recv_p->headerSize+payloadLen;
        recv_p->bufRefCurrent = buf_recv_p;
        payload_p = (uint8_t*)ruc_buf_getPayload(recv_p->bufRefCurrent);
        /*
        ** copy the already received bytes in the allocated received buffer
        */
        memcpy(payload_p,recv_p->buffer_header,recv_p->headerSize);
        recv_p->state = RECV_PAYLOAD;
        break;


      /*
      **_________________________________________________________________
      ** reception of the payload of the message
      **_________________________________________________________________
      */
      case RECV_PAYLOAD:
        /*
        ** attempt to receive the full header to figure out what kind of receive buffer
        ** Must be allocated
        */
        payload_p = (uint8_t*)ruc_buf_getPayload(recv_p->bufRefCurrent);
        status = af_unix_recv_stream_sock_recv(sock_p,payload_p+recv_p->nbread,
                                               recv_p->nb2read- recv_p->nbread ,0,&len_read);
        switch(status)
        {
          case RUC_OK:
	   /*
	   ** update the speculative scheduler
	   */
	   ruc_sockCtrl_speculative_scheduler_decrement(sock_p->connectionId);
           /*
           ** that fine's call the application with that received message
           */
           sock_p->stats.totalRecvBytes += len_read;
           sock_p->stats.totalRecvSuccess++;
           /*
           ** clear the reference of the buffer to avoid a double release that may occur
           ** if the application delete the context
           */
           bufref = recv_p->bufRefCurrent;
           recv_p->bufRefCurrent = NULL;
           (sock_p->userRcvCallBack)(sock_p->userRef,sock_p->index,bufref);
           recv_p->state = RECV_IDLE;
           recv_credit--;
           break;

          case RUC_WOULDBLOCK:
           /*
           ** we don't get the full message so no change, wait for the next receiver event
           */
	   sock_p->stats.emptyRecv++;
           return TRUE;

          case RUC_PARTIAL:
          /*
          ** update the count and re-attempt until getting a EAGAIN or a full header
          */
	  sock_p->stats.partialRecv++;
          sock_p->stats.totalRecvBytes += len_read;
          recv_p->nbread += len_read;
          break;

          case RUC_DISC:
          default:
          /*
          ** socket is dead call the user callback
          */
          bufref = recv_p->bufRefCurrent;
          recv_p->bufRefCurrent = NULL;
          ruc_buf_freeBuffer(bufref);
           /*
          ** general disconnection
          */
          af_unix_sock_stream_disconnect_internal(sock_p);

          /*
          ** it is up to the application to release the buffer if the error is fatal
          ** but for the case of the receiver, no buffer reference is provided
          */
          recv_p->state = RECV_DEAD;
          (sock_p->userDiscCallBack)(sock_p->userRef,sock_p->index,NULL,errno);

          return TRUE;
        }
        break;
      /*
      **_________________________________________________________________
      ** Dead state of the receiver
      **_________________________________________________________________
      */
      case RECV_DEAD:
        return TRUE;
    }
  }
  return TRUE;
}
/**
*  callback associated with the socket controller for receiving a
   RPC message on a AF_UNIX socket operating of datagram mode

  @param socket_pointer: pointer to the socket context
  @param socketId: reference of the socket--> not used

*/
uint32_t af_unix_recv_rpc_stream_generic_cbk(void * socket_pointer,int socketId)
{

  af_unix_ctx_generic_t  *sock_p = (af_unix_ctx_generic_t*)socket_pointer;
  com_recv_template_t    *recv_p;
  uint16_t               recv_credit;
  void                  *buf_recv_p = NULL;
  int                    full_msg_len;
  uint32_t               payloadLen;
  uint8_t               *payload_p;
  uint32_t               status;
  uint32_t              *record_len_p;
  int                    len_read;
  void *bufref = NULL;
  com_rpc_recv_template_t  *rpc;
  /*
  ** set the credit, notice that the credit is decremented upon reception
  ** of a full message
  */
  recv_p = &sock_p->recv;
  recv_credit = recv_p->recv_credit_conf;
  rpc = &recv_p->rpc;

  while(recv_credit != 0)
  {
    switch (recv_p->state)
    {
      /*
      ** There is no recepition in progress
      */
      case RECV_IDLE:
        rpc->last_record   = 0;
        rpc->record_len    = 0;     
        rpc->in_tot_len    = 0;
        rpc->in_wr_offset  = 0; 
     
        recv_p->nbread = 0;
        recv_p->nb2read = recv_p->headerSize;
        recv_p->bufRefCurrent = NULL;
        recv_p->state = RECV_WAIT_HDR;
        break;
      /*
      **_________________________________________________________________
      ** Waiting for the header before allocating the receive buffer
      **_________________________________________________________________
      */
      case RECV_WAIT_HDR:
        /*
        ** attempt to receive the full header to figure out what kind of receive buffer
        ** Must be allocated
        */
        status = af_unix_recv_stream_sock_recv(sock_p,recv_p->buffer_header+recv_p->nbread,
                                               recv_p->nb2read- recv_p->nbread ,0,&len_read);
        switch(status)
        {
          case RUC_OK:
           /*
           ** that's fine : go to the next step to figure out what kind of buffer can be allocated
           */
           sock_p->stats.totalRecvBytes += len_read;
           if (recv_p->bufRefCurrent == NULL)
           {
             /*
             ** buffer has not be yet allocated
             */
             recv_p->state = RECV_ALLOC_BUF;
           }
           else
           {
             /*
             ** Buffer has already been alllocated, so it is not the fisrt received record
             ** get the header of the RPC record in order to extract the length and the type
             ** of the rpc message.
             ** The current length of the rpc record is added with the total length.
             ** Since it is not the first record, the system does not store in the receive 
             ** buffer the first 4 bytes of the rpc record. This is done for the first
             ** record only.
             */
             record_len_p = (uint32_t *)recv_p->buffer_header;    
             rpc->record_len = ntohl(*record_len_p);
             if (rpc->record_len & (~0x7fffffff)) {
	       rpc->last_record = 1;
	     }
             rpc->record_len  &= 0x7fffffff;
             rpc->in_tot_len  += rpc->record_len;           
             if ((rpc->in_tot_len+recv_p->headerSize) > rpc->max_receive_sz)
             {
                /*
                ** release the buffer
                */
                bufref = recv_p->bufRefCurrent;
                recv_p->bufRefCurrent = NULL;
                ruc_buf_freeBuffer(bufref);
                /*
                ** general disconnection
                */
                af_unix_sock_stream_disconnect_internal(sock_p);
                recv_p->state = RECV_DEAD;
                sock_p->stats.totalRecvBadHeader++;
                /*
                ** the length is wrong, we have no choice we need to close the connection
                */
                (sock_p->userDiscCallBack)(sock_p->userRef,sock_p->index,NULL,errno);


                return TRUE;
             }
             /*
             ** set the number of bytes to read and already read
             */
             recv_p->nbread = 0;
             recv_p->nb2read = rpc->record_len;    
             /*
             ** now read the payload of the record
             */
             recv_p->state = RECV_PAYLOAD;
       
           }
           break;

          case RUC_WOULDBLOCK:
           /*
           ** we don't get the full header so no change, wait for the next receiver event
           */
	   sock_p->stats.emptyRecv++;
           return TRUE;

          case RUC_PARTIAL:
          /*
          ** update the count and re-attempt until getting a EAGAIN or a full header
          */
	  sock_p->stats.partialRecv++;
          sock_p->stats.totalRecvBytes += len_read;
          recv_p->nbread += len_read;
          break;

          default:
          case RUC_DISC:
         /*
          ** general disconnection
          */
          af_unix_sock_stream_disconnect_internal(sock_p);
          /*
          ** socket is dead call the user callback
          */
          recv_p->state = RECV_DEAD;
//          warning("af_unix_recv_stream_generic_cbk:%s",strerror(errno));
          (sock_p->userDiscCallBack)(sock_p->userRef,sock_p->index,NULL,errno);
 
          return TRUE;
        }
      break;

      /*
      **_________________________________________________________________
      ** allocate a receive buffer according to the length of the message
      **_________________________________________________________________
      */
      case RECV_ALLOC_BUF:      
        /*
        ** store the total length of the message
        */
        record_len_p = (uint32_t *)recv_p->buffer_header;    
        rpc->record_len = ntohl(*record_len_p);
        if (rpc->record_len & (~0x7fffffff)) rpc->last_record = 1;
        rpc->record_len  &= 0x7fffffff;
        /*
        ** check if the message does not exceed the max buffer size
        */
        if (rpc->last_record == 0)
        {
          /*
          ** assume max length
          */
          full_msg_len = rpc->max_receive_sz;        
        }
        else
        {
           full_msg_len = rpc->record_len + recv_p->headerSize;
        }
        if (full_msg_len > rpc->max_receive_sz)
        {
           /*
           ** general disconnection: purge the xmit side
           */
           af_unix_sock_stream_disconnect_internal(sock_p);
           recv_p->state = RECV_DEAD;
           sock_p->stats.totalRecvBadHeader++;           /*
           ** the length is wrong, we have no choice we need to close the connection
           */
           (sock_p->userDiscCallBack)(sock_p->userRef,sock_p->index,NULL,errno);


           return TRUE;
        }
        /*
        ** Ok now call the application for receive buffer allocation
        */
        if (sock_p->userRcvAllocBufCallBack != NULL)
        {
           buf_recv_p = (sock_p->userRcvAllocBufCallBack)(sock_p->userRef,sock_p->index,full_msg_len);
        }
        else
        {
           fatal("Alloc Buffer callback is mandatory for rpc service");
        }
        if (buf_recv_p == NULL)
        {
          /*
          ** the receiver is out of buffer-> leave the message in the receiver queue and exit
          */
          sock_p->stats.totalRecvOutoFBuf++;
          recv_p->state = RECV_ALLOC_BUF;
          return TRUE;
        }
        /*
        ** set the payload length in the buffer
        */
        rpc->in_tot_len  += rpc->record_len;
        payloadLen = rpc->record_len;       
        
        ruc_buf_setPayloadLen(buf_recv_p,(uint32_t)(payloadLen + recv_p->headerSize));
        /*
        ** Ok now start receiving the payload
        */
        recv_p->nbread = recv_p->headerSize;
        recv_p->nb2read = recv_p->headerSize+payloadLen;
        recv_p->bufRefCurrent = buf_recv_p;
        payload_p = (uint8_t*)ruc_buf_getPayload(recv_p->bufRefCurrent);
        /*
        ** copy the already received bytes in the allocated received buffer
        */
        memcpy(payload_p,recv_p->buffer_header,recv_p->headerSize);
        recv_p->state = RECV_PAYLOAD;
        break;


      /*
      **_________________________________________________________________
      ** reception of the payload of the message
      **_________________________________________________________________
      */
      case RECV_PAYLOAD:
        /*
        ** attempt to receive the full header to figure out what kind of receive buffer
        ** Must be allocated
        */
        payload_p = (uint8_t*)ruc_buf_getPayload(recv_p->bufRefCurrent);
        status = af_unix_recv_stream_sock_recv(sock_p,payload_p+rpc->in_wr_offset+recv_p->nbread,
                                               recv_p->nb2read- recv_p->nbread ,0,&len_read);
        switch(status)
        {
          case RUC_OK:
	   /*
	   ** update the speculative scheduler
	   */
	   ruc_sockCtrl_speculative_scheduler_decrement(sock_p->connectionId);
           /*
           ** that fine's call the application with that received message
           */
           sock_p->stats.totalRecvBytes += len_read;
           sock_p->stats.totalRecvSuccess++;
           recv_p->nbread += len_read;
	   
           /*
           ** Check if it is the last record: in such a case we deliver the rpc message 
           ** to the application
           */
           if (rpc->last_record)
           {
             /*
             ** clear the reference of the buffer to avoid a double release that may occur
             ** if the application delete the context
             ** Update the first length header of the rpc message with the total length of the
             ** RPC message
             */
             bufref = recv_p->bufRefCurrent;
             recv_p->bufRefCurrent = NULL;
             ruc_buf_setPayloadLen(bufref,(uint32_t)(rpc->in_tot_len + recv_p->headerSize));
             record_len_p = (uint32_t *)payload_p;  
             *record_len_p = htonl((rpc->in_tot_len) | 0x80000000);                          
             (sock_p->userRcvCallBack)(sock_p->userRef,sock_p->index,bufref);
             recv_p->state = RECV_IDLE;
             recv_credit--;
             break;
           }
           /*
           ** not the last record:
           ** udpate the in_wr_offset with the current record length and prepare to receive
           ** the next record
           */
           rpc->in_wr_offset+= recv_p->nbread; 
           recv_p->nbread = 0;
           recv_p->nb2read = recv_p->headerSize;	             
           recv_p->state = RECV_WAIT_HDR;
           break;

          case RUC_WOULDBLOCK:
           /*
           ** we don't get the full message so no change, wait for the next receiver event
           */
	   sock_p->stats.emptyRecv++;
           return TRUE;

          case RUC_PARTIAL:
          /*
          ** update the count and re-attempt until getting a EAGAIN or a full header
          */
	  sock_p->stats.partialRecv++;
          sock_p->stats.totalRecvBytes += len_read;
          recv_p->nbread += len_read;
          break;

          case RUC_DISC:
          default:
          /*
          ** socket is dead call the user callback
          */
          bufref = recv_p->bufRefCurrent;
          recv_p->bufRefCurrent = NULL;
          ruc_buf_freeBuffer(bufref);
           /*
          ** general disconnection
          */
          af_unix_sock_stream_disconnect_internal(sock_p);
          /*
          ** it is up to the application to release the buffer if the error is fatal
          ** but for the case of the receiver, no buffer reference is provided
          */
          recv_p->state = RECV_DEAD;
          (sock_p->userDiscCallBack)(sock_p->userRef,sock_p->index,NULL,errno);

          return TRUE;
        }
        break;
      /*
      **_________________________________________________________________
      ** Dead state of the receiver
      **_________________________________________________________________
      */
      case RECV_DEAD:
        return TRUE;
    }
  }
  return TRUE;
}
int storcli_lbg_cnx_sup_is_selectable(int lbg_id)
{
  uint64_t current_date;
  storcli_lbg_cnx_supervision_t *p;
  void *xmit_buf = NULL;
  int ret;

  if (lbg_id >=STORCLI_MAX_LBG) return 0;

  p = &storcli_lbg_cnx_supervision_tab[lbg_id];

  if (p->state == STORCLI_LBG_RUNNING) return 1;

  current_date = timer_get_ticker();

//  if (current_date > p->expiration_date) return 1;
  /*
  ** check if poll is active
  */
  if (p->poll_state == STORCLI_POLL_IN_PRG) return 0;
  /*
  ** check the period
  */
  if (current_date > p->next_poll_date)
  {
    /*
    ** attempt to poll
    */
      p->poll_counter++;
      
      xmit_buf = ruc_buf_getBuffer(ROZOFS_STORCLI_SOUTH_LARGE_POOL);
      if (xmit_buf == NULL)
      {
         return 0; 
      }
      p->poll_state = STORCLI_POLL_IN_PRG;
      /*
      ** increment the inuse to avoid a release of the xmit buffer by rozofs_sorcli_send_rq_common()
      */
      ruc_buf_inuse_increment(xmit_buf);
      
      ret =  rozofs_sorcli_send_rq_common(lbg_id,ROZOFS_TMR_GET(TMR_RPC_NULL_PROC_LBG),STORAGE_PROGRAM,STORAGE_VERSION,SP_NULL,
                                          (xdrproc_t) xdr_void, (caddr_t) NULL,
                                           xmit_buf,
                                           lbg_id,
                                           0,
                                           0,
                                           rozofs_storcli_sp_null_processing_cbk,
                                           (void*)NULL);
      ruc_buf_inuse_decrement(xmit_buf);

     if (ret < 0)
     {
      /*
      ** direct need to free the xmit buffer
      */
      ruc_buf_freeBuffer(xmit_buf);    
      return 0;   

     }
     /*
     ** Check if there is direct response from tx module
     */
     if (p->poll_state == STORCLI_POLL_ERR)
     {
       /*
       ** set the next expiration date
       */
       p->next_poll_date = current_date+STORCLI_LBG_SP_NULL_INTERVAL;
       /*
       ** release the xmit buffer since there was a direct reply from the lbg while attempting to send the buffer
       */
      ruc_buf_freeBuffer(xmit_buf);    
       return 0;
     } 
  }  
  return 0;
}
/**
*  callback associated with the socket controller for receiving a
   message on a AF_UNIX socket operating of datagram mode

  @param socket_pointer: pointer to the socket context
  @param socketId: reference of the socket--> not used

*/
uint32_t af_unix_recv_generic_cbk(void * socket_pointer,int socketId)
{

  uint8_t                buffer_header[ROZOFS_MAX_HEADER_SIZE];
  af_unix_ctx_generic_t  *sock_p = (af_unix_ctx_generic_t*)socket_pointer;
  int                    bytesRcvd;
  struct sockaddr_un     sockAddr;
  int                    sockAddrLen;
  com_recv_template_t    *recv_p;
  uint16_t               recv_credit;
  int                    eintr_count;
  void                  *buf_recv_p;
  int                    full_msg_len;
  uint32_t               payloadLen;
  char                  *sockname_p;
  uint8_t               *payload_p;

  recv_p = &sock_p->recv;
  recv_credit = recv_p->recv_credit_conf;


  sockAddrLen = sizeof(sockAddr);
  /*
  ** Get the header of the message without removing the message from the
  ** socket queue
  */
  eintr_count = 0;
  while(recv_credit != 0)
  {
    bytesRcvd = recvfrom(sock_p->socketRef,
		        buffer_header,
		        recv_p->headerSize,
		        MSG_PEEK,
		        (struct sockaddr *)&sockAddr,
		        ( socklen_t *)&sockAddrLen);
   if (bytesRcvd == -1)
   {
     switch (errno)
     {
       case EAGAIN:
        /*
        ** the socket is empty
        */
        return TRUE;

       case EINTR:
         /*
         ** re-attempt to read the socket
         */
         eintr_count++;
         if (eintr_count < 3) continue;
         /*
         ** here we consider it as a error
         */
         RUC_WARNING(eintr_count);
         sock_p->stats.totalRecvError++;
         return TRUE;

       case EBADF:
       case EFAULT:
       case EINVAL:
       default:
         /*
         ** We might need to double checl if the socket must be killed
         */
         RUC_WARNING(errno);
         sock_p->stats.totalRecvError++;
         return TRUE;
     }
   }
   /*
   ** check we have the right length
   */
   if (bytesRcvd != recv_p->headerSize)
   {
     /*
     ** unable to read the full header, so drop the current message. Notice that for
     ** the AF_UNIX case, the message will be truncated to the max size of buffer_header
     ** Here we will indicate an error an attempt to read the next inflight message if any
     */
     sock_p->stats.totalRecvBadHeader++;
     RUC_WARNING(bytesRcvd);

     recvfrom(sock_p->socketRef,
		      buffer_header,
		      recv_p->headerSize,
		      0,
		      (struct sockaddr *)&sockAddr,
		      ( socklen_t *)&sockAddrLen);
      sock_p->stats.totalRecvBadHeader++;
      recv_credit--;
      continue;
   }
   /*
   ** get the length of the payload of the message
   */
   payloadLen = com_sock_extract_length_from_header_host_format((char*)buffer_header,recv_p->msgLenOffset,recv_p->msgLenSize);
   if (payloadLen == 0)
   {
     /*
     ** the length information is wrong, skip that message and attempt to read the next one
     ** in sequence
     */
     RUC_WARNING(payloadLen);

     recvfrom(sock_p->socketRef,
		      buffer_header,
		      recv_p->headerSize,
		      0,
		      (struct sockaddr *)&sockAddr,
		      ( socklen_t *)&sockAddrLen);
      sock_p->stats.totalRecvBadHeader++;
      recv_credit--;
      continue;
   }
   /*
   ** check if the message does not exceed the max buffer size
   */
   full_msg_len = payloadLen + recv_p->headerSize;
   if (full_msg_len > recv_p->bufSize)
   {
     /*
     ** message exceeds the capacity of the receiver-> drop it
     */
     RUC_WARNING(payloadLen);

     recvfrom(sock_p->socketRef,
		      buffer_header,
		      recv_p->headerSize,
		      0,
		      (struct sockaddr *)&sockAddr,
		      ( socklen_t *)&sockAddrLen);
      sock_p->stats.totalRecvBadLength++;
      recv_credit--;
      continue;
   }
   /*
   ** Ok now call the application for receive buffer allocation
   */
   if (sock_p->userRcvAllocBufCallBack != NULL)
   {
      buf_recv_p = (sock_p->userRcvAllocBufCallBack)(sock_p->userRef,sock_p->index,full_msg_len);
   }
   else
   {
     buf_recv_p = af_unix_alloc_recv_buf();
   }
   if (buf_recv_p == NULL)
   {
     /*
     ** the receiver is out of buffer-> leave the message in the receiver queue and exit
     */
     sock_p->stats.totalRecvOutoFBuf++;
     return TRUE;
   }
   payload_p = (uint8_t*)ruc_buf_getPayload(buf_recv_p);
   /*
   ** OK, we have a receive buffer, so receive the full message and give to the application
   ** but before read it from the socket
   */
  eintr_count = 0;
retry:
   bytesRcvd = recvfrom(sock_p->socketRef,
		       payload_p,
		       full_msg_len,
		       0,
		       (struct sockaddr *)&sockAddr,
		       ( socklen_t *)&sockAddrLen);
    if (bytesRcvd == -1)
    {
      switch (errno)
      {
        case EAGAIN:
         /*
         ** the socket is empty--> that situation MUST not occur:
         */
         ruc_buf_freeBuffer(buf_recv_p);
         return TRUE;
        case EINTR:
          /*
          ** re-attempt to read the socket
          */
          eintr_count++;
          if (eintr_count < 3) goto retry;
          /*
          ** here we consider it as a error
          */
          RUC_WARNING(eintr_count);
          /*
          ** release the receive buffer
          */
          ruc_buf_freeBuffer(buf_recv_p);
          sock_p->stats.totalRecvError++;
          return TRUE;

        case EBADF:
        case EFAULT:
        case EINVAL:
        default:
          /*
          ** We might need to double checl if the socket must be killed
          */
          ruc_buf_freeBuffer(buf_recv_p);
          RUC_WARNING(errno);
          sock_p->stats.totalRecvError++;
          return TRUE;
      }
    }
    /*
    ** check we have the right length
    */
    if (bytesRcvd != full_msg_len)
    {
      /*
      ** that situation must not occur with datagram socket
      */
      RUC_WARNING(errno);
      ruc_buf_freeBuffer(buf_recv_p);
      sock_p->stats.totalRecvError++;
      recv_credit--;
      continue;
    }
    /*
    ** OK, copy the reference of the source in the packet buffer
    */
    sockname_p = ruc_buf_get_usrSrcInfo(buf_recv_p);
    memcpy(sockname_p,&sockAddr.sun_path,sockAddrLen);
    /*
    ** OK, call the receive process of the application
    */
    sock_p->stats.totalRecvBytes += full_msg_len;
    sock_p->stats.totalRecvSuccess++;
    (sock_p->userRcvCallBack)(sock_p->userRef,sock_p->index,buf_recv_p);
    recv_credit--;
  }
  return TRUE;
}
 /*
**__________________________________________________________________________
*/
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;

    }
  }
}
 /*
**__________________________________________________________________________
*/
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;

    }
  }
}