How to get data from POST/GET method in a C program? - c

I want to write a simple program that takes data from forms via POST OR GET. A simple form lets say for adding two numbers.
I saw that libcurl is capable of talking with http protocol but I did not see any example related to this question.
All i saw is how to send data to webpage but not how to get it.
Thank you for your time.

Quick-n-dirty, very untested example based on another project of mine - no warranties express or implied. This assumes that the binary has properly been deployed on the Web server (for example, under the cgi-bin directory on an Apache server) and that the input form has been set up to call it properly:
<form action="http://my-url.com/cgi-bin/adder" method="get"> <!-- or method="post" -->
<label for="v1">V1:</label><input type="text" name="v1"><br>
<label for="v2">V2:</label><input type="text" name="v2"><br>
<input type="submit" name="submitbutton" value="Add">
</form>
Then your C code will look something like
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char **argv )
{
char *interface = getenv( "GATEWAY_INTERFACE" );
/**
* If interface is NULL, then we were not invoked through CGI.
* For this example we just fail silently.
*/
if ( !interface )
exit( EXIT_FAILURE );
char *method = getenv( "REQUEST_METHOD" );
/**
* If method is NULL, then we were not invoked through CGI;
* for this example we'll just fail silently
*/
if ( !method )
exit( EXIT_FAILURE );
if ( strcmp( method, "GET" ) == 0 )
{
/**
* We were invoked from a Web client with the HTTP GET method -
* input parameters will be in the QUERY_STRING environment
* variable as "param=value&param=value"
*/
char *query_string = getenv( "QUERY_STRING" );
do_stuff_with( query_string );
}
else if ( strcmp( method, "POST" ) == 0 )
{
/**
* We were invoked from a Web client with the HTTP POST method -
* input parameters will be received via standard input
*/
char query_string[SOME_SIZE];
if ( fgets( query_string, sizeof query_string, stdin ) )
{
do_stuff_with( query_string );
}
else
// handle error
}
else
{
/**
* Input method is not GET or POST, log an error and fail
*/
fputs( "Don't know how to handle this request\n", stderr );
exit( EXIT_FAILURE );
}
}
Any response back to the Web client will be written through standard output:
printf( "Content-type: text/html\r\n\r\n" );
printf( "<!DOCTYPE HTML><html><head><title>Adder result</title></head>" );
printf( "<body><p>Result of add is %d</p></body></html>", add_result );

Related

Cannot find output of Win32 TraceLogging

I tried to replicate the short sample program for TraceLogging that Microsoft provides (see below, with minor changes). I completed the "development" (rather copy) in Visual Studio 2019. All is fine, compiles without issues, runs without issues, but nowhere on my PC I can find an updated *.etl or *.log file, nor do I find an entry somewhere in the Event Viewer.
I carefully read the Microsoft documentation and I searched the Internet for many hours, but no useful findings.
I know that I'm stupid from time to time and I must miss something obvious, but what is it? Any hints, please? Many thanks!
#include <windows.h> // or <wdm.h> for kernel-mode.
#include <winmeta.h>
#include <TraceLoggingProvider.h>
#include <stdio.h>
// Define the GUID to use in TraceLoggingRegister
// {5B5852D4-DC24-4A0F-87B6-9115AE9D2768}
TRACELOGGING_DEFINE_PROVIDER ( // defines g_hProvider
g_hProvider, // Name of the provider variable
"Test-Test", // Human-readable name of the provider
(0x5b5852d4, 0xdc24, 0x4a0f, 0x87, 0xb6, 0x91, 0x15, 0xae, 0x9d, 0x27, 0x68) ); // Provider GUID
int main ( int argc, char *argv[] ) // or DriverEntry for kernel-mode.
{
HRESULT hrRegister;
hrRegister = TraceLoggingRegister ( g_hProvider );
if ( !SUCCEEDED ( hrRegister ) ) {
printf ( "TraceLoggingRegister failed. Stopping." );
return 1;
}
TraceLoggingWrite (
g_hProvider,
"MyEvent1",
// TraceLoggingChannel ( WINEVENT_CHANNEL_CLASSIC_TRACE ),
// TraceLoggingLevel ( WINEVENT_LEVEL_CRITICAL ),
TraceLoggingString ( argv[0], "arg0" ), // field name is "arg0"
TraceLoggingInt32 ( argc ) ); // field name is implicitly "argc"
TraceLoggingUnregister ( g_hProvider );
return 0;
}
First of all, running this C++ code will not generate the .log or .etl file you want, it just sends the TraceLogging event, you need to capture it in other ways to generate the etl file.
According to the MSDN,You have two steps to capture TraceLogging events:
Capture trace data with WPR
Capture TraceLogging events on Windows Phone
First create a .WPRP file, I used the same C++ code and WPRP file from MSDN as follow.
test.cpp
#include <windows.h> // or <wdm.h> for kernel-mode.
#include <winmeta.h>
#include <TraceLoggingProvider.h>
#include <stdio.h>
// Define the GUID to use in TraceLoggingProviderRegister
// {3970F9cf-2c0c-4f11-b1cc-e3a1e9958833}
TRACELOGGING_DEFINE_PROVIDER(
g_hMyComponentProvider,
"SimpleTraceLoggingProvider",
(0x3970f9cf, 0x2c0c, 0x4f11, 0xb1, 0xcc, 0xe3, 0xa1, 0xe9, 0x95, 0x88, 0x33));
void main()
{
char sampleValue[] = "Sample value";
// Register the provider
TraceLoggingRegister(g_hMyComponentProvider);
// Log an event
TraceLoggingWrite(g_hMyComponentProvider, // handle to my provider
"HelloWorldTestEvent", // Event Name that should uniquely identify your event.
TraceLoggingValue(sampleValue, "TestMessage")); // Field for your event in the form of (value, field name).
// Stop TraceLogging and unregister the provider
TraceLoggingUnregister(g_hMyComponentProvider);
}
Sample WPRP file
<?xml version="1.0" encoding="utf-8"?>
<!-- TODO:
1. Find and replace "SimpleTraceLoggingProvider" with the name of your provider.
2. See TODO below to update GUID for your event provider
-->
<WindowsPerformanceRecorder Version="1.0" Author="Microsoft Corporation" Copyright="Microsoft Corporation" Company="Microsoft Corporation">
<Profiles>
<EventCollector Id="EventCollector_SimpleTraceLoggingProvider" Name="SimpleTraceLoggingProvider">
<BufferSize Value="64" />
<Buffers Value="4" />
</EventCollector>
<!-- TODO:
1. Update Name attribute in EventProvider xml element with your provider GUID, eg: Name="3970F9cf-2c0c-4f11-b1cc-e3a1e9958833". Or
if you specify an EventSource C# provider or call TraceLoggingRegister(...) without a GUID, use star (*) before your provider
name, eg: Name="*MyEventSourceProvider" which will enable your provider appropriately.
2. This sample lists one EventProvider xml element and references it in a Profile with EventProviderId xml element.
For your component wprp, enable the required number of providers and fix the Profile xml element appropriately
-->
<EventProvider Id="EventProvider_SimpleTraceLoggingProvider" Name="*SimpleTraceLoggingProvider" />
<Profile Id="SimpleTraceLoggingProvider.Verbose.File" Name="SimpleTraceLoggingProvider" Description="SimpleTraceLoggingProvider" LoggingMode="File" DetailLevel="Verbose">
<Collectors>
<EventCollectorId Value="EventCollector_SimpleTraceLoggingProvider">
<EventProviders>
<!-- TODO:
1. Fix your EventProviderId with Value same as the Id attribute on EventProvider xml element above
-->
<EventProviderId Value="EventProvider_SimpleTraceLoggingProvider" />
</EventProviders>
</EventCollectorId>
</Collectors>
</Profile>
<Profile Id="SimpleTraceLoggingProvider.Light.File" Name="SimpleTraceLoggingProvider" Description="SimpleTraceLoggingProvider" Base="SimpleTraceLoggingProvider.Verbose.File" LoggingMode="File" DetailLevel="Light" />
<Profile Id="SimpleTraceLoggingProvider.Verbose.Memory" Name="SimpleTraceLoggingProvider" Description="SimpleTraceLoggingProvider" Base="SimpleTraceLoggingProvider.Verbose.File" LoggingMode="Memory" DetailLevel="Verbose" />
<Profile Id="SimpleTraceLoggingProvider.Light.Memory" Name="SimpleTraceLoggingProvider" Description="SimpleTraceLoggingProvider" Base="SimpleTraceLoggingProvider.Verbose.File" LoggingMode="Memory" DetailLevel="Light" />
</Profiles>
</WindowsPerformanceRecorder>
Then start the capture using WPR from an elevated (run as Administrator) Command Prompt window.
wpr.exe -start C:\Users\songz\Desktop\test.wprp
Next you may run the application that contains your events and stop the trace capture.
wpr.exe -stop C:\Users\songz\Desktop\test.etl description
This can generate the etl file you need normally.
After completing the above operations, you should capture TraceLogging events. According to the github, you can use the following commands:
xperf -start MySession -f C:\Users\songz\Desktop\test.etl -on 3970F9cf-2c0c-4f11-b1cc-e3a1e9958833
xperf -stop MySession
Note:You should use like xperf -start MySession -f MyFile.etl -on Id
Finally you can view the corresponding information through WPA.
Zhu Song, thank you very much for your input! Your comments brought me to the right track.
Well, I did not follow strictly your text, but I found new stuff to read.
I want the controller to be part of my application as well. So, what I did is roughly the following:
Prepare EVENT_TRACE_PROPERTIES structure
TraceLogRegister
StartTrace
EnableTraceEx2 (enable)
TraceLoggingWrite
TraceLoggingUnregister
EnableTraceEx2 (disable)
ControlTrace (stop)
This resulted in an xxx.etl file that I could view with tracerpt or WPA.
Thanks again! I'm all fine now.
This is the code in detail:
#include <windows.h> // or <wdm.h> for kernel-mode.
#include <winmeta.h>
#include <TraceLoggingProvider.h>
#include <evntrace.h>
#include <stdio.h>
#include <strsafe.h>
#define LOGFILE_NAME TEXT(".\\Test-Test.etl")
#define LOGSESSION_NAME TEXT("Test-Test-Session")
// Define the GUID to use in TraceLoggingRegister
// {5B5852D4-DC24-4A0F-87B6-9115AE9D2768}
TRACELOGGING_DEFINE_PROVIDER ( // defines g_hProvider
g_hProvider, // Name of the provider variable
"Test-Test", // Human-readable name of the provider
(0x5b5852d4, 0xdc24, 0x4a0f, 0x87, 0xb6, 0x91, 0x15, 0xae, 0x9d, 0x27, 0x68) ); // Provider GUID
static const GUID ProviderGUID = { 0x5b5852d4, 0xdc24, 0x4a0f, {0x87, 0xb6, 0x91, 0x15, 0xae, 0x9d, 0x27, 0x68} };
int main ( int argc, char *argv[] ) // or DriverEntry for kernel-mode.
{
TRACEHANDLE hTrace = 0;
EVENT_TRACE_PROPERTIES *petProperties;
HRESULT hrRegister;
ULONG bufferSize, ret_val;
bufferSize = sizeof ( EVENT_TRACE_PROPERTIES ) + sizeof ( LOGFILE_NAME ) + sizeof ( LOGSESSION_NAME ) + 512; // The additional bytes are necessary because the path of thr LOGFILE_NAME is expanded
petProperties = (EVENT_TRACE_PROPERTIES *) malloc ( bufferSize );
if ( petProperties == NULL ) {
printf ( "Unable to allocate %d bytes for properties structure.\n", bufferSize );
return 1;
}
ZeroMemory ( petProperties, bufferSize );
petProperties->Wnode.BufferSize = bufferSize;
petProperties->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
petProperties->Wnode.ClientContext = 1;
petProperties->Wnode.Guid = ProviderGUID;
petProperties->LogFileMode = EVENT_TRACE_FILE_MODE_SEQUENTIAL | EVENT_TRACE_PRIVATE_LOGGER_MODE | EVENT_TRACE_PRIVATE_IN_PROC;
petProperties->MaximumFileSize = 100; // was 1
petProperties->BufferSize = 512;
petProperties->MinimumBuffers = 8;
petProperties->MaximumBuffers = 64;
petProperties->LoggerNameOffset = sizeof ( EVENT_TRACE_PROPERTIES );
petProperties->LogFileNameOffset = sizeof ( EVENT_TRACE_PROPERTIES ) + sizeof ( LOGSESSION_NAME );
StringCbCopy ( (LPWSTR) ((char *) petProperties + petProperties->LogFileNameOffset), sizeof ( LOGFILE_NAME ), LOGFILE_NAME );
hrRegister = TraceLoggingRegister ( g_hProvider );
if ( !SUCCEEDED ( hrRegister ) ) {
printf ( "TraceLoggingRegister failed. Stopping.\n" );
return 1;
}
ret_val = StartTrace ( &hTrace, LOGSESSION_NAME, petProperties );
if ( ret_val != ERROR_SUCCESS ) {
printf ( "StartTrace failed with %i\n", ret_val );
if ( ret_val != ERROR_ALREADY_EXISTS )
return 1;
}
ret_val = EnableTraceEx2 ( hTrace, &ProviderGUID, EVENT_CONTROL_CODE_ENABLE_PROVIDER, TRACE_LEVEL_VERBOSE, 0, 0, 0, NULL );
if ( ret_val != ERROR_SUCCESS ) {
printf ( "EnableTraceEx2(enable) failed with %i\n", ret_val );
ret_val = ControlTrace ( hTrace, LOGSESSION_NAME, petProperties, EVENT_TRACE_CONTROL_STOP );
if ( ret_val != ERROR_SUCCESS ) {
printf ( "ControlTrace(stop) failed with %i\n", ret_val );
}
return 1;
}
if ( TraceLoggingProviderEnabled ( g_hProvider, 0, 0 ) )
printf ( "TraceLoggingProvider enabled\n" );
else
printf ( "TraceLoggingProvider NOT enabled\n" );
TraceLoggingWrite (
g_hProvider,
"MyEvent1",
TraceLoggingString ( argv[0], "arg0" ), // field name is "arg0"
TraceLoggingInt32 ( argc ) ); // field name is implicitly "argc"
TraceLoggingUnregister ( g_hProvider );
ret_val = EnableTraceEx2 ( hTrace, &ProviderGUID, EVENT_CONTROL_CODE_DISABLE_PROVIDER, TRACE_LEVEL_VERBOSE, 0, 0, 0, NULL );
if ( ret_val != ERROR_SUCCESS ) {
printf ( "EnableTraceEx2(disable) failed with %i\n", ret_val );
}
ret_val = ControlTrace ( hTrace, LOGSESSION_NAME, petProperties, EVENT_TRACE_CONTROL_STOP );
if ( ret_val != ERROR_SUCCESS ) {
printf ( "ControlTrace(stop) failed with %i\n", ret_val );
}
return 0;
}
ETW is an event routing system. TraceLoggingWrite means "send the event to ETW". But if nobody is interested in your event then ETW will just ignore it.
To collect the data from TraceLoggingWrite, there needs to be an ETW session that is listening for events from you. There are many ways to start and control ETW sessions, including the StartTrace API, the AutoLogger registry key, the WPR tool, and the TRACELOG tool.
I usually prefer the TRACELOG tool. It is included with the Windows SDK, so it is installed if I have installed Visual Studio, and it will be on my path if I open a "Developer command prompt". On my computer, TRACELOG is in C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0\x86\tracelog.exe.
To capture events from the provider you show in your source code, I would run:
TRACELOG -start MySessionName -f MySession.etl -guid #5B5852D4-DC24-4A0F-87B6-9115AE9D2768
After my code has run, I would stop the trace with:
TRACELOG -stop MySessionName
I could then use various tools to decode the trace. I usually use the TRACEFMT tool.
TRACEFMT MySession.etl

mbedtls: error on mbedtls_ctr_drbg_seed

I'm using mbedtls to run SSL server.
The function mbedtls_ctr_drbg_seed returned -34.
My code is below:
const char *pers = "ssl_server2";
mbedtls_havege_state hs;
mbedtls_ssl_session ssn;
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
// One HTTPS Request Handling
memset( &ssn, 0, sizeof( mbedtls_ssl_session ) );
/*
* 4. Setup stuff
*/
mbedtls_ssl_init( &ssl );
mbedtls_ssl_config_init( &conf );
mbedtls_ctr_drbg_init( &ctr_drbg );
mbedtls_entropy_init( &entropy );
printf( " . Setting up the RNG and SSL data...." );
if( ( ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *) pers, sizeof( pers ) ) ) != 0 )
{
printf( " failed\n ! mbedtls_ctr_drbg_seed returned -0x%x\n", -ret );
goto ExitFunction;
}
else
printf( " mbedtls_ctr_drbg_seed returned 0x%x ok\n", ret );
As #Gilles rightfully said, the error you are receiving is probably -0x34, which is MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED. This error is returned when the function mbedtls_entropy_func() fails. Please check the the entropy source you are using is strong enough, meaning you have at least one entropy source which is strong, when added with mbedtls_entropy_add_source(). You should also verify that the entropy source you are using can collect enough entropy, and exceeds the threshold set to the source.
There are other locations where mbedtls_entropy_func() might fail, therefore I suggest you check these locations as well.

fgetpos failing in iOS 6.1 simulator when opening files in bundles

I'm working on some multiplatform C++ code. Hence the requirement to use fopen, fgetpos, etc. The following was working earlier on iOS and with my update to the latest version it stopped working.
I have a couple of text files Shader.vsh and Shader.fsh in a Shaders folder that is getting copied over to the bundle. In order to open the file, I do the following..
CFBundleRef mainBundle = CFBundleGetMainBundle();
CFStringRef cfstrFilename = CFSTRFromConstCharPtr( "Shader" );
CFStringRef cfstrFileType = CFSTRFromConstCharPtr( "vsh" );
CFStringRef cfstrSubDir = CFSTRFromConstCharPtr( "Shaders" );
CFURLRef resourcesURL = CFBundleCopyResourceURL( mainBundle, cfstrFilename, cfstrFileType, cfstrSubDir );
CFStringRef str = CFURLCopyFileSystemPath( resourcesURL, kCFURLPOSIXPathStyle );
CFRelease( resourcesURL );
char path[ PATH_MAX ];
CFStringGetCString( str, path, FILENAME_MAX, kCFStringEncodingASCII );
CFRelease( str );
FILE* fp = fopen( path, "rb" );
At this point, fp is Non NULL. So I assume it succeeded. Later, when I try to do
fpos_t pos;
int result = fgetpos( fp, &fpos_t );
result = -1 and errno = 0x2, which I believe is file not found.
As I mentioned earlier, this used to work on a previous version at some point. I started working on this again and in the process updated to the latest XCode, etc and things stopped working.
The path for the file that I pass into fopen turns out to be /Users/shammi/Library/Application Support/iPhone Simulator/6.1/Applications/9132490F-71AC-4C61-A584-E8F6C5B261FF/TestApp.app/Shaders/Shader.vsh
I'm able to see and open that file in finder/console and confirmed that its valid.
What am I doing wrong? Is there another alternative that allows me to use portable IO functions?
Found the problem. What I failed to mention here is what happens between the 2 sections of code above. Prior to this, I used to have my own ref counting solution and I recently changed to using shared_ptr. My own ref counting solution allowed for implicit casts. With shared_ptr, you can't do that. So here is the exact code...
std::shared_ptr< BinaryStream > BundleNamespace::OpenStream( const char* _szPath,
BinaryStream::Mode _eMode )
{
std::shared_ptr< BinaryStream > pStream = __super::OpenStream( _szPath, _eMode );
if ( !pStream )
{
std::string strDir;
std::string strFile;
std::string strExt;
SplitPath( _szPath, strDir, strFile, strExt );
std::string strFullPath = GetResourcePathFor( strFile.c_str(), strExt.c_str(), strDir.c_str() );
FILE* fp = fopen( strFullPath.c_str(), _eMode == BinaryStream::Mode_Read ? "r" : "w+b" );
pStream = std::make_shared<FileStream>( fp, _eMode );
}
return pStream;
}
The problem here is with
pStream = std::make_shared<FileStream>( fp, _eMode );
My FileStream's destructor calls fclose(m_pFile). The fix here is to change it to..
pStream = std::static_pointer_cast< BinaryStream >( std::make_shared<FileStream>( fp, _eMode ) );`
Also, using perror() proved to be more useful compared to trying to decipher errno.

What is the correct ConnectionString to pass SQLConnect?

I've found a good example on the MSDN site. SQLConnect
I want to connect to an SQL server, to my database, but unfortunately, SQLConnect always returns -1, and the application freezes.
I have edited the code above:
direxec::direxec()
{
_mbscpy_s( chr_ds_name, MAX_DATA, ( const unsigned char * )"Server=mySQLServer;Database=myDatabaseName;" );
_mbscpy_s( uid, MAX_DATA, ( const unsigned char * )"testuser" );
_mbscpy_s( pwd, MAX_DATA, ( const unsigned char * )"testpassword" );
printf("\n%s",chr_ds_name);
}
void direxec::sqlconn()
{
SQLAllocEnv( &henv );
SQLAllocConnect( henv, &hdbc );
rc = SQLConnect( hdbc, chr_ds_name, SQL_NTS, uid, SQL_NTS, pwd, SQL_NTS );
// Deallocate handles, display error message, and exit.
if ( !MYSQLSUCCESS( rc ) )
{
printf( "\nFailed %d",rc );
SQLFreeConnect( henv );
SQLFreeEnv( henv );
SQLFreeConnect( hdbc );
if ( hstmt ) error_out();
exit( -1 );
}
printf("\nConnected");
rc = SQLAllocStmt( hdbc, &hstmt );
}
Using SQLDriverConnect i can connect to my database, but i want to use SQLConnect if it is possible.
Does anyone have any idea what am i doing wrong?
Thanks!
SqlConnect doesn't accept a connection string, it only accepts a Data Source Name (DSN). DSN's are configured in the ODBC Administration Tool in Administrative Tools. If you want to use a connection string then you need to use SqlDriverConnect

How to get a sha256 hash of a file using ANSI C

Simply what the topic states, what's a memory efficient way to compute a sha256 hash of a file that's variable in size? I'm also willing to compromise using more memory for faster computation.
I used a simple stand-alone implementation by Christophe Devine -- and while his site seems to be off the Net, Google Code Search finds it
in this place.
Using these sha256.c and sha256.h, the core of his main() function is simply
if( ! ( f = fopen( argv[1], "rb" ) ) )
{
perror( "fopen" );
return( 1 );
}
sha256_starts( &ctx );
while( ( i = fread( buf, 1, sizeof( buf ), f ) ) > 0 )
{
sha256_update( &ctx, buf, i );
}
sha256_finish( &ctx, sha256sum );
for( j = 0; j < 32; j++ )
{
printf( "%02x", sha256sum[j] );
}
printf( " %s\n", argv[1] );
}
The rest of the main() function validates the FIPS-180-2 test vectors, so you get that warm and fuzzy feeling too/ ;-)
Or use the OpenSSL libcrypto:
https://wiki.openssl.org/index.php/EVP_Message_Digests
You may try Con Kolivas's implementation used in multi-threaded multi-pool FPGA and ASIC miner for bitcoin or well profiled Dr Brian Gladman's code.

Resources