zlib gzip invalid response defined in web browser (c++) - c++

I've a FastCGI application with C++. I like to send my response with gzip compression to client.
(ZLIB VERSION "1.2.11")
Here is the sample of my source code:
#pragma warning (disable : 4231)
#pragma warning(disable : 4996)
//3:45 PM 11/24/2018
#if !(defined(_WIN32)||defined(_WIN64)) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)))
#error Have to check !TODO
#else
#if !defined(_IOSTREAM_)
#include <iostream>
#endif//!_IOSTREAM_
#ifndef _WINDOWS_
#include <windows.h>
#endif//!_WINDOWS_
#endif//_WIN32||_WIN64/__unix__
#if !defined(_INC_STDIO)
#include <stdio.h> /* defines FILENAME_MAX, printf, sprintf */
#endif//!_INC_STDIO
#ifndef _XSTRING_
#include <string>// !_XSTRING_// memcpy, memset
#endif //!_XSTRING_
#if !defined(ZLIB_H)
#include <zlib.h>
#endif//!ZLIB_H
#if !defined(_SSTREAM_)
#include <sstream> // std::stringstream
#endif//_SSTREAM_
#if !defined(CHUNK)
#define CHUNK 16384
#endif//!CHUNK
#ifndef OS_CODE
# define OS_CODE 0x03 /* assume Unix */
#endif//!OS_CODE
#if MAX_MEM_LEVEL >= 8
# define DEF_MEM_LEVEL 8
#else
# define DEF_MEM_LEVEL MAX_MEM_LEVEL
#endif//!MAX_MEM_LEVEL
#if !defined(assert)
#define assert(expression) ((void)0)
#endif//!assert
static int gz_magic[2] = { 0x1f, 0x8b }; /* gzip magic header */
void __write_magic_header(std::stringstream&output) {
char*dest = (char*)malloc(10);
sprintf(dest, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], Z_DEFLATED, 0 /*flags*/, 0, 0, 0, 0 /*time*/, 0 /*xflags*/, OS_CODE);
output.write(const_cast<const char*>(dest), 10);
free(dest);
};
int ____def_strm(std::stringstream&source, std::stringstream&dest, int level = Z_BEST_SPEED) {
//6:00 AM 1/18/2019
int ret, flush;
unsigned have;
z_stream strm;
/* allocate deflate state */
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
ret = deflateInit2_(&strm, level, Z_DEFLATED,
-MAX_WBITS,
DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
ZLIB_VERSION, (int)sizeof(z_stream));
if (ret != Z_OK)
return ret;
/* compress until end of stream */
std::streamsize n;
source.seekg(0, std::ios::end);//Go to end of stream
std::streamoff size = source.tellg();
source.seekg(0, std::ios::beg);//Back to begain of stream
int write_len = 0;
do {
char in[CHUNK];
n = source.rdbuf()->sgetn(in, CHUNK);
strm.avail_in = (uInt)n;
size -= n;
flush = size <= 0 ? Z_FINISH : Z_NO_FLUSH;
strm.next_in = (Bytef*)in;
/* run deflate() on input until output buffer not full, finish
compression if all of source has been read in */
do {
char out[CHUNK];
strm.avail_out = CHUNK;
strm.next_out = (Bytef*)out;
ret = deflate(&strm, flush); /* no bad return value */
assert(ret != Z_STREAM_ERROR); /* state not clobbered */
have = CHUNK - strm.avail_out;
dest.write(out, have);
write_len += have;
} while (strm.avail_out == 0);
assert(strm.avail_in == 0); /* all input will be used */
/* done when last data in file processed */
} while (flush != Z_FINISH);
assert(ret == Z_STREAM_END); /* stream will be complete */
/* clean up and return */
(void)deflateEnd(&strm);
return write_len;
};
void compress_gzip (std::stringstream&source, std::stringstream&output) {
__write_magic_header(output);
____def_strm(source, output);
return;
};
void gzip_test(int loop) {
std::stringstream body(std::stringstream::in | std::stringstream::out | std::stringstream::binary);
for (int i = 0; i < loop; i++) {
body << "<b>Hello World</b><br/>";
body << "general-purpose programming language";
body << "\r\n";
}
std::stringstream compressed(std::stringstream::in | std::stringstream::out | std::stringstream::binary);
compress_gzip(body, compressed);
std::stringstream().swap(body);
std::cout << compressed.str();
std::stringstream().swap(compressed);
};
void write_header(const char* ct) {
std::cout << "Content-Type:" << ct << "\n";
std::cout << "Accept-Ranges:bytes\n";
};
int main(int argc, char *argv[], char*envp[]) {
//100 problem ==> ERR_CONTENT_DECODING_FAILED
//1000 problem ==> ERR_CONTENT_DECODING_FAILED
//10000 Ok
write_header("text/plain");
std::cout << "Content-Encoding:gzip\n";
std::cout << "\r\n";
gzip_test(10000);
return EXIT_SUCCESS;
};
Its working but I think this program has bug, but i'm unable to figure it out.
Problems are shown bellow:
if gzip_test(10000); then OK
if gzip_test(100); browser shown ERR_CONTENT_DECODING_FAILED
if gzip_test(1000); browser shown ERR_CONTENT_DECODING_FAILED
Please help me to figure it out this bug.
Success response:
Error response:

You aren't writing the gzip footer containing the CRC and data length:
std::streamoff size = source.tellg();
int totalSize = size;
int tcrc = 0;
...
n = source.rdbuf()->sgetn( in, CHUNK );
strm.avail_in = (uInt)n;
tcrc = crc32( tcrc, (uint8_t*)in, n );
...
(void)deflateEnd( &strm );
dest.write( (char*)&tcrc, sizeof( tcrc ) );
dest.write( (char*)&totalSize, sizeof( totalSize ) );
return write_len;
Your __write_magic_header method is also incorrect as it only allocates 10 bytes but then writes 10 characters with sprintf which will actually write 11 bytes overflowing your buffer.
On windows you can't send binary data through std::cout, you have the same issue as opening a file with ofstream without specifying binary. To fix this call the following before using std::cout:
_setmode( _fileno( stdout ), _O_BINARY );
Some other points unrelated to your issue:
don't wrap your includes with #ifdef, the macros you are using are implementation details and should provide no/negligable performance difference on a modern compiler.
don't use "__" at the beginning of method names or other identifiers, these names (along with "_" followed by a capital letter) are reserved for use by the compiler.

Related

Same code works/gives error in different projects

I am using visual studio 2019.
When I try to run this from a new project it works totally fine. Sends the email and doesn't give any error.
But when I try to run this from my server code it gives this error:
To be more precise:
Project1/DEBUG works fine.
Project1/Release works fine.
Project2/DEBUG works fine.
Project2/Release gives runtime error.
"Exception thrown: read access violation.
this was 0xF. occurred"
And compiler is redirected to "xstring" code page, line 2873.
part from xstring
basic_string& assign(_In_reads_(_Count) const _Elem* const _Ptr, _CRT_GUARDOVERFLOW const size_type _Count) {
// assign [_Ptr, _Ptr + _Count)
if (_Count <= _Mypair._Myval2._Myres) { // LINE 2873
_Elem* const _Old_ptr = _Mypair._Myval2._Myptr();
_Mypair._Myval2._Mysize = _Count;
_Traits::move(_Old_ptr, _Ptr, _Count);
_Traits::assign(_Old_ptr[_Count], _Elem());
return *this;
}
I've tried with totally same code (with copy paste) but still no use.
Project properties are the same. I've checked it several times for any change in properties but there is not even a single difference.
email.h
#pragma warning(disable : 4996) //_CRT_SECURE_NO_WARNINGS
#ifndef EMAIL_H
#define EMAIL_H
#include <vector>
#include <string>
#include "curl/curl.h"
// Enable one of the below depending on your operating system
#define WINDOWS_H
//#define LINUX_H
class Email
{
public:
// default constructor
Email();
// sets who the email is going to
void setTo(const std::string to);
// sets who the email came from
void setFrom(const std::string from);
// sets the cc
void setCc(const std::string to);
// sets the subject of the email
void setSubject(const std::string subject);
// set the body of the email
void setBody(const std::string body);
// sets the smtp username
void setSMTP_username(const std::string username);
// sets the smtp password
void setSMTP_password(const std::string password);
// sets the SMTP HOST
void setSMTP_host(const std::string host);
// adds a binary attachment to the email
void addAttachment(const std::string filepath);
// removes an attachment from the email (Not implemented yet)
void removeAttachment(const std::string filepath);
// removes all attachments
void removeAllAttachments();
// contructs the final email
void constructEmail();
// clears the contents of the email
void clearEmailContents();
// void send email
int send() const; // returns a CURL error code
// dumps the email contents for debugging
void dump() const;
private:
// smtp information
std::string smtp_user;
std::string smtp_password;
std::string smtp_host;
// email data
std::string to;
std::string from;
std::string cc;
std::string subject;
std::string body;
// vector which stores the email data
std::vector<std::string> email_contents;
std::vector<std::string> attachments;
// length of the above vector
int numberOfLines;
};
#endif
email.cpp
#include <iostream>
#include <ctime>
#include <string.h>
// #include "stdafx.h"
#include "email.h"
#define MAX_LEN 255 // this must be divisible by 3 otherwise the SMTP server won't be able to decode the attachment properly
#define ENCODED_LEN 341
// offsets into the email template
#define BOUNDARY 5
#define END_LINE 8
#define ATTACH_TYPE 10
#define ATTACH_TRANSFER 11
#define ATTACH_DEPOSITION 12
#define END_OF_TRANSMISSION_BOUNDARY 15
#define END_OF_TRANSMISSION 16
#ifdef WINDOWS_H
#define DIR_CHAR '\\'
#else
#define DIR_CHAR '/'
#endif
using namespace std;
// base64 encoding functions
void base64_encode(char* input_buf, char* output_buf, size_t input_size);
void encodeblock(char* in, char* out, int len);
// callback function
static size_t payload_source(void* ptr, size_t size, size_t nmemb, void* userp);
// base64 encoding table
const char b64_table[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
// global vector this is TEMP
vector<string> global_vec;
// struct used by the CURL callback
struct upload_status {
int lines_read;
};
static const char* email_template[] = {
/* i = 0 */
"User-Agent: DXF Viewer agent\r\n",
"MIME-Version: 1.0\r\n",
"Content-Type: multipart/mixed;\r\n",
" boundary=\"------------030203080101020302070708\"\r\n",
"\r\nThis is a multi-part message in MIME format.\r\n",
"--------------030203080101020302070708\r\n", // use this type of boundary for subsequent attachments
"Content-Type: text/plain; charset=utf-8; format=flowed\r\n",
"Content-Transfer-Encoding: 7bit\r\n",
/* i = 8 (BODY) */
"\r\n", /* empty line to divide headers from body, see RFC5322 */
"--------------030203080101020302070708\r\n", /* i = 9 */
/* Template for binary attachments i = 10 */
"Content-Type: application/octet-stream\r\n",
"Content-Transfer-Encoding: base64\r\n",
"Content-Disposition: attachment;\r\n",
/* Filename here */
"\r\n",
/* Encoded base64 contents here */
"\r\n",
"--------------030203080101020302070708--\r\n", // this type of boundary indicates that there are no more parts i = 15
"\r\n.\r\n",
NULL
};
Email::Email()
{
// empty constructor
}
void Email::setTo(const string to)
{
this->to = to;
}
void Email::setFrom(const string from)
{
this->from = from;
}
void Email::setCc(const string cc)
{
this->cc = cc;
}
void Email::setSubject(const string subject)
{
this->subject = subject;
}
void Email::setBody(const string body)
{
this->body = body;
}
void Email::setSMTP_username(const string user)
{
this->smtp_user = user;
}
void Email::setSMTP_password(const string pass)
{
this->smtp_password = pass;
}
void Email::setSMTP_host(const string hostname)
{
this->smtp_host = hostname;
}
void Email::addAttachment(const string file_path)
{
/*FILE* fp = NULL;
char buffer[MAX_LEN + 1] = { 0 };
char encodedBuffer[ENCODED_LEN] = { 0 };
char tempBuffer[MAX_LEN] = { 0 };
char* filename = NULL;
unsigned int fileSize = 0;
unsigned int bytesCopied = 0;
int bytesToCopy = 0;
int bytesRead = 0;
fp = fopen(file_path.c_str(), "rb");
if (fp) {
// get the file size
fseek(fp, 0, SEEK_END);
fileSize = ftell(fp);
fseek(fp, 0, SEEK_SET);
// copy the attachment header
string type(email_template[ATTACH_TYPE]);
this->attachments.push_back(type);
string encodingType(email_template[ATTACH_TRANSFER]);
this->attachments.push_back(encodingType);
string deposition(email_template[ATTACH_DEPOSITION]);
this->attachments.push_back(deposition);
// extract the filename from the path
filename = (char*)strrchr(file_path.c_str(), DIR_CHAR);
if (filename != NULL) {
filename += 1;
// push the filename
snprintf(tempBuffer, MAX_LEN, " filename=\"%s\"\r\n", filename);
string filename(tempBuffer);
this->attachments.push_back(filename);
string endLine(email_template[END_LINE]);
this->attachments.push_back(endLine);
// copy the file MAX_LEN bytes at a time into the attachments vector
while (bytesCopied < fileSize) {
// determine how many bytes to read
if (bytesCopied + MAX_LEN > fileSize) {
bytesToCopy = fileSize - bytesCopied;
}
else {
bytesToCopy = MAX_LEN;
}
// read from the file
memset(buffer, 0, MAX_LEN + 1);
bytesRead = fread(buffer, sizeof(char), bytesToCopy, fp);
// encoded the data read
memset(encodedBuffer, 0, ENCODED_LEN);
base64_encode(buffer, encodedBuffer, bytesRead);
// setup the encoded string so that we can push it to attachments
string line(encodedBuffer);
line += endLine;
this->attachments.push_back(line);
// update the number of bytes we have copied
bytesCopied += bytesToCopy;
}
this->attachments.push_back(endLine);
string boundary(email_template[BOUNDARY]);
this->attachments.push_back(boundary);
}
else {
removeAllAttachments();
cout << "Failed to extract filename!" << endl;
}
// close the file
fclose(fp);
}
else {
cout << "Unable to open file." << endl;
}
*/
}
void Email::constructEmail(void)
{
int i = 0;
char buffer[MAX_LEN];
string boundary(email_template[BOUNDARY]);
// time stuff
time_t rawtime;
struct tm* timeinfo;
// store all the email contents in a vector
// TO:
snprintf(buffer, MAX_LEN, "To: %s\r\n", this->to.c_str());
string line1(buffer);
this->email_contents.push_back(line1);
// FROM:
memset(buffer, 0, MAX_LEN);
snprintf(buffer, MAX_LEN, "From: %s\r\n", this->from.c_str());
string line2(buffer);
this->email_contents.push_back(line2);
// CC:
memset(buffer, 0, MAX_LEN);
snprintf(buffer, MAX_LEN, "Cc: %s\r\n", this->cc.c_str());
string line3(buffer);
if (this->cc.length() > 0) {
this->email_contents.push_back(line3);
}
// Subject:
memset(buffer, 0, MAX_LEN);
snprintf(buffer, MAX_LEN, "Subject: %s\r\n", this->subject.c_str());
string line4(buffer);
this->email_contents.push_back(line4);
// time:
time(&rawtime);
timeinfo = localtime(&rawtime);
memset(buffer, 0, MAX_LEN);
strftime(buffer, sizeof(buffer), "%d/%m/%Y %I:%M:%S +1100\r\n", timeinfo);
string time_str(buffer);
this->email_contents.push_back(time_str);
cout << time_str << endl;
for (i = 0; i < END_LINE; i++) { // other stuff e.g user-agent etc
string line(email_template[i]);
this->email_contents.push_back(line);
}
// add in the body
string endLine(email_template[END_LINE]);
this->email_contents.push_back(endLine);
memset(buffer, 0, MAX_LEN);
snprintf(buffer, MAX_LEN, "%s", this->body.c_str()); // Body:
string line5(buffer);
this->email_contents.push_back(line5); // body
this->email_contents.push_back(endLine); // \r\n
this->email_contents.push_back(boundary); // boundary
// add in the attachments
for (i = 0; i < attachments.size(); i++) {
this->email_contents.push_back(this->attachments[i]);
}
// add the last boundary with the two hyphens
string lastBoundary(email_template[END_OF_TRANSMISSION_BOUNDARY]);
this->email_contents.push_back(lastBoundary);
// specify that we don't want to send any more data
string endTransmission(email_template[END_OF_TRANSMISSION]);
this->email_contents.push_back(endTransmission);
}
/*
This function was taken and modified from:
https://curl.haxx.se/libcurl/c/smtp-ssl.html
*/
int Email::send(void) const
{
CURL* curl;
CURLcode res = CURLE_OK;
struct curl_slist* recipients = NULL;
struct upload_status upload_ctx;
upload_ctx.lines_read = 0;
curl = curl_easy_init();
global_vec = this->email_contents;
if (curl) {
/* Set username and password */
curl_easy_setopt(curl, CURLOPT_USERNAME, this->smtp_user.c_str());
curl_easy_setopt(curl, CURLOPT_PASSWORD, this->smtp_password.c_str());
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); // allows emails to be sent
/* This is the URL for your mailserver. Note the use of smtps:// rather
* than smtp:// to request a SSL based connection. */
curl_easy_setopt(curl, CURLOPT_URL, this->smtp_host.c_str());
/* If you want to connect to a site who isn't using a certificate that is
* signed by one of the certs in the CA bundle you have, you can skip the
* verification of the server's certificate. This makes the connection
* A LOT LESS SECURE.
*
* If you have a CA cert for the server stored someplace else than in the
* default bundle, then the CURLOPT_CAPATH option might come handy for
* you. */
#ifdef SKIP_PEER_VERIFICATION
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
#endif
/* If the site you're connecting to uses a different host name that what
* they have mentioned in their server certificate's commonName (or
* subjectAltName) fields, libcurl will refuse to connect. You can skip
* this check, but this will make the connection less secure. */
#ifdef SKIP_HOSTNAME_VERIFICATION
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
#endif
/* Note that this option isn't strictly required, omitting it will result
* in libcurl sending the MAIL FROM command with empty sender data. All
* autoresponses should have an empty reverse-path, and should be directed
* to the address in the reverse-path which triggered them. Otherwise,
* they could cause an endless loop. See RFC 5321 Section 4.5.5 for more
* details.
*/
curl_easy_setopt(curl, CURLOPT_MAIL_FROM, this->from.c_str());
/* Add two recipients, in this particular case they correspond to the
* To: and Cc: addressees in the header, but they could be any kind of
* recipient. */
recipients = curl_slist_append(recipients, this->to.c_str());
if (this->cc.length() > 0) {
recipients = curl_slist_append(recipients, this->cc.c_str());
}
curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);
/* We're using a callback function to specify the payload (the headers and
* body of the message). You could just use the CURLOPT_READDATA option to
* specify a FILE pointer to read from. */
curl_easy_setopt(curl, CURLOPT_READFUNCTION, payload_source);
curl_easy_setopt(curl, CURLOPT_READDATA, &upload_ctx);
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
/* Since the traffic will be encrypted, it is very useful to turn on debug
* information within libcurl to see what is happening during the
* transfer */
// curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
/* Send the message */
res = curl_easy_perform(curl);
/* Check for errors */
if (res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
/* Free the list of recipients */
curl_slist_free_all(recipients);
/* Always cleanup */
curl_easy_cleanup(curl);
}
return (int)res;
}
void Email::removeAllAttachments()
{
this->attachments.clear();
}
void Email::clearEmailContents()
{
this->email_contents.clear();
this->attachments.clear();
}
void Email::dump(void) const
{
int i = 0;
cout << "Email contents: " << endl;
for (i = 0; i < this->email_contents.size(); i++) {
cout << this->email_contents[i];
if (i == 20) {
break;
}
}
cout << "\n\nEmail attachments: " << endl;
for (i = 0; i < this->attachments.size(); i++) {
cout << this->attachments[i];
if (i == 5) {
break;
}
}
}
void base64_encode(char* input_buf, char* output_buf, size_t input_size)
{
char in[3];
char out[4];
size_t len = input_size;
*output_buf = 0;
for (size_t i = 0; i < len; )
{
int buf3_len = 0;
for (int j = 0; j < 3; ++j)
{
in[j] = input_buf[i++];
if (i > len)
in[j] = 0;
else
buf3_len++;
}
if (len > 0)
{
encodeblock(in, out, buf3_len);
strncat(output_buf, out, 4);
}
}
}
void encodeblock(char* in, char* out, int len)
{
out[0] = (char)b64_table[(int)(in[0] >> 2)];
out[1] = (char)b64_table[(int)(((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4))];
out[2] = (char)(len > 1 ? b64_table[(int)(((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6))] : '=');
out[3] = (char)(len > 2 ? b64_table[(int)(in[2] & 0x3f)] : '=');
}
static size_t payload_source(void* ptr, size_t size, size_t nmemb, void* userp)
{
struct upload_status* upload_ctx = (struct upload_status*)userp;
const char* data;
if ((size == 0) || (nmemb == 0) || ((size * nmemb) < 1)) {
return 0;
}
if (upload_ctx->lines_read >= 0 && upload_ctx->lines_read < global_vec.size())
{
data = global_vec[upload_ctx->lines_read].c_str();
if (data) {
size_t len = strlen(data);
memcpy(ptr, data, len);
upload_ctx->lines_read++;
return len;
}
}
return 0;
}
main.cpp
#include <iostream>
#include "email.h"
using namespace std;
int main(void)
{
Email e;
int curlError = 0;
// e.dump();
e.setTo("receiver#example.com");
e.setFrom("sender#example.com");
e.setSubject("Test Email");
e.setCc("");
e.setBody("Do not reply to this email");
e.setSMTP_host("smtp://smtp.mail.com:587");
e.setSMTP_username("sender#example.com");
e.setSMTP_password("sender_password");
e.addAttachment("");
// e.addAttachment("email.h");
// e.addAttachment("main.cpp");
e.constructEmail();
e.dump();
curlError = e.send();
if (curlError) {
cout << "Error sending email!" << endl;
}
else {
cout << "Email sent successfully!" << endl;
}
return 0;
}
What is the reason this same code runs perfectly on one project but doesn't work on another?
EDIT:
error happens in Email::send(void) on the line :
global_vec2 = this->email_contents;
but I cannot try/catch it. it doesn't throws exception.
EDIT2 :
Problem is caused by static vector. It doesn't exist, doesn't initialize. I don't understand what's causing this project to prevent static std::vectors from being created.

GDB in a programming in C

I have a problem with a program in C. I need the absolute memory address of the local variables to the function main. I am debugging with the gdb.
How to know if there is an overflow in the variables.
Thank you
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <ctype.h>
typedef int16_t int16;
#include "mulaw.h"
void decodeFile(FILE * fIn, FILE * fOut, uint32_t samples) {
uint32_t i;
uint8_t * inSamples = malloc(samples * sizeof(uint8_t));
int16_t * outSamples = malloc(samples * sizeof(int16_t));
fread(inSamples, sizeof(uint8_t), samples, fIn);
for (i = 0; i < samples; i++) {
outSamples[i] = 4 * muLaw[inSamples[i]];
}
fwrite(outSamples, sizeof(int16_t), samples, fOut);
free(inSamples);
free(outSamples);
}
#define MAX_FILE_SIZE 256
int main(int argc, char **argv)
{
char inputFile[MAX_FILE_SIZE];
char outputFile[MAX_FILE_SIZE];
FILE * fIn = NULL, * fOut = NULL;
struct header_t {
char ChunkID[4];
int32_t ChunkSize;
char Format[4];
} header;
char SubchunkID[4];
uint32_t SubchunkSize;
struct subheader_t {
int16_t AudioFormat;
int16_t NumChannels;
int32_t SampleRate;
int32_t ByteRate;
int16_t BlockAlign;
int16_t BitsPerSample;
int16_t ExtraParamSize;
int16_t Padding;
} subheader;
/* Usage */
if (argc != 3) {
puts("Usage is: mulaw INFILE OUTFILE\n");
exit(EXIT_FAILURE);
}
/* Careful here!!!!! */
strncpy(inputFile, argv[1], MAX_FILE_SIZE);
strncpy(outputFile, argv[2], MAX_FILE_SIZE);
/* Open input file */
fIn = fopen (inputFile, "rb");
/* Read main header */
fread(&header, sizeof(struct header_t), 1, fIn);
if (memcmp(header.ChunkID, "RIFF", 4) != 0
|| memcmp(header.Format, "WAVE", 4) != 0) {
fprintf(stderr, "Unknown input format\n");
exit(EXIT_FAILURE);
}
/* Read sub header */
while (fread(SubchunkID, sizeof(SubchunkID), 1, fIn)) {
fread(&SubchunkSize, sizeof(SubchunkSize), 1, fIn);
printf("Reading chunk of type %c%c%c%c (%d bytes)\n",
isprint(SubchunkID[0]) ? SubchunkID[0] : '?',
isprint(SubchunkID[1]) ? SubchunkID[1] : '?',
isprint(SubchunkID[2]) ? SubchunkID[2] : '?',
isprint(SubchunkID[3]) ? SubchunkID[3] : '?',
(int) SubchunkSize);
if (memcmp(SubchunkID, "fmt ", 4) == 0) {
/* read a fmt_ header */
fread(&subheader, SubchunkSize, 1, fIn);
/* we are going to adjust this header now to change the audio format */
if (subheader.AudioFormat != 7) {
fprintf(stderr, "Only mu-law audio input is supported\n");
exit(EXIT_FAILURE);
}
/* adjust audio format and bit depth */
subheader.AudioFormat = 1;
subheader.BitsPerSample = 16;
/* fix derivative fields */
subheader.ByteRate = subheader.SampleRate * subheader.NumChannels * subheader.BitsPerSample / 8;
subheader.BlockAlign = subheader.NumChannels * subheader.BitsPerSample / 8;
/* we don't write ExtraParamSize, because for AudioFormat == 1 it is not needed */
SubchunkSize -= 2;
/* Open file and write the header for our updated fmt_ chunk */
fOut = fopen (outputFile, "wb");
fwrite(&header, sizeof(struct header_t), 1, fOut); /* Main header */
fwrite(SubchunkID, sizeof(SubchunkID), 1, fOut); /* Subheader */
fwrite(&SubchunkSize, sizeof(SubchunkSize), 1, fOut);
fwrite(&subheader, SubchunkSize, 1, fOut);
} else if (memcmp(SubchunkID, "data", 4) == 0) {
/* here is our mu-law data */
/* write the header for our new chunk (it is twice as large) */
int32_t tSubchunkSize = SubchunkSize * 2;
fwrite(SubchunkID, sizeof(SubchunkID), 1, fOut);
fwrite(&tSubchunkSize, sizeof(SubchunkSize), 1, fOut);
/* process the data */
(fIn, fOut, SubchunkSize);
} else {
/* unknown chunk, skipping */
fseek(fIn, SubchunkSize, SEEK_CUR);
}
}
/* Cleanup and exit */
fclose(fIn);
fclose(fOut);
exit(EXIT_SUCCESS);
}
}
Just run gdb yourexe
Then in gdb:
break main
run
p &inputFile
That will give you the address of inputFile: ex $2 = (char (*)[256]) 0x62fd60
To get the size of a variable you can use p sizeof(variable) or p sizeof(type_of_the_variable>)
That said, not sure if it will help you to track down your problem.

c++ Zlib fwrite to file not working

I have this procedure I'm working on, to simply do the following:
Open a gzipped file
Uncompress it to a std::string
Compress it from a std::string
Save as gzipped file
However, I cannot seem to write the gzipped data at the end. The error I'm getting is :No Matching Function Call to 'fwrite'.
Am I feeding it the wrong parameters? Or an incorrect type?
Here's the full procedure:
#include <iostream>
#include "zlib-1.2.8/zlib.h"
#include <stdexcept>
#include <iomanip>
#include <sstream>
#include <stdio.h>
#include <assert.h>
#include <cstdio>
#include <string>
#include <cstring>
#include <cstdlib>
#include "zlib.h"
#include "zconf.h"
#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__)
# include <fcntl.h>
# include <io.h>
# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
#else
# define SET_BINARY_MODE(file)
#endif
#define CHUNK 16384
using namespace std;
bool gzipInflate( const std::string& compressedBytes, std::string& uncompressedBytes ) {
if ( compressedBytes.size() == 0 ) {
uncompressedBytes = compressedBytes ;
return true ;
}
uncompressedBytes.clear() ;
unsigned full_length = compressedBytes.size() ;
unsigned half_length = compressedBytes.size() / 2;
unsigned uncompLength = full_length ;
char* uncomp = (char*) calloc( sizeof(char), uncompLength );
z_stream strm;
strm.next_in = (Bytef *) compressedBytes.c_str();
strm.avail_in = compressedBytes.size() ;
strm.total_out = 0;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
bool done = false ;
if (inflateInit2(&strm, (16+MAX_WBITS)) != Z_OK) {
free( uncomp );
return false;
}
while (!done) {
// If our output buffer is too small
if (strm.total_out >= uncompLength ) {
// Increase size of output buffer
char* uncomp2 = (char*) calloc( sizeof(char), uncompLength + half_length );
memcpy( uncomp2, uncomp, uncompLength );
uncompLength += half_length ;
free( uncomp );
uncomp = uncomp2 ;
}
strm.next_out = (Bytef *) (uncomp + strm.total_out);
strm.avail_out = uncompLength - strm.total_out;
// Inflate another chunk.
int err = inflate (&strm, Z_SYNC_FLUSH);
if (err == Z_STREAM_END) done = true;
else if (err != Z_OK) {
break;
}
}
if (inflateEnd (&strm) != Z_OK) {
free( uncomp );
return false;
}
for ( size_t i=0; i<strm.total_out; ++i ) {
uncompressedBytes += uncomp[ i ];
}
free( uncomp );
return true ;
}
/** Compress a STL string using zlib with given compression level and return
* the binary data. */
std::string compress_string(const std::string& str, int compressionlevel = Z_BEST_COMPRESSION)
{
z_stream zs; // z_stream is zlib's control structure
memset(&zs, 0, sizeof(zs));
if (deflateInit(&zs, compressionlevel) != Z_OK)
throw(std::runtime_error("deflateInit failed while compressing."));
zs.next_in = (Bytef*)str.data();
zs.avail_in = str.size(); // set the z_stream's input
int ret;
char outbuffer[32768];
std::string outstring;
// retrieve the compressed bytes blockwise
do {
zs.next_out = reinterpret_cast<Bytef*>(outbuffer);
zs.avail_out = sizeof(outbuffer);
ret = deflate(&zs, Z_FINISH);
if (outstring.size() < zs.total_out) {
// append the block to the output string
outstring.append(outbuffer,zs.total_out - outstring.size());
}
}
while (ret == Z_OK);
deflateEnd(&zs);
if (ret != Z_STREAM_END) { // an error occurred that was not EOF
std::ostringstream oss;
oss << "Exception during zlib compression: (" << ret << ") " << zs.msg;
throw(std::runtime_error(oss.str()));
}
return outstring;
}
/* Reads a file into memory. */
bool loadBinaryFile( const std::string& filename, std::string& contents ) {
// Open the gzip file in binary mode
FILE* f = fopen( filename.c_str(), "rb" );
if ( f == NULL )
return false ;
// Clear existing bytes in output vector
contents.clear();
// Read all the bytes in the file
int c = fgetc( f );
while ( c != EOF ) {
contents += (char) c ;
c = fgetc( f );
}
fclose (f);
return true ;
}
int main(int argc, char *argv[]) {
// Read the gzip file data into memory
std::string fileData ;
if ( !loadBinaryFile( "myfilein.gz", fileData ) ) {
printf( "Error loading input file." );
return 0 ;
}
// Uncompress the file data
std::string data ;
if ( !gzipInflate( fileData, data ) ) {
printf( "Error decompressing file." );
return 0 ;
}
// Print the data
printf( "Data: \"" );
for ( size_t i=0; i<data.size(); ++i ) {
printf( "%c", data[i] );
}
printf ( "\"\n" );
std::string outy;
// Compress the file data
outy = compress_string(data, 0);
//Write the gzipped data to a file.
FILE *handleWrite=fopen("myfileout.gz","wb");
fwrite(outy,sizeof(outy),1,handleWrite);
fclose(handleWrite);
return 0;
}
std::string cannot be cast to void* (what fwrite expects).
Try:
fwrite(outy.data(),outy.size(),1,handleWrite);
Although I'm not sure if storing binary data inside std::string is a good idea.

MQTT connect with activeMQ

I have written a client code for mqtt which is supposed to connect (just connect to server for now) to a active mq server. following is the code:
#include "stdafx.h"
#include<iostream>
#include<winsock2.h>
#include "mqtt.h"
#pragma comment(lib,"ws2_32.lib") //Winsock Library
#include <stdlib.h>
#include <winsock2.h>
void mqtt_init(mqtt_broker_handle_t* broker, const char* clientid) {
// Connection options
broker->alive = 300; // 300 seconds = 5 minutes
broker->seq = 1; // Sequence for message identifiers
// Client options
memset(broker->clientid, 0, sizeof(broker->clientid));
memset(broker->username, 0, sizeof(broker->username));
memset(broker->password, 0, sizeof(broker->password));
if(clientid) {
strncpy_s(broker->clientid, clientid, sizeof(broker->clientid));
} else {
strcpy_s(broker->clientid, "emqtt");
}
// Will topic
broker->clean_session = 1;
}
void mqtt_init_auth(mqtt_broker_handle_t* broker, const char* username, const char* password)
{
if(username && username[0] != '\0')
strncpy_s(broker->username, username, sizeof(broker->username)-1);
if(password && password[0] != '\0')
strncpy_s(broker->password, password, sizeof(broker->password)-1);
}
using namespace std;
int main(int argc , char *argv[])
{
WSADATA wsa;
SOCKET s;
struct sockaddr_in server;
char message[1000] , server_reply[2000];
int recv_size;
int packet_length;
uint16_t msg_id, msg_id_rcv;
mqtt_broker_handle_t broker;
mqtt_init(&broker, "localhost");
mqtt_init_auth(&broker, "cid", "campeador");
printf("\nInitialising Winsock...");
if (WSAStartup(MAKEWORD(2,2),&wsa) != 0) {
cout<<"Failed. Error Code : "<<WSAGetLastError();
return 1;
}
cout<<"Initialised.\n";
//Create a socket
if((s = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
{
cout<<"Could not create socket : " << WSAGetLastError();
}
cout<<"Socket created.\n";
server.sin_addr.s_addr = inet_addr("127.0.0.1");
server.sin_family = AF_INET;
server.sin_port = htons( 1993);
//Connect to remote server
if (connect(s , (struct sockaddr *)&server , sizeof(server)) < 0)
{
puts("connect error");
return 1;
}
puts("Connected");
mqtt_connect(&broker);
recv_size = recv(s, server_reply, 2000, 0);
server_reply[recv_size] = '\0';
while ( server_reply != "end"){
cout<<server_reply<<endl;
recv_size = recv(s, server_reply, 2000, 0);
server_reply[recv_size] = '\0';
}
closesocket(s);
WSACleanup();
return 0;
}
And also the following is the code for mqtt.h
#ifndef __LIBEMQTT_H__
#define __LIBEMQTT_H__
#endif
#include <stdint.h>
#include <string.h>
#ifndef MQTT_CONF_USERNAME_LENGTH
#define MQTT_CONF_USERNAME_LENGTH 13 // Recommended by MQTT Specification (12 + '\0')
#endif
#ifndef MQTT_CONF_PASSWORD_LENGTH
#define MQTT_CONF_PASSWORD_LENGTH 13 // Recommended by MQTT Specification (12 + '\0')
#endif
#define MQTT_MSG_CONNECT 1<<4
#define MQTT_MSG_CONNACK 2<<4
#define MQTT_MSG_PUBLISH 3<<4
#define MQTT_MSG_PUBACK 4<<4
#define MQTT_MSG_PUBREC 5<<4
#define MQTT_MSG_PUBREL 6<<4
#define MQTT_MSG_PUBCOMP 7<<4
#define MQTT_MSG_SUBSCRIBE 8<<4
#define MQTT_MSG_SUBACK 9<<4
#define MQTT_MSG_UNSUBSCRIBE 10<<4
#define MQTT_MSG_UNSUBACK 11<<4
#define MQTT_MSG_PINGREQ 12<<4
#define MQTT_MSG_PINGRESP 13<<4
#define MQTT_MSG_DISCONNECT 14<<4
#define MQTT_DUP_FLAG 1<<3
#define MQTT_QOS0_FLAG 0<<1
#define MQTT_QOS1_FLAG 1<<1
#define MQTT_QOS2_FLAG 2<<1
#define MQTT_RETAIN_FLAG 1
#define MQTT_CLEAN_SESSION 1<<1
#define MQTT_WILL_FLAG 1<<2
#define MQTT_WILL_RETAIN 1<<5
#define MQTT_USERNAME_FLAG 1<<7
#define MQTT_PASSWORD_FLAG 1<<6
typedef struct {
void* socket_info;
int (*send)(void* socket_info, const void* buf, unsigned int count);
// Connection info
char clientid[50];
// Auth fields
char username[MQTT_CONF_USERNAME_LENGTH];
char password[MQTT_CONF_PASSWORD_LENGTH];
// Will topic
uint8_t will_retain;
uint8_t will_qos;
uint8_t clean_session;
// Management fields
uint16_t seq;
uint16_t alive;
} mqtt_broker_handle_t;
int mqtt_connect(mqtt_broker_handle_t* broker)
{
uint8_t flags = 0x00;
uint16_t clientidlen = strlen(broker->clientid);
uint16_t usernamelen = strlen(broker->username);
uint16_t passwordlen = strlen(broker->password);
uint16_t payload_len = clientidlen + 2;
// Preparing the flags
if(usernamelen) {
payload_len += usernamelen + 2;
flags |= MQTT_USERNAME_FLAG;
}
if(passwordlen) {
payload_len += passwordlen + 2;
flags |= MQTT_PASSWORD_FLAG;
}
if(broker->clean_session) {
flags |= MQTT_CLEAN_SESSION;
}
// Variable header
uint8_t var_header[] = {
0x00,0x06,0x4d,0x51,0x49,0x73,0x64,0x70, // Protocol name: MQTT
0x03, // Protocol version
flags, // Connect flags
broker->alive>>8, broker->alive&0xFF, // Keep alive
};
// Fixed header
uint8_t fixedHeaderSize = 2; // Default size = one byte Message Type + one byte Remaining Length
uint8_t remainLen = sizeof(var_header)+payload_len;
if (remainLen > 127) {
fixedHeaderSize++; // add an additional byte for Remaining Length
}
uint8_t fixed_header[2];
// Message Type
fixed_header[0] = MQTT_MSG_CONNECT;
// Remaining Length
if (remainLen <= 127) {
fixed_header[1] = remainLen;
} else {
// first byte is remainder (mod) of 128, then set the MSB to indicate more bytes
fixed_header[1] = remainLen % 128;
fixed_header[1] = fixed_header[1] | 0x80;
// second byte is number of 128s
fixed_header[2] = remainLen / 128;
}
uint16_t offset = 0;
uint8_t packet[sizeof(fixed_header)+sizeof(var_header)+ sizeof(payload_len)];
memset(packet, 0, sizeof(packet));
memcpy(packet, fixed_header, sizeof(fixed_header));
offset += sizeof(fixed_header);
memcpy(packet+offset, var_header, sizeof(var_header));
offset += sizeof(var_header);
// Client ID - UTF encoded
packet[offset++] = clientidlen>>8;
packet[offset++] = clientidlen&0xFF;
memcpy(packet+offset, broker->clientid, clientidlen);
offset += clientidlen;
if(usernamelen) {
// Username - UTF encoded
packet[offset++] = usernamelen>>8;
packet[offset++] = usernamelen&0xFF;
memcpy(packet+offset, broker->username, usernamelen);
offset += usernamelen;
}
if(passwordlen) {
// Password - UTF encoded
packet[offset++] = passwordlen>>8;
packet[offset++] = passwordlen&0xFF;
memcpy(packet+offset, broker->password, passwordlen);
offset += passwordlen;
}
return 1;
}
When I debug the code there are no errors however when I run the code I get error stating that "the stack around the variable 'packet' is corrupt". I am very new to socket programming and mqtt in general so any help would be great.
What you've shown is derived from libemqtt (which is GPL licensed by the way, don't forget that :), have you tried starting from the examples that they provide?
libemqtt isn't actively developed and has a notice saying "DO NOT USE". Unless you're particularly interested in solving the problem of using MQTT for yourself, I'd suggest you look at something different, like the Paho or mosquitto client libraries.

Why is MD5Sum so fast

I've been studying hashing in C/C++ and tried to replicate the md5sum command in Linux. After analysing the source code, it seems that md5sum relies on the md5 library's md5_stream. I've approximated the md5_stream function from the md5.h library into the code below, and it runs in ~13-14 seconds. I've tried to call the md5_stream function directly and got ~13-14 seconds. The md5sum runs in 4 seconds. What have the GNU people done to get the speed out of the code?
The md5.h/md5.c code is available in the CoreUtils source code.
#include <QtCore/QCoreApplication>
#include <QtCore/QDebug>
#include <iostream>
#include <iomanip>
#include <fstream>
#include "md5.h"
#define BLOCKSIZE 32784
int main()
{
FILE *fpinput, *fpoutput;
if ((fpinput = fopen("/dev/sdb", "rb")) == 0) {
throw std::runtime_error("input file doesn't exist");
}
struct md5_ctx ctx;
size_t sum;
char *buffer = (char*)malloc (BLOCKSIZE + 72);
unsigned char *resblock = (unsigned char*)malloc (16);
if (!buffer)
return 1;
md5_init_ctx (&ctx);
size_t n;
sum = 0;
while (!ferror(fpinput) && !feof(fpinput)) {
n = fread (buffer + sum, 1, BLOCKSIZE - sum, fpinput);
if (n == 0){
break;
}
sum += n;
if (sum == BLOCKSIZE) {
md5_process_block (buffer, BLOCKSIZE, &ctx);
sum = 0;
}
}
if (n == 0 && ferror (fpinput)) {
free (buffer);
return 1;
}
/* Process any remaining bytes. */
if (sum > 0){
md5_process_bytes (buffer, sum, &ctx);
}
/* Construct result in desired memory. */
md5_finish_ctx (&ctx, resblock);
free (buffer);
for (int x = 0; x < 16; ++x){
std::cout << std::setfill('0') << std::setw(2) << std::hex << static_cast<uint16_t>(resblock[x]);
std::cout << " ";
}
std::cout << std::endl;
free(resblock);
return 0;
}
EDIT: Was a default mkspec problem in Fedora 19 64-bit.
fread() is convenient, but don't use fread() if you care about performance. fread() will copy from the OS to a libc buffer, then to your buffer. This extra copying cost CPU cycles and cache.
For better performance use open() then read() to avoid the extra copy. Make sure your read() calls are multiples of the block size, but lower than your CPU cache size.
For best performance use mmap() map the disk directly to RAM.
If you try something like the below code, it should go faster.
// compile gcc mmap_md5.c -lgcrypt
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <gcrypt.h>
#include <linux/fs.h> // ioctl
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
int main(int argc, char *argv[])
{
char *addr;
int fd;
struct stat sb;
off_t offset, pa_offset;
size_t length;
ssize_t s;
unsigned char digest[16];
char digest_ascii[32+1] = {0,};
int digest_length = gcry_md_get_algo_dlen (GCRY_MD_MD5);
int i;
if (argc < 3 || argc > 4) {
fprintf(stderr, "%s file offset [length]\n", argv[0]);
exit(EXIT_FAILURE);
}
fd = open(argv[1], O_RDONLY);
if (fd == -1)
handle_error("open");
if (fstat(fd, &sb) == -1) /* To obtain file size */
handle_error("fstat");
offset = atoi(argv[2]);
pa_offset = offset & ~(sysconf(_SC_PAGE_SIZE) - 1);
if (sb.st_mode | S_IFBLK ) {
// block device. use ioctl to find length
ioctl(fd, BLKGETSIZE64, &length);
} else {
/* offset for mmap() must be page aligned */
if (offset >= sb.st_size) {
fprintf(stderr, "offset is past end of file size=%zd, offset=%d\n", sb.st_size, (int) offset);
exit(EXIT_FAILURE);
}
if (argc == 4) {
length = atoi(argv[3]);
if (offset + length > sb.st_size)
length = sb.st_size - offset;
/* Canaqt display bytes past end of file */
} else { /* No length arg ==> display to end of file */
length = sb.st_size - offset;
}
}
printf("length= %zd\n", length);
addr = mmap(NULL, length + offset - pa_offset, PROT_READ,
MAP_PRIVATE, fd, pa_offset);
if (addr == MAP_FAILED)
handle_error("mmap");
gcry_md_hash_buffer(GCRY_MD_MD5, digest, addr + offset - pa_offset, length);
for (i=0; i < digest_length; i++) {
sprintf(digest_ascii+(i*2), "%02x", digest[i]);
}
printf("hash=%s\n", digest_ascii);
exit(EXIT_SUCCESS);
}
It turned out to be an error in the Qt mkspecs regarding an optimization flag not being set properly.