Numerical result out of range - c++

I have a program that creates semaphore. But when i try to use SETALL, i get the error in errno as
Numerical result out of range
if((temp_semid = semget(IPC_PRIVATE, 250, 0666 | IPC_CREAT)) != -1)
{
semun arg;
ushort array[100];
memset(array,0, 100);
arg.array = array;
if(semctl(temp_semid, 0, SETALL, arg) == -1){
std::cout << " failed to setall semaphore" << std::endl;
std::cout << strerror(errno) << std::endl;
break;
}
}
What is wrong?

This worked.
if((temp_semid = semget(IPC_PRIVATE, 250, 0666 | IPC_CREAT)) != -1)
{
semun arg;
ushort array[100] = { 0 };
arg.array = array;
if(semctl(temp_semid, 0, SETALL, arg) == -1){
std::cout << " failed to setall semaphore" << std::endl;
std::cout << strerror(errno) << std::endl;
break;
}
}
i was using memset in the wrong way. thanks to hmjd for pointing that out.

Related

audio do not stop recording after pause ffmpeg c++

I am developing an application that record the screen and the audio from microphone. I implemented the pause function stopping video and audio thread on a condition variable, resuming them with a notify on the same condition variable. This is done in captureAudio(), in the main while. In this way works on macOS and linux, where I use avfoudation and alsa respectively, but on windows, with dshow, keep recording audio during the pause, when the thread is waiting on the condition variable. Does anybody know how can I fix this behaviour?
#include "ScreenRecorder.h"
using namespace std;
ScreenRecorder::ScreenRecorder() : pauseCapture(false), stopCapture(false), started(false), activeMenu(true) {
avcodec_register_all();
avdevice_register_all();
width = 1920;
height = 1200;
}
ScreenRecorder::~ScreenRecorder() {
if (started) {
value = av_write_trailer(outAVFormatContext);
if (value < 0) {
cerr << "Error in writing av trailer" << endl;
exit(-1);
}
avformat_close_input(&inAudioFormatContext);
if(inAudioFormatContext == nullptr){
cout << "inAudioFormatContext close successfully" << endl;
}
else{
cerr << "Error: unable to close the inAudioFormatContext" << endl;
exit(-1);
//throw "Error: unable to close the file";
}
avformat_free_context(inAudioFormatContext);
if(inAudioFormatContext == nullptr){
cout << "AudioFormat freed successfully" << endl;
}
else{
cerr << "Error: unable to free AudioFormatContext" << endl;
exit(-1);
}
avformat_close_input(&pAVFormatContext);
if (pAVFormatContext == nullptr) {
cout << "File close successfully" << endl;
}
else {
cerr << "Error: unable to close the file" << endl;
exit(-1);
//throw "Error: unable to close the file";
}
avformat_free_context(pAVFormatContext);
if (pAVFormatContext == nullptr) {
cout << "VideoFormat freed successfully" << endl;
}
else {
cerr << "Error: unable to free VideoFormatContext" << endl;
exit(-1);
}
}
}
/*==================================== VIDEO ==============================*/
int ScreenRecorder::openVideoDevice() throw() {
value = 0;
options = nullptr;
pAVFormatContext = nullptr;
pAVFormatContext = avformat_alloc_context();
string dimension = to_string(width) + "x" + to_string(height);
av_dict_set(&options, "video_size", dimension.c_str(), 0); //option to set the dimension of the screen section to record
#ifdef _WIN32
pAVInputFormat = av_find_input_format("gdigrab");
if (avformat_open_input(&pAVFormatContext, "desktop", pAVInputFormat, &options) != 0) {
cerr << "Couldn't open input stream" << endl;
exit(-1);
}
#elif defined linux
int offset_x = 0, offset_y = 0;
string url = ":0.0+" + to_string(offset_x) + "," + to_string(offset_y); //custom string to set the start point of the screen section
pAVInputFormat = av_find_input_format("x11grab");
value = avformat_open_input(&pAVFormatContext, url.c_str(), pAVInputFormat, &options);
if (value != 0) {
cerr << "Error in opening input device (video)" << endl;
exit(-1);
}
#else
value = av_dict_set(&options, "pixel_format", "0rgb", 0);
if (value < 0) {
cerr << "Error in setting pixel format" << endl;
exit(-1);
}
value = av_dict_set(&options, "video_device_index", "1", 0);
if (value < 0) {
cerr << "Error in setting video device index" << endl;
exit(-1);
}
pAVInputFormat = av_find_input_format("avfoundation");
if (avformat_open_input(&pAVFormatContext, "Capture screen 0:none", pAVInputFormat, &options) != 0) { //TODO trovare un modo per selezionare sempre lo schermo (forse "Capture screen 0")
cerr << "Error in opening input device" << endl;
exit(-1);
}
#endif
//set frame per second
value = av_dict_set(&options, "framerate", "30", 0);
if (value < 0) {
cerr << "Error in setting dictionary value (setting framerate)" << endl;
exit(-1);
}
value = av_dict_set(&options, "preset", "medium", 0);
if (value < 0) {
cerr << "Error in setting dictionary value (setting preset value)" << endl;
exit(-1);
}
/*
value = av_dict_set(&options, "vsync", "1", 0);
if(value < 0){
cerr << "Error in setting dictionary value (setting vsync value)" << endl;
exit(-1);
}
*/
value = av_dict_set(&options, "probesize", "60M", 0);
if (value < 0) {
cerr << "Error in setting probesize value" << endl;
exit(-1);
}
//get video stream infos from context
value = avformat_find_stream_info(pAVFormatContext, nullptr);
if (value < 0) {
cerr << "Error in retrieving the stream info" << endl;
exit(-1);
}
VideoStreamIndx = -1;
for (int i = 0; i < pAVFormatContext->nb_streams; i++) {
if (pAVFormatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
VideoStreamIndx = i;
break;
}
}
if (VideoStreamIndx == -1) {
cerr << "Error: unable to find video stream index" << endl;
exit(-2);
}
pAVCodecContext = pAVFormatContext->streams[VideoStreamIndx]->codec;
pAVCodec = avcodec_find_decoder(pAVCodecContext->codec_id/*params->codec_id*/);
if (pAVCodec == nullptr) {
cerr << "Error: unable to find decoder video" << endl;
exit(-1);
}
cout << "Insert height and width [h w]: "; //custom screen dimension to record
cin >> h >> w;*/
return 0;
}
/*========================================== AUDIO ============================*/
int ScreenRecorder::openAudioDevice() {
audioOptions = nullptr;
inAudioFormatContext = nullptr;
inAudioFormatContext = avformat_alloc_context();
value = av_dict_set(&audioOptions, "sample_rate", "44100", 0);
if (value < 0) {
cerr << "Error: cannot set audio sample rate" << endl;
exit(-1);
}
value = av_dict_set(&audioOptions, "async", "1", 0);
if (value < 0) {
cerr << "Error: cannot set audio sample rate" << endl;
exit(-1);
}
#if defined linux
audioInputFormat = av_find_input_format("alsa");
value = avformat_open_input(&inAudioFormatContext, "hw:0", audioInputFormat, &audioOptions);
if (value != 0) {
cerr << "Error in opening input device (audio)" << endl;
exit(-1);
}
#endif
#if defined _WIN32
audioInputFormat = av_find_input_format("dshow");
value = avformat_open_input(&inAudioFormatContext, "audio=Microfono (Realtek(R) Audio)", audioInputFormat, &audioOptions);
if (value != 0) {
cerr << "Error in opening input device (audio)" << endl;
exit(-1);
}
#endif
value = avformat_find_stream_info(inAudioFormatContext, nullptr);
if (value != 0) {
cerr << "Error: cannot find the audio stream information" << endl;
exit(-1);
}
audioStreamIndx = -1;
for (int i = 0; i < inAudioFormatContext->nb_streams; i++) {
if (inAudioFormatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
audioStreamIndx = i;
break;
}
}
if (audioStreamIndx == -1) {
cerr << "Error: unable to find audio stream index" << endl;
exit(-2);
}
}
int ScreenRecorder::initOutputFile() {
value = 0;
outAVFormatContext = nullptr;
outputAVFormat = av_guess_format(nullptr, "output.mp4", nullptr);
if (outputAVFormat == nullptr) {
cerr << "Error in guessing the video format, try with correct format" << endl;
exit(-5);
}
avformat_alloc_output_context2(&outAVFormatContext, outputAVFormat, outputAVFormat->name, "..\\media\\output.mp4");
if (outAVFormatContext == nullptr) {
cerr << "Error in allocating outAVFormatContext" << endl;
exit(-4);
}
/*===========================================================================*/
this->generateVideoStream();
this->generateAudioStream();
//create an empty video file
if (!(outAVFormatContext->flags & AVFMT_NOFILE)) {
if (avio_open2(&outAVFormatContext->pb, "..\\media\\output.mp4", AVIO_FLAG_WRITE, nullptr, nullptr) < 0) {
cerr << "Error in creating the video file" << endl;
exit(-10);
}
}
if (outAVFormatContext->nb_streams == 0) {
cerr << "Output file does not contain any stream" << endl;
exit(-11);
}
value = avformat_write_header(outAVFormatContext, &options);
if (value < 0) {
cerr << "Error in writing the header context" << endl;
exit(-12);
}
return 0;
}
/*=================================== VIDEO ==================================*/
void ScreenRecorder::generateVideoStream() {
//Generate video stream
videoSt = avformat_new_stream(outAVFormatContext, nullptr);
if (videoSt == nullptr) {
cerr << "Error in creating AVFormatStream" << endl;
exit(-6);
}
outVideoCodec = avcodec_find_encoder(AV_CODEC_ID_MPEG4); //AV_CODEC_ID_MPEG4
if (outVideoCodec == nullptr) {
cerr << "Error in finding the AVCodec, try again with the correct codec" << endl;
exit(-8);
}
avcodec_alloc_context3(outAVCodec)
outVideoCodecContext = avcodec_alloc_context3(outVideoCodec);
if (outVideoCodecContext == nullptr) {
cerr << "Error in allocating the codec context" << endl;
exit(-7);
}
//set properties of the video file (stream)
outVideoCodecContext = videoSt->codec;
outVideoCodecContext->codec_id = AV_CODEC_ID_MPEG4;
outVideoCodecContext->codec_type = AVMEDIA_TYPE_VIDEO;
outVideoCodecContext->pix_fmt = AV_PIX_FMT_YUV420P;
outVideoCodecContext->bit_rate = 10000000;
outVideoCodecContext->width = width;
outVideoCodecContext->height = height;
outVideoCodecContext->gop_size = 10;
outVideoCodecContext->global_quality = 500;
outVideoCodecContext->max_b_frames = 2;
outVideoCodecContext->time_base.num = 1;
outVideoCodecContext->time_base.den = 30;
outVideoCodecContext->bit_rate_tolerance = 400000;
if (outVideoCodecContext->codec_id == AV_CODEC_ID_H264) {
av_opt_set(outVideoCodecContext->priv_data, "preset", "slow", 0);
}
if (outAVFormatContext->oformat->flags & AVFMT_GLOBALHEADER) {
outVideoCodecContext->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
}
value = avcodec_open2(outVideoCodecContext, outVideoCodec, nullptr);
if (value < 0) {
cerr << "Error in opening the AVCodec" << endl;
exit(-9);
}
outVideoStreamIndex = -1;
for (int i = 0; i < outAVFormatContext->nb_streams; i++) {
if (outAVFormatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_UNKNOWN) {
outVideoStreamIndex = i;
}
}
if (outVideoStreamIndex < 0) {
cerr << "Error: cannot find a free stream index for video output" << endl;
exit(-1);
}
avcodec_parameters_from_context(outAVFormatContext->streams[outVideoStreamIndex]->codecpar, outVideoCodecContext);
}
/*=============================== AUDIO ==================================*/
void ScreenRecorder::generateAudioStream() {
AVCodecParameters* params = inAudioFormatContext->streams[audioStreamIndx]->codecpar;
inAudioCodec = avcodec_find_decoder(params->codec_id);
if (inAudioCodec == nullptr) {
cerr << "Error: cannot find the audio decoder" << endl;
exit(-1);
}
inAudioCodecContext = avcodec_alloc_context3(inAudioCodec);
if (avcodec_parameters_to_context(inAudioCodecContext, params) < 0) {
cout << "Cannot create codec context for audio input" << endl;
}
value = avcodec_open2(inAudioCodecContext, inAudioCodec, nullptr);
if (value < 0) {
cerr << "Error: cannot open the input audio codec" << endl;
exit(-1);
}
//Generate audio stream
outAudioCodecContext = nullptr;
outAudioCodec = nullptr;
int i;
AVStream* audio_st = avformat_new_stream(outAVFormatContext, nullptr);
if (audio_st == nullptr) {
cerr << "Error: cannot create audio stream" << endl;
exit(1);
}
outAudioCodec = avcodec_find_encoder(AV_CODEC_ID_AAC);
if (outAudioCodec == nullptr) {
cerr << "Error: cannot find requested encoder" << endl;
exit(1);
}
outAudioCodecContext = avcodec_alloc_context3(outAudioCodec);
if (outAudioCodecContext == nullptr) {
cerr << "Error: cannot create related VideoCodecContext" << endl;
exit(1);
}
if ((outAudioCodec)->supported_samplerates) {
outAudioCodecContext->sample_rate = (outAudioCodec)->supported_samplerates[0];
for (i = 0; (outAudioCodec)->supported_samplerates[i]; i++) {
if ((outAudioCodec)->supported_samplerates[i] == inAudioCodecContext->sample_rate)
outAudioCodecContext->sample_rate = inAudioCodecContext->sample_rate;
}
}
outAudioCodecContext->codec_id = AV_CODEC_ID_AAC;
outAudioCodecContext->sample_fmt = (outAudioCodec)->sample_fmts ? (outAudioCodec)->sample_fmts[0] : AV_SAMPLE_FMT_FLTP;
outAudioCodecContext->channels = inAudioCodecContext->channels;
outAudioCodecContext->channel_layout = av_get_default_channel_layout(outAudioCodecContext->channels);
outAudioCodecContext->bit_rate = 96000;
outAudioCodecContext->time_base = { 1, inAudioCodecContext->sample_rate };
outAudioCodecContext->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
if ((outAVFormatContext)->oformat->flags & AVFMT_GLOBALHEADER) {
outAudioCodecContext->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
}
if (avcodec_open2(outAudioCodecContext, outAudioCodec, nullptr) < 0) {
cerr << "error in opening the avcodec" << endl;
exit(1);
}
//find a free stream index
outAudioStreamIndex = -1;
for (i = 0; i < outAVFormatContext->nb_streams; i++) {
if (outAVFormatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_UNKNOWN) {
outAudioStreamIndex = i;
}
}
if (outAudioStreamIndex < 0) {
cerr << "Error: cannot find a free stream for audio on the output" << endl;
exit(1);
}
avcodec_parameters_from_context(outAVFormatContext->streams[outAudioStreamIndex]->codecpar, outAudioCodecContext);
}
int ScreenRecorder::init_fifo()
{
/* Create the FIFO buffer based on the specified output sample format. */
if (!(fifo = av_audio_fifo_alloc(outAudioCodecContext->sample_fmt,
outAudioCodecContext->channels, 1))) {
fprintf(stderr, "Could not allocate FIFO\n");
return AVERROR(ENOMEM);
}
return 0;
}
int ScreenRecorder::add_samples_to_fifo(uint8_t** converted_input_samples, const int frame_size) {
int error;
/* Make the FIFO as large as it needs to be to hold both,
* the old and the new samples. */
if ((error = av_audio_fifo_realloc(fifo, av_audio_fifo_size(fifo) + frame_size)) < 0) {
fprintf(stderr, "Could not reallocate FIFO\n");
return error;
}
/* Store the new samples in the FIFO buffer. */
if (av_audio_fifo_write(fifo, (void**)converted_input_samples, frame_size) < frame_size) {
fprintf(stderr, "Could not write data to FIFO\n");
return AVERROR_EXIT;
}
return 0;
}
int ScreenRecorder::initConvertedSamples(uint8_t*** converted_input_samples,
AVCodecContext* output_codec_context,
int frame_size) {
int error;
/* Allocate as many pointers as there are audio channels.
* Each pointer will later point to the audio samples of the corresponding
* channels (although it may be NULL for interleaved formats).
*/
if (!(*converted_input_samples = (uint8_t**)calloc(output_codec_context->channels,
sizeof(**converted_input_samples)))) {
fprintf(stderr, "Could not allocate converted input sample pointers\n");
return AVERROR(ENOMEM);
}
/* Allocate memory for the samples of all channels in one consecutive
* block for convenience. */
if (av_samples_alloc(*converted_input_samples, nullptr,
output_codec_context->channels,
frame_size,
output_codec_context->sample_fmt, 0) < 0) {
exit(1);
}
return 0;
}
static int64_t pts = 0;
void ScreenRecorder::captureAudio() {
int ret;
AVPacket* inPacket, * outPacket;
AVFrame* rawFrame, * scaledFrame;
uint8_t** resampledData;
init_fifo();
//allocate space for a packet
inPacket = (AVPacket*)av_malloc(sizeof(AVPacket));
if (!inPacket) {
cerr << "Cannot allocate an AVPacket for encoded video" << endl;
exit(1);
}
av_init_packet(inPacket);
//allocate space for a packet
rawFrame = av_frame_alloc();
if (!rawFrame) {
cerr << "Cannot allocate an AVPacket for encoded video" << endl;
exit(1);
}
scaledFrame = av_frame_alloc();
if (!scaledFrame) {
cerr << "Cannot allocate an AVPacket for encoded video" << endl;
exit(1);
}
outPacket = (AVPacket*)av_malloc(sizeof(AVPacket));
if (!outPacket) {
cerr << "Cannot allocate an AVPacket for encoded video" << endl;
exit(1);
}
//init the resampler
SwrContext* resampleContext = nullptr;
resampleContext = swr_alloc_set_opts(resampleContext,
av_get_default_channel_layout(outAudioCodecContext->channels),
outAudioCodecContext->sample_fmt,
outAudioCodecContext->sample_rate,
av_get_default_channel_layout(inAudioCodecContext->channels),
inAudioCodecContext->sample_fmt,
inAudioCodecContext->sample_rate,
0,
nullptr);
if (!resampleContext) {
cerr << "Cannot allocate the resample context" << endl;
exit(1);
}
if ((swr_init(resampleContext)) < 0) {
fprintf(stderr, "Could not open resample context\n");
swr_free(&resampleContext);
exit(1);
}
while (true) {
if (pauseCapture) {
cout << "Pause audio" << endl;
}
cv.wait(ul, [this]() { return !pauseCapture; });
if (stopCapture) {
break;
}
ul.unlock();
if (av_read_frame(inAudioFormatContext, inPacket) >= 0 && inPacket->stream_index == audioStreamIndx) {
//decode audio routing
av_packet_rescale_ts(outPacket, inAudioFormatContext->streams[audioStreamIndx]->time_base, inAudioCodecContext->time_base);
if ((ret = avcodec_send_packet(inAudioCodecContext, inPacket)) < 0) {
cout << "Cannot decode current audio packet " << ret << endl;
continue;
}
while (ret >= 0) {
ret = avcodec_receive_frame(inAudioCodecContext, rawFrame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
break;
else if (ret < 0) {
cerr << "Error during decoding" << endl;
exit(1);
}
if (outAVFormatContext->streams[outAudioStreamIndex]->start_time <= 0) {
outAVFormatContext->streams[outAudioStreamIndex]->start_time = rawFrame->pts;
}
initConvertedSamples(&resampledData, outAudioCodecContext, rawFrame->nb_samples);
swr_convert(resampleContext,
resampledData, rawFrame->nb_samples,
(const uint8_t**)rawFrame->extended_data, rawFrame->nb_samp
add_samples_to_fifo(resampledData, rawFrame->nb_samples);
//raw frame ready
av_init_packet(outPacket);
outPacket->data = nullptr;
outPacket->size = 0;
const int frame_size = FFMAX(av_audio_fifo_size(fifo), outAudioCodecContext->frame_size);
scaledFrame = av_frame_alloc();
if (!scaledFrame) {
cerr << "Cannot allocate an AVPacket for encoded video" << endl;
exit(1);
}
scaledFrame->nb_samples = outAudioCodecContext->frame_size;
scaledFrame->channel_layout = outAudioCodecContext->channel_layout;
scaledFrame->format = outAudioCodecContext->sample_fmt;
scaledFrame->sample_rate = outAudioCodecContext->sample_rate;
av_frame_get_buffer(scaledFrame, 0);
while (av_audio_fifo_size(fifo) >= outAudioCodecContext->frame_size) {
ret = av_audio_fifo_read(fifo, (void**)(scaledFrame->data), outAudioCodecContext->frame_size);
scaledFrame->pts = pts;
pts += scaledFrame->nb_samples;
if (avcodec_send_frame(outAudioCodecContext, scaledFrame) < 0) {
cout << "Cannot encode current audio packet " << endl;
exit(1);
}
while (ret >= 0) {
ret = avcodec_receive_packet(outAudioCodecContext, outPacket);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
break;
else if (ret < 0) {
cerr << "Error during encoding" << endl;
exit(1);
}
av_packet_rescale_ts(outPacket, outAudioCodecContext->time_base, outAVFormatContext->streams[outAudioStreamIndex]->time_base);
outPacket->stream_index = outAudioStreamIndex;
write_lock.lock();
if (av_write_frame(outAVFormatContext, outPacket) != 0)
{
cerr << "Error in writing audio frame" << endl;
}
write_lock.unlock();
av_packet_unref(outPacket);
}
ret = 0;
}
av_frame_free(&scaledFrame);
av_packet_unref(outPacket);
}
}
}
}
int ScreenRecorder::captureVideoFrames() {
int64_t pts = 0;
int flag;
int frameFinished = 0;
bool endPause = false;
int numPause = 0;
ofstream outFile{ "..\\media\\log.txt", ios::out };
int frameIndex = 0;
value = 0;
pAVPacket = (AVPacket*)av_malloc(sizeof(AVPacket));
if (pAVPacket == nullptr) {
cerr << "Error in allocating AVPacket" << endl;
exit(-1);
}
pAVFrame = av_frame_alloc();
if (pAVFrame == nullptr) {
cerr << "Error: unable to alloc the AVFrame resources" << endl;
exit(-1);
}
outFrame = av_frame_alloc();
if (outFrame == nullptr) {
cerr << "Error: unable to alloc the AVFrame resources for out frame" << endl;
exit(-1);
}
int videoOutBuffSize;
int nBytes = av_image_get_buffer_size(outVideoCodecContext->pix_fmt, outVideoCodecContext->width, outVideoCodecContext->height, 32);
uint8_t* videoOutBuff = (uint8_t*)av_malloc(nBytes);
if (videoOutBuff == nullptr) {
cerr << "Error: unable to allocate memory" << endl;
exit(-1);
}
value = av_image_fill_arrays(outFrame->data, outFrame->linesize, videoOutBuff, AV_PIX_FMT_YUV420P, outVideoCodecContext->width, outVideoCodecContext->height, 1);
if (value < 0) {
cerr << "Error in filling image array" << endl;
}
SwsContext* swsCtx_;
if (avcodec_open2(pAVCodecContext, pAVCodec, nullptr) < 0) {
cerr << "Could not open codec" << endl;
exit(-1);
}
swsCtx_ = sws_getContext(pAVCodecContext->width, pAVCodecContext->height, pAVCodecContext->pix_fmt, outVideoCodecContext->width, outVideoCodecContext->height, outVideoCodecContext->pix_fmt, SWS_BICUBIC,
nullptr, nullptr, nullptr);
AVPacket outPacket;
int gotPicture;
time_t startTime;
time(&startTime);
while (true) {
if (pauseCapture) {
cout << "Pause" << endl;
outFile << "/////////////////// Pause ///////////////////" << endl;
cout << "outVideoCodecContext->time_base: " << outVideoCodecContext->time_base.num << ", " << outVideoCodecContext->time_base.den << endl;
}
cv.wait(ul, [this]() { return !pauseCapture; }); //pause capture (not busy waiting)
if (endPause) {
endPause = false;
}
if (stopCapture) //check if the capture has to stop
break;
ul.unlock();
if (av_read_frame(pAVFormatContext, pAVPacket) >= 0 && pAVPacket->stream_index == VideoStreamIndx) {
av_packet_rescale_ts(pAVPacket, pAVFormatContext->streams[VideoStreamIndx]->time_base, pAVCodecContext->time_base);
value = avcodec_decode_video2(pAVCodecContext, pAVFrame, &frameFinished, pAVPacket);
if (value < 0) {
cout << "Unable to decode video" << endl;
}
if (frameFinished) { //frame successfully decoded
//sws_scale(swsCtx_, pAVFrame->data, pAVFrame->linesize, 0, pAVCodecContext->height, outFrame->data, outFrame->linesize);
av_init_packet(&outPacket);
outPacket.data = nullptr;
outPacket.size = 0;
if (outAVFormatContext->streams[outVideoStreamIndex]->start_time <= 0) {
outAVFormatContext->streams[outVideoStreamIndex]->start_time = pAVFrame->pts;
}
//disable warning on the console
outFrame->width = outVideoCodecContext->width;
outFrame->height = outVideoCodecContext->height;
outFrame->format = outVideoCodecContext->pix_fmt;
sws_scale(swsCtx_, pAVFrame->data, pAVFrame->linesize, 0, pAVCodecContext->height, outFrame->data, outFrame->linesize);
avcodec_encode_video2(outVideoCodecContext, &outPacket, outFrame, &gotPicture);
if (gotPicture) {
if (outPacket.pts != AV_NOPTS_VALUE) {
outPacket.pts = av_rescale_q(outPacket.pts, videoSt->codec->time_base, videoSt->time_base);
}
if (outPacket.dts != AV_NOPTS_VALUE) {
outPacket.dts = av_rescale_q(outPacket.dts, videoSt->codec->time_base, videoSt->time_base);
}
//cout << "Write frame " << j++ << " (size = " << outPacket.size / 1000 << ")" << endl;
//cout << "(size = " << outPacket.size << ")" << endl;
//av_packet_rescale_ts(&outPacket, outVideoCodecContext->time_base, outAVFormatContext->streams[outVideoStreamIndex]->time_base);
//outPacket.stream_index = outVideoStreamIndex;
outFile << "outPacket->duration: " << outPacket.duration << ", " << "pAVPacket->duration: " << pAVPacket->duration << endl;
outFile << "outPacket->pts: " << outPacket.pts << ", " << "pAVPacket->pts: " << pAVPacket->pts << endl;
outFile << "outPacket.dts: " << outPacket.dts << ", " << "pAVPacket->dts: " << pAVPacket->dts << endl;
time_t timer;
double seconds;
mu.lock();
if (!activeMenu) {
time(&timer);
seconds = difftime(timer, startTime);
int h = (int)(seconds / 3600);
int m = (int)(seconds / 60) % 60;
int s = (int)(seconds) % 60;
std::cout << std::flush << "\r" << std::setw(2) << std::setfill('0') << h << ':'
<< std::setw(2) << std::setfill('0') << m << ':'
<< std::setw(2) << std::setfill('0') << s << std::flush;
}
mu.unlock();
write_lock.lock();
if (av_write_frame(outAVFormatContext, &outPacket) != 0) {
cerr << "Error in writing video frame" << endl;
}
write_lock.unlock();
av_packet_unref(&outPacket);
}
av_packet_unref(&outPacket);
av_free_packet(pAVPacket); //avoid memory saturation
}
}
}
outFile.close();
av_free(videoOutBuff);
return 0;
}
I resolved this problem performing an avformat_close_input(&inAudioFormatContext) before enter in pause, and an avformat_open_input(&inAudioFormatContext, "audio=Microfono (Realtek(R) Audio)", audioInputFormat, &audioOptions) after resume the recording. In this way the final file seems well syncronized with video.

ptrace - Input/Output Error (errno 5) on 32 bits only

I was trying to inject a shared library in another process and I managed to get it working on x64. Though, when I tried using it for 32bits, something weird is happening: ptrace is not being able to execute properly due to an Input/Output error (errno 5). I don't know what to do, since this same code worked for x64.
Then, I tried to make a smaller example using a function that I called test_ptrace. Surprisingly, the error doesn't happen there, though it is doing essentially the same thing (allocate memory on target process, inject a payload, set registers to match the payload, run the payload). When I saw the error was not happening, I tried again injecting the shared library with ptrace using a function called load_library. But unfortunately, there the error was again.
//this is the function that is NOT working, 'load_library'
void* load_library(pid_t pid, std::string path, int mode)
{
int status;
struct user_regs_struct old_regs, regs;
void* dlopen_ex = (void*)0xf7c29700; //I disabled ASLR, so this address does not change
void* handle_ex = (void*)-1;
unsigned char inj_buf[] =
{
0x51, //push ecx
0x53, //push ebx
0xFF, 0xD0, //call eax
0xCC, //int3 (SIGTRAP)
};
size_t path_size = path.size();
size_t inj_size = sizeof(inj_buf) + path_size;
void* inj_addr = allocate_memory(pid, inj_size, PROT_EXEC | PROT_READ | PROT_WRITE);
void* path_addr = (void*)((uintptr_t)inj_addr + sizeof(inj_buf));
write_memory(pid, inj_addr, (void*)inj_buf, sizeof(inj_buf));
write_memory(pid, path_addr, (void*)path.c_str(), path_size);
if(ptrace(PTRACE_ATTACH, pid, NULL, NULL))
{
perror("PTRACE_ATTACH");
std::cout << "Errno: " << errno << std::endl;
return handle_ex;
}
wait(&status);
if(ptrace(PTRACE_GETREGS, pid, NULL, &old_regs) == -1)
{
perror("PTRACE_GETREGS");
std::cout << "Errno: " << errno << std::endl;
return handle_ex;
}
regs.eax = (unsigned long)dlopen_ex;
regs.ebx = (unsigned long)path_addr;
regs.ecx = (unsigned long)mode;
regs.eip = (unsigned long)inj_addr;
if(ptrace(PTRACE_SETREGS, pid, NULL, &regs) == -1)
{
perror("PTRACE_SETREGS");
std::cout << "Errno: " << errno << std::endl;
return handle_ex;
}
if(ptrace(PTRACE_CONT, pid, NULL, NULL) == -1)
{
perror("PTRACE_CONT");
std::cout << "Errno: " << errno << std::endl;
return handle_ex;
}
waitpid(pid, &status, WSTOPPED);
if(ptrace(PTRACE_GETREGS, pid, NULL, &regs) == -1)
{
perror("PTRACE_GETREGS");
std::cout << "Errno: " << errno << std::endl;
return handle_ex;
}
handle_ex = (void*)old_regs.eax;
if(ptrace(PTRACE_SETREGS, pid, NULL, &old_regs) == -1)
{
perror("PTRACE_SETREGS");
std::cout << "Errno: " << errno << std::endl;
return handle_ex;
}
if(ptrace(PTRACE_DETACH, pid, NULL, NULL) == -1)
{
perror("PTRACE_DETACH");
std::cout << "Errno: " << errno << std::endl;
return handle_ex;
}
deallocate_memory(pid, inj_addr, inj_size);
return handle_ex;
}
//this one, though, is working, but it is very similar to the function
//above (except it doesn't restore the execution, but the code of the
//other function doesn't even get there anyway.
void test_ptrace(pid_t pid)
{
int status;
struct user_regs_struct regs;
unsigned char inj_buf[] =
{
0xCD, 0x80, //int80 (syscall)
0xCC, //int3 (SIGTRAP)
};
void* inj_addr = allocate_memory(pid, sizeof(inj_buf), PROT_EXEC | PROT_READ | PROT_WRITE);
write_memory(pid, inj_addr, inj_buf, sizeof(inj_buf));
std::cout << "--ptrace test started--" << std::endl;
if(ptrace(PTRACE_ATTACH, pid, NULL, NULL) == -1)
{
perror("PTRACE_ATTACH");
std::cout << "Errno: " << errno << std::endl;
return;
}
wait(&status);
if(ptrace(PTRACE_GETREGS, pid, NULL, &regs) == -1)
{
perror("PTRACE_GETREGS");
std::cout << "Errno: " << errno << std::endl;
return;
}
regs.eax = __NR_exit;
regs.ebx = 222;
regs.eip = (unsigned long)inj_addr;
if(ptrace(PTRACE_SETREGS, pid, NULL, &regs) == -1)
{
perror("PTRACE_SETREGS");
std::cout << "Errno: " << errno << std::endl;
return;
}
if(ptrace(PTRACE_DETACH, pid, NULL, NULL) == -1)
{
perror("PTRACE_DETACH");
std::cout << "Errno: " << errno << std::endl;
return;
}
std::cout << "--ptrace test ended--" << std::endl;
}
Program entry:
int main()
{
pid_t pid = get_process_id("target");
std::cout << "PID: " << pid << std::endl;
std::string lib_path = "<my_path>/ptrace-test/libtest.so";
load_library(pid, lib_path, RTLD_LAZY);
return 0;
}
Output:
PID: 2383
PTRACE_SETREGS: Input/output error
Errno: 5
If you need the whole project as a 'minimal' reproducible example, here you go: https://github.com/rdbo/ptrace-test
The PID is correct, I'm running as root, both the tracer and the tracee are compiled with G++ on 32 bits. Running up-to-date Manjaro. Any ideas?
I fixed it. Don't ask me how, though, I have no clue. I followed the exact same logic and out of sudden it worked. I used the working test_ptrace and kept putting the load_library code on it line by line to see what could be causing the problem. Turns out, I got it fixed and still don't know what it was. Anyways, here's the code (it is a bit messed up, because I didn't expect it to work):
void load_library(pid_t pid, std::string lib_path)
{
int status;
struct user_regs_struct old_regs, regs;
unsigned char inj_buf[] =
{
0x51, //push ecx
0x53, //push ebx
0xFF, 0xD0, //call eax
0xCC, //int3 (SIGTRAP)
};
size_t inj_size = sizeof(inj_buf) + lib_path.size();
void* inj_addr = allocate_memory(pid, inj_size, PROT_EXEC | PROT_READ | PROT_WRITE);
void* path_addr = (void*)((uintptr_t)inj_addr + sizeof(inj_buf));
write_memory(pid, inj_addr, inj_buf, sizeof(inj_buf));
write_memory(pid, path_addr, (void*)lib_path.c_str(), lib_path.size());
std::cout << "--ptrace test started--" << std::endl;
if(ptrace(PTRACE_ATTACH, pid, NULL, NULL) == -1)
{
perror("PTRACE_ATTACH");
std::cout << "Errno: " << errno << std::endl;
return;
}
wait(&status);
if(ptrace(PTRACE_GETREGS, pid, NULL, &old_regs) == -1)
{
perror("PTRACE_GETREGS");
std::cout << "Errno: " << errno << std::endl;
return;
}
regs = old_regs;
long dlopen_ex = 0xf7c28700;
regs.eax = dlopen_ex;
regs.ebx = (long)path_addr;
regs.ecx = RTLD_LAZY;
regs.eip = (unsigned long)inj_addr;
if(ptrace(PTRACE_SETREGS, pid, NULL, &regs) == -1)
{
perror("PTRACE_SETREGS");
std::cout << "Errno: " << errno << std::endl;
return;
}
ptrace(PTRACE_CONT, pid, NULL, NULL);
waitpid(pid, &status, WSTOPPED);
ptrace(PTRACE_SETREGS, pid, NULL, &old_regs);
if(ptrace(PTRACE_DETACH, pid, NULL, NULL) == -1)
{
perror("PTRACE_DETACH");
std::cout << "Errno: " << errno << std::endl;
return;
}
deallocate_memory(pid, inj_addr, inj_size);
std::cout << "--ptrace test ended--" << std::endl;
}
Output:
PID: 24615
--ptrace test started--
--ptrace test ended--
Target Process:
PID: 24615
dlopen: 0xf7c28700
Waiting...
Injected!
Waiting...
Waiting...
Waiting...
Waiting...
EDIT:
I just remembered I ran the following command as root (could've been it, not sure though):
echo 0 > /proc/sys/kernel/yama/ptrace_scope
EDIT2: It was not it, the code is still working after a reboot. Also, I improved the code a bit on the GitHub repository.

QueryChangesVirtualDisk is returning ERROR_INVALID_HANDLE(6) even though OpenVirtualDisk is succesfull

I am trying out VirtualDisk APIs,
So far I am able to Open a VHDX file, get some of the properties by using GetVirtualDiskInformation.
But I am not able to get RCT information and ChangedAreas.
The first call to GetVirtualDiskInformation is successful.
The second call to GetVirtualDiskInformation fails with insufficient buffer ERROR_INSUFFICIENT_BUFFER(122).
Call to QueryChangesVirtualDisk fails with ERROR_INVALID_HANDLE(6).
The RCT ID hardcoded in the code is proper, I am able to get the ChangedAreas using WMI Explorer.
Attached screenshot of the same.
If it is invalid handle, then GetVirtualDiskInformation should also throw the same error?
#include "pch.h"
#include <iostream>
#include <string>
#include <cstdlib>
#define WINVER _WIN32_WINNT_WIN10
#include <windows.h>
#include <winioctl.h>
#include <virtdisk.h>
#include <initguid.h>
#pragma comment(lib, "virtdisk.lib")
DEFINE_GUID(VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT, 0xec984aec, 0xa0f9, 0x47e9, 0x90, 0x1f, 0x71, 0x41, 0x5a, 0x66, 0x34, 0x5b);
DEFINE_GUID(VIRTUAL_STORAGE_TYPE_VENDOR_UNKNOWN, 0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
int main()
{
HANDLE vhdHandle;
_VIRTUAL_STORAGE_TYPE storageType;
storageType.DeviceId = VIRTUAL_STORAGE_TYPE_DEVICE_UNKNOWN;
storageType.VendorId = VIRTUAL_STORAGE_TYPE_VENDOR_UNKNOWN;
wchar_t path[] = L"C:\\Hyper-V\\Virtual Hard Disks\\Lacazette\\Windows2016.vhdx";
VIRTUAL_DISK_ACCESS_MASK mask = VIRTUAL_DISK_ACCESS_GET_INFO;
PGET_VIRTUAL_DISK_INFO diskInfo;
ULONG diskInfoSize = sizeof(GET_VIRTUAL_DISK_INFO);
std::wcout << "size of diskinfo structure " << diskInfoSize << std::endl;
diskInfo = (PGET_VIRTUAL_DISK_INFO)malloc(diskInfoSize);
if (diskInfo == NULL)
{
std::cout << "Failed to malloc disk info, ret=" << std::endl;
return 0;
}
std::wcout << "Opening Virtual disk " << path << std::endl;
DWORD res = OpenVirtualDisk(&storageType, path,
VIRTUAL_DISK_ACCESS_GET_INFO,
OPEN_VIRTUAL_DISK_FLAG_NO_PARENTS,
NULL,
&vhdHandle);
if (res != ERROR_SUCCESS)
{
std::cout << "Failed to open disk, ret=" << res << std::endl;
return 0;
}
diskInfo->Version = GET_VIRTUAL_DISK_INFO_SIZE;
res = GetVirtualDiskInformation(vhdHandle, &diskInfoSize, diskInfo, NULL);
if (res != ERROR_SUCCESS)
{
std::cout << "Failed to GET_VIRTUAL_DISK_INFO_SIZE, ret=" << res << std::endl;
}
long physicalSize = diskInfo->Size.PhysicalSize;
long virtualSize = diskInfo->Size.VirtualSize;
long sectorSize = diskInfo->Size.SectorSize;
long blockSize = diskInfo->Size.BlockSize;
std::wcout << "physicalSize :" << physicalSize << std::endl;
std::wcout << "virtualSize :" << virtualSize << std::endl;
std::wcout << "sectorSize :" << sectorSize << std::endl;
std::wcout << "blockSize :" << blockSize << std::endl;
diskInfo->Version = GET_VIRTUAL_DISK_INFO_CHANGE_TRACKING_STATE;
res = GetVirtualDiskInformation(vhdHandle, &diskInfoSize, diskInfo, NULL);
if (res != ERROR_SUCCESS)
{
std::cout << "Failed to GET_VIRTUAL_DISK_INFO_CHANGE_TRACKING_STATE, ret=" << res << std::endl;
}
std::cout << "\nrct id:" << diskInfo->ChangeTrackingState.MostRecentId << std::endl;
std::cout << "\nQuerying for changed disk areas...\n" << std::endl;
wchar_t rctId[] = L"rctX:c2eb01d9:ccb1:405d:acb6:f0e76d055906:00000001";
ULONG64 byteOffset = 0L;
ULONG64 byteLength = 19327352832;
QUERY_CHANGES_VIRTUAL_DISK_RANGE* changedAreas = NULL;
ULONG rangeCount = 0L;
ULONG64 processedLength = 0L;
res = QueryChangesVirtualDisk(&vhdHandle, rctId, byteOffset, byteLength,
QUERY_CHANGES_VIRTUAL_DISK_FLAG_NONE,
changedAreas, &rangeCount, &processedLength);
if (res != ERROR_SUCCESS)
{
std::cout << "Failed to get chanegd areas, ret=" << res << std::endl;
if (vhdHandle != NULL)
{
CloseHandle(vhdHandle);
std::cout << "closing handle!" <<std::endl;
}
return 0;
}
std::cout << "Total changed areas:" << rangeCount << std::endl;
std::cout << "Total processed length:" << processedLength << std::endl;
if (vhdHandle != NULL)
{
CloseHandle(vhdHandle);
}
return 0;
}
Output of the program:
Screenshot of wmi explorer output.
Here's something that more or less works.. the issue was with the format of the rctid which I was passing to the QueryChangesVirtualDisk API. Should be as in the below sample. I was enclosing it inside the braces {} which was not correct. The below code returns RCT changed blocks successfully
Another observation is that it seems the ChangeTrackingState.MostRecentId which we get from GetVirtualDiskInformation for a offline vhdx is one more than what we initially created while the VM was up.. For example, I created a reference point with rctid: rctX:4abdf273:7e45:4748:85af:78ec4af82ebf:00000000 Now when the vhdx is offline and if I query the ChangeTrackingState.MostRecentId it is giving me this : rctX:4abdf273:7e45:4748:85af:78ec4af82ebf:00000001 which fails the QueryChangesVirtualDisk with invalid rctid error. The below function expects the user to pass the correct rctid externally. Apparently, the Get-VmReferencePoints still lists only the earlier 00000 reference point.. This one (00001) seems to be returned only by the GetVirtualDiskInformation API
Finally, for the other issue of getting access denied with a live VM, it seems we have to set the VIRTUAL_DISK_ACCESS_MASK in OpenVirtualDisk to 0 along with version 3 of OPEN_VIRTUAL_DISK_PARAMETERS as shown below. With this we we are able to query RCT CBT from a live checkpointed VM's base disk. Got clarified from https://github.com/cloudbase/rct-service/issues/1
#include <windows.h>
#include <virtdisk.h>
#include <iostream>
bool QueryRCTData(const std::wstring& file, const std::wstring& rctid)
{
DWORD fRet;
HANDLE hVHD;
VIRTUAL_STORAGE_TYPE vst =
{
VIRTUAL_STORAGE_TYPE_DEVICE_UNKNOWN,
{0xEC984AEC, 0xA0F9, 0x47e9, { 0x90, 0x1F, 0x71, 0x41, 0x5A, 0x66, 0x34, 0x5B }}
};
OPEN_VIRTUAL_DISK_PARAMETERS params = { 0 };
params.Version = OPEN_VIRTUAL_DISK_VERSION_3;
DWORD fRet = OpenVirtualDisk(
&vst,
file.c_str(),
(VIRTUAL_DISK_ACCESS_MASK) 0, //VIRTUAL_DISK_ACCESS_ALL, //VIRTUAL_DISK_ACCESS_GET_INFO,
OPEN_VIRTUAL_DISK_FLAG_NONE,
&params,
&hvhd);
if (fRet != ERROR_SUCCESS)
{
std::cout << "OpenVirtualDisk failed " << fRet << "\n";
return false;
}
//query rctid
WCHAR vdinfo[2048];
ZeroMemory(vdinfo, sizeof(vdinfo));
((GET_VIRTUAL_DISK_INFO *)vdinfo)->Version = GET_VIRTUAL_DISK_INFO_CHANGE_TRACKING_STATE;
ULONG vdinfoSize = sizeof(vdinfo);
fRet = GetVirtualDiskInformation(
hVHD,
&vdinfoSize,
(PGET_VIRTUAL_DISK_INFO)vdinfo,
NULL);
if (fRet != ERROR_SUCCESS)
{
std::cout << "GetVirtualDiskInformation GET_VIRTUAL_DISK_INFO_CHANGE_TRACKING_STATE failed " << fRet << "\n";
return false;
}
std::wcout << "RCT ID : " << std::wstring(((GET_VIRTUAL_DISK_INFO *)vdinfo)->ChangeTrackingState.MostRecentId) << "\n";
//query disk length
ZeroMemory(vdinfo, sizeof(vdinfo));
((GET_VIRTUAL_DISK_INFO *)vdinfo)->Version = GET_VIRTUAL_DISK_INFO_SIZE;
vdinfoSize = sizeof(vdinfo);
fRet = GetVirtualDiskInformation(
hVHD,
&vdinfoSize,
(PGET_VIRTUAL_DISK_INFO)vdinfo,
NULL);
if (fRet != ERROR_SUCCESS)
{
std::cout << "GetVirtualDiskInformation GET_VIRTUAL_DISK_INFO_SIZE failed " << fRet << "\n";
return false;
}
std::cout << "Disk length : " << ((GET_VIRTUAL_DISK_INFO *)vdinfo)->Size.VirtualSize << "\n";
ULONG RangeCount = 1024;
ULONG64 ProcessedLength = 0;
QUERY_CHANGES_VIRTUAL_DISK_RANGE Ranges[1024] = { 0 };
fRet = QueryChangesVirtualDisk(
hVHD,
rctid.c_str(), //((GET_VIRTUAL_DISK_INFO *)vdinfo)->ChangeTrackingState.MostRecentId,
0,
((GET_VIRTUAL_DISK_INFO *)vdinfo)->Size.VirtualSize,
QUERY_CHANGES_VIRTUAL_DISK_FLAG_NONE,
Ranges,
&RangeCount,
&ProcessedLength);
if (fRet != ERROR_SUCCESS)
{
std::cout << "QueryChangesVirtualDisk failed " << fRet << "\n";
return false;
}
std::cout << "RangeCount : " << RangeCount << "\n";
std::cout << "ProcessedLength : " << ProcessedLength << "\n";
for (int i = 0; i < RangeCount; i++)
{
std::cout << "Range offset : " << Ranges[i].ByteOffset << "\n";
std::cout << "Range length : " << Ranges[i].ByteLength << "\n";
}
CloseHandle(hVHD);
return true;
}
int main(void)
{
QueryRCTData(L"D:\\BACKUP\\INCR\\Virtual Hard Disks\\2019.vhdx", L"rctX:4abdf273:7e45:4748:85af:78ec4af82ebf:00000000");
return 0;
}
#pragma comment(lib, "virtdisk.lib")
Here is my working code for getting changed blocks from offline VHDX.
(most credit goes to Neelabh Mam who posted above)
Hope it might help someone struggling to make RCT work with C++.
BOOLEAN VHDWRAP_CONVENTION CloseVhd(HANDLE hDisk)
{
return CloseHandle(hDisk) == TRUE;
}
HANDLE VHDWRAP_CONVENTION OpenVhdx(PCWSTR path, unsigned mask)
{
DWORD fRet;
HANDLE hVHD;
VIRTUAL_STORAGE_TYPE vst =
{
VIRTUAL_STORAGE_TYPE_DEVICE_UNKNOWN,
{0xEC984AEC, 0xA0F9, 0x47e9, { 0x90, 0x1F, 0x71, 0x41, 0x5A, 0x66, 0x34, 0x5B }}
};
OPEN_VIRTUAL_DISK_PARAMETERS params = { 0 };
params.Version = OPEN_VIRTUAL_DISK_VERSION_3;
fRet = OpenVirtualDisk(
&vst,
path, (VIRTUAL_DISK_ACCESS_MASK)mask,
OPEN_VIRTUAL_DISK_FLAG_NONE,
&params,
&hVHD);
g_dwLastError = fRet;
return hVHD;
}
VHDWRAP_API BOOLEAN VHDWRAP_CONVENTION EnableVhdRct(HANDLE hVHD)
{
SET_VIRTUAL_DISK_INFO vdinfo;
vdinfo.Version = SET_VIRTUAL_DISK_INFO_CHANGE_TRACKING_STATE;
vdinfo.ChangeTrackingEnabled = TRUE;
DWORD fRet = SetVirtualDiskInformation(hVHD, &vdinfo);
g_dwLastError = fRet;
return fRet == 0;
}
VHDWRAP_API BOOLEAN VHDWRAP_CONVENTION DisableVhdRct(HANDLE hVHD)
{
SET_VIRTUAL_DISK_INFO vdinfo;
vdinfo.Version = SET_VIRTUAL_DISK_INFO_CHANGE_TRACKING_STATE;
vdinfo.ChangeTrackingEnabled = FALSE;
DWORD fRet = SetVirtualDiskInformation(hVHD, &vdinfo);
g_dwLastError = fRet;
return fRet == 0;
}
VHDWRAP_API BOOLEAN VHDWRAP_CONVENTION QueryVhdRct(HANDLE hVHD, LPCWSTR szRctId)
{
//query rctid
WCHAR vdinfo[1024];
ZeroMemory(vdinfo, sizeof(vdinfo));
((GET_VIRTUAL_DISK_INFO*)vdinfo)->Version = GET_VIRTUAL_DISK_INFO_CHANGE_TRACKING_STATE;
ULONG vdinfoSize = sizeof(vdinfo);
DWORD fRet = GetVirtualDiskInformation(
hVHD,
&vdinfoSize,
(PGET_VIRTUAL_DISK_INFO)vdinfo,
NULL);
g_dwLastError = fRet;
if (fRet != ERROR_SUCCESS)
{
std::cout << "GetVirtualDiskInformation GET_VIRTUAL_DISK_INFO_CHANGE_TRACKING_STATE failed " << fRet << "\n";
return false;
}
std::wcout << L"RCT status : " << ((((GET_VIRTUAL_DISK_INFO*)vdinfo)->ChangeTrackingState.Enabled) ? L"enabled" : L"disabled") << L"\n";
std::wcout << L"RCT ID : " << std::wstring(((GET_VIRTUAL_DISK_INFO*)vdinfo)->ChangeTrackingState.MostRecentId) << "\n";
std::wcout << L"RCT changes : " << ((((GET_VIRTUAL_DISK_INFO*)vdinfo)->ChangeTrackingState.NewerChanges) ? L"yes": L"no") << "\n";
//query disk length
_GET_VIRTUAL_DISK_INFO sizeInfo;
sizeInfo.Version = GET_VIRTUAL_DISK_INFO_SIZE;
vdinfoSize = sizeof(sizeInfo);
fRet = GetVirtualDiskInformation(
hVHD,
&vdinfoSize,
(PGET_VIRTUAL_DISK_INFO)&sizeInfo,
NULL);
g_dwLastError = fRet;
if (fRet != ERROR_SUCCESS)
{
std::cout << "GetVirtualDiskInformation GET_VIRTUAL_DISK_INFO_SIZE failed " << fRet << "\n";
return FALSE;
}
std::cout << "Disk length : " << sizeInfo.Size.VirtualSize << "\n";
const ULONG MaxRangeCount = 4096*1024;
ULONG RangeCount = MaxRangeCount;
ULONG64 ProcessedLength = 0;
QUERY_CHANGES_VIRTUAL_DISK_RANGE* Ranges = new QUERY_CHANGES_VIRTUAL_DISK_RANGE[MaxRangeCount];
fRet = QueryChangesVirtualDisk(
hVHD,
szRctId?szRctId : ((GET_VIRTUAL_DISK_INFO *)vdinfo)->ChangeTrackingState.MostRecentId,
0,
sizeInfo.Size.VirtualSize,
QUERY_CHANGES_VIRTUAL_DISK_FLAG_NONE,
Ranges,
&RangeCount,
&ProcessedLength);
g_dwLastError = fRet;
if (fRet != ERROR_SUCCESS)
{
delete[] Ranges;
std::cout << "QueryChangesVirtualDisk failed " << fRet << " ranges:" << RangeCount << " len " << ProcessedLength << "\n";
return FALSE;
}
if (MaxRangeCount <= RangeCount || ProcessedLength < sizeInfo.Size.VirtualSize)
{
delete[] Ranges;
std::cout << "Not enough resources to capture all the changes \n";
return FALSE;
}
std::cout << "RangeCount : " << RangeCount << "\n";
std::cout << "ProcessedLength : " << ProcessedLength << "\n";
for (int i = 0; i < RangeCount; i++)
{
std::cout << "Range offset : " << Ranges[i].ByteOffset << "\n";
std::cout << "Range length : " << Ranges[i].ByteLength << "\n";
}
delete[] Ranges;
return TRUE;
}

Empty buffer after successful recv

I'm writing a server on Windows in C++ and I'm facing a strange behavior using recv().
I wrote this function:
bool readN(SOCKET s, int size, char* buffer){
fd_set readset;
struct timeval tv;
int left, res;
FD_ZERO(&readset);
FD_SET(s, &readset);
left = size;
std::cout << "-----called readN to read " << size << " byte" << std::endl;
while (left > 0) {
tv.tv_sec = MAXWAIT;
tv.tv_usec = 0;
res = select(0, &readset, NULL, NULL, &tv);
if (res > 0) {
res = recv(s, buffer, left, 0);
if (res == 0) {//connection closed by client
return false;
}
left -= res;
std::cout << "\treceived " << res << " left " << left << std::endl;
if (left != 0) {
buffer += res;
}
}
else if (res == 0) { //timer expired
return false;
}
else { //socket error
return false;
}
}
std::cout << "\t" << buffer << std::endl;
return true;
}
And I call it like this:
std::unique_ptr<char[]> buffer = std::make_unique<char[]>(size_);
if (readN(sck, size_, buffer.get())) {
std::cout << "----read message----" << std::endl;
std::cout <<"\t"<< buffer.get()<< std::endl;
}
The problem is that even if recv() returns a positive number, the buffer is still empty. What am I missing?
I see a few problems in your code.
you are not resetting the readset variable each time you call select(). select() modifies the variable. For a single-socket case, this is not too bad, but you should get in the habit of resetting the variable each time.
you are not checking for errors returned by recv(). You assume any non-graceful-disconnect is success, but that is not always true.
at the end of readN() before returning true, you are outputting the buffer parameter to std::cout, however buffer will be pointing at the END of the data, not the BEGINNING, since it was advanced by the reading loop. This is likely where your confusion about an "empty buffer" is coming from. readN() itself should not even be outputting the data at all, since you do that after readN() exits, otherwise you end up with redundant output messages.
if readN() returns true, you are passing the final buffer to std::cout using an operator<< that expects a null terminated char string, but your buffer is not guaranteed to be null-terminated.
Try something more like this instead:
bool readN(SOCKET s, int size, char* buffer){
fd_set readset;
struct timeval tv;
int res;
std::cout << "-----called readN to read " << size << " byte(s)" << std::endl;
while (size > 0) {
FD_ZERO(&readset);
FD_SET(s, &readset);
tv.tv_sec = MAXWAIT;
tv.tv_usec = 0;
res = select(0, &readset, NULL, NULL, &tv);
if (res > 0) {
res = recv(s, buffer, size, 0);
if (res == SOCKET_ERROR) {
res = WSAGetLastError();
if (res == WSAEWOULDBLOCK) {
continue; //call select() again
}
return false; //socket error
}
if (res == 0) {
return false; //connection closed by client
}
buffer += res;
size -= res;
std::cout << "\treceived " << res << " byte(s), " << size << " left" << std::endl;
}
/*
else if (res == 0) {
return false; //timer expired
}
else {
return false; //socket error
}
*/
else {
return false; //timer expired or socket error
}
}
return true;
}
std::unique_ptr<char[]> buffer = std::make_unique<char[]>(size_);
if (readN(sck, size_, buffer.get())) {
std::cout << "----read message----" << std::endl;
std::cout << "\t";
std::cout.write(buffer.get(), size_);
std::cout << std::endl;
}
With that said, I would suggest an alternative implementation of readN(), depending on whether you are using a blocking or non-blocking socket.
If blocking, use setsockopt(SO_RCVTIMEO) instead of select(). If recv() fails with a timeout, WSAGetLastError() will report WSAETIMEDOUT:
sck = socket(...);
DWORD timeout = MAXWAIT * 1000;
setsockopt(sck, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));
bool readN(SOCKET s, int size, char* buffer){
int res;
std::cout << "-----called readN to read " << size << " byte(s)" << std::endl;
while (size > 0) {
res = recv(s, buffer, size, 0);
if (res == SOCKET_ERROR) {
/*
res = WSAGetLastError();
if (res == WSAETIMEDOUT) {
return false; //timer expired
}
else {
return false; //socket error
}
*/
return false; //timer expired or socket error
}
if (res == 0) {
return false; //connection closed by client
}
buffer += res;
size -= res;
std::cout << "\treceived " << res << " byte(s), " << size << " left" << std::endl;
}
return true;
}
If non-blocking, don't call select() unless recv() asks you to call it:
bool readN(SOCKET s, int size, char* buffer){
fd_set readset;
struct timeval tv;
int res;
std::cout << "-----called readN to read " << size << " byte(s)" << std::endl;
while (size > 0) {
res = recv(s, buffer, size, 0);
if (res == SOCKET_ERROR) {
res = WSAGetLastError();
if (res != WSAEWOULDBLOCK) {
return false; //socket error
}
FD_ZERO(&readset);
FD_SET(s, &readset);
tv.tv_sec = MAXWAIT;
tv.tv_usec = 0;
res = select(0, &readset, NULL, NULL, &tv);
if (res > 0) {
continue; //call recv() again
}
/*
else if (res == 0) {
return false; //timer expired
}
else {
return false; //socket error
}
*/
return false; //timer expired or socket error
}
if (res == 0) {
return false; //connection closed by client
}
buffer += res;
size -= res;
std::cout << "\treceived " << res << " byte(s), " << size << " left" << std::endl;
}
return true;
}
At the end of the readN() there is
std::cout << "\t" << buffer << std::endl;
The problem is that the buffer points now to buffer + size in respect to the original value of buffer. The value has been modified by
buffer += res;
This should output the buffer,
std::cout << "\t" << (buffer - size) << std::endl;
After experimenting readN() with the following main(), it seems that readN() works if the socket is not invalid handle (text/binary data sent by ncat). If the socket is a invalid handle, the function returns quickly.
#include <iostream>
#include <memory>
#include <string.h>
#ifdef _WIN64
#include <ws2tcpip.h>
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#endif
#include <errno.h>
#define MAXWAIT 5000
bool readN(SOCKET fd, int size, char *buffer)
{
fd_set readset;
struct timeval tv;
int left, res;
FD_ZERO(&readset);
FD_SET(fd, &readset);
left = size;
std::cout << "-----called readN to read " << size << " byte" << std::endl;
while (left > 0) {
tv.tv_sec = MAXWAIT;
tv.tv_usec = 0;
res = select(fd + 1, &readset, NULL, NULL, &tv);
if (res > 0) {
res = recv(fd, buffer, left, 0);
if (res == 0) { //connection closed by client
return false;
}
left -= res;
std::cout << "\treceived " << res << " left " << left << std::endl;
buffer += res;
} else if (res == 0) { //timer expired
std::cout << "\ttimer expired" << std::endl;
return false;
} else { //socket error
std::cout << "\tsocket error " << WSAGetLastError() << std::endl;
return false;
}
}
std::cout << "Print the buffer now\n" << (buffer - size) << std::endl;
return true;
}
int main(void)
{
int err;
SOCKET cfd = 0;
SOCKET afd = 0;
struct sockaddr_in addr;
socklen_t clen;
struct sockaddr_in caddr;
#ifdef _WIN64
WORD ver = 0x202;
WSADATA wsa_data;
memset(&wsa_data, 0, sizeof(wsa_data));
std::cout << "WSAStartup" << std::endl;
err = WSAStartup(ver, &wsa_data);
if (err < 0) goto error_exit;
#endif
memset(&addr, 0, sizeof(addr));
memset(&caddr, 0, sizeof(caddr));
std::cout << "socket" << std::endl;
afd = socket(AF_INET, SOCK_STREAM, 0);
if (afd < 0) goto error_exit;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(1234);
std::cout << "bind" << std::endl;
err = bind(afd, (struct sockaddr *)&addr, sizeof(addr));
if (err < 0) goto error_exit;
std::cout << "listen" << std::endl;
listen(afd, 5);
clen = sizeof(caddr);
std::cout << "accept" << std::endl;
cfd = accept(afd, (struct sockaddr *) &caddr, &clen);
if (cfd == INVALID_SOCKET) goto error_exit;
{
int size_ = 1024;
std::unique_ptr<char[]> buffer2 = std::make_unique<char[]>(size_);
std::cout << "readN" << std::endl;
if (readN(cfd, 1024, buffer2.get())) {
std::cout << "----read message----" << std::endl;
std::cout <<"\t"<< buffer2.get() << std::endl;
}
}
return 0;
error_exit:
std::cout << "Error!" << std::endl;
std::cout << "\tsocket error " << WSAGetLastError() << std::endl;
return 1;
}

Simple External hack for Assault Cube gone wrong?

So I'm following a Youtube tutorial on making a simple external hack for Assault Cube.
I reach part 6 of the tutorial and... blam. My compiler is giving me the error:
[Error] expected declaration before '}' token
So I add that. And it just repeats.
I'm using Orwells Dev C++ and have NO idea where I've gone wrong.
Harsh criticism welcome, including those "you're jumping too ahead of yourself. Try something more simple." etc etc
// Youtube Console Trainer Tutorial -- Trainer for Assault Cube
#include <iostream>
#include <windows.h>
#include <string>
#include <ctime>
std::string GameName = "AssaultCube";
LPCSTR LGameWindow = "AssaultCube";
std::string GameStatus;
bool IsGameAvail;
bool UpdateOnNextRun;
//Ammo Variables
bool AmmoStatus;
BYTE AmmoValue[] = {0xA3, 0X1C, 0X0, 0X0};
DWORD AmmoBaseAddress = {0x004DF73C};
DWORD AmmoOffsets[] = {0x378, 0x14, 0x0};
//Health Variables
bool HealthStatus;
BYTE HealthValue[] = {0x39, 0X5, 0X0, 0X0};
DWORD HealthBaseAddress = {0x004DF73C};
DWORD HealthOffsets[] = {0xF4};
int main()
{
HWND hGameWindow = NULL;
int timeSinceLastUpdate = clock();
int GameAvailTMR = clock();
int onePressTMR = clock();
DWORD dwProcID = NULL;
HANDLE hProcHandle = NULL;
UpdateOnNextRun = true;
std::string sAmmoStatus = "OFF";
std::string sHealthStatus = "OFF";
while(!GetAsyncKeyState(VK_INSERT))
{
if(clock() - GameAvailTMR > 100)
{
GameAvailTMR = clock();
IsGameAvail = false;
hGameWindow = FindWindow(NULL,LGameWindow);
if (hGameWindow)
{
GetWindowThreadProcessId( hGameWindow, &dwProcID);
if(dwProcID != 0);
{
hProcHandle =
OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcID);
if(hProcHandle == INVALID_HANDLE_VALUE || hProcHandle == NULL )
{
GameStatus = "Failed to open process for valid handle";
}
else{
GameStatus = "AssaultCube Ready To Hack";
IsGameAvail = true;
}
else{
GameStatus = "Failed to get process ID";
}
else {
GameStatus = "AssaultCube NOT FOUND";
}
if(UpdateOnNextRun || clock() - timeSinceLastUpdate > 5000 )
system("cls");
std::cout << "-------------------------------------"<< std::endl;
std::cout << " AssaultCube memory hacker" << std::endl;std::endl;
std::cout << "-------------------------------------"<< std::endl;
std::cout << "GAME STATUS:" << GameStatus << std::endl << std::endl;
std::cout << "[F1] Unlimited Ammo -> " << sAmmoStatus << " <- " << std::endl << std::endl;
std::cout << "[F2] Unlimited Health -> " << sHealthStatus << " <- " << std::endl << std::endl;
}
}
}
}
}
}
}
A missing { here:
if(UpdateOnNextRun || clock() - timeSinceLastUpdate > 5000 )
And after the line with GameStatus = "AssaultCube Ready To Hack"; there are two other else without if. Remove/comment them.
And next time, better indentation!
The problem is that your else clauses are nested, when they should be outside their respective if clauses. Let's shuffle some braces around:
hGameWindow = FindWindow(NULL,LGameWindow);
if (hGameWindow)
{
GetWindowThreadProcessId( hGameWindow, &dwProcID);
if(dwProcID != 0);
{
hProcHandle =
OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcID);
if(hProcHandle == INVALID_HANDLE_VALUE || hProcHandle == NULL )
{
GameStatus = "Failed to open process for valid handle";
}
else{
GameStatus = "AssaultCube Ready To Hack";
IsGameAvail = true;
}
}
else{
GameStatus = "Failed to get process ID";
}
}
else {
GameStatus = "AssaultCube NOT FOUND";
}
if(UpdateOnNextRun || clock() - timeSinceLastUpdate > 5000 )
{
system("cls");
std::cout << "-------------------------------------"<< std::endl;
std::cout << " AssaultCube memory hacker" << std::endl;std::endl;
std::cout << "-------------------------------------"<< std::endl;
std::cout << "GAME STATUS:" << GameStatus << std::endl << std::endl;
std::cout << "[F1] Unlimited Ammo -> " << sAmmoStatus << " <- " << std::endl << std::endl;
std::cout << "[F2] Unlimited Health -> " << sHealthStatus << " <- " << std::endl << std::endl;
}
GetWindowThreadProcessId( hGameWindow, &dwProcID);
if(dwProcID != 0);
{
it should be:
GetWindowThreadProcessId( hGameWindow, &dwProcId);
if(dwProcID != 0);
{
it's a little d. in dwProcID