Beispiel #1
0
EXTERN_DLL_EXPORT bool openavbTLReadIniFileOsal(tl_handle_t TLhandle, const char *fileName, openavb_tl_cfg_t *pCfg, openavb_tl_cfg_name_value_t *pNVCfg)
{
	AVB_TRACE_ENTRY(AVB_TRACE_TL);

	parse_ini_data_t parseIniData;
	parseIniData.pTLState = (tl_state_t *)TLhandle;
	parseIniData.pCfg = pCfg;
	parseIniData.pNVCfg = pNVCfg;

	int result = ini_parse(fileName, openavbTLCfgCallback, &parseIniData);
	if (result == 0) {
		if_info_t ifinfo;
		if (!openavbCheckInterface(&parseIniData.pCfg->ifname, &ifinfo)) {
			AVB_LOGF_ERROR("Invalid value: name=%s, value=%s", "ifname", parseIniData.pCfg->ifname);
			return FALSE;
		}
	}
	if (result < 0) {
		AVB_LOGF_ERROR("Couldn't parse INI file: %s", fileName);
		return FALSE;
	}
	if (result > 0) {
		AVB_LOGF_ERROR("Error in INI file: %s, line %d", fileName, result);
		return FALSE;
	}

	AVB_TRACE_EXIT(AVB_TRACE_TL);
	return TRUE;
}
Beispiel #2
0
// Open a rawsock for TX or RX
void *pcapRawsockOpen(pcap_rawsock_t* rawsock, const char *ifname, bool rx_mode, bool tx_mode, U16 ethertype, U32 frame_size, U32 num_frames)
{
	AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK);

	AVB_LOGF_DEBUG("Open, rx=%d, tx=%d, ethertype=%x size=%d, num=%d",	rx_mode, tx_mode, ethertype, frame_size, num_frames);

	baseRawsockOpen(&rawsock->base, ifname, rx_mode, tx_mode, ethertype, frame_size, num_frames);

	if (tx_mode) {
		AVB_LOG_DEBUG("pcap rawsock transmit mode will bypass FQTSS");
	}

	rawsock->handle = 0;

	// Get info about the network device
	if (!simpleAvbCheckInterface(ifname, &(rawsock->base.ifInfo))) {
		AVB_LOGF_ERROR("Creating rawsock; bad interface name: %s", ifname);
		free(rawsock);
		AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
		return NULL;
	}

	// Deal with frame size.
	if (rawsock->base.frameSize == 0) {
		// use interface MTU as max frames size, if none specified
		rawsock->base.frameSize = rawsock->base.ifInfo.mtu + ETH_HLEN + VLAN_HLEN;
	}
	else if (rawsock->base.frameSize > rawsock->base.ifInfo.mtu + ETH_HLEN + VLAN_HLEN) {
		AVB_LOG_ERROR("Creating rawsock; requested frame size exceeds MTU");
		free(rawsock);
		AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
		return NULL;
	}

	char errbuf[PCAP_ERRBUF_SIZE];
	rawsock->handle = open_pcap_dev(ifname, rawsock->base.frameSize, errbuf);
	if (!rawsock->handle) {
		AVB_LOGF_ERROR("Cannot open device %s: %s", ifname, errbuf);
		free(rawsock);
		AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
		return NULL;
	}

	// fill virtual functions table
	rawsock_cb_t *cb = &rawsock->base.cb;
	cb->close = pcapRawsockClose;
	cb->getTxFrame = pcapRawsockGetTxFrame;
	cb->txFrameReady = pcapRawsockTxFrameReady;
	cb->send = pcapRawsockSend;
	cb->getRxFrame = pcapRawsockGetRxFrame;
	cb->rxMulticast = pcapRawsockRxMulticast;
	cb->rxParseHdr = pcapRawsockRxParseHdr;

	AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
	return rawsock;
}
/* Listener client attaches to a stream
 */
bool openavbEptSrvrAttachStream(int h,
                            AVBStreamID_t *streamID,
                            openavbSrpLsnrDeclSubtype_t ld)
{
	openavbRC rc = OPENAVB_SUCCESS;
	static U8 emptyMAC[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
	static AVBTSpec_t emptytSpec = {0, 0};

	AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);

	clientStream_t *ps = findStream(streamID);
	if (ps && ps->clientHandle != h) {
		AVB_LOGF_ERROR("Error attaching listener: multiple clients for stream %d", streamID->uniqueID);
		AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
		return FALSE;
	}

	if (!ps) {
		ps = addStream(h, streamID);
		if (!ps) {
			AVB_LOGF_ERROR("Error attaching listener: unable to add client stream %d", streamID->uniqueID);
			AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
			return FALSE;
		}
		ps->role = clientListener;
	}

	if(x_cfg.noSrp) {
		// we are operating in a mode supporting preconfigured streams; SRP is not in use,
		if(ld == openavbSrp_LDSt_Interest) {
			// As a proxy for SRP, which would normally make this call after confirming
			// availability of the stream, call the callback from here
			strmRegCb((void*)ps, openavbSrp_AtTyp_TalkerAdvertise,
					  emptyMAC, // a flag to listener to read info from configuration file
					  &emptytSpec,
					  MAX_AVB_SR_CLASSES, // srClass - value doesn't matter because openavbEptSrvrNotifyLstnrOfSrpCb() throws it away
					  1, // accumLatency
					  NULL); // *failInfo
		}
	} else {
		// Normal SRP Operation so pass to SRP
		rc = openavbSrpAttachStream((void*)ps, streamID, ld);
		if (!IS_OPENAVB_SUCCESS(rc))
			delStream(ps);
	}

	openavbEndPtLogAllStaticStreams();

	AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
	return IS_OPENAVB_SUCCESS(rc);
}
Beispiel #4
0
// 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;
}
Beispiel #5
0
U8 *pcapRawsockGetRxFrame(void *pvRawsock, U32 timeout, unsigned int *offset, unsigned int *len)
{
	pcap_rawsock_t *rawsock = (pcap_rawsock_t*)pvRawsock;

	rawsock->rxHeader = 0;
	const u_char *packet = 0;
	int ret;

	if (rawsock) {
		ret = pcap_next_ex(rawsock->handle, &rawsock->rxHeader, &packet);
		switch(ret) {
		case 1:
			*offset = 0;
			*len = rawsock->rxHeader->caplen;
			return (U8*)packet;
		case -1:
			AVB_LOGF_ERROR("pcap_next_ex failed: %s", pcap_geterr(rawsock->handle));
			break;
		case 0:
			// timeout;
			break;
		case -2:
			// no packets to be read from savefile
			// this should not happened
			break;
		default:
			break;
		}
	}

	return NULL;
}
bool openavbAvdeccMsgSrvrTalkerStreamID(int avdeccMsgHandle,
	U8 sr_class, U8 stream_id_valid, const U8 stream_src_mac[6], U16 stream_uid, U8 stream_dest_valid, const U8 stream_dest_mac[6], U8 stream_vlan_id_valid, U16 stream_vlan_id)
{
	AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
	openavbAvdeccMessage_t msgBuf;

	avdecc_msg_state_t *pState = AvdeccMsgStateListGet(avdeccMsgHandle);
	if (!pState) {
		AVB_LOGF_ERROR("avdeccMsgHandle %d not valid", avdeccMsgHandle);
		AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
		return false;
	}

	// Send the stream information to the client.
	memset(&msgBuf, 0, OPENAVB_AVDECC_MSG_LEN);
	msgBuf.type = OPENAVB_AVDECC_MSG_S2C_TALKER_STREAM_ID;
	openavbAvdeccMsgParams_S2C_TalkerStreamID_t * pParams =
		&(msgBuf.params.s2cTalkerStreamID);
	pParams->sr_class = sr_class;
	pParams->stream_id_valid = stream_id_valid;
	memcpy(pParams->stream_src_mac, stream_src_mac, 6);
	pParams->stream_uid = htons(stream_uid);
	pParams->stream_dest_valid = stream_dest_valid;
	memcpy(pParams->stream_dest_mac, stream_dest_mac, 6);
	pParams->stream_vlan_id_valid = stream_vlan_id_valid;
	pParams->stream_vlan_id = htons(stream_vlan_id);
	bool ret = openavbAvdeccMsgSrvrSendToClient(avdeccMsgHandle, &msgBuf);

	AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
	return ret;
}
bool openavbAvdeccMsgSrvrChangeRequest(int avdeccMsgHandle, openavbAvdeccMsgStateType_t desiredState)
{
	AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
	openavbAvdeccMessage_t msgBuf;

	avdecc_msg_state_t *pState = AvdeccMsgStateListGet(avdeccMsgHandle);
	if (!pState) {
		AVB_LOGF_ERROR("avdeccMsgHandle %d not valid", avdeccMsgHandle);
		AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
		return false;
	}

	memset(&msgBuf, 0, OPENAVB_AVDECC_MSG_LEN);
	msgBuf.type = OPENAVB_AVDECC_MSG_CLIENT_CHANGE_REQUEST;
	openavbAvdeccMsgParams_ClientChangeRequest_t * pParams =
		&(msgBuf.params.clientChangeRequest);
	pParams->desired_state = (U8) desiredState;
	bool ret = openavbAvdeccMsgSrvrSendToClient(avdeccMsgHandle, &msgBuf);
	if (ret) {
		// Save the requested state for future reference.
		pState->lastRequestedState = desiredState;
	}

	AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
	return ret;
}
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;
}
bool openavbEndpointServerOpen(void)
{
    AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
    int i;

    for (i=0; i < POLL_FD_COUNT; i++) {
        fds[i].fd = SOCK_INVALID;
        fds[i].events = 0;
    }

    lsock = socket(AF_UNIX, SOCK_STREAM, 0);
    if (lsock < 0) {
        AVB_LOGF_ERROR("Failed to open socket: %s", strerror(errno));
        goto error;
    }
    // serverAddr is file static
    serverAddr.sun_family = AF_UNIX;
    snprintf(serverAddr.sun_path, UNIX_PATH_MAX, AVB_ENDPOINT_UNIX_PATH);

    int rslt = bind(lsock, (struct sockaddr*)&serverAddr, sizeof(struct sockaddr_un));
    if (rslt != 0) {
        AVB_LOGF_ERROR("Failed to create %s: %s", serverAddr.sun_path, strerror(errno));
        AVB_LOG_WARNING("** If endpoint process crashed, run the cleanup script **");
        goto error;
    }

    rslt = listen(lsock, 5);
    if (rslt != 0) {
        AVB_LOGF_ERROR("Failed to listen on socket: %s", strerror(errno));
        goto error;
    }
    AVB_LOGF_DEBUG("Listening on socket: %s", serverAddr.sun_path);

    fds[AVB_ENDPOINT_LISTEN_FDS].fd = lsock;
    fds[AVB_ENDPOINT_LISTEN_FDS].events = POLLIN;

    AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
    return TRUE;

error:
    if (lsock >= 0) {
        close(lsock);
        lsock = -1;
    }
    AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
    return FALSE;
}
Beispiel #10
0
bool parse_mac(const char *str, cfg_mac_t *mac)
{
	memset(&mac->buffer, 0, sizeof(struct ether_addr));

	mac->mac = ether_aton_r(str, &mac->buffer);
	if (mac->mac)
		return TRUE;

	AVB_LOGF_ERROR("Failed to parse addr: %s", str);
	return FALSE;
}
bool openavbAvdeccMsgSrvrHndlTalkerStreamIDFromClient(int avdeccMsgHandle, U8 sr_class, const U8 stream_src_mac[6], U16 stream_uid, const U8 stream_dest_mac[6], U16 stream_vlan_id)
{
	AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);

	avdecc_msg_state_t *pState = AvdeccMsgStateListGet(avdeccMsgHandle);
	if (!pState) {
		AVB_LOGF_ERROR("avdeccMsgHandle %d not valid", avdeccMsgHandle);
		AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
		return false;
	}

	openavb_tl_data_cfg_t *pCfg = pState->stream;
	if (!pCfg) {
		AVB_LOGF_ERROR("avdeccMsgHandle %d stream not valid", avdeccMsgHandle);
		AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
		return false;
	}

	// Update the stream information supplied by the client.
	pCfg->sr_class = sr_class;
	memcpy(pCfg->stream_addr.buffer.ether_addr_octet, stream_src_mac, 6);
	pCfg->stream_addr.mac = &(pCfg->stream_addr.buffer); // Indicate that the MAC Address is valid.
	pCfg->stream_uid = stream_uid;
	memcpy(pCfg->dest_addr.buffer.ether_addr_octet, stream_dest_mac, 6);
	pCfg->dest_addr.mac = &(pCfg->dest_addr.buffer); // Indicate that the MAC Address is valid.
	pCfg->vlan_id = stream_vlan_id;
	AVB_LOGF_DEBUG("Talker-supplied sr_class:  %u", pCfg->sr_class);
	AVB_LOGF_DEBUG("Talker-supplied stream_id:  " ETH_FORMAT "/%u",
		ETH_OCTETS(pCfg->stream_addr.buffer.ether_addr_octet), pCfg->stream_uid);
	AVB_LOGF_DEBUG("Talker-supplied dest_addr:  " ETH_FORMAT,
		ETH_OCTETS(pCfg->dest_addr.buffer.ether_addr_octet));
	AVB_LOGF_DEBUG("Talker-supplied vlan_id:  %u", pCfg->vlan_id);

	// Notify the state machine that we received this information.
	openavbAcmpSMTalker_updateStreamInfo(pCfg);

	AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
	return true;
}
Beispiel #12
0
// Setup the rawsock to receive multicast packets
bool pcapRawsockRxMulticast(void *pvRawsock, bool add_membership, const U8 addr[ETH_ALEN])
{
	pcap_rawsock_t *rawsock = (pcap_rawsock_t*)pvRawsock;

	struct bpf_program comp_filter_exp;
	char filter_exp[30];

	sprintf(filter_exp, "ether dst %02x:%02x:%02x:%02x:%02x:%02x", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);

	AVB_LOGF_DEBUG("%s %d %s", __func__, (int)add_membership, filter_exp);

	if (pcap_compile(rawsock->handle, &comp_filter_exp, filter_exp, 0, PCAP_NETMASK_UNKNOWN) < 0) {
		AVB_LOGF_ERROR("Could not parse filter %s: %s", filter_exp, pcap_geterr(rawsock->handle));
		return false;
	}

	if (pcap_setfilter(rawsock->handle, &comp_filter_exp) < 0) {
		AVB_LOGF_ERROR("Could not install filter %s: %s", filter_exp, pcap_geterr(rawsock->handle));
		return false;
	}

	return true;
}
// Parse ini file, and create config data
//
int openavbReadConfig(const char *ini_file, openavb_endpoint_cfg_t *pCfg)
{
	AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);

	// defaults - most are handled by setting everything to 0
	memset(pCfg, 0, sizeof(openavb_endpoint_cfg_t));
	pCfg->fqtss_mode = -1;

	int result = ini_parse(ini_file, cfgCallback, pCfg);
	if (result < 0) {
		AVB_LOGF_ERROR("Couldn't parse INI file: %s", ini_file);
		return -1;
    }
	if (result > 0) {
		AVB_LOGF_ERROR("Error in INI file: %s, line %d", ini_file, result);
		return -1;
    }

	AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);

	// Yay, we did it.
	return 0;
}
Beispiel #14
0
bool pcapRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len, U64 timeNsec)
{
	pcap_rawsock_t *rawsock = (pcap_rawsock_t*)pvRawsock;
	int ret = -1;

	if (timeNsec) {
		IF_LOG_INTERVAL(1000) AVB_LOG_WARNING("launch time is unsupported in pcap_rawsock");
	}

	if (rawsock) {
		ret = pcap_sendpacket(rawsock->handle, pBuffer, len);
		if (ret == -1) {
			AVB_LOGF_ERROR("pcap_sendpacket failed: %s", pcap_geterr(rawsock->handle));
		}

	}
	return ret == 0;
}
void openavbEndpointServerClose(void)
{
    AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
    int i;
    for (i = 0; i < POLL_FD_COUNT; i++) {
        if (fds[i].fd != SOCK_INVALID) {
            close(fds[i].fd);
        }
    }
    if (lsock != SOCK_INVALID) {
        close(lsock);
    }

    if (unlink(serverAddr.sun_path) != 0) {
        AVB_LOGF_ERROR("Failed to unlink %s: %s", serverAddr.sun_path, strerror(errno));
    }
    AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
}
/* Client (talker or listener) going away
 */
bool openavbEptSrvrStopStream(int h, AVBStreamID_t *streamID)
{
	AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);

	clientStream_t *ps = findStream(streamID);
	if (!ps || ps->clientHandle != h) {
		AVB_LOGF_ERROR("Error stopping client: missing record for stream %d", streamID->uniqueID);
		AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
		return FALSE;
	}

	bool rc = FALSE;
	if (ps->role == clientTalker)
		rc = x_talkerDeregister(ps);
	else if (ps->role == clientListener)
		rc = x_listenerDetach(ps);

	AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
	return rc;
}
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;
}
Beispiel #18
0
static bool openMapLib(tl_state_t *pTLState)
{
// OpenAVB using static mapping plugins therefore don't attempt to open a library
#if 0
	// Opening library
	if (pTLState->mapLib.libName) {
		AVB_LOGF_INFO("Attempting to open library: %s", pTLState->mapLib.libName);
		pTLState->mapLib.libHandle = dlopen(pTLState->mapLib.libName, RTLD_LAZY);
		if (!pTLState->mapLib.libHandle) {
			AVB_LOG_ERROR("Unable to open the mapping library.");
			return FALSE;
		}
	}
#endif

	// Looking up function entry
	if (!pTLState->mapLib.funcName) {
		AVB_LOG_ERROR("Mapping initialize function not set.");
		return FALSE;
	}

	char *error;
	AVB_LOGF_INFO("Looking up symbol for function: %s", pTLState->mapLib.funcName);
	if (pTLState->mapLib.libHandle) {
		pTLState->cfg.pMapInitFn = dlsym(pTLState->mapLib.libHandle, pTLState->mapLib.funcName);
	}
	else {
		pTLState->cfg.pMapInitFn = dlsym(RTLD_DEFAULT, pTLState->mapLib.funcName);
	}
	if ((error = dlerror()) != NULL)  {
		AVB_LOGF_ERROR("Mapping initialize function lookup error: %s.", error);
		return FALSE;
	}

	return TRUE;
}
// A call to this callback indicates that this interface module will be
// a listener. Any listener initialization can be done in this function.
void openavbIntfMpeg2tsGstRxInitCB(media_q_t *pMediaQ)
{
	AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);

	if (pMediaQ)
	{
		pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
		if (!pPvtData)
		{
			AVB_LOG_ERROR("Private interface module data not allocated.");
			return;
		}

		pPvtData->pipe = (GstElement*)NULL;
		pPvtData->appsink = (GstAppSink*)NULL;
		pPvtData->appsrc = (GstAppSrc*)NULL;
		pPvtData->bus = (GstBus*)NULL;
		pPvtData->srcPaused = FALSE;

		GError *error = NULL;
		pPvtData->pipe = gst_parse_launch(pPvtData->pPipelineStr, &error);
		if (error)
		{
			AVB_LOGF_ERROR("Error creating pipeline: %s", error->message);
			return;
		}

		AVB_LOGF_INFO("Pipeline: %s", pPvtData->pPipelineStr);
		pPvtData->appsrc = GST_APP_SRC(gst_bin_get_by_name(GST_BIN(pPvtData->pipe), APPSRC_NAME));
		if (!pPvtData->appsrc)
		{
			AVB_LOG_ERROR("Failed to find appsrc element");
			return;
		}

		// Make appsrc non-blocking
		g_object_set(G_OBJECT(pPvtData->appsrc), "block", FALSE, NULL);

		// create bus
		pPvtData->bus = gst_pipeline_get_bus(GST_PIPELINE(pPvtData->pipe));
		if (!pPvtData->bus)
		{
			AVB_LOG_ERROR("Failed to create bus");
			return;
		}

		/* add callback for bus messages */
		gst_bus_add_watch(pPvtData->bus, (GstBusFunc)bus_message, pMediaQ);

		// Setup callback function to handle request from src to pause/start data flow
		GstAppSrcCallbacks cbfns;
		memset(&cbfns, 0, sizeof(GstAppSrcCallbacks));
		cbfns.enough_data = srcStopFeed;
		cbfns.need_data = srcStartFeed;
		gst_app_src_set_callbacks(pPvtData->appsrc, &cbfns, (gpointer)(pMediaQ), NULL);

		// Set most capabilities in pipeline (config), not code

		// Don't block
		g_object_set(pPvtData->appsrc, "block", 0, NULL);

		// PLAY
		gst_element_set_state(pPvtData->pipe, GST_STATE_PLAYING);
	}

	AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
}
bool openavbIntfMpeg2tsGstTxCB(media_q_t *pMediaQ)
{
	AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);

	if (!pMediaQ)
	{
		AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
		return FALSE;
	}

	pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
	if (!pPvtData)
	{
		AVB_LOG_ERROR("Private interface module data not allocated.");
		return FALSE;
	}

	if (!pPvtData->appsink)
	{
		AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
		return FALSE;
	}

	media_q_item_t *pMediaQItem;
	GstAlBuf *txBuf;

	while (g_atomic_int_get(&pPvtData->nWaiting) > 0)
	{

		// Get a mediaQItem to hold the buffered data
		pMediaQItem = openavbMediaQHeadLock(pMediaQ);
		if (!pMediaQItem)
		{
			IF_LOG_INTERVAL(1000) AVB_LOG_ERROR("Media queue full");
			break;
		}

		/* Retrieve the buffer
		 */
		txBuf = gst_al_pull_buffer(pPvtData->appsink);

		if (txBuf)
		{
			g_atomic_int_add(&pPvtData->nWaiting, -1);
			if ( GST_AL_BUF_SIZE(txBuf) > pMediaQItem->itemSize )
			{
				AVB_LOGF_ERROR("GStreamer buffer too large (size=%d) for mediaQ item (dataLen=%d)",
				               GST_AL_BUF_SIZE(txBuf), pMediaQItem->itemSize);
				pMediaQItem->dataLen = 0;
				openavbMediaQHeadUnlock(pMediaQ);
			}
			else
			{
				memcpy(pMediaQItem->pPubData, GST_AL_BUF_DATA(txBuf), GST_AL_BUF_SIZE(txBuf));
				pMediaQItem->dataLen = GST_AL_BUF_SIZE(txBuf);
				openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime);
				openavbMediaQHeadPush(pMediaQ);
			}
			gst_al_buffer_unref(txBuf);
		}
		else
		{
			AVB_LOG_ERROR("GStreamer buffer pull failed");
			// assume the pipeline is empty
			g_atomic_int_set(&pPvtData->nWaiting, 0);
			// abandon the mediaq item
			pMediaQItem->dataLen = 0;
			openavbMediaQHeadUnlock(pMediaQ);
			// and get out
			break;
		}
	}

	AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
	return TRUE;
}
// A call to this callback indicates that this interface module will be
// a talker. Any talker initialization can be done in this function.
void openavbIntfMpeg2tsGstTxInitCB(media_q_t *pMediaQ)
{
	AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);

	if (pMediaQ)
	{
		pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
		if (!pPvtData)
		{
			AVB_LOG_ERROR("Private interface module data not allocated.");
			return;
		}

		pPvtData->pipe = (GstElement*)NULL;
		pPvtData->appsink = (GstAppSink*)NULL;
		pPvtData->appsrc = (GstAppSrc*)NULL;
		pPvtData->bus = (GstBus*)NULL;
		pPvtData->nWaiting = 0;

		GError *error = NULL;
		pPvtData->pipe = gst_parse_launch(pPvtData->pPipelineStr, &error);
		if (error)
		{
			AVB_LOGF_ERROR("Error creating pipeline: %s", error->message);
			return;
		}

		AVB_LOGF_INFO("Pipeline: %s", pPvtData->pPipelineStr);
		pPvtData->appsink = GST_APP_SINK(gst_bin_get_by_name(GST_BIN(pPvtData->pipe), APPSINK_NAME));
		if (!pPvtData->appsink)
		{
			AVB_LOG_ERROR("Failed to find appsink element");
			return;
		}

		// create bus
		pPvtData->bus = gst_pipeline_get_bus(GST_PIPELINE(pPvtData->pipe));
		if (!pPvtData->bus)
		{
			AVB_LOG_ERROR("Failed to create bus");
			return;
		}

		/* add callback for bus messages */
		gst_bus_add_watch(pPvtData->bus, (GstBusFunc)bus_message, pMediaQ);

		// Setup callback function to handle new buffers delivered to sink
		GstAppSinkCallbacks cbfns;
		memset(&cbfns, 0, sizeof(GstAppSinkCallbacks));

		gst_al_set_callback(&cbfns, sinkNewBufferSample);

		gst_app_sink_set_callbacks(pPvtData->appsink, &cbfns, (gpointer)(pMediaQ), NULL);

		// Set most capabilities in pipeline (config), not code

		// Don't drop buffers
		g_object_set(pPvtData->appsink, "drop", 0, NULL);

		// Start playing
		gst_element_set_state(pPvtData->pipe, GST_STATE_PLAYING);
	}

	AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
}
static gboolean
bus_message(GstBus *bus, GstMessage *message, void *pv)
{
	switch (GST_MESSAGE_TYPE(message))
	{
		case GST_MESSAGE_ERROR:
		{
			GError *err = NULL;
			gchar *dbg_info = NULL;

			gst_message_parse_error(message, &err, &dbg_info);
			AVB_LOGF_ERROR("GStreamer ERROR message from element %s: %s",
			               GST_OBJECT_NAME(message->src),
			               err->message);
			AVB_LOGF_ERROR("Additional info: %s\n", (dbg_info) ? dbg_info : "none");
			g_error_free(err);
			g_free(dbg_info);
			break;
		}
		case GST_MESSAGE_WARNING:
		{
			GError *err = NULL;
			gchar *dbg_info = NULL;

			gst_message_parse_warning(message, &err, &dbg_info);
			AVB_LOGF_WARNING("GStreamer WARNING message from element %s: %s",
			                 GST_OBJECT_NAME(message->src),
			                 err->message);
			AVB_LOGF_WARNING("Additional info: %s\n", (dbg_info) ? dbg_info : "none");
			g_error_free(err);
			g_free(dbg_info);
			break;
		}
		case GST_MESSAGE_INFO:
		{
			GError *err = NULL;
			gchar *dbg_info = NULL;

			gst_message_parse_info(message, &err, &dbg_info);
			AVB_LOGF_ERROR("GStreamer INFO message from element %s: %s",
			               GST_OBJECT_NAME(message->src),
			               err->message);
			AVB_LOGF_ERROR("Additional info: %s\n", (dbg_info) ? dbg_info : "none");
			g_error_free(err);
			g_free(dbg_info);
			break;
		}
		case GST_MESSAGE_STATE_CHANGED:
		{
			GstState old_state, new_state;
			gst_message_parse_state_changed(message, &old_state, &new_state, NULL);
			AVB_LOGF_DEBUG("Element %s changed state from %s to %s",
			               GST_OBJECT_NAME(message->src),
			               gst_element_state_get_name(old_state),
			               gst_element_state_get_name(new_state));
			break;
		}
		case GST_MESSAGE_STREAM_STATUS:
		{
			// not so valuable
			break;
		}
		case GST_MESSAGE_EOS:
			AVB_LOG_INFO("EOS received");
			break;
		default:
			AVB_LOGF_INFO("GStreamer '%s' message from element %s",
			              gst_message_type_get_name(GST_MESSAGE_TYPE(message)),
			              GST_OBJECT_NAME(message->src));
			break;
	}

	return TRUE;
}
bool openavbAvdeccMsgSrvrHndlChangeNotificationFromClient(int avdeccMsgHandle, openavbAvdeccMsgStateType_t currentState)
{
	AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);

	avdecc_msg_state_t *pState = AvdeccMsgStateListGet(avdeccMsgHandle);
	if (!pState) {
		AVB_LOGF_ERROR("avdeccMsgHandle %d not valid", avdeccMsgHandle);
		AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
		return false;
	}

	// Save the updated state.
	if (currentState != pState->lastReportedState) {
		openavbAvdeccMsgStateType_t previousState = pState->lastReportedState;
		pState->lastReportedState = currentState;
		AVB_LOGF_INFO("Notified of client %d state change from %s to %s (Last requested:  %s)",
				avdeccMsgHandle, GetStateString(previousState), GetStateString(currentState), GetStateString(pState->lastRequestedState));

		// If AVDECC did not yet set the client state, set the client state to the desired state.
		if (pState->lastRequestedState == OPENAVB_AVDECC_MSG_UNKNOWN) {
			if (pState->stream->initial_state == TL_INIT_STATE_RUNNING && pState->lastReportedState != OPENAVB_AVDECC_MSG_RUNNING) {
				// Have the client be running if the user explicitly requested it to be running.
				openavbAvdeccMsgSrvrChangeRequest(avdeccMsgHandle, OPENAVB_AVDECC_MSG_RUNNING);
			}
			else if (pState->stream->initial_state != TL_INIT_STATE_RUNNING && pState->lastReportedState == OPENAVB_AVDECC_MSG_RUNNING) {
				// Have the client not be running if the user didn't explicitly request it to be running.
				openavbAvdeccMsgSrvrChangeRequest(avdeccMsgHandle, OPENAVB_AVDECC_MSG_STOPPED);
			}
			else if (gAvdeccCfg.bFastConnectSupported &&
					!(pState->bTalker) &&
					pState->lastReportedState == OPENAVB_AVDECC_MSG_STOPPED) {
				// Listener started as not running, and is not configured to start in the running state.
				// See if we should do a fast connect using the saved state.
				openavb_tl_data_cfg_t *pCfg = pState->stream;
				if (pCfg) {
					U16 flags, talker_unique_id;
					U8 talker_entity_id[8], controller_entity_id[8];
					bool bAvailable = openavbAvdeccGetSaveStateInfo(pCfg, &flags, &talker_unique_id, &talker_entity_id, &controller_entity_id);
					if (bAvailable) {
						openavbAcmpSMListenerSet_doFastConnect(pCfg, flags, talker_unique_id, talker_entity_id, controller_entity_id);
					}
				}
			}
		}
		else if (currentState == OPENAVB_AVDECC_MSG_STOPPED_UNEXPECTEDLY) {
			if (previousState != OPENAVB_AVDECC_MSG_STOPPED_UNEXPECTEDLY &&
					pState->lastRequestedState == OPENAVB_AVDECC_MSG_RUNNING &&
					gAvdeccCfg.bFastConnectSupported) {
				// The Talker disappeared.  Use fast connect to assist with reconnecting if it reappears.
				openavb_tl_data_cfg_t *pCfg = pState->stream;
				if (pCfg) {
					U16 flags, talker_unique_id;
					U8 talker_entity_id[8], controller_entity_id[8];
					bool bAvailable = openavbAvdeccGetSaveStateInfo(pCfg, &flags, &talker_unique_id, &talker_entity_id, &controller_entity_id);
					if (bAvailable) {
						// Set the timed-out status for the Listener's descriptor.
						// The next time the Talker advertises itself, openavbAcmpSMListenerSet_talkerTestFastConnect() should try to reconnect.
						openavb_aem_descriptor_stream_io_t *pDescriptor;
						U16 listenerUniqueId;
						for (listenerUniqueId = 0; listenerUniqueId < 0xFFFF; ++listenerUniqueId) {
							pDescriptor = openavbAemGetDescriptor(openavbAemGetConfigIdx(), OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, listenerUniqueId);
							if (pDescriptor && pDescriptor->stream &&
									strcmp(pDescriptor->stream->friendly_name, pCfg->friendly_name) == 0) {
								// We found a match.
								AVB_LOGF_INFO("Listener %s waiting to fast connect to flags=0x%04x, talker_unique_id=0x%04x, talker_entity_id=" ENTITYID_FORMAT ", controller_entity_id=" ENTITYID_FORMAT,
										pCfg->friendly_name,
										flags,
										talker_unique_id,
										ENTITYID_ARGS(talker_entity_id),
										ENTITYID_ARGS(controller_entity_id));
								pDescriptor->fast_connect_status = OPENAVB_FAST_CONNECT_STATUS_TIMED_OUT;
								memcpy(pDescriptor->fast_connect_talker_entity_id, talker_entity_id, sizeof(pDescriptor->fast_connect_talker_entity_id));
								CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &pDescriptor->fast_connect_start_time);
								pDescriptor->fast_connect_start_time.tv_sec += 5;	// Give the Talker some time to shutdown or stabilize
								break;
							}
						}
					}
				}
			}

			// Now that we have handled this, treat this state as a normal stop.
			pState->lastReportedState = OPENAVB_AVDECC_MSG_STOPPED;
		}
	}

	AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
	return true;
}
bool openavbEptClntService(int h, int timeout)
{
	AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
	bool rc = FALSE;

	if (h == AVB_ENDPOINT_HANDLE_INVALID) {
		AVB_LOG_ERROR("Client service: invalid socket");
		AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
		return FALSE;
	}
	
	struct pollfd fds[1];
	memset(fds, 0, sizeof(struct pollfd));
	fds[0].fd = h;
	fds[0].events = POLLIN;

	AVB_LOG_VERBOSE("Waiting for event...");
	int pRet = poll(fds, 1, timeout);

	if (pRet == 0) {
		AVB_LOG_VERBOSE("Poll timeout");
		AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
		return TRUE;
	}
	else if (pRet < 0) {
		if (errno == EINTR) {
			AVB_LOG_VERBOSE("Poll interrupted");
			AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
			return TRUE;
		}
		else {
			AVB_LOGF_ERROR("Poll error: %s", strerror(errno));
		}
	}
	else {
		AVB_LOGF_DEBUG("Poll returned %d events", pRet);
		// only one fd, so it's readable.
		openavbEndpointMessage_t msgBuf;
		memset(&msgBuf, 0, OPENAVB_ENDPOINT_MSG_LEN);
		ssize_t nRead = read(h, &msgBuf, OPENAVB_ENDPOINT_MSG_LEN);
					
		if (nRead < OPENAVB_ENDPOINT_MSG_LEN) {
			// sock closed
			if (nRead == 0) {
				AVB_LOG_ERROR("Socket closed unexpectedly");
			}
			else if (nRead < 0) {
				AVB_LOGF_ERROR("Socket read error: %s", strerror(errno));
			}
			else {
				AVB_LOG_ERROR("Socket read to short");
			}
			socketClose(h);
		}
		else {
			// got a message
			if (openavbEptClntReceiveFromServer(h, &msgBuf)) {
				rc = TRUE;
			}
			else {
				AVB_LOG_ERROR("Invalid message received");
				socketClose(h);
			}
		}
	}
	AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
	return rc;
}
bool openavbAvdeccMsgSrvrHndlInitIdentifyFromClient(int avdeccMsgHandle, char * friendly_name, U8 talker)
{
	AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
	openavb_tl_data_cfg_t * currentStream;

	avdecc_msg_state_t *pState = AvdeccMsgStateListGet(avdeccMsgHandle);
	if (pState) {
		// The handle was already specified.  Something has gone terribly wrong!
		AVB_LOGF_ERROR("avdeccMsgHandle %d already used", avdeccMsgHandle);
		AvdeccMsgStateListRemove(pState);
		free(pState);
		AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
		return false;
	}

	// Make sure the supplied string is nil-terminated.
	friendly_name[FRIENDLY_NAME_SIZE - 1] = '\0';

	// Create a structure to hold the client information.
	pState = (avdecc_msg_state_t *) calloc(1, sizeof(avdecc_msg_state_t));
	if (!pState) {
		AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
		return false;
	}
	pState->avdeccMsgHandle = avdeccMsgHandle;
	pState->bTalker = (talker != 0);
	pState->lastRequestedState = pState->lastReportedState = OPENAVB_AVDECC_MSG_UNKNOWN;

	// Find the state information matching this item.
	for (currentStream = streamList; currentStream != NULL; currentStream = currentStream->next) {
		if (strncmp(currentStream->friendly_name, friendly_name, FRIENDLY_NAME_SIZE) == 0)
		{
			break;
		}
	}
	if (!currentStream) {
		AVB_LOGF_WARNING("Ignoring unexpected client %d, friendly_name:  %s",
			avdeccMsgHandle, friendly_name);
		free(pState);
		AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
		return false;
	}

	// Keep track of this new state item.
	if (!AvdeccMsgStateListAdd(pState)) {
		AVB_LOGF_ERROR("Error saving client identity information %d", avdeccMsgHandle);
		free(pState);
		AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
		return false;
	}

	// Associate this Listener instance with the stream information.
	pState->stream = currentStream;
	currentStream->client = pState;

	AVB_LOGF_INFO("Client %d Detected, friendly_name:  %s",
		avdeccMsgHandle, friendly_name);

	// Enable ADP support, now that we have at least one Talker/Listener.
	openavbAdpHaveTL(true);

	AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
	return true;
}
Beispiel #26
0
// callback function - called for each name/value pair by ini parsing library
static int openavbTLCfgCallback(void *user, const char *tlSection, const char *name, const char *value)
{
	AVB_TRACE_ENTRY(AVB_TRACE_TL);

	parse_ini_data_t *pParseIniData = (parse_ini_data_t *)user;
	openavb_tl_cfg_t *pCfg = pParseIniData->pCfg;
	openavb_tl_cfg_name_value_t *pNVCfg = pParseIniData->pNVCfg;
	tl_state_t *pTLState = pParseIniData->pTLState;

	AVB_LOGF_DEBUG("name=[%s] value=[%s]", name, value);

	bool valOK = FALSE;
	char *pEnd;
	int i;

	if (MATCH(name, "role")) {
		if (MATCH(value, "talker")) {
			pCfg->role = AVB_ROLE_TALKER;
			valOK = TRUE;
		}
		else if (MATCH(value, "listener")) {
			pCfg->role = AVB_ROLE_LISTENER;
			valOK = TRUE;
		}
	}
	else if (MATCH(name, "dest_addr")) {
		valOK = parse_mac(value, &pCfg->dest_addr);
	}
	else if (MATCH(name, "stream_addr")) {
		valOK = parse_mac(value, &pCfg->stream_addr);
	}
	else if (MATCH(name, "stream_uid")) {
		errno = 0;
		pCfg->stream_uid = strtol(value, &pEnd, 10);
		if (*pEnd == '\0' && errno == 0
			&& pCfg->stream_uid <= UINT16_MAX)
			valOK = TRUE;
	}
	else if (MATCH(name, "max_interval_frames")) {
		errno = 0;
		pCfg->max_interval_frames = strtol(value, &pEnd, 10);
		if (*pEnd == '\0' && errno == 0
			&& pCfg->max_interval_frames <= UINT16_MAX)
			valOK = TRUE;
	}
	else if (MATCH(name, "max_frame_size")) {
		errno = 0;
		pCfg->max_frame_size = strtol(value, &pEnd, 10);
		if (*pEnd == '\0' && errno == 0
			&& pCfg->max_interval_frames <= UINT16_MAX)
			valOK = TRUE;
	}
	else if (MATCH(name, "sr_class")) {
		if (strlen(value) == 1) {
			if (tolower(value[0]) == 'a') {
				pCfg->sr_class = SR_CLASS_A;
				valOK = TRUE;
			}
			else if (tolower(value[0]) == 'b') {
				pCfg->sr_class = SR_CLASS_B;
				valOK = TRUE;
			}
		}
	}
	else if (MATCH(name, "sr_rank")) {
		if (strlen(value) == 1) {
			if (value[0] == '1') {
				pCfg->sr_rank = SR_RANK_REGULAR;
				valOK = TRUE;
			}
			else if (value[0] == '0') {
				pCfg->sr_rank = SR_RANK_EMERGENCY;
				valOK = TRUE;
			}
		}
	}
	else if (MATCH(name, "max_transit_usec")) {
		errno = 0;
		pCfg->max_transit_usec = strtol(value, &pEnd, 10);
		if (*pEnd == '\0' && errno == 0
			&& pCfg->max_transit_usec <= UINT32_MAX)
			valOK = TRUE;
	}
	else if (MATCH(name, "max_transmit_deficit_usec")) {
		errno = 0;
		pCfg->max_transmit_deficit_usec = strtol(value, &pEnd, 10);
		if (*pEnd == '\0' && errno == 0
			&& pCfg->max_transmit_deficit_usec <= UINT32_MAX)
			valOK = TRUE;
	}
	else if (MATCH(name, "internal_latency")) {
		errno = 0;
		pCfg->internal_latency = strtol(value, &pEnd, 10);
		if (*pEnd == '\0' && errno == 0
			&& pCfg->internal_latency <= UINT32_MAX)
			valOK = TRUE;
	}
	else if (MATCH(name, "batch_factor")) {
		errno = 0;
		pCfg->batch_factor = strtol(value, &pEnd, 10);
		if (*pEnd == '\0' && errno == 0
			&& pCfg->batch_factor > 0
			&& pCfg->batch_factor <= INT32_MAX)
			valOK = TRUE;
	}
	else if (MATCH(name, "max_stale")) {
		errno = 0;
		pCfg->max_stale = strtol(value, &pEnd, 10);
		if (*pEnd == '\0' && errno == 0
			&& pCfg->max_stale >= 0
			&& pCfg->max_stale <= INT32_MAX)
			valOK = TRUE;
	}
	else if (MATCH(name, "raw_tx_buffers")) {
		errno = 0;
		pCfg->raw_tx_buffers = strtol(value, &pEnd, 10);
		if (*pEnd == '\0' && errno == 0
			&& pCfg->raw_tx_buffers <= UINT32_MAX)
			valOK = TRUE;
	}
	else if (MATCH(name, "raw_rx_buffers")) {
		errno = 0;
		pCfg->raw_rx_buffers = strtol(value, &pEnd, 10);
		if (*pEnd == '\0' && errno == 0
			&& pCfg->raw_rx_buffers <= UINT32_MAX)
			valOK = TRUE;
	}
	else if (MATCH(name, "report_seconds")) {
		errno = 0;
		pCfg->report_seconds = strtol(value, &pEnd, 10);
		if (*pEnd == '\0' && errno == 0
			&& (int)pCfg->report_seconds >= 0
			&& pCfg->report_seconds <= INT32_MAX)
			valOK = TRUE;
	}
	else if (MATCH(name, "start_paused")) {
		// ignore this item - tl_host doesn't use it because
		// it pauses before reading any of its streams.
		errno = 0;
		long tmp;
		tmp = strtol(value, &pEnd, 10);
		if (*pEnd == '\0' && errno == 0
			&& tmp >= 0
			&& tmp <= 1) {
			pCfg->start_paused = (tmp == 1);
			valOK = TRUE;
		}
	}
	else if (MATCH(name, "ifname")) {
		if_info_t ifinfo;
		if (openavbCheckInterface(value, &ifinfo)) {
			strncpy(pCfg->ifname, value, IFNAMSIZ - 1);
			valOK = TRUE;
		}
	}
	else if (MATCH(name, "vlan_id")) {
		errno = 0;
		long tmp;
		tmp = strtol(value, &pEnd, 0);
		// vlanID is 12 bit field
		if (*pEnd == '\0' && errno == 0
			&& tmp >= 0x0
			&& tmp <= 0xFFF) {
			pCfg->vlan_id = tmp;
			valOK = TRUE;
		}
	}

	else if (MATCH(name, "map_lib")) {
		if (pTLState->mapLib.libName)
			free(pTLState->mapLib.libName);
		pTLState->mapLib.libName = strdup(value);
		valOK = TRUE;
	}
	else if (MATCH(name, "map_fn")) {
		if (pTLState->mapLib.funcName)
			free(pTLState->mapLib.funcName);
		pTLState->mapLib.funcName = strdup(value);
		valOK = TRUE;
	}

	else if (MATCH(name, "intf_lib")) {
		if (pTLState->intfLib.libName)
			free(pTLState->intfLib.libName);
		pTLState->intfLib.libName = strdup(value);
		valOK = TRUE;
	}
	else if (MATCH(name, "intf_fn")) {
		if (pTLState->intfLib.funcName)
			free(pTLState->intfLib.funcName);
		pTLState->intfLib.funcName = strdup(value);
		valOK = TRUE;
	}

	else if (MATCH_LEFT(name, "intf_nv_", 8)
		|| MATCH_LEFT(name, "map_nv_", 7)) {
		// Need to save the interface and mapping module configuration
		// until later (after those libraries are loaded.)

		// check if this setting replaces an earlier one
		for (i = 0; i < pNVCfg->nLibCfgItems; i++) {
			if (MATCH(name, pNVCfg->libCfgNames[i])) {
				if (pNVCfg->libCfgValues[i])
					free(pNVCfg->libCfgValues[i]);
				pNVCfg->libCfgValues[i] = strdup(value);
				valOK = TRUE;
			}
		}
		if (i >= pNVCfg->nLibCfgItems) {
			// is a new name/value
			if (i >= MAX_LIB_CFG_ITEMS) {
				AVB_LOG_ERROR("Too many INI settings for interface/mapping modules");
			}
			else {
				pNVCfg->libCfgNames[i] = strdup(name);
				pNVCfg->libCfgValues[i] = strdup(value);
				pNVCfg->nLibCfgItems++;
				valOK = TRUE;
			}
		}
	}
	else {
		// unmatched item, fail
		AVB_LOGF_ERROR("Unrecognized configuration item: name=%s", name);
		return 0;
	}

	if (!valOK) {
		// bad value
		AVB_LOGF_ERROR("Invalid value: name=%s, value=%s", name, value);
		return 0;
	}

	AVB_TRACE_EXIT(AVB_TRACE_TL);

	return 1; // OK
}
Beispiel #27
0
// Open a rawsock for TX or RX
void* ringRawsockOpen(ring_rawsock_t *rawsock, const char *ifname, bool rx_mode, bool tx_mode, U16 ethertype, U32 frame_size, U32 num_frames)
{
	AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK);

	if (!simpleRawsockOpen((simple_rawsock_t*)rawsock, ifname, rx_mode,
			       tx_mode, ethertype, frame_size, num_frames))
	{
		AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
		return NULL;
	}

	rawsock->pMem = (void*)(-1);

	// Use version 2 headers for the MMAP packet stuff - avoids 32/64
	// bit problems, gives nanosecond timestamps, and allows rx of vlan id
	int val = TPACKET_V2;
	if (setsockopt(rawsock->sock, SOL_PACKET, PACKET_VERSION, &val, sizeof(val)) < 0) {
		AVB_LOGF_ERROR("Creating rawsock; get PACKET_VERSION: %s", strerror(errno));
		ringRawsockClose(rawsock);
		AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
		return NULL;
	}

	// Get the size of the headers in the ring
	unsigned len = sizeof(val);
	if (getsockopt(rawsock->sock, SOL_PACKET, PACKET_HDRLEN, &val, &len) < 0) {
		AVB_LOGF_ERROR("Creating rawsock; get PACKET_HDRLEN: %s", strerror(errno));
		ringRawsockClose(rawsock);
		AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
		return NULL;
	}
	rawsock->bufHdrSize = TPACKET_ALIGN(val);

	if (rawsock->base.rxMode) {
		rawsock->bufHdrSize = rawsock->bufHdrSize + TPACKET_ALIGN(sizeof(struct sockaddr_ll));
	}
	rawsock->bufferSize = rawsock->base.frameSize + rawsock->bufHdrSize;
	rawsock->frameCount = num_frames;
	AVB_LOGF_DEBUG("frameSize=%d, bufHdrSize=%d(%d+%zu) bufferSize=%d, frameCount=%d",
				   rawsock->base.frameSize, rawsock->bufHdrSize, val, sizeof(struct sockaddr_ll),
				   rawsock->bufferSize, rawsock->frameCount);

	// Get number of bytes in a memory page.  The blocks we ask for
	// must be a multiple of pagesize.  (Actually, it should be
	// (pagesize * 2^N) to avoid wasting memory.)
	int pagesize = getpagesize();
	rawsock->blockSize = pagesize * 4;
	AVB_LOGF_DEBUG("pagesize=%d blockSize=%d", pagesize, rawsock->blockSize);

	// Calculate number of buffers and frames based on blocks
	int buffersPerBlock = rawsock->blockSize / rawsock->bufferSize;
	rawsock->blockCount = rawsock->frameCount / buffersPerBlock + 1;
	rawsock->frameCount = buffersPerBlock * rawsock->blockCount;

	AVB_LOGF_DEBUG("frameCount=%d, buffersPerBlock=%d, blockCount=%d",
				   rawsock->frameCount, buffersPerBlock, rawsock->blockCount);

	// Fill in the kernel structure with our calculated values
	struct tpacket_req s_packet_req;
	memset(&s_packet_req, 0, sizeof(s_packet_req));
	s_packet_req.tp_block_size = rawsock->blockSize;
	s_packet_req.tp_frame_size = rawsock->bufferSize;
	s_packet_req.tp_block_nr = rawsock->blockCount;
	s_packet_req.tp_frame_nr = rawsock->frameCount;

	// Ask the kernel to create the TX_RING or RX_RING
	if (rawsock->base.txMode) {
		if (setsockopt(rawsock->sock, SOL_PACKET, PACKET_TX_RING,
					   (char*)&s_packet_req, sizeof(s_packet_req)) < 0) {
			AVB_LOGF_ERROR("Creating rawsock; TX_RING: %s", strerror(errno));
			ringRawsockClose(rawsock);
			AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
			return NULL;
		}
		AVB_LOGF_DEBUG("PACKET_%s_RING OK", "TX");
	}
	else {
		if (setsockopt(rawsock->sock, SOL_PACKET, PACKET_RX_RING,
					   (char*)&s_packet_req, sizeof(s_packet_req)) < 0) {
			AVB_LOGF_ERROR("Creating rawsock, RX_RING: %s", strerror(errno));
			ringRawsockClose(rawsock);
			AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
			return NULL;
		}
		AVB_LOGF_DEBUG("PACKET_%s_RING OK", "TX");
	}

	// Call MMAP to get access to the memory used for the ring
	rawsock->memSize = rawsock->blockCount * rawsock->blockSize;
	AVB_LOGF_DEBUG("memSize=%zu (%d, %d), sock=%d",
				   rawsock->memSize,
				   rawsock->blockCount,
				   rawsock->blockSize,
				   rawsock->sock);
	rawsock->pMem = mmap((void*)0, rawsock->memSize, PROT_READ|PROT_WRITE, MAP_SHARED, rawsock->sock, (off_t)0);
	if (rawsock->pMem == (void*)(-1)) {
		AVB_LOGF_ERROR("Creating rawsock; MMAP: %s", strerror(errno));
		ringRawsockClose(rawsock);
		AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
		return NULL;
	}
	AVB_LOGF_DEBUG("mmap: %p", rawsock->pMem);

	// Initialize the memory
	memset(rawsock->pMem, 0, rawsock->memSize);

	// Initialize the state of the ring
	rawsock->blockIndex = 0;
	rawsock->bufferIndex = 0;
	rawsock->buffersOut = 0;
	rawsock->buffersReady = 0;

	// fill virtual functions table
	rawsock_cb_t *cb = &rawsock->base.cb;
	cb->close = ringRawsockClose;
	cb->getTxFrame = ringRawsockGetTxFrame;
	cb->relTxFrame = ringRawsockRelTxFrame;
	cb->txFrameReady = ringRawsockTxFrameReady;
	cb->send = ringRawsockSend;
	cb->txBufLevel = ringRawsockTxBufLevel;
	cb->rxBufLevel = ringRawsockRxBufLevel;
	cb->getRxFrame = ringRawsockGetRxFrame;
	cb->rxParseHdr = ringRawsockRxParseHdr;
	cb->relRxFrame = ringRawsockRelRxFrame;
	cb->getTXOutOfBuffers = ringRawsockGetTXOutOfBuffers;
	cb->getTXOutOfBuffersCyclic = ringRawsockGetTXOutOfBuffersCyclic;

	AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
	return rawsock;
}
// This callback is called when acting as a listener.
bool openavbIntfMpeg2tsGstRxCB(media_q_t *pMediaQ)
{
	AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);

	if (!pMediaQ)
	{
		AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
		return FALSE;
	}

	pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
	if (!pPvtData)
	{
		AVB_LOG_ERROR("Private interface module data not allocated.");
		return FALSE;
	}
	if (!pPvtData->appsrc)
	{
		AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
		return FALSE;
	}

	bool moreData = TRUE;
	bool retval = TRUE;

	while (moreData)
	{
		media_q_item_t *pMediaQItem = openavbMediaQTailLock(pMediaQ, pPvtData->ignoreTimestamp);
		if (pMediaQItem)
		{
			unsigned long len = pMediaQItem->dataLen;
			if (len > 0)
			{
				GstAlBuf *rxBuf = gst_al_alloc_buffer(len);

				if (rxBuf)
				{
					GST_AL_BUFFER_TIMESTAMP(rxBuf) = GST_CLOCK_TIME_NONE;
					GST_AL_BUFFER_DURATION(rxBuf) = GST_CLOCK_TIME_NONE;

					memcpy(GST_AL_BUF_DATA(rxBuf), pMediaQItem->pPubData, GST_AL_BUF_SIZE(rxBuf));

					GstFlowReturn gstret = gst_al_push_buffer(GST_APP_SRC(pPvtData->appsrc), rxBuf);
					if (gstret != GST_FLOW_OK)
					{
						AVB_LOGF_ERROR("Pushing buffer to gstreamer failed: %d", gstret);
						retval = moreData = FALSE;
					}
				}
				else
				{
					AVB_LOG_ERROR("Failed to get gstreamer buffer");
					retval = moreData = FALSE;
				}
			}
			openavbMediaQTailPull(pMediaQ);
		}
		else
		{
			moreData = FALSE;
		}
	}

	AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
	return retval;
}
Beispiel #29
0
/**********************************************
 * main
 */
int main(int argc, char *argv[])
{
	AVB_TRACE_ENTRY(AVB_TRACE_HOST);

	int iniIdx = 0;
	char *programName;
	char *optIfnameGlobal = NULL;

	programName = strrchr(argv[0], '/');
	programName = programName ? programName + 1 : argv[0];

	if (argc < 2) {
		openavbTlHostUsage(programName);
		exit(-1);
	}

	tl_handle_t *tlHandleList = NULL;
	int i1;

	// Process command line
	bool optDone = FALSE;
	while (!optDone) {
		int opt = getopt(argc, argv, "hI:");
		if (opt != EOF) {
			switch (opt) {
				case 'I':
					optIfnameGlobal = strdup(optarg);
					break;
				case 'h':
				default:
					openavbTlHostUsage(programName);
					exit(-1);
			}
		}
		else {
			optDone = TRUE;
		}
	}

	osalAVBInitialize(optIfnameGlobal);

	iniIdx = optind;
	U32 tlCount = argc - iniIdx;

	if (!openavbTLInitialize(tlCount)) {
		AVB_LOG_ERROR("Unable to initialize talker listener library");
		osalAVBFinalize();
		exit(-1);
	}

	// Setup signal handler
	// We catch SIGINT and shutdown cleanly
	bool err;
	struct sigaction sa;
	sa.sa_handler = openavbTLSigHandler;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;
	err = sigaction(SIGINT, &sa, NULL);
	if (err)
	{
		AVB_LOG_ERROR("Failed to setup SIGINT handler");
		osalAVBFinalize();
		exit(-1);
	}
	err = sigaction(SIGUSR1, &sa, NULL);
	if (err)
	{
		AVB_LOG_ERROR("Failed to setup SIGUSR1 handler");
		osalAVBFinalize();
		exit(-1);
	}

	registerStaticMapModule(openavbMapPipeInitialize);
	registerStaticMapModule(openavbMapAVTPAudioInitialize);
	registerStaticMapModule(openavbMapCtrlInitialize);
	registerStaticMapModule(openavbMapH264Initialize);
	registerStaticMapModule(openavbMapMjpegInitialize);
	registerStaticMapModule(openavbMapMpeg2tsInitialize);
	registerStaticMapModule(openavbMapNullInitialize);
	registerStaticMapModule(openavbMapUncmpAudioInitialize);

	registerStaticIntfModule(openavbIntfEchoInitialize);
	registerStaticIntfModule(openavbIntfCtrlInitialize);
	registerStaticIntfModule(openavbIntfLoggerInitialize);
	registerStaticIntfModule(openavbIntfNullInitialize);
	registerStaticIntfModule(openavbIntfToneGenInitialize);
	registerStaticIntfModule(openavbIntfViewerInitialize);
	registerStaticIntfModule(openavbIntfAlsaInitialize);
	registerStaticIntfModule(openavbIntfMjpegGstInitialize);
	registerStaticIntfModule(openavbIntfMpeg2tsFileInitialize);
	registerStaticIntfModule(openavbIntfMpeg2tsGstInitialize);
	registerStaticIntfModule(openavbIntfWavFileInitialize);
	registerStaticIntfModule(openavbIntfH264RtpGstInitialize);

	tlHandleList = calloc(1, sizeof(tl_handle_t) * tlCount);

	// Open all streams
	for (i1 = 0; i1 < tlCount; i1++) {
		tlHandleList[i1] = openavbTLOpen();
	}

	// Parse ini and configure all streams
	for (i1 = 0; i1 < tlCount; i1++) {
		openavb_tl_cfg_t cfg;
		openavb_tl_cfg_name_value_t NVCfg;
		char iniFile[1024];

		snprintf(iniFile, sizeof(iniFile), "%s", argv[i1 + iniIdx]);

		if (optIfnameGlobal && !strcasestr(iniFile, ",ifname=")) {
			snprintf(iniFile + strlen(iniFile), sizeof(iniFile), ",ifname=%s", optIfnameGlobal);
		}

		openavbTLInitCfg(&cfg);
		memset(&NVCfg, 0, sizeof(NVCfg));

		if (!openavbTLReadIniFileOsal(tlHandleList[i1], iniFile, &cfg, &NVCfg)) {
			AVB_LOGF_ERROR("Error reading ini file: %s\n", argv[i1 + 1]);
			osalAVBFinalize();
			exit(-1);
		}
		if (!openavbTLConfigure(tlHandleList[i1], &cfg, &NVCfg)) {
			AVB_LOGF_ERROR("Error configuring: %s\n", argv[i1 + 1]);
			osalAVBFinalize();
			exit(-1);
		}

		int i2;
		for (i2 = 0; i2 < NVCfg.nLibCfgItems; i2++) {
			free(NVCfg.libCfgNames[i2]);
			free(NVCfg.libCfgValues[i2]);
		}
	}

#ifdef AVB_FEATURE_GSTREAMER
	// If we're supporting the interface modules which use GStreamer,
	// initialize GStreamer here to avoid errors.
	gst_init(0, NULL);
#endif

	for (i1 = 0; i1 < tlCount; i1++) {
		openavbTLRun(tlHandleList[i1]);
	}

	while (bRunning) {
		sleep(1);
	}

	for (i1 = 0; i1 < tlCount; i1++) {
		openavbTLStop(tlHandleList[i1]);
	}

	for (i1 = 0; i1 < tlCount; i1++) {
		openavbTLClose(tlHandleList[i1]);
	}

	openavbTLCleanup();

#ifdef AVB_FEATURE_GSTREAMER
	// If we're supporting the interface modules which use GStreamer,
	// De-initialize GStreamer to clean up resources.
	gst_deinit();
#endif

	osalAVBFinalize();

	AVB_TRACE_EXIT(AVB_TRACE_HOST);
	exit(0);
}
Beispiel #30
0
// 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;
}