static bool openavbEptClntSendToServer(int h, openavbEndpointMessage_t *msg) { AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT); if (!msg || h == AVB_ENDPOINT_HANDLE_INVALID) { AVB_LOG_ERROR("Client send: invalid argument passed"); AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT); return FALSE; } ssize_t nWrite = write(h, msg, OPENAVB_ENDPOINT_MSG_LEN); AVB_LOGF_VERBOSE("Sent message, len=%zu, nWrite=%zu", OPENAVB_ENDPOINT_MSG_LEN, nWrite); if (nWrite < OPENAVB_ENDPOINT_MSG_LEN) { if (nWrite < 0) { AVB_LOGF_ERROR("Client failed to write socket: %s", strerror(errno)); } else if (nWrite == 0) { AVB_LOG_ERROR("Client send: socket closed unexpectedly"); } else { AVB_LOG_ERROR("Client send: short write"); } socketClose(h); AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT); return FALSE; } AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT); return TRUE; }
// Release a TX frame, and mark it as ready to send bool ringRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len, U64 timeNsec) { AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL); ring_rawsock_t *rawsock = (ring_rawsock_t*)pvRawsock; if (!VALID_TX_RAWSOCK(rawsock)) { AVB_LOG_ERROR("Marking TX frame ready; invalid argument"); AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL); return FALSE; } if (timeNsec) { IF_LOG_INTERVAL(1000) AVB_LOG_WARNING("launch time is unsupported in ring_rawsock"); } volatile struct tpacket2_hdr *pHdr = (struct tpacket2_hdr*)(pBuffer - rawsock->bufHdrSize); AVB_LOGF_VERBOSE("pBuffer=%p, pHdr=%p szFrame=%d, len=%d", pBuffer, pHdr, rawsock->base.frameSize, len); assert(len <= rawsock->bufferSize); pHdr->tp_len = len; pHdr->tp_status = TP_STATUS_SEND_REQUEST; rawsock->buffersReady += 1; if (rawsock->buffersReady >= rawsock->frameCount) { AVB_LOG_WARNING("All buffers in ready/unsent state, calling send"); ringRawsockSend(pvRawsock); } AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL); return TRUE; }
// Parse the ethernet frame header. Returns length of header, or -1 for failure int ringRawsockRxParseHdr(void *pvRawsock, U8 *pBuffer, hdr_info_t *pInfo) { AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL); ring_rawsock_t *rawsock = (ring_rawsock_t*)pvRawsock; int hdrLen; if (!VALID_RX_RAWSOCK(rawsock)) { AVB_LOG_ERROR("Parsing Ethernet headers; invalid arguments"); AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL); return -1; } volatile struct tpacket2_hdr *pHdr = (struct tpacket2_hdr*)(pBuffer - rawsock->bufHdrSize); AVB_LOGF_VERBOSE("ringRawsockRxParseHdr: pBuffer=%p, pHdr=%p", pBuffer, pHdr); memset(pInfo, 0, sizeof(hdr_info_t)); eth_hdr_t *pNoTag = (eth_hdr_t*)((U8*)pHdr + pHdr->tp_mac); hdrLen = pHdr->tp_net - pHdr->tp_mac; pInfo->shost = pNoTag->shost; pInfo->dhost = pNoTag->dhost; pInfo->ethertype = ntohs(pNoTag->ethertype); pInfo->ts.tv_sec = pHdr->tp_sec; pInfo->ts.tv_nsec = pHdr->tp_nsec; if (pInfo->ethertype == ETHERTYPE_8021Q) { pInfo->vlan = TRUE; pInfo->vlan_vid = pHdr->tp_vlan_tci & 0x0FFF; pInfo->vlan_pcp = (pHdr->tp_vlan_tci >> 13) & 0x0007; pInfo->ethertype = ntohs(*(U16*)( ((U8*)(&pNoTag->ethertype)) + 4)); hdrLen += 4; }
// Send all packets that are ready (i.e. tell kernel to send them) int ringRawsockSend(void *pvRawsock) { AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL); ring_rawsock_t *rawsock = (ring_rawsock_t*)pvRawsock; if (!VALID_TX_RAWSOCK(rawsock)) { AVB_LOG_ERROR("Send; invalid argument"); AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL); return -1; } // Linux does something dumb to wait for frames to be sent. // Without MSG_DONTWAIT, CPU usage is bad. int flags = MSG_DONTWAIT; int sent = send(rawsock->sock, NULL, 0, flags); if (errno == EINTR) { // ignore } else if (sent < 0) { AVB_LOGF_ERROR("Send failed: %s", strerror(errno)); assert(0); } else { AVB_LOGF_VERBOSE("Sent %d bytes, %d frames", sent, rawsock->buffersReady); rawsock->buffersOut -= rawsock->buffersReady; rawsock->buffersReady = 0; } AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL); return sent; }
static bool openavbAvdeccMsgSrvrReceiveFromClient(int avdeccMsgHandle, openavbAvdeccMessage_t *msg) { AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG); if (!msg) { AVB_LOG_ERROR("Receiving message; invalid argument passed"); AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG); return FALSE; } bool ret = FALSE; switch (msg->type) { case OPENAVB_AVDECC_MSG_VERSION_REQUEST: AVB_LOG_DEBUG("Message received: OPENAVB_AVDECC_MSG_VERSION_REQUEST"); ret = openavbAvdeccMsgSrvrHndlVerRqstFromClient(avdeccMsgHandle); break; case OPENAVB_AVDECC_MSG_CLIENT_INIT_IDENTIFY: AVB_LOG_DEBUG("Message received: OPENAVB_AVDECC_MSG_CLIENT_INIT_IDENTIFY"); ret = openavbAvdeccMsgSrvrHndlInitIdentifyFromClient(avdeccMsgHandle, msg->params.clientInitIdentify.friendly_name, msg->params.clientInitIdentify.talker); break; case OPENAVB_AVDECC_MSG_C2S_TALKER_STREAM_ID: AVB_LOG_DEBUG("Message received: OPENAVB_AVDECC_MSG_C2S_TALKER_STREAM_ID"); ret = openavbAvdeccMsgSrvrHndlTalkerStreamIDFromClient(avdeccMsgHandle, msg->params.c2sTalkerStreamID.sr_class, msg->params.c2sTalkerStreamID.stream_src_mac, ntohs(msg->params.c2sTalkerStreamID.stream_uid), msg->params.c2sTalkerStreamID.stream_dest_mac, ntohs(msg->params.c2sTalkerStreamID.stream_vlan_id)); break; case OPENAVB_AVDECC_MSG_CLIENT_CHANGE_NOTIFICATION: AVB_LOG_DEBUG("Message received: OPENAVB_AVDECC_MSG_CLIENT_CHANGE_NOTIFICATION"); ret = openavbAvdeccMsgSrvrHndlChangeNotificationFromClient(avdeccMsgHandle, (openavbAvdeccMsgStateType_t) msg->params.clientChangeNotification.current_state); break; default: AVB_LOG_ERROR("Unexpected message received at server"); break; } AVB_LOGF_VERBOSE("Message handled, ret=%d", ret); AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG); return ret; }
static bool openavbEptSrvrReceiveFromClient(int h, openavbEndpointMessage_t *msg) { AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT); if (!msg) { AVB_LOG_ERROR("Receiving message; invalid argument passed"); AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT); return FALSE; } bool ret = FALSE; switch (msg->type) { case OPENAVB_ENDPOINT_TALKER_REGISTER: AVB_LOGF_DEBUG("TalkerRegister from client uid=%d", msg->streamID.uniqueID); ret = openavbEptSrvrRegisterStream(h, &msg->streamID, msg->params.talkerRegister.destAddr, &msg->params.talkerRegister.tSpec, msg->params.talkerRegister.srClass, msg->params.talkerRegister.srRank, msg->params.talkerRegister.latency); break; case OPENAVB_ENDPOINT_LISTENER_ATTACH: AVB_LOGF_DEBUG("ListenerAttach from client uid=%d", msg->streamID.uniqueID); ret = openavbEptSrvrAttachStream(h, &msg->streamID, msg->params.listenerAttach.lsnrDecl); break; case OPENAVB_ENDPOINT_CLIENT_STOP: AVB_LOGF_DEBUG("Stop from client uid=%d", msg->streamID.uniqueID); ret = openavbEptSrvrStopStream(h, &msg->streamID); break; case OPENAVB_ENDPOINT_VERSION_REQUEST: AVB_LOG_DEBUG("Version request from client"); ret = openavbEptSrvrHndlVerRqstFromClient(h); break; default: AVB_LOG_ERROR("Unexpected message received at server"); break; } AVB_LOGF_VERBOSE("Message handled, ret=%d", ret); AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT); return ret; }
// Release a TX frame, without marking it as ready to send bool ringRawsockRelTxFrame(void *pvRawsock, U8 *pBuffer) { AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL); ring_rawsock_t *rawsock = (ring_rawsock_t*)pvRawsock; if (!VALID_TX_RAWSOCK(rawsock) || pBuffer == NULL) { AVB_LOG_ERROR("Releasing TX frame; invalid argument"); AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL); return FALSE; } volatile struct tpacket2_hdr *pHdr = (struct tpacket2_hdr*)(pBuffer - rawsock->bufHdrSize); AVB_LOGF_VERBOSE("pBuffer=%p, pHdr=%p", pBuffer, pHdr); pHdr->tp_len = 0; pHdr->tp_status = TP_STATUS_KERNEL; rawsock->buffersOut -= 1; AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL); return TRUE; }
static bool openavbEptSrvrSendToClient(int h, openavbEndpointMessage_t *msg) { AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT); if (h < 0 || h >= POLL_FD_COUNT) { AVB_LOG_ERROR("Sending message; invalid handle"); AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT); return FALSE; } if (!msg) { AVB_LOG_ERROR("Sending message; invalid argument passed"); AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT); return FALSE; } int csock = fds[h].fd; if (csock == SOCK_INVALID) { AVB_LOG_ERROR("Socket closed unexpectedly"); return FALSE; } ssize_t nWrite = write(csock, msg, OPENAVB_ENDPOINT_MSG_LEN); AVB_LOGF_VERBOSE("Sent message, len=%zu, nWrite=%zu", OPENAVB_ENDPOINT_MSG_LEN, nWrite); if (nWrite < OPENAVB_ENDPOINT_MSG_LEN) { if (nWrite < 0) { AVB_LOGF_ERROR("Failed to write socket: %s", strerror(errno)); } else if (nWrite == 0) { AVB_LOG_ERROR("Socket closed unexpectedly"); } else { AVB_LOG_ERROR("Socket write too short"); } socketClose(h); AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT); return FALSE; } AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT); return TRUE; }
// Get a RX frame U8* ringRawsockGetRxFrame(void *pvRawsock, U32 timeout, unsigned int *offset, unsigned int *len) { AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL); ring_rawsock_t *rawsock = (ring_rawsock_t*)pvRawsock; if (!VALID_RX_RAWSOCK(rawsock)) { AVB_LOG_ERROR("Getting RX frame; invalid arguments"); AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL); return NULL; } if (rawsock->buffersOut >= rawsock->frameCount) { AVB_LOG_ERROR("Too many RX buffers in use"); AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL); return NULL; } // Get pointer to active buffer in ring volatile struct tpacket2_hdr *pHdr = (struct tpacket2_hdr*)(rawsock->pMem + (rawsock->blockIndex * rawsock->blockSize) + (rawsock->bufferIndex * rawsock->bufferSize)); volatile U8 *pBuffer = (U8*)pHdr + rawsock->bufHdrSize; AVB_LOGF_VERBOSE("block=%d, buffer=%d, out=%d, pBuffer=%p, pHdr=%p", rawsock->blockIndex, rawsock->bufferIndex, rawsock->buffersOut, pBuffer, pHdr); // Check if buffer ready for user // In receive mode, we want TP_STATUS_USER flag set if ((pHdr->tp_status & TP_STATUS_USER) == 0) { struct timespec ts, *pts = NULL; struct pollfd pfd; // Use poll to wait for "ready to read" condition // Poll even if our timeout is 0 - to catch the case where // kernel is writing to the wrong slot (see below.) if (timeout != OPENAVB_RAWSOCK_BLOCK) { ts.tv_sec = timeout / MICROSECONDS_PER_SECOND; ts.tv_nsec = (timeout % MICROSECONDS_PER_SECOND) * NANOSECONDS_PER_USEC; pts = &ts; } pfd.fd = rawsock->sock; pfd.events = POLLIN; pfd.revents = 0; int ret = ppoll(&pfd, 1, pts, NULL); if (ret < 0) { if (errno != EINTR) { AVB_LOGF_ERROR("Getting RX frame; poll failed: %s", strerror(errno)); } AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL); return NULL; } if ((pfd.revents & POLLIN) == 0) { // timeout AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL); return NULL; } if ((pHdr->tp_status & TP_STATUS_USER) == 0) { // Hmmm, this is unexpected. poll indicated that the // socket was ready to read, but the slot in the TX ring // that we're looking for the kernel to fill isn't filled. // If there aren't any RX buffers held by the application, // we can try to fix this sticky situation... if (rawsock->buffersOut == 0) { // Scan forward through the RX ring, and look for a // buffer that's ready for us to read. The kernel has // a bad habit of not starting at the beginning of the // ring when the listener process is restarted. int nSkipped = 0; while((pHdr->tp_status & TP_STATUS_USER) == 0) { // Move to next slot in ring. // (Increment buffer/block indexes) if (++(rawsock->bufferIndex) >= (rawsock->frameCount/rawsock->blockCount)) { rawsock->bufferIndex = 0; if (++(rawsock->blockIndex) >= rawsock->blockCount) { rawsock->blockIndex = 0; } } // Adjust pHdr, pBuffer to point to the new slot pHdr = (struct tpacket2_hdr*)(rawsock->pMem + (rawsock->blockIndex * rawsock->blockSize) + (rawsock->bufferIndex * rawsock->bufferSize)); pBuffer = (U8*)pHdr + rawsock->bufHdrSize; // If we've scanned all the way around the ring, bail out. if (++nSkipped > rawsock->frameCount) { AVB_LOG_WARNING("Getting RX frame; no frame after poll"); AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL); return NULL; } } // We found a slot that's ready. Hopefully, we're good now. AVB_LOGF_WARNING("Getting RX frame; skipped %d empty slots (rawsock=%p)", nSkipped, rawsock); } else { AVB_LOG_WARNING("Getting RX frame; no frame after poll"); AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL); return NULL; } } } AVB_LOGF_VERBOSE("Buffer status=0x%4.4lx", (unsigned long)pHdr->tp_status); if (pHdr->tp_status & TP_STATUS_COPY) { AVB_LOG_WARNING("Frame too big for receive buffer"); } // Check the "losing" flag. That indicates that the ring is full, // and the kernel had to toss some frames. There is no "winning" flag. if ((pHdr->tp_status & TP_STATUS_LOSING)) { if (!rawsock->bLosing) { AVB_LOG_WARNING("Getting RX frame; mmap buffers full"); rawsock->bLosing = TRUE; } } else { rawsock->bLosing = FALSE; } // increment indexes for next time if (++(rawsock->bufferIndex) >= (rawsock->frameCount/rawsock->blockCount)) { rawsock->bufferIndex = 0; if (++(rawsock->blockIndex) >= rawsock->blockCount) { rawsock->blockIndex = 0; } } // Remember that the client has another buffer rawsock->buffersOut += 1; if (pHdr->tp_snaplen < pHdr->tp_len) { #if (AVB_LOG_LEVEL >= AVB_LOG_LEVEL_VERBOSE) AVB_LOGF_WARNING("Getting RX frame; partial frame ignored (len %d, snaplen %d)", pHdr->tp_len, pHdr->tp_snaplen); AVB_LOG_BUFFER(AVB_LOG_LEVEL_VERBOSE, (const U8 *) pBuffer + (pHdr->tp_mac - rawsock->bufHdrSize), pHdr->tp_len, 16); #else IF_LOG_INTERVAL(1000) AVB_LOGF_WARNING("Getting RX frame; partial frame ignored (len %d, snaplen %d)", pHdr->tp_len, pHdr->tp_snaplen); #endif ringRawsockRelRxFrame(rawsock, (U8*)pBuffer); AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL); return NULL; } // Return pointer to the buffer and length *offset = pHdr->tp_mac - rawsock->bufHdrSize; *len = pHdr->tp_snaplen; AVB_LOGF_VERBOSE("Good RX frame (len %d, snaplen %d)", pHdr->tp_len, pHdr->tp_snaplen); AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL); return (U8*)pBuffer; }
// Get a buffer from the ring to use for TX U8* ringRawsockGetTxFrame(void *pvRawsock, bool blocking, unsigned int *len) { AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL); ring_rawsock_t *rawsock = (ring_rawsock_t*)pvRawsock; // Displays only warning when buffer busy after second try int bBufferBusyReported = 0; if (!VALID_TX_RAWSOCK(rawsock) || len == NULL) { AVB_LOG_ERROR("Getting TX frame; bad arguments"); AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL); return NULL; } if (rawsock->buffersOut >= rawsock->frameCount) { AVB_LOG_ERROR("Getting TX frame; too many TX buffers in use"); AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL); return NULL; } // Get pointer to next framebuf. volatile struct tpacket2_hdr *pHdr = (struct tpacket2_hdr*)(rawsock->pMem + (rawsock->blockIndex * rawsock->blockSize) + (rawsock->bufferIndex * rawsock->bufferSize)); // And pointer to portion of buffer to be filled with frame volatile U8 *pBuffer = (U8*)pHdr + rawsock->bufHdrSize; AVB_LOGF_VERBOSE("block=%d, buffer=%d, out=%d, pBuffer=%p, pHdr=%p", rawsock->blockIndex, rawsock->bufferIndex, rawsock->buffersOut, pBuffer, pHdr); // Check if buffer ready for user // In send mode, we want to see TP_STATUS_AVAILABLE while (pHdr->tp_status != TP_STATUS_AVAILABLE) { switch (pHdr->tp_status) { case TP_STATUS_SEND_REQUEST: case TP_STATUS_SENDING: if (blocking) { #if 0 // We should be able to poll on the socket to wait for the buffer to // be ready, but it doesn't work (at least on 2.6.37). // Keep this code, because it may work on newer kernels // poll until tx buffer is ready struct pollfd pfd; pfd.fd = rawsock->sock; pfd.events = POLLWRNORM; pfd.revents = 0; int ret = poll(&pfd, 1, -1); if (ret < 0 && errno != EINTR) { AVB_LOGF_DEBUG("getting TX frame; poll failed: %s", strerror(errno)); } #else // Can't poll, so sleep instead to avoid tight loop if(0 == bBufferBusyReported) { if(!rawsock->txOutOfBuffer) { // Display this info only once just to let know that something like this happened AVB_LOGF_INFO("Getting TX frame (sock=%d): TX buffer busy", rawsock->sock); } ++rawsock->txOutOfBuffer; ++rawsock->txOutOfBufferCyclic; } else if(1 == bBufferBusyReported) { //Display this warning if buffer was busy more than once because it might influence late/lost AVB_LOGF_WARNING("Getting TX frame (sock=%d): TX buffer busy after usleep(50) verify if there are any lost/late frames", rawsock->sock); } ++bBufferBusyReported; usleep(50); #endif } else { AVB_LOG_DEBUG("Non-blocking, return NULL"); AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL); return NULL; } break; case TP_STATUS_WRONG_FORMAT: default: pHdr->tp_status = TP_STATUS_AVAILABLE; break; } } // Remind client how big the frame buffer is if (len) *len = rawsock->base.frameSize; // increment indexes to point to next buffer if (++(rawsock->bufferIndex) >= (rawsock->frameCount/rawsock->blockCount)) { rawsock->bufferIndex = 0; if (++(rawsock->blockIndex) >= rawsock->blockCount) { rawsock->blockIndex = 0; } } // increment the count of buffers held by client rawsock->buffersOut += 1; // warn if too many are out if (rawsock->buffersOut >= (rawsock->frameCount * 4)/5) { AVB_LOGF_WARNING("Getting TX frame; consider increasing buffers: count=%d, out=%d", rawsock->frameCount, rawsock->buffersOut); } AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL); return (U8*)pBuffer; }
void openavbEptSrvrService(void) { AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT); struct sockaddr_un addrClient; socklen_t lenAddr; int i, j; int csock; int nfds = POLL_FD_COUNT; int pRet; AVB_LOG_VERBOSE("Waiting for event..."); pRet = poll(fds, nfds, 1000); if (pRet == 0) { AVB_LOG_VERBOSE("poll timeout"); } else if (pRet < 0) { if (errno == EINTR) { AVB_LOG_VERBOSE("Poll interrupted"); } else { AVB_LOGF_ERROR("Poll error: %s", strerror(errno)); } } else { AVB_LOGF_VERBOSE("Poll returned %d events", pRet); for (i=0; i<nfds; i++) { if (fds[i].revents != 0) { AVB_LOGF_VERBOSE("%d sock=%d, event=0x%x, revent=0x%x", i, fds[i].fd, fds[i].events, fds[i].revents); if (i == AVB_ENDPOINT_LISTEN_FDS) { // listen sock - indicates new connection from client lenAddr = sizeof(addrClient); csock = accept(lsock, (struct sockaddr*)&addrClient, &lenAddr); if (csock < 0) { AVB_LOGF_ERROR("Failed to accept connection: %s", strerror(errno)); } else { for (j = 0; j < POLL_FD_COUNT; j++) { if (fds[j].fd == SOCK_INVALID) { fds[j].fd = csock; fds[j].events = POLLIN; break; } } if (j >= POLL_FD_COUNT) { AVB_LOG_ERROR("Too many client connections"); close(csock); } } } else { csock = fds[i].fd; openavbEndpointMessage_t msgBuf; memset(&msgBuf, 0, OPENAVB_ENDPOINT_MSG_LEN); ssize_t nRead = read(csock, &msgBuf, OPENAVB_ENDPOINT_MSG_LEN); AVB_LOGF_VERBOSE("Socket read h=%d,fd=%d: read=%zu, expect=%zu", i, csock, nRead, OPENAVB_ENDPOINT_MSG_LEN); if (nRead < OPENAVB_ENDPOINT_MSG_LEN) { // sock closed if (nRead == 0) { AVB_LOGF_DEBUG("Socket closed, h=%d", i); } else if (nRead < 0) { AVB_LOGF_ERROR("Socket read, h=%d: %s", i, strerror(errno)); } else { AVB_LOGF_ERROR("Short read, h=%d", i); } socketClose(i); } else { // got a message if (!openavbEptSrvrReceiveFromClient(i, &msgBuf)) { AVB_LOG_ERROR("Failed to handle message"); socketClose(i); } } } } } } AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT); }