/* * Copyright (c) Dialogic (R) 2009 - 2010 * This source file is supplied for the use with Eicon Networks range of DIVA Server Adapters. * Dialogic (R) File Revision : 1.9 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include "platform.h" #include "pc.h" #include "diva_streaming_result.h" #include "diva_streaming_vector.h" #include "diva_streaming_manager.h" #include "diva_streaming_messages.h" #include "diva_segment_alloc_ifc.h" #include "diva_streaming_idi_host_ifc.h" typedef struct _diva_stream_manager { diva_stream_t ifc; int user_segment_alloc; struct _diva_segment_alloc* segment_alloc; diva_segment_alloc_access_t* segment_alloc_ifc; struct _diva_streaming_idi_host_ifc_w* tx; struct _diva_streaming_idi_host_ifc_w_access* tx_ifc; struct _diva_streaming_idi_host_ifc_r* rx; struct _diva_streaming_idi_host_ifc_r_access* rx_ifc; diva_streaming_idi_rx_notify_user_proc_t rx_proc; void* rx_proc_context; byte description[0xff-32]; char trace_ident[DIVA_STREAMING_MAX_TRACE_IDENT_LENGTH+1]; } diva_stream_manager_t; /* * LOCALS */ static int message_input_proc (void* user_context, dword message, dword length, const diva_streaming_vector_t* v, dword nr_v); static diva_streaming_idi_result_t diva_stream_manager_release (struct _diva_stream* ifc); static diva_streaming_idi_result_t diva_stream_manager_release_stream (struct _diva_stream* ifc); static diva_streaming_idi_result_t diva_stream_manager_write (struct _diva_stream* ifc, dword message, const void* data, dword length); static diva_streaming_idi_result_t diva_stream_manager_wakeup (struct _diva_stream* ifc); static const byte* diva_stream_manager_description (struct _diva_stream* ifc, const byte* addie, byte addielen); static diva_streaming_idi_result_t diva_stream_manager_sync_req (struct _diva_stream* ifc, dword ident); static diva_streaming_idi_result_t diva_stream_flush (struct _diva_stream* ifc); static dword diva_stream_get_tx_free (const struct _diva_stream* ifc); static dword diva_stream_get_tx_in_use (const struct _diva_stream* ifc); static void diva_notify_os_resource_removed (struct _diva_stream* ifc); diva_streaming_idi_result_t diva_stream_create (struct _diva_stream** ifc, void* os_context, dword length, diva_streaming_idi_rx_notify_user_proc_t rx, void* rx_context, const char* trace_ident) { return (diva_stream_create_with_user_segment_alloc (ifc, os_context, length, rx, rx_context, trace_ident, 0)); } diva_streaming_idi_result_t diva_stream_create_with_user_segment_alloc (struct _diva_stream** ifc, void* os_context, dword length, diva_streaming_idi_rx_notify_user_proc_t rx, void* rx_context, const char* trace_ident, struct _diva_segment_alloc* user_segment_alloc) { diva_stream_manager_t* pI; diva_streaming_idi_result_t ret = DivaStreamingIdiResultError; #ifdef DIVA_USERMODE dbg_init ("DIVA STREAM", "109-1", 0); #endif pI = diva_os_malloc (0, sizeof(*pI)); if (pI != 0) { memset (pI, 0x00, sizeof(*pI)); memcpy(pI->trace_ident, trace_ident, MIN(strlen(trace_ident), DIVA_STREAMING_MAX_TRACE_IDENT_LENGTH)); pI->trace_ident[DIVA_STREAMING_MAX_TRACE_IDENT_LENGTH] = 0; if (user_segment_alloc != 0) { pI->segment_alloc = user_segment_alloc; pI->user_segment_alloc = 1; ret = 0; } else { ret = diva_create_segment_alloc (os_context, &pI->segment_alloc); pI->user_segment_alloc = 0; } if (ret == 0) { dword number_segments = length/4096 + ((length%4096) != 0); pI->segment_alloc_ifc = diva_get_segment_alloc_ifc (pI->segment_alloc); ret = diva_streaming_idi_host_ifc_create (&pI->tx, number_segments, pI->segment_alloc, trace_ident); if (ret == 0) { pI->tx_ifc = diva_streaming_idi_host_ifc_get_access (pI->tx); ret = diva_streaming_idi_host_rx_ifc_create (&pI->rx, number_segments, pI->segment_alloc, pI->tx, pI->tx_ifc, message_input_proc, pI, &pI->ifc, trace_ident); if (ret == 0) { pI->rx_ifc = diva_streaming_idi_host_rx_ifc_get_access (pI->rx); pI->ifc.release = diva_stream_manager_release; pI->ifc.release_stream = diva_stream_manager_release_stream; pI->ifc.write = diva_stream_manager_write; pI->ifc.wakeup = diva_stream_manager_wakeup; pI->ifc.description = diva_stream_manager_description; pI->ifc.sync = diva_stream_manager_sync_req; pI->ifc.flush_stream = diva_stream_flush; pI->ifc.get_tx_free = diva_stream_get_tx_free; pI->ifc.get_tx_in_use = diva_stream_get_tx_in_use; pI->ifc.notify_os_resource_removed = diva_notify_os_resource_removed; pI->rx_proc = rx; pI->rx_proc_context = rx_context; *ifc = &pI->ifc; ret = DivaStreamingIdiResultOK; } else { DBG_ERR(("failed to create rx stream [%s]", trace_ident)) } } else { DBG_ERR(("failed to create tx stream [%s]", trace_ident)) } } else { DBG_ERR(("failed to create segment alloc [%s]", trace_ident)) } } if (ret != 0) diva_stream_manager_release (&pI->ifc); return (ret); } static int message_input_proc (void* user_context, dword message, dword length, const diva_streaming_vector_t* v, dword nr_v) { diva_stream_manager_t* pI = (diva_stream_manager_t*)user_context; return (pI->rx_proc (pI->rx_proc_context, message, length, v, nr_v)); } static diva_streaming_idi_result_t diva_stream_manager_release (struct _diva_stream* ifc) { if (ifc != 0) { diva_stream_manager_t* pI = DIVAS_CONTAINING_RECORD(ifc, diva_stream_manager_t, ifc); if (pI->rx != 0) pI->rx_ifc->release (pI->rx); if (pI->tx != 0) pI->tx_ifc->release (pI->tx); if (pI->segment_alloc != 0 && pI->user_segment_alloc == 0) pI->segment_alloc_ifc->release (&pI->segment_alloc); diva_os_free (0, pI); } return (DivaStreamingIdiResultOK); } static diva_streaming_idi_result_t diva_stream_manager_release_stream (struct _diva_stream* ifc) { if (ifc != 0) { diva_stream_manager_t* pI = DIVAS_CONTAINING_RECORD(ifc, diva_stream_manager_t, ifc); return (pI->tx_ifc->release_stream (pI->tx)); } return (DivaStreamingIdiResultError); } static diva_streaming_idi_result_t diva_stream_manager_write (struct _diva_stream* ifc, dword message, const void* data, dword length) { diva_stream_manager_t* pI = DIVAS_CONTAINING_RECORD(ifc, diva_stream_manager_t, ifc); return (pI->tx_ifc->write_message (pI->tx, message, data, length)); } static diva_streaming_idi_result_t diva_stream_manager_wakeup (struct _diva_stream* ifc) { diva_stream_manager_t* pI = DIVAS_CONTAINING_RECORD(ifc, diva_stream_manager_t, ifc); return (pI->rx_ifc->wakeup (pI->rx)); } const byte* diva_stream_manager_description (struct _diva_stream* ifc, const byte* addie, byte addielen) { diva_stream_manager_t* pI = DIVAS_CONTAINING_RECORD(ifc, diva_stream_manager_t, ifc); byte length = 4, len_tx, len_rx; len_tx = pI->tx_ifc->description (pI->tx, &pI->description[length], sizeof(pI->description)-length); if (len_tx != 0) { length += len_tx; len_rx = pI->rx_ifc->description (pI->rx, &pI->description[length], sizeof(pI->description)-length); if (len_rx != 0) { length += len_rx; pI->description[0] = length-1; /* Structure length */ pI->description[1] = 0; /* Request */ pI->description[2] = len_rx+len_tx+1; /* Structure length */ pI->description[3] = 0; /* Version */ if (addie != 0 && addielen != 0) { byte* description = &pI->description[0]; byte* start = &description[3]; start[0] |= 2U; start = start + start[-1]; memcpy (start, addie, addielen); start += addielen; *start++ = 0; description[2] += addielen+1; description[0] += addielen+1; length += addielen+1; } DBG_TRC(("description length %u [%s]", length, pI->trace_ident)) DBG_BLK(((void*)pI->description, length)) return (&pI->description[0]); } } return (0); } static diva_streaming_idi_result_t diva_stream_manager_sync_req (struct _diva_stream* ifc, dword ident) { diva_stream_manager_t* pI = DIVAS_CONTAINING_RECORD(ifc, diva_stream_manager_t, ifc); return (pI->tx_ifc->sync (pI->tx, ident)); } static diva_streaming_idi_result_t diva_stream_flush (struct _diva_stream* ifc) { diva_stream_manager_t* pI = DIVAS_CONTAINING_RECORD(ifc, diva_stream_manager_t, ifc); return (pI->tx_ifc->update_remote (pI->tx) == 0 ? DivaStreamingIdiResultOK : DivaStreamingIdiResultError); } static dword diva_stream_get_tx_free (const struct _diva_stream* ifc) { diva_stream_manager_t* pI = DIVAS_CONTAINING_RECORD(ifc, diva_stream_manager_t, ifc); return (pI->tx_ifc->get_free (pI->tx)); } static dword diva_stream_get_tx_in_use (const struct _diva_stream* ifc) { const diva_stream_manager_t* pI = DIVAS_CONTAINING_RECORD(ifc, const diva_stream_manager_t, ifc); return (pI->tx_ifc->get_in_use (pI->tx)); } static void diva_notify_os_resource_removed (struct _diva_stream* ifc) { diva_stream_manager_t* pI = DIVAS_CONTAINING_RECORD(ifc, diva_stream_manager_t, ifc); if (pI->segment_alloc != 0) { pI->segment_alloc_ifc->resource_removed (pI->segment_alloc); } } dword diva_streaming_read_vector_data (const diva_streaming_vector_t* v, int nr_v, dword *vector_offset, dword *vector_position, byte* dst, dword length) { dword to_copy; dword count; for (count = 0; vector_offset[0] < ((dword)nr_v) && length != 0;) { to_copy = MIN((v[vector_offset[0]].length - vector_position[0]), length); if (dst != 0) { const byte* tmp = v[vector_offset[0]].data; memcpy (dst, &tmp[vector_position[0]], to_copy); dst += to_copy; } length -= to_copy; count += to_copy; if (v[vector_offset[0]].length == vector_position[0]+to_copy) { vector_offset[0]++; vector_position[0]=0; } else { vector_position[0] += to_copy; } } return (count); } dword diva_streaming_get_indication_data (dword handle, dword message, dword length, const diva_streaming_vector_t* v, int nr_v, byte* pInd, diva_streaming_vector_t* vind, int *pvind_nr) { dword vector_offset = (byte)handle; dword vector_position = handle >> 8; byte Ind = (byte)(message >> 8); byte header[4]; dword indication_data_length; int dst_nr_v = *pvind_nr; int i; if ((Ind & 0x0f) == 8 /* N_DATA */) { *pInd = Ind; for (i = 0; i < nr_v; i++) { vind[i] = v[i]; } *pvind_nr = nr_v; return (0); } /* Combined indication data[0] = Ind; data[1] = IndCh; data[2] = (byte)length; data[3] = (byte)(length >> 8); */ if (vector_offset >= ((dword)nr_v) || vector_position >= v[vector_offset].length) { DBG_ERR(("%s at %d wrong combined indication format", __FILE__, __LINE__)) *pInd = 0; return (0); } { const byte* tmp = v[vector_offset].data; if (tmp[vector_position] == 0) { DBG_ERR(("%s at %d wrong combined indication format", __FILE__, __LINE__)) *pInd = 0; return (0); } } if (diva_streaming_read_vector_data (v, nr_v, &vector_offset, &vector_position, header, sizeof(header)) != sizeof(header)) { DBG_ERR(("%s at %d wrong combined indication format", __FILE__, __LINE__)) *pInd = 0; return (0); } indication_data_length = ((word)header[2] | (word)header[3] << 8); for (i = 0; i < dst_nr_v && indication_data_length != 0; i++) { const byte* tmp = v[vector_offset].data; vind[i].data = &tmp[vector_position]; vind[i].length = MIN((v[vector_offset].length - vector_position), indication_data_length); *pvind_nr = i + 1; indication_data_length -= vind[i].length; if (diva_streaming_read_vector_data (v, nr_v, &vector_offset, &vector_position, 0, vind[i].length) != vind[i].length) { DBG_ERR(("%s at %d wrong combined indication format", __FILE__, __LINE__)) *pInd = 0; return (0); } } if (indication_data_length != 0) { DBG_ERR(("%s at %d wrong combined indication format", __FILE__, __LINE__)) *pInd = 0; return (0); } *pInd = header[0]; { const byte* tmp = v[vector_offset].data; if (tmp[vector_position] == 0) { return (0); } } return (vector_offset | (vector_position << 8)); }