I am writing a client-server program which uses shared memory. I have created an shm.c and shm.h to make the client and server file a lot nicer. However,I would like to know how can I initialise the shared memory using accessSHM (missing as I have no clue how could I reach it if someone could explain that as well that would be quite helpful) in the code below.
#include <stdbool.h>
#include <time.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include "shm.h"
char * getTimeStamp() {
time_t ltime = time(NULL);
return strtok(ctime(<ime), "\n");
}
int createSHM(char * shname)
{
if ((shmid = shmget(key, sizeof(msg), IPC_CREAT)) < 0) {
perror("shmget");
exit(1);
}
}
int loadSHM(char * shname)
{
if (shname< 0)
{
printf("shmget error\n");
exit(1);
}
}
SHMstruct * accessSHM(int fd) {
}
SHMstruct * initSHM(int fd, SHMstruct *data) {
}
void clearSHM(SHMstruct * shm)
{
int status = munmap(shm, sizeof(SHMstruct));
if (status ==-1){
fprintf(stderr, "Failure in clearSHM",strerror(errno));
exit(errno);
}
}
void closeSHM(int fd)
{
int status = close(fd);
if (status ==-1){
fprintf(stderr, "Failure in closeSHM",strerror(errno));
exit(errno);
}
}
void destroySHM(char * shname)
{
int status = shm_unlink (shname);
if (status ==-1){
fprintf(stderr, "Failure in destroySHM",strerror(errno));
exit(errno);
}
}
shm.h
#ifndef _shm_h_
#define _shm_h_
#include <stdbool.h>
#define SHNAME "/shmserver" // shared memory
#define MAX_TICKETS 10
#define MAX_SLEEP 1 // seconds
typedef struct SHM {
int ticket;
bool isTaken;
bool soldOut;
} SHMstruct;
extern char * getTimeStamp();
extern int createSHM(char *shname);
extern int loadSHM( char *shname);
extern SHMstruct* initSHM( int fd, SHMstruct *data);
extern SHMstruct * accessSHM(int fd);
extern void clearSHM(SHMstruct * shm);
extern void closeSHM(int fd);
extern void destroySHM(char * shname);
#endif
Shared memory is a fairly large topic; it really isn't enough to just say "this is how you open one." Before writing one yourself, you may want to make sure you need to do it.
There are several libraries, including Boost interprocess, that provide a wrapper around creating and accessing shared memory. You may want to look there before deciding to write your own.
If you can't use Boost (or some other library), and really have to write one yourself, keep in mind that you are also going to need to provide a way for synchronization (locking) so that reads and writes aren't occurring at the same time from multiple processes. I would suggest looking at some code from some of those libraries, or even code from right here on stackoverflow: A simple shared memory application written on Linux to get the basics, but just go into this knowing it's going to be quite a bit of code to get a working library.
you can attach and get the address using shmat call.
p_mem = (message *) shmat(shmid,0,0);
In this example, message is a structure. You can use any data type.
p_mem is like any other pointer.
char *p_mem;
p_mem = (char *) shmat(shmid,0,0);
strcpy(p_mem, "test");
Related
I wrote a c-code designed for linux platform.
Now, I want to make it cross-platform so to use in Windows as-well.
In my code, I dlopen an so file and utilize the functions inside it.
Below is how my code looks like. But I just found out that in windows, the way to load and use dynamic library is quite different.
void *mydynlib
mydynlib= dlopen("/libpath/dynlib.so",RTLD_LAZY);
void (*dynfunc1)() = dlsym(mydynlib,"dynfunc1");
void (*dynfunc2)(char*, char*, double) = dlsym(mydynlib,"dynfunc2");
int (*dynfunc3)() = dlsym(mydynlib,"dynfunc3");
From what I found, I need to use LoadLibrary & GetProcAddress instead of dlopen & dlsym. However, I do not know how to convert above line for windows using those. I've tried to search some examples for hours but couldn't find exact solution. If someone had this kind of experience, please give me a tip.
Excuse me if this is too obvious problem. I'm quite new to C. I usually write my program in python.
Once in my youth I created something like this:
/* dlfcn.h */
#ifndef DLFCN_H
#define DLFCN_H
#define RTLD_GLOBAL 0x100 /* do not hide entries in this module */
#define RTLD_LOCAL 0x000 /* hide entries in this module */
#define RTLD_LAZY 0x000 /* accept unresolved externs */
#define RTLD_NOW 0x001 /* abort if module has unresolved externs */
/*
How to call in Windows:
void *h = dlopen ("path\\library.dll", flags)
void (*fun)() = dlsym (h, "entry")
*/
#ifdef __cplusplus
extern "C" {
#endif
void *dlopen (const char *filename, int flag);
int dlclose (void *handle);
void *dlsym (void *handle, const char *name);
const char *dlerror (void);
#ifdef __cplusplus
}
#endif
#endif
and dlfcn.c:
/* dlfcn.c */
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
static struct {
long lasterror;
const char *err_rutin;
} var = {
0,
NULL
};
void *dlopen (const char *filename, int flags)
{
HINSTANCE hInst;
hInst= LoadLibrary (filename);
if (hInst==NULL) {
var.lasterror = GetLastError ();
var.err_rutin = "dlopen";
}
return hInst;
}
int dlclose (void *handle)
{
BOOL ok;
int rc= 0;
ok= FreeLibrary ((HINSTANCE)handle);
if (! ok) {
var.lasterror = GetLastError ();
var.err_rutin = "dlclose";
rc= -1;
}
return rc;
}
void *dlsym (void *handle, const char *name)
{
FARPROC fp;
fp= GetProcAddress ((HINSTANCE)handle, name);
if (!fp) {
var.lasterror = GetLastError ();
var.err_rutin = "dlsym";
}
return (void *)(intptr_t)fp;
}
const char *dlerror (void)
{
static char errstr [88];
if (var.lasterror) {
sprintf (errstr, "%s error #%ld", var.err_rutin, var.lasterror);
return errstr;
} else {
return NULL;
}
}
You could use a set of macros that change depending on the OS you're on:
#ifdef __linux__
#define LIBTYPE void*
#define OPENLIB(libname) dlopen((libname), RTLD_LAZY)
#define LIBFUNC(lib, fn) dlsym((lib), (fn))
#elif defined(WINVER)
#define LIBTYPE HINSTANCE
#define OPENLIB(libname) LoadLibraryW(L ## libname)
#define LIBFUNC(lib, fn) GetProcAddress((lib), (fn))
#endif
I am trying to use the Boost 1.60.0 library with Intel Pin 2.14-71313-msvc12-windows. The following piece of code is the simple implementation I did to try things out:
#define _CRT_SECURE_NO_WARNINGS
#include "pin.H"
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <stdlib.h>
#include <sstream>
#include <time.h>
#include <boost/lockfree/spsc_queue.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
namespace boost_network{
#include <boost/asio.hpp>
#include <boost/array.hpp>
}
//Buffersize of lockfree queue to use
const int BUFFERSIZE = 1000;
//Tracefiles for error / debug purpose
std::ofstream TraceFile;
//String wrapper for boost queue
class statement {
public:
statement(){ s = ""; }
statement(const std::string &n) : s(n) {}
std::string s;
};
//string queue to store inserts
boost::lockfree::spsc_queue<statement, boost::lockfree::capacity<BUFFERSIZE>> buffer; // need lockfree queue for multithreading
//Pin Lock to synchronize buffer pushes between threads
PIN_LOCK lock;
KNOB<string> KnobOutputFile(KNOB_MODE_WRITEONCE, "pintool", "o", "calltrace.txt", "specify trace file name");
KNOB<BOOL> KnobPrintArgs(KNOB_MODE_WRITEONCE, "pintool", "a", "0", "print call arguments ");
INT32 Usage()
{
cerr << "This tool produces a call trace." << endl << endl;
cerr << KNOB_BASE::StringKnobSummary() << endl;
return -1;
}
VOID ImageLoad(IMG img, VOID *)
{
//save module informations
buffer.push(statement("" + IMG_Name(img) + "'; '" + IMG_Name(img).c_str() + "'; " + IMG_LowAddress(img) + ";"));
}
VOID Fini(INT32 code, VOID *v)
{
}
void do_somenetwork(std::string host, int port, std::string message)
{
boost_network::boost::asio::io_service ios;
boost_network::boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::address::from_string(host), port);
boost_network::boost::asio::ip::tcp::socket socket(ios);
socket.connect(endpoint);
boost_network::boost::system::error_code error;
socket.write_some(boost_network::boost::asio::buffer(message.data(), message.size()), error);
socket.close();
}
void WriteData(void * arg)
{
int popped; //actual amount of popped objects
const int pop_amount = 10000;
statement curr[pop_amount];
string statement = "";
while (1) {
//pop more objects from buffer
while (popped = buffer.pop(curr, pop_amount))
{
//got new statements in buffer to insert into db: clean up statement
statement.clear();
//concat into one statement
for (int i = 0; i < popped; i++){
statement += curr[i].s;
}
do_somenetwork(std::string("127.0.0.1"), 50000, sql_statement.c_str());
}
PIN_Sleep(1);
}
}
int main(int argc, char *argv[])
{
PIN_InitSymbols();
//write address of label to TraceFile
TraceFile.open(KnobOutputFile.Value().c_str());
TraceFile << &label << endl;
TraceFile.close();
// Initialize the lock
PIN_InitLock(&lock);
// Initialize pin
if (PIN_Init(argc, argv)) return Usage();
// Register ImageLoad to be called when an image is loaded
IMG_AddInstrumentFunction(ImageLoad, 0);
//Start writer thread
PIN_SpawnInternalThread(WriteData, 0, 0, 0);
PIN_AddFiniFunction(Fini, 0);
// Never returns
PIN_StartProgram();
return 0;
}
When I build the above code, Visual Studio cannot find boost_network::boost::asio::ip and keeps giving error saying asio::ip does not exist. I had previously posted this question myself:
Sending data from a boost asio client
and after using the provided solution in the same workspace, the code worked fine and I was able to communicate over the network. I am not sure what is going wrong here. For some reason using the different namespace seems to not work out because it says boost must be in the default namespace.
However, if I do not add the namespace, in that case the line,
KNOB<BOOL> KnobPrintArgs(KNOB_MODE_WRITEONCE, "pintool", "a", "0", "print call arguments ");
throws an error saying BOOL is ambiguous.
Kindly suggest what should be a viable solution in this situation. I am using Visual Studio 2013.
The same piece of code with only Pin also works with out the network part and I can write data generated from Pin into a flat file.
I am relatively new to C++, so please forgive my lack of knowledge. I need help regarding TFTP packets. Below is the code I am using to generate a WRQ (write request package) and DATA packet which will be sent to a designated server.
bool createWRQ(char * filename) {
/* structure is the same as RRQ */
clear();
addWord(TFTP_OPCODE_WRITE);
addString(filename);
addByte(0);
addString(TFTP_DEFAULT_TRANSFER_MODE);
addByte(0);
return true;
}
bool createData(int block, char * mData, int data_size) {
/* 2 bytes 2 bytes n bytes
----------------------------------------
DATA | 03 | Block # | Data |
---------------------------------------- */
clear(); // to clean the memory location
addWord(TFTP_OPCODE_DATA);
addWord(block);
addMemory(mData, data_size);
return true;
}
I will include the declarations and required functions.
#include "stdafx.h"
#include "WebComm.h"
#include "WebCommDlg.h"
#include <stdio.h>
#include <stdlib.h>
#include "visa.h"
#include <cstring>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <winsock.h>
#include <string.h>
#include <string>
#include <fstream>
#include <cstdio>
#include <cerrno>
int mCurPacketSize = 512;
char mData[512];
#define VIBUF_LEN 255
#define TFTP_OPCODE_READ 1
#define TFTP_OPCODE_WRITE 2
#define TFTP_OPCODE_DATA 3
#define TFTP_OPCODE_ACK 4
#define TFTP_OPCODE_ERROR 5
#define cTFTPPacket_MAX_SIZE 1024
#define cTFTPPacket_DATA_SIZE 512
#define TFTP_DEFAULT_TRANSFER_MODE "octet" //"netascii", "octet", or "mail"
typedef unsigned char BYTE;
typedef unsigned short WORD;
bool addByte(BYTE b) {
if(mCurPacketSize >= cTFTPPacket_MAX_SIZE)
return false;
mData[mCurPacketSize] = (unsigned char)b;
mCurPacketSize++;
return true;
}
bool addWord(WORD w) {
w = htons(w);
if(!addByte(*(((BYTE*)&w)+1)))
return false;
return !addByte(*((BYTE*)&w));
}
bool addString(char * str) {
int n = strlen(str);
for(int i=0; i<n; i++)
if(!addByte(str[i]))
return false;
return true;
}
bool addMemory(char * buffer, int len) {
bool oStatus = false;
if(mCurPacketSize + len >= cTFTPPacket_MAX_SIZE) {
AfxMessageBox("Packet max size exceeded");
return false;
} else {
memcpy(mData + mCurPacketSize), buffer, len);
mCurPacketSize += len;
return true;
}
}
void clear() {
mCurPacketSize = 0;
memset(mData, mCurPacketSize, cTFTPPacket_MAX_SIZE);
}
I am aware these function have been declared mostly as type bool, however I need to send a WRQ packet to the server and wait for an ACK response before sending a DATA packet.
Something along the lines of:
while(/* something */)
if(!sendto(socket, WRQ, 512, NULL, (sockaddr*)&Addr, sizeof(struct sockaddr_in)))){
if(!recvfrom(socket, ACK, /* ... */))
sendto(socket, DATA_Packet, 512, NULL, (sockaddr*)&Addr, sizeof(struct sockaddr_in))));
My question is: how can I modify the createWRQ() and createData() functions so that I can return them as packets to use for transmission, since bool only returns true or false as 1 or 0.
I need to be able to send them using the winsock send and receive functions. Apologies for the silly question. If anyone could point me in the right direction I would greatly appreciate it.
your whole approach has a few issues...
When you create your packets relying on functions like
bool addByte(BYTE b)
they use global variables
mCurPacketSize, mData
that's not good. You could use instead something on these lines
int addByte(char* Pkt, int PktIdx, BYTE b)
{
if (PktIdx > cTFTPPacket_MAX_SIZE)
{
return 0;
}
Pkt[PktIdx] = (unsigned char)b;
PktIdx++;
return PktIdx;
}
then you know that Pkt is always the head of your packet and PktIdx is either the place for a new byte (or string) and "also" the size of the packet.
When you create packets that have a fixed length structure (or a fixed length header followed by a variable length payload area) it is a good idea to represent the fixed length area with a "packed" (pay attention to memory alignment) C/C++ structure and then populate the structure.
I'm trying to improve my knowledge of OOP and decided to create a simple class to simplify sockets programming.
This is a learning experiment so I do not want to use boost, or other libraries.
I want to implement an event-driven recv(). Meaning, everytime there is new data coming in, it should call my function.
I think I need to create a thread to run a recv() loop and then call my function everytime there is new data. Is there other way around using threads? I want my code to be portable.
Here is my simple Class and example code:
class.h:
#ifndef _SOCKETSCLASS_H
#define _SOCKETSCLASS_H
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__)
#define W32
#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib")
#else
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#define SOCKET int
#endif
#include <string>
#include<ctime>
#include <stdio.h>
#include <stdarg.h>
#include <varargs.h>
#include <tchar.h>
using namespace std;
#ifdef _DEBUG
#define DEBUG(msg) XTrace(msg)
#else
#define DEBUG(msg, params)
#endif
struct TCP_Client_opts
{
BOOL UseSCprotocol;
BOOL UseEncryption;
BOOL UseCompression;
int CompressionLevel;
void *Callback;
BOOL async;
};
struct TCP_Stats
{
unsigned long int upload; //bytes
unsigned long int download;//bytes
time_t uptime; //seconds
};
class TCP_Client
{
public:
TCP_Client();
TCP_Client(TCP_Client_opts opts_set);
~TCP_Client();
SOCKET GetSocket();
void SetOptions(TCP_Client_opts opts_set);
TCP_Client_opts GetOptions();
BOOL Connect(string server, int port);
int Send(string data);
int Recv(string *data);
BOOL IsConnected();
int Disconnect();
TCP_Stats GetStats();
private:
SOCKET s = SOCKET_ERROR;
TCP_Client_opts opts;
TCP_Stats stats;
BOOL connected = FALSE;
time_t starttime;
};
#endif
class.cpp:
#include "SocketsClass.h"
void XTrace(LPCTSTR lpszFormat, ...)
{
va_list args;
va_start(args, lpszFormat);
int nBuf;
TCHAR szBuffer[512]; // get rid of this hard-coded buffer
nBuf = _vsnwprintf_s(szBuffer, 511, lpszFormat, args);
::OutputDebugString(szBuffer);
va_end(args);
}
TCP_Client::TCP_Client(TCP_Client_opts opts_set)
{
SetOptions(opts_set);
}
TCP_Client::~TCP_Client()
{
Disconnect();
}
TCP_Client::TCP_Client()
{
}
void TCP_Client::SetOptions(TCP_Client_opts opts_set)
{
opts = opts_set;
}
TCP_Client_opts TCP_Client::GetOptions()
{
return opts;
}
SOCKET TCP_Client::GetSocket()
{
return s;
}
BOOL TCP_Client::IsConnected()
{
return connected;
}
int TCP_Client::Disconnect()
{
connected = FALSE;
stats.uptime = time(0) - starttime;
return shutdown(s, 2);
}
BOOL TCP_Client::Connect(string server, int port)
{
struct sockaddr_in RemoteHost;
#ifdef W32
WSADATA wsd;
if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0)
{
DEBUG(L"Failed to load Winsock!\n");
return FALSE;
}
#endif
//create socket if it is not already created
if (s == SOCKET_ERROR)
{
//Create socket
s = socket(AF_INET, SOCK_STREAM, 0);
if (s == SOCKET_ERROR)
{
DEBUG(L"Could not create socket");
return FALSE;
}
}
//setup address structure
if (inet_addr(server.c_str()) == INADDR_NONE)
{
struct hostent *he;
//resolve the hostname, its not an ip address
if ((he = gethostbyname(server.c_str())) == NULL)
{
//gethostbyname failed
DEBUG(L"gethostbyname() - Failed to resolve hostname\n");
return FALSE;
}
}
else//plain ip address
{
RemoteHost.sin_addr.s_addr = inet_addr(server.c_str());
}
RemoteHost.sin_family = AF_INET;
RemoteHost.sin_port = htons(port);
//Connect to remote server
if (connect(s, (struct sockaddr *)&RemoteHost, sizeof(RemoteHost)) < 0)
{
DEBUG(L"connect() failed");
return FALSE;
}
connected = TRUE;
starttime = time(0);
stats.download = 0;
stats.upload = 0;
return TRUE;
}
TCP_Stats TCP_Client::GetStats()
{
if (connected==TRUE)
stats.uptime = time(0)-starttime;
return stats;
}
int TCP_Client::Send(string data)
{
stats.upload += data.length();
return send(s, data.c_str(), data.length(), 0);
}
int TCP_Client::Recv(string *data)
{
int ret = 0;
char buffer[512];
ret = recv(s, buffer, sizeof(buffer), 0);
data->assign(buffer);
data->resize(ret);
stats.download += data->length();
return ret;
}
main.cpp:
#include <stdio.h>
#include <string.h>
#include "SocketsClass.h"
using namespace std;
int main(int argc, char *argv)
{
TCP_Client tc;
tc.Connect("127.0.0.1", 9999);
tc.Send("HEllo");
string data;
tc.Recv(&data);
puts(data.c_str());
tc.Disconnect();
printf("\n\nDL: %i\nUP: %i\nUptime: %u\n", tc.GetStats().download, tc.GetStats().upload, tc.GetStats().uptime);
return 0;
}
Some extra questions:
Imagine I'm sending a file. How would my function know that the current data is related to the previous message?
How is my class design and implementation? SHould I change anything?
Thank you
If by "portable" you mean runs on other platforms besides Windows then a recv() loop in a worker thread is your only portable option. On Windows specifically, you have some additional choices:
Allocate a hidden window and then use WSAAsyncSelect() to receive FD_READ notifications. This requires a message loop, which you can put in a worker thread.
Use WSAEventSelect() to register a waitable event for FD_READ notifications and then wait for those events via WSAWaitForMultipleEvents() in a thread.
use WSARecv() with an I/O Completion Port. Poll the IOCP via GetQueuedCompletionResult() in a thread.
As for your question regarding messaging, TCP is a byte stream, it has no concept of messages. You have to frame your messages yourself. You can either:
give each message a fixed header that contains the message length. Read the header first, then read however many bytes it says, then read the next header, and so on.
separate each message with a unique delimiter that does not appear in the message data. Read until you encounter that delimiter, then read until the next delimiter, and so on.
Have your event loop call either poll or select to determine if there is data that can be read on the socket(s). Then read it, and call the appropriate callback function.
Is there any way to create a memory buffer as a FILE*. In TiXml it can print the xml to a FILE* but i cant seem to make it print to a memory buffer.
There is a POSIX way to use memory as a FILE descriptor: fmemopen or open_memstream, depending on the semantics you want: Difference between fmemopen and open_memstream
I guess the proper answer is that by Kevin. But here is a hack to do it with FILE *. Note that if the buffer size (here 100000) is too small then you lose data, as it is written out when the buffer is flushed. Also, if the program calls fflush() you lose the data.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
FILE *f = fopen("/dev/null", "w");
int i;
int written = 0;
char *buf = malloc(100000);
setbuffer(f, buf, 100000);
for (i = 0; i < 1000; i++)
{
written += fprintf(f, "Number %d\n", i);
}
for (i = 0; i < written; i++) {
printf("%c", buf[i]);
}
}
fmemopen can create FILE from buffer, does it make any sense to you?
I wrote a simple example how i would create an in-memory FILE:
#include <unistd.h>
#include <stdio.h>
int main(){
int p[2]; pipe(p); FILE *f = fdopen( p[1], "w" );
if( !fork() ){
fprintf( f, "working" );
return 0;
}
fclose(f); close(p[1]);
char buff[100]; int len;
while( (len=read(p[0], buff, 100))>0 )
printf(" from child: '%*s'", len, buff );
puts("");
}
C++ basic_streambuf inheritance
In C++, you should avoid FILE* if you can.
Using only the C++ stdlib, it is possible to make a single interface that transparently uses file or memory IO.
This uses techniques mentioned at: Setting the internal buffer used by a standard stream (pubsetbuf)
#include <cassert>
#include <cstring>
#include <fstream>
#include <iostream>
#include <ostream>
#include <sstream>
/* This can write either to files or memory. */
void write(std::ostream& os) {
os << "abc";
}
template <typename char_type>
struct ostreambuf : public std::basic_streambuf<char_type, std::char_traits<char_type> > {
ostreambuf(char_type* buffer, std::streamsize bufferLength) {
this->setp(buffer, buffer + bufferLength);
}
};
int main() {
/* To memory, in our own externally supplied buffer. */
{
char c[3];
ostreambuf<char> buf(c, sizeof(c));
std::ostream s(&buf);
write(s);
assert(memcmp(c, "abc", sizeof(c)) == 0);
}
/* To memory, but in a hidden buffer. */
{
std::stringstream s;
write(s);
assert(s.str() == "abc");
}
/* To file. */
{
std::ofstream s("a.tmp");
write(s);
s.close();
}
/* I think this is implementation defined.
* pusetbuf calls basic_filebuf::setbuf(). */
{
char c[3];
std::ofstream s;
s.rdbuf()->pubsetbuf(c, sizeof c);
write(s);
s.close();
//assert(memcmp(c, "abc", sizeof(c)) == 0);
}
}
Unfortunately, it does not seem possible to interchange FILE* and fstream: Getting a FILE* from a std::fstream
You could use the CStr method of TiXMLPrinter which the documentation states:
The TiXmlPrinter is useful when you
need to:
Print to memory (especially in non-STL mode)
Control formatting (line endings, etc.)
https://github.com/Snaipe/fmem is a wrapper for different platform/version specific implementations of memory streams
It tries in sequence the following implementations:
open_memstream.
fopencookie, with growing dynamic buffer.
funopen, with growing dynamic buffer.
WinAPI temporary memory-backed file.
When no other mean is available, fmem falls back to tmpfile()