Python C API, override the PyNumberMethods nb_add field also changes the field in tp_base - subclassing

I develop a new type: PyAlignArray_Type which derived from PyArray_Type
PyAlignArray_Type.tp_base = &PyArray_Type;
I override the nb_add field of tp_as_number as follow:
PyAlignArray_Type.tp_as_number->nb_add = (binaryfunc)ndarray_add ;
This works fine, but the field is also changed for base type (PyArray_Type).
My question is: How to overriding a PyNumberMethods field without changing it in the base type ?
typedef struct {
PyArrayObject array;
int pitch;
size_t size;
} PyAlignArrayObject;
/*---------------PyAlignArray_Type------------------*/
static PyTypeObject PyAlignArray_Type = {
PyObject_HEAD_INIT(NULL)
"plibs_8.ndarray", /* tp_name */
sizeof(PyAlignArrayObject), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)array_dealloc,/* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_reserved */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT |
Py_TPFLAGS_BASETYPE, /* tp_flags */
0, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
ndarray_methods, /* tp_methods */
ndarray_members, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
(newfunc)ndarray_new, /* tp_new */
};
static PyModuleDef ndarraymodule = {
PyModuleDef_HEAD_INIT,
"ndarray",
"ndarray module",
-1,
NULL, NULL, NULL, NULL, NULL
};
PyMODINIT_FUNC
PyInit_ndarray(void)
{
PyObject *m;
import_array();
PyAlignArray_Type.tp_base = &PyArray_Type;
if (PyType_Ready(&PyAlignArray_Type) < 0)
return NULL;
// __add__ overloading
PyAlignArray_Type.tp_as_number->nb_add = (binaryfunc)ndarray_add ;
m = PyModule_Create(&ndarraymodule);
if (m == NULL)
return NULL;
Py_INCREF(&PyAlignArray_Type);
PyModule_AddObject(m, "ndarray", (PyObject *) &PyAlignArray_Type);
return m;
}

I think you're right - this is odd, non-intuitive behaviour. It is fixable though. The documentation says
The tp_as_number field is not inherited, but the contained fields are inherited individually.
which implies that it should be OK to override them as you've done. What it actually seems to mean is:
The tp_as_number field is not inherited, but the contained fields are inherited individually if you provide space for them. If you don't provide space for them then the tp_as_number field is set to point at the base classes tp_as_number field.
(Italics are my addition. See code at https://github.com/python/cpython/blob/3e8d6cb1892377394e4b11819c33fbac728ea9e0/Objects/typeobject.c#L5111 and https://github.com/python/cpython/blob/3e8d6cb1892377394e4b11819c33fbac728ea9e0/Objects/typeobject.c#L4757). This means that, as in your example, you're also changing the base class methods.
The solution to this is to create a zero initialized PyNumberMethods and reference that in your class
static PyNumberMethods align_array_number_methods = { NULL };
/* You could also specify the nb_add field here and you wouldn't
have to do it in your module init */
static PyTypeObject PyAlignArray_Type = {
/* whole bunch of code unchanged */
&align_array_number_methods, /* tp_as_number */
/* whole bunch of code unchanged */
The slots you left as NULL are filled in according to the inheritance rules in PyType_Ready
I think the reason for this odd behaviour is to avoid introducing memory leaks. When you call PyType_Ready (which is where the inheritance is dealt with) it can't allocate PyNumberMethods statically so it would have to to malloc it. Since you don't know whether it's malloced these fields or not the memory that never get freed. (This is only a concern for dynamically created types).

Related

STM32L486 enable LPUART1 with DMA

I'm trying to enable LPUART1 to write/read traces and debug my code.
Im setting PC0/PC1 pin:
/*Configure GPIO pins : PC0 PC1 */
GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF8_LPUART1;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
Created the handlers:
UART_HandleTypeDef hlpuart1;
DMA_HandleTypeDef hdma_lpuart_tx;
DMA_HandleTypeDef hdma_lpuart_rx;
My init function. I call it from main.c:
/* LPUART1 init function */
void MX_LPUART1_UART_Init(void)
{
hlpuart1.Instance = LPUART1;
hlpuart1.Init.BaudRate = 115200;
hlpuart1.Init.WordLength = UART_WORDLENGTH_8B;
hlpuart1.Init.StopBits = UART_STOPBITS_1;
hlpuart1.Init.Parity = UART_PARITY_NONE;
hlpuart1.Init.Mode = UART_MODE_TX_RX;
hlpuart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
hlpuart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
hlpuart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&hlpuart1) != HAL_OK)
{
Error_Handler();
}
}
The function HAL_UART_Init:
/* USER CODE BEGIN LPUART1_MspInit 0 */
/* USER CODE END LPUART1_MspInit 0 */
/* LPUART1 clock enable */
__HAL_RCC_LPUART1_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
/**LPUART1 GPIO Configuration
PC0 ------> LPUART1_RX
PC1 ------> LPUART1_TX
*/
GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF8_LPUART1;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/* LPUART1 DMA Init */
/* LPUART_RX Init */
hdma_lpuart_rx.Instance = DMA2_Channel7;
hdma_lpuart_rx.Init.Request = DMA_REQUEST_4;
hdma_lpuart_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_lpuart_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_lpuart_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_lpuart_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_lpuart_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_lpuart_rx.Init.Mode = DMA_CIRCULAR;
hdma_lpuart_rx.Init.Priority = DMA_PRIORITY_LOW;
if (HAL_DMA_Init(&hdma_lpuart_rx) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(uartHandle,hdmarx,hdma_usart1_rx);
/* LPUART_TX Init */
hdma_lpuart_tx.Instance = DMA2_Channel6;
hdma_lpuart_tx.Init.Request = DMA_REQUEST_4;
hdma_lpuart_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_lpuart_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_lpuart_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_lpuart_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_lpuart_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_lpuart_tx.Init.Mode = DMA_NORMAL;
hdma_lpuart_tx.Init.Priority = DMA_PRIORITY_LOW;
if (HAL_DMA_Init(&hdma_lpuart_tx) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(uartHandle,hdmatx,hdma_lpuart_tx);
/* LPUART1 interrupt Init */
HAL_NVIC_SetPriority(LPUART1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(LPUART1_IRQn);
I have set the NVIC LPUART1 at the end of the last code. I have enable too the DMA2 channel 6 and 7 interrupts:
/**
* Enable DMA controller clock
*/
void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
__HAL_RCC_DMA2_CLK_ENABLE();
/* DMA interrupt init */
/* DMA1_Channel1_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
/* DMA1_Channel2_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
/* DMA1_Channel4_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel4_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn);
/* DMA1_Channel5_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
/* DMA2_Channel1_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA2_Channel1_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(DMA2_Channel1_IRQn);
/* DMA2_Channel2_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA2_Channel2_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(DMA2_Channel2_IRQn);
/* DMA2_Channel6_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA2_Channel6_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(DMA2_Channel6_IRQn);
/* DMA2_Channel7_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA2_Channel7_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(DMA2_Channel7_IRQn);
}
In my main.c im trying to print something and it always return "HAL_OK":
HAL_UART_Transmit_DMA(&hlpuart1, (uint8_t *)'ACK\n', 5);
Inside the last function, we have set this callback:
/* Set the UART DMA transfer complete callback */
huart->hdmatx->XferCpltCallback = UART_DMATransmitCplt;
And inside this one, we have this callback:
HAL_UART_TxCpltCallback(huart);
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) {
/* Set transmission flag: transfer complete */
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
if(huart->Instance == USART1)
{
if(UART_TX_Acess != NULL)
{
xSemaphoreGiveFromISR(UART_TX_Acess, &xHigherPriorityTaskWoken); //Usart transmision complete
}
}
else if(huart->Instance == LPUART1)
{
modbus_tx_finish = 0;
}
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
Everything seems to be fine coded but DMA2_Channel6_IRQHandler is jumping and and inside DMA IRQhandler an error appears:
/* Transfer Error Interrupt management **************************************/
But I cant understand why...
Ok I noticed the error. I was writting wrong the function to write. THis was the original:
HAL_UART_Transmit_DMA(&hlpuart1, (uint8_t *)'ACK\n', 5);
And this is the change:
HAL_UART_Transmit_DMA(&hlpuart1, (uint8_t *)"ACK\n", 5);

How does Linux kernel detect use-after-free corruption via slab poisoning?

I'm pretty new to Linux kernel and please forgive my stupidity if this is a naive question.
I understand that with CONFIG_SLAB_DEBUG turned on and SLAB_POISON passed in, the slab (de)allocation mechanism would fill freed slab memory with 0x6b (POISON_FREE) so that use-after-free (UAF) behaviors can be detected. My question is: How does the kernel perform this detection?
Empirically, with the following code and it's execution result (which comes from an exercise), it turns out that the kernel also fills the freshly initialized slab object with 0x6b. So how does the kernel distinguish a newly allocated slab object from a freed memory zone? More preciously, how does this magic detection mechanism raise an alert when some 0x6b bytes are overwritten and why the first legal write does not trigger this alert?
By the way, if it matters, the kernel version is 5.4
/* Our 'demo' structure; one that we imagine is often allocated and freed;
* hence, we create a custom slab cache to hold pre-allocated 'instances'
* of it... It's size: 152 bytes.
*/
struct myctx {
u32 iarr[10];
u64 uarr[6];
char config[64];
};
static struct kmem_cache *gctx_cachep;
struct myctx *obj;
static void use_the_object(void *s, u8 c, size_t n)
{
memset(s, c, n);
pr_info(" -------------- after memset s, '%c', %zu : ------------\n", c, n);
print_hex_dump_bytes("obj: ", DUMP_PREFIX_ADDRESS, s, sizeof(struct myctx));
}
static void use_our_cache(void)
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)
pr_debug("Cache name is %s\n", kmem_cache_name(gctx_cachep));
#else
pr_debug("[ker ver > 2.6.38 cache name deprecated...]\n");
#endif
obj = kmem_cache_alloc(gctx_cachep, GFP_KERNEL);
if (!obj) { /* pedantic warning printk below... */
pr_warn("kmem_cache_alloc() failed\n");
}
pr_info("Our cache object (# 0x%pK, actual=0x%px) size is %u bytes; ksize=%zu\n",
obj, obj, kmem_cache_size(gctx_cachep), ksize(obj));
print_hex_dump_bytes("obj: ", DUMP_PREFIX_OFFSET, obj, sizeof(struct myctx));
use_the_object(obj, 'z', 16);
}
/* The parameter is the pointer to the just allocated memory 'object' from
* our custom slab cache; here, this is our 'constructor' routine; so, we
* initialize our just allocated memory object.
*/
static void our_ctor(void *new)
{
struct myctx *ctx = new;
struct task_struct *p = current;
pr_info("in ctor: just alloced mem object is # 0x%px\n", ctx); /* %pK in production */
memset(ctx, 0, sizeof(struct myctx));
/* As a demo, we init the 'config' field of our structure to some
* (arbitrary) 'accounting' values from our task_struct
*/
snprintf(ctx->config, 6 * sizeof(u64) + 5, "%d.%d,%ld.%ld,%ld,%ld",
p->tgid, p->pid, p->nvcsw, p->nivcsw, p->min_flt, p->maj_flt);
}
static int create_our_cache(void)
{
int ret = 0;
void *ctor_fn = NULL;
if (use_ctor == 1)
ctor_fn = our_ctor;
pr_info("sizeof our ctx structure is %zu bytes\n"
" using custom constructor routine? %s\n",
sizeof(struct myctx), use_ctor == 1 ? "yes" : "no");
/* Create a new slab cache:
* kmem_cache_create(const char *name, unsigned int size, unsigned int align,
slab_flags_t flags, void (*ctor)(void *));
*/
gctx_cachep = kmem_cache_create(OURCACHENAME,
sizeof(struct myctx), // (min) size of each object
sizeof(long), // alignment
SLAB_POISON | /* the whole point here */
SLAB_RED_ZONE | /* good for catching buffer under|over-flow bugs */
SLAB_HWCACHE_ALIGN, /* good for performance */
ctor_fn); // ctor: NULL by default
if (!gctx_cachep) {
/* When a mem alloc fails we'll usually not require a warning
* message as the kernel will definitely emit warning printk's
* We do so here pedantically...
*/
pr_warn("kmem_cache_create() failed\n");
if (IS_ERR(gctx_cachep))
ret = PTR_ERR(gctx_cachep);
}
return ret;
}
static int __init slab_custom_init(void)
{
pr_info("inserted\n");
create_our_cache();
use_our_cache();
return 0; /* success */
}
static void __exit slab_custom_exit(void)
{
kmem_cache_free(gctx_cachep, obj);
use_the_object(obj, '!', 10); /* the (here pretty obvious) UAF BUG ! */
kmem_cache_destroy(gctx_cachep);
pr_info("custom cache destroyed; removed\n");
}
module_init(slab_custom_init);
module_exit(slab_custom_exit);

Windows WriteFile and ReadFile interferes with each other

I have two threads, one calls WriteFile, the other calls ReadFile, both uses the same serial port at 115200. What I have found repeatedly is that when I add more sequential WriteFile calls in the writing thread, is that I have an increased number of check-sum failures i.e. corrupt data. If I add delays between the WriteFile calls in the writing thread (using CBaseDLIMessage::CrossSleep(20) ), the check-sum errors reduce or even completely go away (depending on the sleep time), however the problem comes back when adding additional WriteFile methods.
Is it possible that the WriteFile method can somehow write data into a shared buffer, which is also used for reading (at driver level), which subsequently corrupts my read data?
My serial setup code looks like this:
CommHandle OpenSerialPort(int nId, long baud)
{
#if defined(USE_WINDOWS_SERIAL_PORT_LIB)
char szCOM[16];
/* COM waiting */
COMMTIMEOUTS g_cto =
{
MAXDWORD, /* ReadIntervalTimeOut */
0, /* ReadTotalTimeOutMultiplier */
0, /* ReadTotalTimeOutConstant */
0, /* WriteTotalTimeOutMultiplier */
0 /* WriteTotalTimeOutConstant */
};
/* COM configuration */
DCB g_dcb =
{
sizeof(DCB), /* DCBlength */
baud, /* BaudRate */
TRUE, /* fBinary */
FALSE, /* fParity */
FALSE, /* fOutxCtsFlow */
FALSE, /* fOutxDsrFlow */
DTR_CONTROL_DISABLE, /* fDtrControl */
FALSE, /* fDsrSensitivity */
FALSE, /* fTXContinueOnXoff */
FALSE, /* fOutX */
FALSE, /* fInX */
FALSE, /* fErrorChar */
FALSE, /* fNull */
RTS_CONTROL_DISABLE, /* fRtsControl */
FALSE, /* fAbortOnError */
0, /* fDummy2 */
0, /* wReserved */
0x100, /* XonLim */
0x100, /* XoffLim */
8, /* ByteSize */
NOPARITY, /* Parity */
ONESTOPBIT, /* StopBits */
0x11, /* XonChar */
0x13, /* XoffChar */
'?', /* ErrorChar */
0x1A, /* EofChar */
0x10 /* EvtChar */
};
//cout << "COM:::" << nId;
sprintf(szCOM, "\\\\.\\COM%d", nId);
HANDLE hCOM = CreateFile(szCOM, /* lpFileName */
GENERIC_READ|GENERIC_WRITE, /* dwDesiredAccess */
0, /* dwShareMode */
NULL, /* lpSecurityAttributes */
OPEN_EXISTING, /* dwCreationDisposition */
FILE_ATTRIBUTE_SYSTEM, /* dwFlagsAndAttributes */
NULL); /* hTemplateFile */
//std::cout << "COM: " << (int)nId << "\n";
if(hCOM == INVALID_HANDLE_VALUE)
{
//std::cout << "INVALID_HANDLE_VALUE \n" ;
DWORD err = GetLastError();
if (err == ERROR_FILE_NOT_FOUND)
{
std::cout << "Error: Failed to open COM[" << nId << "]\n";
}
else if(err == ERROR_INVALID_NAME)
{
std::cout << "\nError: \n%s 'filename, directory name, or volume label syntax is incorrect'\n"; //error code 0x7B
}
else
{
//cout << "\nHandle creation error code: %x\n" << err;
}
return 0;
}
else
{
std::cout << "COM[" << nId << "] OPEN. Baud: " << baud <<"\n";
}
// COM buffer size
SetupComm(hCOM, RX_SIZE, TX_SIZE);
// COM config
if(!SetCommTimeouts(hCOM, &g_cto) || !SetCommState(hCOM, &g_dcb))
{
CloseHandle(hCOM);
return 0;
}
// COM buffer purge
PurgeComm(hCOM, PURGE_TXCLEAR|PURGE_RXCLEAR|PURGE_TXABORT|PURGE_RXABORT);
EscapeCommFunction(hCOM, SETDTR);
return hCOM;
#else
wxSerialPort *pwxSerialPort = new wxSerialPort();
char szPort[32];
sprintf(szPort,"com%d", nId);
if(pwxSerialPort->Open(szPort) < 0) {
return 0;
}
// set the baudrate
pwxSerialPort->SetBaudRate((wxBaud)baud);
return pwxSerialPort;
#endif
}
int CloseSerialPort(CommHandle hSerialPort)
{
#if defined(USE_WINDOWS_SERIAL_PORT_LIB)
CloseHandle(hSerialPort);
return 1;
#else
hSerialPort->Close();
delete hSerialPort;
return 1;
#endif
}
int WriteDataToSerialPort(CommHandle hSerialPort, void *pMsg, unsigned short messageLength, unsigned int *pBytesWritten)
{
*pBytesWritten = 0;
if(hSerialPort == 0)
{
//cout << "hSerialPort ====== 0";
return -1;
}
#if defined(USE_WINDOWS_SERIAL_PORT_LIB)
return WriteFile(hSerialPort, (char*)pMsg, messageLength, (DWORD*)pBytesWritten, NULL);
#else
*pBytesWritten = hSerialPort->Write((char*)pMsg, messageLength);
return 1;
#endif
}
int ReadDataFromSerialPort(CommHandle hSerialPort, void *pMsg, unsigned short messageLength, unsigned int *pBytesRead)
{
unsigned short i;
*pBytesRead = 0;
i = 0;
if(hSerialPort == 0)
{
return -1;
}
#if defined(USE_WINDOWS_SERIAL_PORT_LIB)
return ReadFile(hSerialPort, (char*)pMsg, messageLength, (DWORD*)pBytesRead, NULL);
#else
*pBytesRead = hSerialPort->Read((char*)pMsg, messageLength);
return 1;
#endif
}
Communication through serial port is slow.
You should use WriteFileEx instead of WriteFile.
You can specify a routine which may execute when the writting(transmitting) is completed or failed.
If you write next data after that routine has been executed, overflow of data may not be occured.

Callback function with carbon API

I'm trying to install a callback function with a carbon API but it doesn't work: it is triggered correctly by the event (when it finishes speaking) but it returns a segmentation fault 11 instead of printing "...Finished.".
Here's the code:
...
/* Creates SpeechChannel */
SpeechChannel speechchannel;
NewSpeechChannel(NULL,&speechchannel);
/* Sets callback */
CFNumberRef cbf = CFNumberCreate (
NULL,
kCFNumberLongType,
MySpeechDoneProc
);
OSErr error1;
error1 = SetSpeechProperty (speechchannel,kSpeechSpeechDoneCallBack,cbf);
/* Speaks it */
OSErr error2;
error2 = SpeakCFString(speechchannel, finalString, NULL);
...
later there is:
void MySpeechDoneProc (SpeechChannel chan,long refCon)
{
printf("...Finished.");
};
I guess I'm not installing the callback function properly?
The problem was that I didn't use the pointer to callback function in the creation of the CFNumberRef. The solution is twofold:
1) Declare the pointer for the function along with the function:
/* callback function */
void MySpeechDoneProc (SpeechChannel chan,long refCon);
/* callback function pointer */
void (*MySpeechDoneProcPtr)(SpeechChannel,long);
2) Pass the address of the callback function pointer as third argument in CFNumberCreate:
error1 = SetSpeechProperty (speechchannel,kSpeechSpeechDoneCallBack,cbf);
Here is the working code:
...
/* Creates SpeechChannel */
SpeechChannel speechchannel;
NewSpeechChannel(NULL,&speechchannel);
/* Sets callback */
MySpeechDoneProcPtr = &MySpeechDoneProc;
CFNumberRef cbf = CFNumberCreate (
NULL,
kCFNumberLongType,
&MySpeechDoneProcPtr
);
OSErr error1;
error1 = SetSpeechProperty (speechchannel,kSpeechSpeechDoneCallBack,cbf);
/* Speaks it */
OSErr error2;
printf("Speaking...\n");
error2 = SpeakCFString(speechchannel, finalString, NULL);
...

implementation of mib2c generated code

/*
* Note: this file originally auto-generated by mib2c using
* $
*/
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include "pool.h"
/** Initializes the pool module */
void
init_pool(void)
{
/* here we initialize all the tables we're planning on supporting */
initialize_table_poolTable();
}
//Determine the first/last column names
/** Initialize the poolTable table by defining its contents and how it's structured */
void
initialize_table_poolTable(void)
{
const oid poolTable_oid[] = {1,3,6,1,4,1,21068,4,2};
const size_t poolTable_oid_len = OID_LENGTH(poolTable_oid);
netsnmp_handler_registration *reg;
netsnmp_iterator_info *iinfo;
netsnmp_table_registration_info *table_info;
DEBUGMSGTL(("pool:init", "initializing table poolTable\n"));
reg = netsnmp_create_handler_registration(
"poolTable", poolTable_handler,
poolTable_oid, poolTable_oid_len,
HANDLER_CAN_RONLY
);
table_info = SNMP_MALLOC_TYPEDEF( netsnmp_table_registration_info );
netsnmp_table_helper_add_indexes(table_info,
ASN_INTEGER, /* index: ifIndex */
0);
table_info->min_column = 1;
table_info->max_column = COLUMN_POOLINOCTETS;
iinfo = SNMP_MALLOC_TYPEDEF( netsnmp_iterator_info );
iinfo->get_first_data_point = poolTable_get_first_data_point;
iinfo->get_next_data_point = poolTable_get_next_data_point;
iinfo->table_reginfo = table_info;
netsnmp_register_table_iterator( reg, iinfo );
/* Initialise the contents of the table here */
}
/* Typical data structure for a row entry */
struct poolTable_entry {
/* Index values */
long ifIndex;
/* Column values */
u_long poolInOctets;
/* Illustrate using a simple linked list */
int valid;
struct poolTable_entry *next;
};
struct poolTable_entry *poolTable_head;
/* create a new row in the (unsorted) table */
struct poolTable_entry *
poolTable_createEntry(
long ifIndex
) {
struct poolTable_entry *entry;
entry = SNMP_MALLOC_TYPEDEF(struct poolTable_entry);
if (!entry)
return NULL;
entry->ifIndex = ifIndex;
entry->next = poolTable_head;
poolTable_head = entry;
return entry;
}
/* remove a row from the table */
void
poolTable_removeEntry( struct poolTable_entry *entry ) {
struct poolTable_entry *ptr, *prev;
if (!entry)
return; /* Nothing to remove */
for ( ptr = poolTable_head, prev = NULL;
ptr != NULL;
prev = ptr, ptr = ptr->next ) {
if ( ptr == entry )
break;
}
if ( !ptr )
return; /* Can't find it */
if ( prev == NULL )
poolTable_head = ptr->next;
else
prev->next = ptr->next;
SNMP_FREE( entry ); /* XXX - release any other internal resources */
}
/* Example iterator hook routines - using 'get_next' to do most of the work */
netsnmp_variable_list *
poolTable_get_first_data_point(void **my_loop_context,
void **my_data_context,
netsnmp_variable_list *put_index_data,
netsnmp_iterator_info *mydata)
{
*my_loop_context = poolTable_head;
return poolTable_get_next_data_point(my_loop_context, my_data_context,
put_index_data, mydata );
}
netsnmp_variable_list *
poolTable_get_next_data_point(void **my_loop_context,
void **my_data_context,
netsnmp_variable_list *put_index_data,
netsnmp_iterator_info *mydata)
{
struct poolTable_entry *entry = (struct poolTable_entry *)*my_loop_context;
netsnmp_variable_list *idx = put_index_data;
if ( entry ) {
snmp_set_var_typed_integer( idx, ASN_INTEGER, entry->ifIndex );
idx = idx->next_variable;
*my_data_context = (void *)entry;
*my_loop_context = (void *)entry->next;
return put_index_data;
} else {
return NULL;
}
}
/** handles requests for the poolTable table */
int
poolTable_handler(
netsnmp_mib_handler *handler,
netsnmp_handler_registration *reginfo,
netsnmp_agent_request_info *reqinfo,
netsnmp_request_info *requests) {
netsnmp_request_info *request;
netsnmp_table_request_info *table_info;
struct poolTable_entry *table_entry;
DEBUGMSGTL(("pool:handler", "Processing request (%d)\n", reqinfo->mode));
switch (reqinfo->mode) {
/*
* Read-support (also covers GetNext requests)
*/
case MODE_GET:
for (request=requests; request; request=request->next) {
table_entry = (struct poolTable_entry *)
netsnmp_extract_iterator_context(request);
table_info = netsnmp_extract_table_info( request);
switch (table_info->colnum) {
case COLUMN_POOLINOCTETS:
if ( !table_entry ) {
netsnmp_set_request_error(reqinfo, request,
SNMP_NOSUCHINSTANCE);
continue;
}
snmp_set_var_typed_integer( request->requestvb, ASN_COUNTER,
table_entry->poolInOctets);
break;
default:
netsnmp_set_request_error(reqinfo, request,
SNMP_NOSUCHOBJECT);
break;
}
}
break;
}
return SNMP_ERR_NOERROR;
}
above is my mib2c generated code. I am compiling it as subagent... but it is not showing any kind of values. What should be my next step to implement it ? from where can I get data? Please help me to implement it.
snmpwalk -c public -v 2c localhost 1.3.6.1.4.1.21068
POOL-MIB::elite = No Such Object available on this agent at this OID
Thansks in advance.
You need to add data to the poolTable_head linked list of data. You can do this like so:
struct poolTable_entry *entry = poolTable_createEntry(1);
entry->poolInOctets = 42;
And then put that code, which is just very basic example code with static numbers, somewhere that will get called. You could, for example, put it at the bottom of the initialize_table_poolTable() function.
Note that mib2c generates a lot of different coding styles, and based on what I see above I'm not quite convinced you chose the right style as it doesn't look like your data will be highly static and thus you'll need to set an alarm (see snmp_alarm(3)) to update the poolInOctets numbers on a regular basis.

Resources