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