/* Open the device */
if ( (adhandle= pcap_open(d->name,
65536,
PCAP_OPENFLAG_PROMISCUOUS,
1000,
NULL,
errbuf)
) == 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;
}
This code is in this.
I included pcap.h.
But I can't use pcap_open() function.
identifier "pcap_open" is undefined
Please help me.
So, we've got a program from our professor, that supposedly will enumerate through the devieces connected to usb hub. I won't get into the specifics, cause that's not what my question is about.
This is one of the functions, and in specified line I've got a 2233 error which states: "'identifier' : arrays of objects containing zero-size arrays are illegal.
Each object in an array must contain at least one element."
void getDSPortData(HANDLE devHandle, UCHAR connectionIndex)
{
ULONG bytesReturned;
bool success;
PUSB_NODE_CONNECTION_INFORMATION pConnectionInformation = NULL;
ULONG nBytes = sizeof(USB_NODE_CONNECTION_INFORMATION) + sizeof(USB_PIPE_INFO) * 30; //15 EP IN + 15 EP OUT
pConnectionInformation = new USB_NODE_CONNECTION_INFORMATION[nBytes]; //error 2233
pConnectionInformation->ConnectionIndex = connectionIndex;
success = DeviceIoControl(devHandle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION, pConnectionInformation, nBytes,
pConnectionInformation, nBytes, &bytesReturned, NULL);
if (!success) {
delete[] pConnectionInformation;
return;
}
(...)
delete[] pConnectionInformation;
}
So I checked the usbioctl.h header file:
typedef struct _USB_NODE_CONNECTION_INFORMATION {
ULONG ConnectionIndex; /* INPUT */
/* usb device descriptor returned by this device
during enumeration */
USB_DEVICE_DESCRIPTOR DeviceDescriptor; /* OUTPUT */
UCHAR CurrentConfigurationValue;/* OUTPUT */
BOOLEAN LowSpeed;/* OUTPUT */
BOOLEAN DeviceIsHub;/* OUTPUT */
USHORT DeviceAddress;/* OUTPUT */
ULONG NumberOfOpenPipes;/* OUTPUT */
USB_CONNECTION_STATUS ConnectionStatus;/* OUTPUT */
USB_PIPE_INFO PipeList[0];/* OUTPUT */
} USB_NODE_CONNECTION_INFORMATION, *PUSB_NODE_CONNECTION_INFORMATION;
As it seems, the problem seems to stem from the PipeList[0] thing. So, is it even legal to type something like this? As far as I know that's declaration of zero elements array. And is there any way to trick it to make it work?
I currently have a C/C++ program which uses a barcode scanner as a keyboard, catches the input and does something with it. Here's the relevant parts of code:
int get_InStream() {
struct timeval tv;
fd_set fds;
tv.tv_sec = 0;
tv.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
select(STDIN_FILENO+1, &fds, NULL, NULL, &tv);
return FD_ISSET(STDIN_FILENO, &fds);
}
void nonblock(int state) {
struct termios ttystate;
tcgetattr(STDIN_FILENO, &ttystate);
if (state == 1) {
// ~ICANON: turn off canonical mode
// ~ECHO: not display character
//~ ttystate.c_lflag &= ~ECHO; // (ICANON & ECHO);
tcgetattr( 0, &ttystate); /* read curr. setting */
original_mode = ttystate; /* remember these */
ttystate.c_lflag &= ~ICANON; /* no buffering */
//~ ttystate.c_lflag &= ~ECHO; /* no echo either */
tcsetattr( 0 , TCSANOW, &ttystate); /* install settings */
//minimum of number input read.
ttystate.c_cc[VMIN] = 1;
}
else if (state == 0) {
//~ // turn on canonical mode
//~ ttystate.c_lflag |= ECHO;
tcsetattr(0, TCSANOW, &original_mode); /* undo -icanon, -echo */
}
// set the terminal attributes.
tcsetattr(STDIN_FILENO, TCSANOW, &ttystate);
}
bool keyState(int key) { // Uses ASCII table
bool pressed = false;
int i = get_InStream(); // Allows to read from terminal
if (i != 0) {
char c = fgetc(stdin);
if (c == (char) key) {
pressed = true;
} else {
pressed = false;
char string_key = c;
pthread_mutex_lock(&id_mutex);
// Append character to content buffer
strcat(content, string_key);
pthread_mutex_unlock(&id_mutex);
}
}
return pressed;
}
void* get_inputContent(void* arg) {
pthread_detach(pthread_self());
nonblock(1);
while (1) {
// if this returns True, content contains data
if (keyState(0x0A)) { // 0x0A in ASCII table corresponds to New Line
pthread_mutex_lock(&id_mutex);
printf("Read this %d characters through barcode scanner: %s\n", strlen(content), content); //DEBUG
// doSomething()
strcpy(content, "\0"); // empty out content
pthread_mutex_unlock(&id_mutex);
}
}
nonblock(0);
pthread_exit(NULL);
}
Right now this works well as a separate thread from the main program, but if I open another terminal while the main program is running and I leave the focus on the new one, the barcode input is not caught by the thread.
So I'd like, either in C/C++ or in Bash, to let's say share the input accross various terminals, so that my thread can use it. Is there any way to do this?
I've searched for various options:
another descriptor to use in select()
using export in Bash
writing to a shared file
but I'm not so sure for any of those. Any suggestions?
EDIT: the program is being run on Raspberry Pi OS, previously Raspbian if I'm not mistaken
This is a XY problem situation right here. Your problem 'X' is
How can I access the keyboard device as which the barcode scanner presents itself to the system regardless of the current state of the system?
But you think, that by solving the problem 'Y'
How can I keygrab input directed to a different terminal?
Problem Y is hard, because it has security implications. Problem X is easy, but its solution depends on the operating system being used.
You mention bash and POSIX style file descriptor. So I'm guessing, that you're on some flavor of Linux. And with that, the problem is easy to solve! Each and every input device presents itself as a evdev device under /dev/input/event<X>. Your barcode scanner will show up there, as well.
You could either implement the evdev protocol yourself. Or just use libinput to do the heavy lifting.
And it being present as an independent input device allows you to do a few things:
Use udev to control which user accounts get access to it.
Use udev to actually detach it from the terminals, so that the barcode scanner can not be used to input (possibly harmful) commands.
The following call to SetSystemFileCacheSize() fails, however it passes if replace "FILE_CACHE_MIN_HARD_ENABLE " with 0.
What am I doing wrong?
SIZE_T dwMinimumFileCacheSize = 1048576; // Exact number reported by SetSystemFileCacheSize.
SIZE_T dwMaximumFileCacheSize = 1099511627776; // Exact number reported by SetSystemFileCacheSize.
int result = SetSystemFileCacheSize(
dwMinimumFileCacheSize, // dwMinimumWorkingSetSize
dwMaximumFileCacheSize, // dwMaximumWorkingSetSize,
FILE_CACHE_MIN_HARD_ENABLE // Works if this flag is set to 0.
);
if (result == 0)
{
// Error is "5" if it fails.
wprintf(L" Error E2469: Could not set size of system cache, error %u.\n", GetLastError());
}
else
{
wprintf(L" Pass.\n");
}
It turns out that dwMinimumFileCacheSize must be 64KB less than dwMaximumFileCacheSize, if FILE_CACHE_MIN_HARD_ENABLE is enabled.
Here is the fix:
int result = SetSystemFileCacheSize(
dwMinimumFileCacheSize - 64 * 1024, // dwMinimumWorkingSetSize
dwMaximumFileCacheSize, // dwMaximumWorkingSetSize,
FILE_CACHE_MIN_HARD_ENABLE // Works if this flag is set to 0.
);
I wrote a UNIX daemon (targeting Debian, but it shouldn't matter) and I wanted to provide some way of creating a ".pid" file, (a file which contains the process identifier of the daemon).
I searched for a way of opening a file only if it doesn't exist, but couldn't find one.
Basically, I could do something like:
if (fileexists())
{
//fail...
}
else
{
//create it with fopen() or similar
}
But as it stands, this code does not perform the task in a atomic fashion, and doing so would be dangerous, because another process might create the file during my test, and the file creation.
Do you guys have any idea on how to do that?
Thank you.
P.S: Bonus point for a solution which only involves std::streams.
man 2 open:
O_EXCL Ensure that this call creates the file: if this flag is specified in conjunction with O_CREAT, and pathname already exists, then open()
will fail. The behavior of O_EXCL is undefined if O_CREAT is not specified.
so, you could call fd = open(name, O_CREAT | O_EXCL, 0644); /* Open() is atomic. (for a reason) */
UPDATE: and you should of course OR one of the O_RDONLY, O_WRONLY, or O_RDWR flags into the flags argument.
I learned about proper daemonizing here (back in the day):
http://www.enderunix.org/docs/eng/daemon.php
It is a good read. I have since improved the locking code to eliminate race conditions on platforms that allow advisory file locking with specific regions specified.
Here is a relevant snippet from a project that I was involved in:
static int zfsfuse_do_locking(int in_child)
{
/* Ignores errors since the directory might already exist */
mkdir(LOCKDIR, 0700);
if (!in_child)
{
ASSERT(lock_fd == -1);
/*
* before the fork, we create the file, truncating it, and locking the
* first byte
*/
lock_fd = creat(LOCKFILE, S_IRUSR | S_IWUSR);
if(lock_fd == -1)
return -1;
/*
* only if we /could/ lock all of the file,
* we shall lock just the first byte; this way
* we can let the daemon child process lock the
* remainder of the file after forking
*/
if (0==lockf(lock_fd, F_TEST, 0))
return lockf(lock_fd, F_TLOCK, 1);
else
return -1;
} else
{
ASSERT(lock_fd != -1);
/*
* after the fork, we instead try to lock only the region /after/ the
* first byte; the file /must/ already exist. Only in this way can we
* prevent races with locking before or after the daemonization
*/
lock_fd = open(LOCKFILE, O_WRONLY);
if(lock_fd == -1)
return -1;
ASSERT(-1 == lockf(lock_fd, F_TEST, 0)); /* assert that parent still has the lock on the first byte */
if (-1 == lseek(lock_fd, 1, SEEK_SET))
{
perror("lseek");
return -1;
}
return lockf(lock_fd, F_TLOCK, 0);
}
}
void do_daemon(const char *pidfile)
{
chdir("/");
if (pidfile) {
struct stat dummy;
if (0 == stat(pidfile, &dummy)) {
cmn_err(CE_WARN, "%s already exists; aborting.", pidfile);
exit(1);
}
}
/*
* info gleaned from the web, notably
* http://www.enderunix.org/docs/eng/daemon.php
*
* and
*
* http://sourceware.org/git/?p=glibc.git;a=blob;f=misc/daemon.c;h=7597ce9996d5fde1c4ba622e7881cf6e821a12b4;hb=HEAD
*/
{
int forkres, devnull;
if(getppid()==1)
return; /* already a daemon */
forkres=fork();
if (forkres<0)
{ /* fork error */
cmn_err(CE_WARN, "Cannot fork (%s)", strerror(errno));
exit(1);
}
if (forkres>0)
{
int i;
/* parent */
for (i=getdtablesize();i>=0;--i)
if ((lock_fd!=i) && (ioctl_fd!=i)) /* except for the lockfile and the comm socket */
close(i); /* close all descriptors */
/* allow for airtight lockfile semantics... */
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 200000; /* 0.2 seconds */
select(0, NULL, NULL, NULL, &tv);
VERIFY(0 == close(lock_fd));
lock_fd == -1;
exit(0);
}
/* child (daemon) continues */
setsid(); /* obtain a new process group */
VERIFY(0 == chdir("/")); /* change working directory */
umask(027); /* set newly created file permissions */
devnull=open("/dev/null",O_RDWR); /* handle standard I/O */
ASSERT(-1 != devnull);
dup2(devnull, 0); /* stdin */
dup2(devnull, 1); /* stdout */
dup2(devnull, 2); /* stderr */
if (devnull>2)
close(devnull);
/*
* contrary to recommendation, do _not_ ignore SIGCHLD:
* it will break exec-ing subprocesses, e.g. for kstat mount and
* (presumably) nfs sharing!
*
* this will lead to really bad performance too
*/
signal(SIGTSTP,SIG_IGN); /* ignore tty signals */
signal(SIGTTOU,SIG_IGN);
signal(SIGTTIN,SIG_IGN);
}
if (0 != zfsfuse_do_locking(1))
{
cmn_err(CE_WARN, "Unexpected locking conflict (%s: %s)", strerror(errno), LOCKFILE);
exit(1);
}
if (pidfile) {
FILE *f = fopen(pidfile, "w");
if (!f) {
cmn_err(CE_WARN, "Error opening %s.", pidfile);
exit(1);
}
if (fprintf(f, "%d\n", getpid()) < 0) {
unlink(pidfile);
exit(1);
}
if (fclose(f) != 0) {
unlink(pidfile);
exit(1);
}
}
}
See also http://gitweb.zfs-fuse.net/?p=sehe;a=blob;f=src/zfs-fuse/util.c;h=7c9816cc895db4f65b94592eebf96d05cd2c369a;hb=refs/heads/maint
The only way I can think of is to use system level locks. See this: C++ how to check if file is in use - multi-threaded multi-process system
One way to approach this problem is to open the file for appending. If the function succeeds and the position is at 0 then you can be fairly certain this is a new file. Could still be an empty file but that scenario may not be important.
FILE* pFile = fopen(theFilePath, "a+");
if (pFile && gfetpos(pFile) == 0) {
// Either file didn't previously exist or it did and was empty
} else if (pFile) {
fclose(pFile);
}
It would appear that there's no way to do it strictly using streams.
You can, instead, use open (as mentioned above by wildplasser) and if that succeeds, proceed to open the same file as a stream. Of course, if all you're writing to the file is a PID, it is unclear why you wouldn't just write it using C-style write().
O_EXCL only excludes other processes that are attempting to open the same file using O_EXCL. This, of course, means that you never have a perfect guarantee, but if the file name/location is somewhere nobody else is likely to be opening (other than folks you know are using O_EXCL) you should be OK.