FastCGI with C++ other ways to start than spawn-fcgi - c++

I'm currently working on a project that involves FastCGI and C++. Now I found the official FCGI Library. I tried out the echo example.
/*
* echo.c --
*
* Produce a page containing all FastCGI inputs
*
*
* Copyright (c) 1996 Open Market, Inc.
*
* See the file "LICENSE.TERMS" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
*/
#ifndef lint
static const char rcsid[] = "$Id: echo.c,v 1.1.1.1 2001/04/25 00:43:49 robs Exp $";
#endif /* not lint */
#include "fcgi_stdio.h"
#include <stdlib.h>
extern char **environ;
void PrintEnv(char *label, char **envp)
{
printf("%s:<br>\n<pre>\n", label);
for(; *envp != NULL; envp++) {
printf("%s\n", *envp);
}
printf("</pre><p>\n");
}
void main ()
{
char **initialEnv = environ;
int count = 0;
while(FCGI_Accept() >= 0) {
char *contentLength = getenv("CONTENT_LENGTH");
int len;
printf("Content-type: text/html\r\n"
"\r\n"
"<title>FastCGI echo</title>"
"<h1>FastCGI echo</h1>\n"
"Request number %d <p>\n", ++count);
if(contentLength != NULL) {
len = strtod(contentLength, NULL);
} else {
len = 0;
}
if(len <= 0) {
printf("No data from standard input.<p>\n");
} else {
int i, ch;
printf("Standard input:<br>\n<pre>\n");
for(i = 0; i < len; i++) {
if((ch = getchar()) < 0) {
printf("Error: Not enough bytes received "
"on standard input<p>\n");
break;
}
putchar(ch);
}
printf("\n</pre><p>\n");
}
PrintEnv("Request environment", environ);
PrintEnv("Initial environment", initialEnv);
} /* while */
}
I start this script with the command spawn-fcgi -p 8000 -n hello.
But is it also possible to just start the program xy without the spawn-fcgi. Do you know a good example, or a documentation?
thanks for your answer

The spawn-fcgi command opens a TCP connection for you and starts listening on the specified port (8000 in your case). It forwards the request coming in on the TCP connection to your application's stdin. It also forwards your writes to the stdout back to the TCP connection.
You can create the connection yourself using FCGX_OpenSocket() call and then pass the returned socket to FCGX_InitRequest(). After that you can go for the loop using FCGX_Accept_r() instead of FCGI_Accept()!
BTW: there is another tool that many people use instead of spawn-fcgi - supervisor. In addition to managing the connection for you, it also monitors your process. So, if your process crashes because of some wierd request, it re-launches your application!

Related

Accessing /dev/mem from GNU Radio on ZedBoard

I'm trying to access a custom IP block from GNU Radio [ZedBoard] using /dev/mem. I tested the code routine writing and doing iterative reading from /dev/mem from a local c file. The code running directly from the console correctly sets the registers and reads the correct values back.
I made a custom GNU Radio block using this code but when executing the grc flow python script I receive the error that /dev/mem was not accessible.
I know that this is NOT a safe way to interact with the device and am working on a driver to replace this. Currently I need this to work for testing and development. I went so far as to change permissions to /dev/mem to 777, I added my local user (Linaro) to the kmem group as well. I execute the python file for the flowgraph using sudo as well.
What am I overlooking? Thank you.
edit: Adding the output error is : "Permission Denied" if run from sudo after chmod 777 /dev/mem the error is : "Operation not permitted"
/* -*- c++ -*- */
/*
* Copyright 1970 <+YOU OR YOUR COMPANY+>.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gnuradio/io_signature.h>
#include "qpskModulator_impl.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#define READ 0
#define WRITE 1
#define SAMPLES 64
#define INPUT_WIDTH 32
int memmap_fpga(int direction, char * address, float value);
namespace gr {
namespace fpga_accelerators {
qpskModulator::sptr
qpskModulator::make()
{
return gnuradio::get_initial_sptr
(new qpskModulator_impl());
}
/*
* The private constructor
*/
qpskModulator_impl::qpskModulator_impl()
: gr::block("qpskModulator",
gr::io_signature::make(1, 1, sizeof(float)),
gr::io_signature::make(2, 2, sizeof(short)))
{}
/*
* Our virtual destructor.
*/
qpskModulator_impl::~qpskModulator_impl()
{
}
void
qpskModulator_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required)
{
ninput_items_required[0] = noutput_items;
ninput_items_required[1] = noutput_items;
}
int
qpskModulator_impl::general_work (int noutput_items,
gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
{
const float *in = (const float *) input_items[0];
short *out0 = (short *) output_items[0]; // I CHANNEL
short *out1 = (short *) output_items[1]; // Q CHANNEL
short data_valid;
const float BLANK = 0;
float GO = 1;
//int hwI_mod[SAMPLES*INPUT_WIDTH/2];
//int hwQ_mod[SAMPLES*INPUT_WIDTH/2];
int i;
char * DATA_IN_ADDR = "0x43c00004";
char * GO_ADDR = "0x43c00000";
char * DATA_OUT_ADDR = "0x43c00008";
char * DATA_VALID_ADDR = "0x43c0000C";
// transfer input array and size to FPGA
memmap_fpga(WRITE, DATA_IN_ADDR, *in);
memmap_fpga(WRITE, GO_ADDR, GO); // assert go
GO = 0;
memmap_fpga(WRITE, GO_ADDR, GO); // reset go value
data_valid = 0;
while (data_valid == 0) {
data_valid = memmap_fpga(READ, DATA_VALID_ADDR, BLANK);
}
// read the outputs back from the FPGA
unsigned temp_dataout;
unsigned y;
for (i=0; i < SAMPLES*INPUT_WIDTH/2 - 8; i++)
{
temp_dataout = memmap_fpga(READ, DATA_OUT_ADDR, BLANK);
out0[i] = temp_dataout & 0xfff; // I channel
y = out0[i] >> 11;
if (y == 1)
out0[i] = out0[i] - 4096;
out1[i] = (temp_dataout >> 12) & 0xfff;
y = out1[i] >> 11;
if (y == 1)
out1[i] = out1[i] - 4096;
//printf("%d: HW: I_mod = %d and Q_mod = %d\n", i, hwI_mod[i], hwQ_mod[i]);
}
// Do <+signal processing+>
// Tell runtime system how many input items we consumed on
// each input stream.
consume_each (noutput_items);
// Tell runtime system how many output items we produced.
return noutput_items;
}
} /* namespace fpga_accelerators */
} /* namespace gr */
int memmap_fpga(int direction, char * address, float value){
unsigned gpio_addr = strtoul(address, NULL, 0);
/* DEBUG INFO
printf("address: %08x\n",gpio_addr);
if (direction == IN)
printf("direction: IN\n");
else
printf("direction: OUT\n");
printf("value: %d\n",value);
*/
int fd;
unsigned page_addr, page_offset;
void *ptr;
unsigned page_size=sysconf(_SC_PAGESIZE);
short temp_value;
if (gpio_addr == 0) {
printf("GPIO physical address is required.\n");
return -1;
}
/* Open /dev/mem file */
fd = open ("/dev/mem", O_RDWR);
if (fd < 1) {
printf("Couldn't open /dev/mem\n");
return -1;
}
/* mmap the device into memory */
page_addr = (gpio_addr & (~(page_size-1)));
page_offset = gpio_addr - page_addr;
ptr = mmap(NULL, page_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, page_addr);
if (direction == READ) {
/* Read value from the device register */
temp_value = *((unsigned *)(ptr + page_offset));
//printf("gpio dev-mem test: input: %08x\n",temp_value);
munmap(ptr, page_size);
return(temp_value);
} else {
/* Write value to the device register */
*((unsigned *)(ptr + page_offset)) = value;
munmap(ptr, page_size);
//printf("Wrote to register\n");
}
munmap(ptr, page_size);
return 0;
}
Two things:
You open and memmap the same file for Read/Write access multiple times, without closing it in between – that's a recipe for disaster. Maybe you're just running out of file descriptors (there's a limit on that). Actually reading the errno (you should be doing that!!) would tell you the reason.
Then: Even opening and closing the file repeatedly is a bad idea, performance wise– just open and mmap it once in the constructor. There's no advantage reopening it constantly.

c++ Jackaudio can't get stereo sound

I am trying JackAudio with c++ on Windows 8.1 and it works.
I am using a simple client code that can be found on the git. This code should send a low pitch signal to one hear and a high pitch signal to the other but for me it sends both signals to both hear.
I don't know what is wrong since two are registered and both get access to the correct speakers.
/** #file simple_client.c
*
* #brief This simple client demonstrates the basic features of JACK
* as they would be used by many applications.
*/
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <signal.h>
#ifndef WIN32
#include <unistd.h>
#endif
#include <jack/jack.h>
jack_port_t *output_port1, *output_port2;
jack_client_t *client;
#ifndef M_PI
#define M_PI (3.14159265)
#endif
#define TABLE_SIZE (200)
typedef struct
{
float sine[TABLE_SIZE];
int left_phase;
int right_phase;
}
paTestData;
static void signal_handler(int sig)
{
jack_client_close(client);
fprintf(stderr, "signal received, exiting ...\n");
exit(0);
}
/**
* The process callback for this JACK application is called in a
* special realtime thread once for each audio cycle.
*
* This client follows a simple rule: when the JACK transport is
* running, copy the input port to the output. When it stops, exit.
*/
int
process(jack_nframes_t nframes, void *arg)
{
jack_default_audio_sample_t *out1, *out2;
paTestData *data = (paTestData*)arg;
int i;
out1 = (jack_default_audio_sample_t*)jack_port_get_buffer(output_port1, nframes);
out2 = (jack_default_audio_sample_t*)jack_port_get_buffer(output_port2, nframes);
for (i = 0; i<nframes; i++)
{
out1[i] = data->sine[data->left_phase]; // left
out2[i] = data->sine[data->right_phase]; // right
data->left_phase += 1;
if (data->left_phase >= TABLE_SIZE) data->left_phase -= TABLE_SIZE;
data->right_phase += 10; // higher pitch so we can distinguish left and right.
if (data->right_phase >= TABLE_SIZE) data->right_phase -= TABLE_SIZE;
}
return 0;
}
/**
* JACK calls this shutdown_callback if the server ever shuts down or
* decides to disconnect the client.
*/
void
jack_shutdown(void *arg)
{
exit(1);
}
int
main(int argc, char *argv[])
{
const char **ports;
const char *client_name;
const char *server_name = NULL;
jack_options_t options = JackNullOption;
jack_status_t status;
paTestData data;
int i;
/*if (argc >= 2) { // client name specified?
client_name = argv[1];
if (argc >= 3) { // server name specified?
server_name = argv[2];
int my_option = JackNullOption | JackServerName;
options = (jack_options_t)my_option;
}
}
else { // use basename of argv[0]
client_name = strrchr(argv[0], '/');
if (client_name == 0) {
client_name = argv[0];
}
else {
client_name++;
}
}*/
client_name = "mytest";
for (i = 0; i<TABLE_SIZE; i++)
{
data.sine[i] = 0.2 * (float)sin(((double)i / (double)TABLE_SIZE) * M_PI * 2.);
}
data.left_phase = data.right_phase = 0;
// open a client connection to the JACK server
client = jack_client_open(client_name, options, &status, server_name);
if (client == NULL) {
fprintf(stderr, "jack_client_open() failed, "
"status = 0x%2.0x\n", status);
if (status & JackServerFailed) {
fprintf(stderr, "Unable to connect to JACK server\n");
}
exit(1);
}
if (status & JackServerStarted) {
fprintf(stderr, "JACK server started\n");
}
if (status & JackNameNotUnique) {
client_name = jack_get_client_name(client);
fprintf(stderr, "unique name `%s' assigned\n", client_name);
}
// tell the JACK server to call `process()' whenever
//there is work to be done.
jack_set_process_callback(client, process, &data);
// tell the JACK server to call `jack_shutdown()' if
//it ever shuts down, either entirely, or if it
//just decides to stop calling us.
jack_on_shutdown(client, jack_shutdown, 0);
// create two ports
output_port1 = jack_port_register(client, "output1",
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsOutput, 0);
output_port2 = jack_port_register(client, "output2",
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsOutput, 0);
if ((output_port1 == NULL) || (output_port2 == NULL)) {
fprintf(stderr, "no more JACK ports available\n");
exit(1);
}
//Tell the JACK server that we are ready to roll. Our
// process() callback will start running now.
if (jack_activate(client)) {
fprintf(stderr, "cannot activate client");
exit(1);
}
// Connect the ports. You can't do this before the client is
// activated, because we can't make connections to clients
// that aren't running. Note the confusing (but necessary)
// orientation of the driver backend ports: playback ports are
// "input" to the backend, and capture ports are "output" from
// it.
ports = jack_get_ports(client, NULL, NULL,
JackPortIsPhysical | JackPortIsInput);
if (ports == NULL) {
fprintf(stderr, "no physical playback ports\n");
exit(1);
}
if (jack_connect(client, jack_port_name(output_port1), ports[0])) {
fprintf(stderr, "cannot connect output ports\n");
}
if (jack_connect(client, jack_port_name(output_port2), ports[1])) {
fprintf(stderr, "cannot connect output ports\n");
}
jack_free(ports);
// install a signal handler to properly quits jack client
#ifdef WIN32
signal(SIGINT, signal_handler);
signal(SIGABRT, signal_handler);
signal(SIGTERM, signal_handler);
#else
signal(SIGQUIT, signal_handler);
signal(SIGTERM, signal_handler);
signal(SIGHUP, signal_handler);
signal(SIGINT, signal_handler);
#endif
// keep running until the Ctrl+C
while (1) {
#ifdef WIN32
Sleep(1000);
#else
sleep(1);
#endif
}
jack_client_close(client);
exit(0);
}
Did you ever figure this out? I'm quite new to coding with and configuring Jack myself but my hunch is, the problem is not in the code, rather it's a mixer issue. I suspect there's a setting somewhere that has put the jack server in a mono mode of sorts which would mean all output streams are multed (yes spell checker, multed is a word in the audio engineering world :) ) to all physical audio outputs. So... stream 1 would be connected to the left and right physical output, and stream 2 would also be connected to the physical left and right outputs.
There is nothing anywhere that would necessarily say that stream 1 goes to the left output and stream 2 goes to the right... in fact, if you're running an SDDS configuration the first stream might be the left output, and the 2nd might be the left center... you wouldn't get to the right channel until you hit the 5th stream (with the 2nd, 3rd, and 4th being left center, center, and right center respectively).
Again, this is just a guess but check to see if there's a mixer or "patch bay" style application on your platform that allows you to route streams to physical outputs. In the meantime, I'll give this code a go on my system (Debian unstable/w experimental 4.3 kernel) to see what happens.
Cheers, Joe
Pardon, me - it's an old question, but for the benefit of whoever reads it... I tested this program on my System and found it works correctly!
Question to the original poster: Would you object to having this example included in the JackD example repository (https://github.com/jackaudio/example-clients)? I feel that it's a very good example on how to use the audio streaming part of the JackD API. It would probably need some small rewrite as a generic platform C program; it would be under the same license as the other examples in the JackD example repo (GPL 2). I've sent a mail to the JackD developer's list (jack-devel#lists.jackaudio.org) asking what they think.
Anyway - shewhorn had the correct hunch - nothing wrong with your code, but when you tested your program there was something wrong with the port mappings on your system (i.e. how the ports were mapped to the physical ports on your soundcard). The way to fix it is outside your application: Use some mixer or patch bay style application to route your program's streams correctly. Not your (code's) fault, your program works fine and does what you intended.

Running an executable from a C++ program in the same process

Is that possible? I'd like an easy access to the executable's memory to edit it. Alternately, when I'm not the administrator, is it possible to edit the executable's memory from another process? I've tried the ptrace library and it fails if I'm not the administrator. I'm on Linux
I'm not entirely sure what you are asking, but this is possible with shared memory.
See here: http://www.kernel.org/doc/man-pages/online/pages/man7/shm_overview.7.html
This is what a debugger does. You could look at the code of an open source debugger, e.g. gdb, to see how it works.
The answer:
Yes - it works: you don't have to be administrator / root, but of course you need the rights to access the process' memory, i.e. same user.
No - it is not easy
The possibility to write to /proc/pid/mem was added some time ago to the Linux kernel. Therefore it depends on the kernel you are using. The small programs were checked with kernel 3.2 where this works and 2.6.32 where it fails.
The solution consists of two programs:
A 'server' which is started, allocates some memory, writes some pattern into this memory and outputs every three seconds the memory contents which is placed after the pattern is printed.
A 'client' which connects via the /proc/pid/maps and /proc/pid/mem to the server, searches for the pattern and writes some other string into the server's memory.
The implementation uses heap - but as long as the permissions allow - it is also possible to change other portions of the other process' memory.
This is implemented in C, because it is very 'low level' - but it should work in C++. It is a proof of concept - no production code - e.g. there are some error checks missing and it has some fixed size buffers.
memholder.c
/*
* Alloc memory - write in some pattern and print out the some bytes
* after the pattern.
*
* Compile: gcc -Wall -Werror memholder.c -o memholder.o
*/
#include <sys/types.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
int main() {
char * m = (char*) malloc(2048);
memset(m, '\xAA', 1024);
strcpy(m + 1024, "Some local data.");
printf("PID: %d\n", getpid());
while(1) {
printf("%s\n", m + 1024);
sleep(3);
}
return 0;
}
memwriter.c
/*
* Searches for a pattern in the given PIDs memory
* and changes some bytes after them.
*
* Compile: gcc -Wall -std=c99 -Werror memwriter.c -o memwriter
*/
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
int open_proc_file(pid_t other_pid, char const * const sn,
int flags) {
char fname[1024];
snprintf(fname, 1023, "/proc/%d/%s", other_pid, sn);
// Open file for reading and writing
int const fd = open(fname, flags );
if(fd==-1) {
perror("Open file");
exit(1);
}
return fd;
}
void get_heap(int fd_maps, size_t * heap_start, size_t * heap_end) {
char buf[65536];
ssize_t const r = read(fd_maps, buf, 65535);
if(r==-1) {
perror("Reading maps file");
exit(1);
}
buf[r] = '\0';
char * const heap = strstr(buf, "[heap]");
if(heap==NULL) {
printf("[heap] not found in maps file");
exit(1);
}
// Look backward to the latest newline
char const * hl_start;
for(hl_start = heap; hl_start > buf && *hl_start != '\n';
--hl_start) {}
// skip \n
++hl_start;
// Convert to beginnig and end address
char * lhe;
*heap_start = strtol(hl_start, &lhe, 16);
++lhe;
*heap_end = strtol(lhe, &lhe, 16);
}
int main(int argc, char *argv[]) {
if(argc!=2) {
printf("Usage: memwriter <pid>\n");
return 1;
}
pid_t const other_pid = atoi(argv[1]);
int fd_mem = open_proc_file(other_pid, "mem", O_RDWR);
int fd_maps = open_proc_file(other_pid, "maps", O_RDONLY);
size_t other_mem_start;
size_t other_mem_end;
get_heap(fd_maps, &other_mem_start, &other_mem_end);
ptrace(PTRACE_ATTACH, other_pid, NULL, NULL);
waitpid(other_pid, NULL, 0);
if( lseek(fd_mem, other_mem_start, SEEK_SET) == -1 ) {
perror("lseek");
return 1;
}
char buf[512];
do {
ssize_t const r = read(fd_mem, buf, 512);
if(r!=512) {
perror("read?");
break;
}
// Check for pattern
int pat_found = 1;
for(int i = 0; i < 512; ++i) {
if( buf[i] != '\xAA' )
pat_found = 0;
break;
}
if( ! pat_found ) continue;
// Write about one k of strings
char const * const wbuf = "REMOTE DATA - ";
for(int i = 0; i < 70; ++i) {
ssize_t const w = write(fd_mem, wbuf, strlen(wbuf));
if( w == -1) {
perror("Write");
return 1;
}
}
// Append a \0
write(fd_mem, "\0", 1);
break;
} while(1);
ptrace(PTRACE_DETACH, other_pid, NULL, NULL);
close(fd_mem);
close(fd_maps);
return 0;
}
Example output
$ ./memholder
PID: 2621
Some local data.
Some local data.
MOTE DATA - REMOTE DA...
Other interpretation
There is also another interpretation of your question (when reading the headline and not the question), that you want to replace the 'executable' from one process with another one. That can be easily handled by exec() (and friends):
From man exec:
The exec() family of functions replaces the current process image with a new process image.
In Windows, the methods used for this are named ReadProcessMemory / WriteProcessMemory, you will, however, need administrative rights for this. The same is for linux, as I've said in my comment, no sane system would allow user process to modify non-owned memory.
For linux, the only function is ptrace. You will need to be administrator.
http://cboard.cprogramming.com/cplusplus-programming/92093-readprocessmemory-writeprocessmemory-linux-equivalent.html contains more detailed discussion.
Can you imagine the consequences of allowing process to modify other process memory, without being administrator?

inotify notifies of a new file wrongly multiple times

Using inotify to monitor a directory for any new file created in the directory by adding a watch on the directory by
fd = inotify_init();
wd = inotify_add_watch(fd, "filename_with_path", IN_CLOSE_WRITE);
inotify_add_watch(fd, directory_name, IN_CLOSE_WRITE);
const int event_size = sizeof(struct inotify_event);
const int buf_len = 1024 * (event_size + FILENAME_MAX);
while(true) {
char buf[buf_len];
int no_of_events, count = 0;
no_of_events = read(fd, buf, buf_len);
while(count < no_of_events) {
struct inotify_event *event = (struct inotify_event *) &buf[count];
if (event->len) {
if (event->mask & IN_CLOSE_WRITE) {
if (!(event->mask & IN_ISDIR)) {
//It's here multiple times
}
}
}
count += event_size + event->len;
}
When I scp a file to the directory, this loops infinitely. What is the problem with this code ? It shows the same event name and event mask too. So , it shows that the event for the same, infinite times.
There are no break statements. If I find an event, I just print it and carry on waiting for another event on read(), which should be a blocking call. Instead, it starts looping infinitely. This means, read doesn't block it but returns the same value for one file infinitely.
This entire operation runs on a separate boost::thread.
EDIT:
Sorry all. The error I was getting was not because of the inotify but because of sqlite which was tricky to detect at first. I think I jumped the gun here. With further investigation, I did find that the inotify works perfectly well. But the error actually came from the sqlite command : ATTACH
That command was not a ready-only command as it was supposed to. It was writing some meta data to the file. So inotify gets notification again and again. Since they were happening so fast, it screwed up the application.I finally had to breakup the code to understand why.
Thanks everyone.
I don't see anything wrong with your code...I'm running basically the same thing and it's working fine. I'm wondering if there's a problem with the test, or some part of the code that's omitted. If you don't mind, let's see if we can remove any ambiguity.
Can you try this out (I know it's almost the same thing, but just humor me) and let me know the results of the exact test?
1) Put the following code into test.c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <sys/inotify.h>
int main (int argc, char *argv[])
{
char target[FILENAME_MAX];
int result;
int fd;
int wd; /* watch descriptor */
const int event_size = sizeof(struct inotify_event);
const int buf_len = 1024 * (event_size + FILENAME_MAX);
strcpy (target, ".");
fd = inotify_init();
if (fd < 0) {
printf ("Error: %s\n", strerror(errno));
return 1;
}
wd = inotify_add_watch (fd, target, IN_CLOSE_WRITE);
if (wd < 0) {
printf ("Error: %s\n", strerror(errno));
return 1;
}
while (1) {
char buff[buf_len];
int no_of_events, count = 0;
no_of_events = read (fd, buff, buf_len);
while (count < no_of_events) {
struct inotify_event *event = (struct inotify_event *)&buff[count];
if (event->len){
if (event->mask & IN_CLOSE_WRITE)
if(!(event->mask & IN_ISDIR)){
printf("%s opened for writing was closed\n", target);
fflush(stdout);
}
}
count += event_size + event->len;
}
}
return 0;
}
2) Compile it with gcc:
gcc test.c
3) kick it off in one window:
./a.out
4) in a second window from the same directory try this:
echo "hi" > blah.txt
Let me know if that works correctly to show output every time the file is written to and does not loop as your code does. If so, there's something important your omiting from your code. If not, then there's some difference in the systems.
Sorry for putting this in the "answer" section, but too much for a comment.
My guess is that read is returning -1 and since you dont ever try to fix the error, you get another error on the next call to read which also returns -1.

Winpcap saving raw packets not from an adapter

I am trying to build an application that converts my old custom Ethernet logs (bin files) to standard winpcap style logs.
The problem is that I can't seem to find an example of how to opening a pcap_t* without using an adapter (network card). The temp.pkt has not been created.
I have looked thou the examples provided with Winpcap and all of them use a live adapter when dumping packets. This example is the closest \WpdPack\Examples-pcap\savedump\savedump.c is the closest, see example below slightly modified.
#ifdef _MSC_VER
/*
* we do not want the warnings about the old deprecated and unsecure CRT functions
* since these examples can be compiled under *nix as well
*/
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "pcap.h"
int main(int argc, char **argv)
{
pcap_if_t *alldevs;
pcap_if_t *d;
int inum;
int i=0;
pcap_t *adhandle;
char errbuf[PCAP_ERRBUF_SIZE];
pcap_dumper_t *dumpfile;
/* Open the adapter */
if ((adhandle= pcap_open(??????, // name of the device
65536, // portion of the packet to capture.
// 65536 grants that the whole packet will be captured on all the MACs.
1, // promiscuous mode (nonzero means promiscuous)
1000, // read timeout
errbuf // error buffer
)) == NULL)
{
fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name);
/* Free the device list */
pcap_freealldevs(alldevs);
return -1;
}
/* Open the dump file */
dumpfile = pcap_dump_open(adhandle, argv[1]);
if(dumpfile==NULL) {
fprintf(stderr,"\nError opening output file\n");
return -1;
}
// ---------------------------
struct pcap_pkthdr header;
header.ts.tv_sec = 1 ; /* seconds */
header.ts.tv_usec = 1; /* and microseconds */
header.caplen = 100; /* length of portion present */
header.len = 100 ; /* length this packet (off wire) */
u_char pkt_data[100];
for( int i = 0 ; i < 100 ; i++ ) {
pkt_data[i] = i ;
}
pcap_dump( (u_char *) dumpfile, &header, (u_char *) &pkt_data);
// ---------------------------
/* start the capture */
// pcap_loop(adhandle, 0, packet_handler, (unsigned char *)dumpfile);
pcap_close(adhandle);
return 0;
}
I suggest doing that using pcap_t since using WinPcap is better than writing it yourself.
The following steps is how to do it:
Use pcap_open_dead() function to create a pcap_t. Read the function description here. The linktype for Ethernet is 1.
Use pcap_dump_open() function to create a pcap_dumper_t.
Use pcap_dump() function to write the packet to the dump file.
I hope this would help you.
If all you're doing is converting your own file format to .pcap, you don't need a pcap_t*, you can just use something like:
FILE* create_pcap_file(const char *filename, int linktype)
{
struct pcap_file_header fh;
fh.magic = TCPDUMP_MAGIC;
fh.sigfigs = 0;
fh.version_major = 2;
fh.version_minor = 4;
fh.snaplen = 2<<15;
fh.thiszone = 0;
fh.linktype = linktype;
FILE *file = fopen(filename, "wb");
if(file != NULL) {
if(fwrite(&fh, sizeof(fh), 1, file) != 1) {
fclose(file);
file = NULL;
}
}
return file;
}
int write_pcap_packet(FILE* file,size_t length,const unsigned char *data,const struct timeval *tval)
{
struct pcap_pkthdr pkhdr;
pkhdr.caplen = length;
pkhdr.len = length;
pkhdr.ts = *tval;
if(fwrite(&pkhdr, sizeof(pkhdr), 1, file) != 1) {
return 1;
}
if(fwrite(data, 1, length, file) != length) {
return 2;
}
return 0;
}