Is the return value of pycurl.CurlMulti.info_read still usable after call to remove_handle? - libcurl

I am using pycurl.CurlMulti interface in python3 and I want to use info_read to check for the succeeded and failed connections.
According to the documentation of the c interface curl_multi_info_read of libcurl:
WARNING: The data the returned pointer points to will not survive calling curl_multi_cleanup, curl_multi_remove_handle or curl_easy_cleanup.
However, the documentation of pycurl.CurlMulti does not mention whether the curl error message in the return value of pycurl.CurlMulti.info_read() is valid after a call to curl_multi_remove_handle.
The only way to check this is read the source code of pycurl.

I checked the source code for pycurl.CurlMulti.info_read and it shows that:
/* When an error occurs */
else {
/* Create a result tuple that will get added to err_list. */
PyObject *v = Py_BuildValue("(Ois)", (PyObject *)co, (int)msg->data.result, co->error);
/* Append curl object to list of objects which failed */
if (v == NULL || PyList_Append(err_list, v) != 0) {
Py_XDECREF(v);
goto error;
}
Py_DECREF(v);
}
where co is retrieved from L781:
/* Fetch the curl object that corresponds to the curl handle in the message */
res = curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, (char **) &co);
And CURLINFO_PRIVATE and co->error is set at src/easy.c#L52:
/* Set curl error buffer and zero it */
res = curl_easy_setopt(self->handle, CURLOPT_ERRORBUFFER, self->error);
if (res != CURLE_OK) {
return (-1);
}
memset(self->error, 0, sizeof(self->error));
/* Set backreference */
res = curl_easy_setopt(self->handle, CURLOPT_PRIVATE, (char *) self);
if (res != CURLE_OK) {
return (-1);
}
which means that given the pycurl.Curl object is not reused for another connection or destroyed, it should be pretty safe to use the curl error message in the return value of pycurl.CurlMulti.info_read().
This answer gives me another interesting fact:
It is not safe to set CURLOPT_PRIVATE on the pycurl.Curl object.

Related

freeDiameter based server cannot read received buffer

I have tried to set up a server with a specific IP address and Port number by freeDiameter libraries. In other side, there is a client that sends a string message via freeDiameter libraries successfully; I checked it out in Wireshark.
So, here is the problem; when I start listening from the server side, it has no problem until a client sends a connection request; if you look at the below code, "fd_cnx_serv_accept(listener)" is listening to a socket named "listener" which is bind to a specific IP address and Port number.
uint8_t * rcv_buf;
size_t rcv_size;
struct cnxctx * listener_side = NULL;
int ret;
listener_side = fd_cnx_serv_accept(listener);
ret = fd_cnx_start_clear(listener_side, 0);
if(ret != 0){
std::cout<<side<<" is unable to accept connections."<<std::endl;
return -1;
}
ret = fd_cnx_receive(listener_side, NULL, &rcv_buf, &rcv_size);
if(ret == 0){
std::cout<<"Message received."<<std::endl;
listener_side = NULL;
free(rcv_buf);
}
The program works fine until it gets a client request; when "fd_cnx_serv_accept" accept the client side, the program tries to receive the message by "fd_cnx_receive"; but the program stops and shows the error "Segmentation fault (core dumped)". Then, I test the program by gdb and it shows that it is something wrong with the line 309 of "hook.c". Here is the image of the error which is shown by gdb.
Error Screenshot
transcript
multi-thre Thread 0x7fffff72a77 In: fd_hook_call
[New Thread 0x7fffff72a7700 (LWP 1612914)
Thread 2 "server" received signal SIGSEGEV, Segmentation Fault
[Switching to Thread 0x7fffff72a7700 (LWP 1612914)
--Type <RET> for more, q to quit, c to continue without paging --c
0x00007ffff7f2cefc in fd_hook_call (type=HOOD_DATA_RECEIVED, msg=0x0, peer=0x0, other=0x7ffff72a6be0, pmdl=0x7ffff0000ba8 at /root/projects/start_cnx_free/third-party/libfdcore/hooks.c:309
It is good to mention that I am trying to write a c++ program.
How can I solve this problem ?
I solved this problem myself. I forgot to use fd_hooks_init() at the begining of my program to initialize necessary libraries and objects.
Here is the modified code:
/* Initialize the library -- must come first since it initializes the debug facility */
int ret = fd_libproto_init();
if (ret != 0) {
fprintf(stderr, "Unable to initialize libfdproto: %s\n", strerror(ret));
return ret;
}
ret = fd_hooks_init();
if(ret != 0){
std::cout<<"Unable to initialize the hooks."<<std::endl;
return ret;
}
/* Initialize the config with default values */
memset(&g_conf, 0, sizeof(struct fd_config));
fd_g_config = &g_conf;
ret = fd_conf_init();
if (ret != 0) {
printf("Unable to initialize the config with default values.");
return ret;
}
/* Add definitions of the base protocol */
ret = fd_dict_base_protocol(fd_g_config->cnf_dict);
if (ret != 0) {
printf("Unable to add definitions of the base protocol.");
return ret;
}

What is the preferred way to get a device path for CreateFile() in a UWP C++ App?

I am converting a project to a UWP App, and thus have been following guidelines outlined in the MSDN post here. The existing project heavily relies on CreateFile() to communicate with connected devices.
There are many posts in SO that show us how to get a CreateFile()-accepted device path using SetupAPI's SetupDiGetDeviceInterfaceDetail() Is there an alternative way to do this using the PnP Configuration Manager API? Or an alternative, user-mode way at all?
I had some hope when I saw this example in Windows Driver Samples github, but quickly became dismayed when I saw that the function they used in the sample is ironically not intended for developer use, as noted in this MSDN page.
function GetDevicePath in general correct and can be used as is. about difference between CM_*(..) and CM_*_Ex(.., HMACHINE hMachine) - the CM_*(..) simply call CM_*_Ex(.., NULL) - so for local computer versions with and without _Ex suffix the same.
about concrete GetDevicePath code - call CM_Get_Device_Interface_List_Size and than CM_Get_Device_Interface_List only once not 100% correct - because between this two calls new device with this interface can be arrived to system and buffer size returned by CM_Get_Device_Interface_List_Size can be already not enough for CM_Get_Device_Interface_List. of course possibility of this very low, and you can ignore this. but i prefer make code maximum theoretical correct and call this in loop, until we not receive error other than CR_BUFFER_SMALL. also need understand that CM_Get_Device_Interface_List return multiple, NULL-terminated Unicode strings - so we need iterate here. in [example] always used only first returned symbolic link name of an interface instance. but it can be more than 1 or at all - 0 (empty). so better name function - GetDevicePaths - note s at the end. i be use code like this:
ULONG GetDevicePaths(LPGUID InterfaceClassGuid, PWSTR* pbuf)
{
CONFIGRET err;
ULONG len = 1024;//first try with some reasonable buffer size, without call *_List_SizeW
for(PWSTR buf;;)
{
if (!(buf = (PWSTR)LocalAlloc(0, len * sizeof(WCHAR))))
{
return ERROR_NO_SYSTEM_RESOURCES;
}
switch (err = CM_Get_Device_Interface_ListW(InterfaceClassGuid, 0, buf, len, CM_GET_DEVICE_INTERFACE_LIST_PRESENT))
{
case CR_BUFFER_SMALL:
err = CM_Get_Device_Interface_List_SizeW(&len, InterfaceClassGuid, 0, CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
default:
LocalFree(buf);
if (err)
{
return CM_MapCrToWin32Err(err, ERROR_UNIDENTIFIED_ERROR);
}
continue;
case CR_SUCCESS:
*pbuf = buf;
return NOERROR;
}
}
}
and usage example:
void example()
{
PWSTR buf, sz;
if (NOERROR == GetDevicePaths((GUID*)&GUID_DEVINTERFACE_VOLUME, &buf))
{
sz = buf;
while (*sz)
{
DbgPrint("%S\n", sz);
HANDLE hFile = CreateFile(sz, FILE_GENERIC_READ, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
// do something
CloseHandle(hFile);
}
sz += 1 + wcslen(sz);
}
LocalFree(buf);
}
}
so we must not simply use in returned DevicePathS (sz) only first string, but iterate it
while (*sz)
{
// use sz
sz += 1 + wcslen(sz);
}
I got a valid Device Path to a USB Hub Device, and used it successfully to get various device descriptors by sending some IOCTLs, by using the function I posted in my own answer to another question
I'm reporting the same function below:
This function returns a list of NULL-terminated Device Paths (that's what we get from CM_Get_Device_Interface_List())
You need to pass it the DEVINST, and the wanted interface GUID.
Since both the DEVINST and interface GUID are specified, it is highly likely that CM_Get_Device_Interface_List() will return a single Device Path for that interface, but technically you should be prepared to get more than one result.
It is responsibility of the caller to delete[] the returned list if the function returns successfully (return code 0)
int GetDevInstInterfaces(DEVINST dev, LPGUID interfaceGUID, wchar_t**outIfaces, ULONG* outIfacesLen)
{
CONFIGRET cres;
if (!outIfaces)
return -1;
if (!outIfacesLen)
return -2;
// Get System Device ID
WCHAR sysDeviceID[256];
cres = CM_Get_Device_ID(dev, sysDeviceID, sizeof(sysDeviceID) / sizeof(sysDeviceID[0]), 0);
if (cres != CR_SUCCESS)
return -11;
// Get list size
ULONG ifaceListSize = 0;
cres = CM_Get_Device_Interface_List_Size(&ifaceListSize, interfaceGUID, sysDeviceID, CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
if (cres != CR_SUCCESS)
return -12;
// Allocate memory for the list
wchar_t* ifaceList = new wchar_t[ifaceListSize];
// Populate the list
cres = CM_Get_Device_Interface_List(interfaceGUID, sysDeviceID, ifaceList, ifaceListSize, CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
if (cres != CR_SUCCESS) {
delete[] ifaceList;
return -13;
}
// Return list
*outIfaces = ifaceList;
*outIfacesLen = ifaceListSize;
return 0;
}
Please note that, as RbMm already said in his answer, you may get a CR_BUFFER_SMALL error from the last CM_Get_Device_Interface_List() call, since the device list may have been changed in the time between the CM_Get_Device_Interface_List_Size() and CM_Get_Device_Interface_List() calls.

Delphi - Convert (read) C++ NULL terminated array from dll call

Help, I'm getting crazy :)
I'm playing around with TeamSpeak3 and have a dll call which returns an array of Clients (ID's) online. My problem is that it is returned in a structure I cannot figure out to read in Object Pascal.
The SDK manual specifies this:
This is what the docs says
To get a list of all currently visible clients on the specified virtual server:
unsigned intts3client_getClientList(serverConnectionHandlerID, result);
uint64 serverConnectionHandlerID;
anyID** result;
Parameters
• serverConnectionHandlerID
ID of the server connection handler for which the list of clients is requested.
• result
Address of a variable that receives a NULL-termianted array of client IDs. Unless an error occurs, the array must be released
using ts3client_freeMemory.
Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h. If an error has occured, the
result array is uninitialized and must not be released.
This is my Delphi code so far.
type
PPanyID = ^PAnyID;
PanyID = ^anyID;
anyID = word;
// declaration looks like this, some guy called CodeJunkie ported it from C++)
function ts3client_getClientList(serverConnectionHandlerID: uint64; result: PPanyID): longword; cdecl; external CLIENT_DLL {$IFDEF MACOS}name '_ts3client_getClientList'{$ENDIF};
procedure TfrmMain.RequestOnlineClients;
var
clientids : PAnyId;
i : Integer;
begin
error := ts3client_getClientList(FTSServerHandlerID, #clientids);
if (error <> ERROR_ok) then
begin
if (ts3client_getErrorMessage(error, #errormsg) = ERROR_ok) then
begin
LogMsg(Format('Error requesting online clients: %s', [errormsg]));
ts3client_freeMemory(errormsg);
end;
end else
begin
// Put in into some regular Object array here, but how the h......
// Or at least interate the received array of ID's
end;
end;
The example code in C++ looks like this and it works, I didn't write it :)
void showClients(uint64 serverConnectionHandlerID) {
anyID *ids;
anyID ownClientID;
int i;
unsigned int error;
printf("\nList of all visible clients on virtual server %llu:\n", (unsigned long long)serverConnectionHandlerID);
if((error = ts3client_getClientList(serverConnectionHandlerID, &ids)) != ERROR_ok) { /* Get array of client IDs */
printf("Error getting client list: %d\n", error);
return;
}
if(!ids[0]) {
printf("No clients\n\n");
ts3client_freeMemory(ids);
return;
}
/* Get own clientID as we need to call CLIENT_FLAG_TALKING with getClientSelfVariable for own client */
if((error = ts3client_getClientID(serverConnectionHandlerID, &ownClientID)) != ERROR_ok) {
printf("Error querying own client ID: %d\n", error);
return;
}
for(i=0; ids[i]; i++) {
char* name;
int talkStatus;
if((error = ts3client_getClientVariableAsString(serverConnectionHandlerID, ids[i], CLIENT_NICKNAME, &name)) != ERROR_ok) { /* Query client nickname... */
printf("Error querying client nickname: %d\n", error);
break;
}
if(ids[i] == ownClientID) { /* CLIENT_FLAG_TALKING must be queried with getClientSelfVariable for own client */
if((error = ts3client_getClientSelfVariableAsInt(serverConnectionHandlerID, CLIENT_FLAG_TALKING, &talkStatus)) != ERROR_ok) {
printf("Error querying own client talk status: %d\n", error);
break;
}
} else {
if((error = ts3client_getClientVariableAsInt(serverConnectionHandlerID, ids[i], CLIENT_FLAG_TALKING, &talkStatus)) != ERROR_ok) {
printf("Error querying client talk status: %d\n", error);
break;
}
}
printf("%u - %s (%stalking)\n", ids[i], name, (talkStatus == STATUS_TALKING ? "" : "not "));
ts3client_freeMemory(name);
}
printf("\n");
ts3client_freeMemory(ids); /* Release array */
}
Please, can anybody help out here??
The pointer you get back points to the first result. Doing Inc(clientids) moves you on to the next result. Keep going until you reach an anyid that is zero ("NULL").
(You also need to save the original value of clientids so you can pass it to the free function as the documentation says to avoid leaking the memory.)
G is this for real, is this seriously the only way of reading arrays returned from a c++ dll? And will this work with 64bit too?
procedure TfrmMain.RequestOnlineClients;
var
ids : array of anyID;
pids : PanyID;
aid : anyID;
begin
error := ts3client_getClientList(FTSServerHandlerID, #ids);
if (error <> ERROR_ok) then
begin
if (ts3client_getErrorMessage(error, #errormsg) = ERROR_ok) then
begin
LogMsg(Format('Error requesting online clients: %s', [errormsg]));
ts3client_freeMemory(errormsg);
end;
end else
begin
pids := #ids[0];
while (pids^ <> 0) do
begin
aid := pids^;
LogMsg(format('id %u',[aid]));
inc(pids);
end;
ts3client_freeMemory(#pids^);
end;
end;

pcap_next_ex() never sets the pointer to the raw packet?

I tried to read in the raw packet with libpcap (1.4.0 on CentOS 6).
However, for some reasons, rawPacket is always NULL after pcap_next_ex().
However, pcap_next_ex() does return 1 though it could mean timeout expired (where the timeout is set by the way?).
First, I thought that the filter string I passed into pcap_compile() was wrong. But I tried to copy and paste the same string to tcpdump, it worked fine -- I see expected packets being captured.
struct pcap_pkthdr *pHeader;
const u_char* rawPacket = NULL;
int rc = 0;
while (1) {
rc = pcap_next_ex(pDevice, &pHeader, &rawPacket);
if (-1 != rc && NULL != rawPacket) {
// process
struct ether_header* eptr = (struct ether_header *) rawPacket;
if (ntohs (eptr->ether_type) == ETHERTYPE_IP) {
printf("Ethernet type hex:%x dec:%d is an IP packet\n",
ntohs(eptr->ether_type),
ntohs(eptr->ether_type));
}
}
}
Any idea?
Thanks in advance.
Actually, what the pcap_next_ex() man page says is
pcap_next_ex() returns 1 if the packet was read without problems, 0 if
packets are being read from a live capture, and the timeout expired, -1
if an error occurred while reading the packet, and -2 if packets are
being read from a ``savefile'', and there are no more packets to read
from the savefile. If -1 is returned, pcap_geterr() or pcap_perror()
may be called with p as an argument to fetch or display the error text.
I need to edit it to remove the comment between "live capture" and "and the timeout expired", because what that means is that pcap_next_ex() returns:
1, if a packet was read or captured, in which case the pointer should be set to the raw packet;
0, if this is a live capture and the timeout (as specified in pcap_open_live() or, if you used pcap_create() and pcap_activate(), pcap_set_timeout()) expired while waiting for a packet, in which case no packet was read and the pointer will be set to NULL;
-1, if an error occurred while reading or capturing, in which case no packet was read and the pointer will be set to NULL;
-2, if this is a file being read and there are no more packets left to be read, in which case no packet was read and the pointer will be set to NULL.
So what you should do, after the pcap_next_ex() call, is:
if (1 == rc) {
// process
struct ether_header* eptr = (struct ether_header *) rawPacket;
if (ntohs (eptr->ether_type) == ETHERTYPE_IP) {
printf("Ethernet type hex:%x dec:%d is an IP packet\n",
ntohs(eptr->ether_type),
ntohs(eptr->ether_type));
}
} else if (0 == rc) {
// do nothing here - this isn't an error, but you have no packet
;
} else if (-1 == rc) {
// error
fprintf(stderr, "Error capturing or reading: %s\n", pcap_geterr(pDevice));
// quit trying to read or capture packets here
} else if (-2 == rc) {
// end of file if you're reading from a file
// this isn't an error, but there are no more packets to read
// so quit trying to read packets here
}

sqlite3_open - problems checking if a file is a sqlite3 database

I'm working with sqlite3 for the first time, and cannot get it to properly check a file before it opens it. So far, sqlite always returns OK on any file.
Also, the file name is a variable returned from the GTK file chooser. It returns an absolute path, I'm guessing this is not a problem.
Thanks for any help.
This is a snippet of the code:
int rc;
char *filename;
sqlite3 *db;
filename = gtk_file_chooser_get_filename(etc.);
if(SQLITE_OK == rc = sqlite3_open(filename,&db))
{ etc. }
sqlite3_open doesn't actually read the file until the first non-pragma statement is prepared.
sqlite3_open_v2 provides other options.
Does your code compile?
I believe this is an error
if (SQLITE_OK == rc = sqlite3_open(filename,&db)) { /* ... */ }
it's the same as
if ((SQLITE_OK == rc) = sqlite3_open(filename,&db)) { /* ... */ }
and you cannot assign something (the result of the sqlite3_open() call) to (SQLITE_OK == rc).
Try this:
if ((rc = sqlite3_open(filename,&db)) == SQLITE_OK) { /* ... */ }
/* or, if you really want the constant on the left side of the comparison */
if (SQLITE_OK == (rc = sqlite3_open(filename,&db))) { /* ... */ }