My first windows named pipe, not sure what is wrong - c

Edit: Here is the entire code, ignore Romanian comments. Also 2 or 3 names are untranslated from Romanian: http://pastebin.com/JjtayvXX
I am trying to learn the basics of OS, now I'm working with named pipes under windows and I can't tell what's wrong.
Honestly I'm working off an example a friend did, but he's just as bad as me if not worse. While hi's program works (albeit it does something else), he can't explain anything, most likely just copied from somewhere, still ... not important, what I was trying to say I'm learning from examples, and not professional ones.
Server receives a message from the client, returns max and min numbers.
Server.c:
#include "windows.h"
#include "stdio.h"
struct Msg {
int numbers[20];
int length;
};
...
int main () {
HANDLE inputPipe, outputPipe;
Msg msg;
while (true) {
inputPipe = CreateNamedPipe ("\\\\.\\pipe\\Client2Server",
PIPE_ACCESS_INBOUND,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES,
0, //Numb of output bytes
sizeof(Msg), // Numb of input bytes
0, // Wait forever
NULL); // Don't know how to use security
ConnectNamedPipe (inputPipe,NULL);
// Here is where the server dies
ReadFile (inputPipe, &msg,sizeof(Msg),NULL,NULL);
Now Client.c:
struct Msg {
int numbers[20];
int length;
};
int main () {
HANDLE outputPipe, inputPipe;
Msg msg;
// #misc: read data from keyboard, create msg
outputPipe = CreateFile ("\\\\.\\pipe\\Client2Server",
GENERIC_WRITE,
FILE_SHARE_READ, // * comment after code
NULL, // again, I know nothing about security attributes
CREATE_ALWAYS, // either create or overwrite
0,
NULL);
// Here is where it dies
WriteFile (outputPipe, &msg, sizeof(Msg), NULL, NULL);
I get Access violation writing location 0x00000000. No idea why.
I would like that this process only writes, and another process (server) only reads. Is FILE_SHARE_READ OK ?
Also I don't know how to mess with CreationDisposition / FlagsAndAttributes (last 2 parameters at CreateFile), are they OK ?

Edit: Added actual answer, reference to other topic, tried it myself
WriteFile()'s fourth parameter (pointer to variable that will store number of bytes) should not be null. Based on the API description, this parameter can ONLY be NULL if the fifth param, lpOverlapped, is NOT null.
See similar topic here:
Why does WriteFile crash when writing to the standard output?
Can you check/printf the return values of ReadFile() (failed if return = 0 or FALSE) and client.c CreateFile() (failed if returns INVALID_HANDLE_VALUE) to see if they succeed?
If failed, can you print the value returned by GetLastError() immediately after the call so that we can see the specific error?

Related

Segmentation fault when writing to comport

I am writing a small program to communicate with a USB to UART bridge (CP210x).
The program is fairly simple, but when ever I decrease the size of the outbound message array below (wm_size < 25) I get a segmentation fault.
The code yielding the segmentation fault looks as follows:
HANDLE prog_com_port;
prog_com_port = CreateFileA("\\\\.\\COM4",
GENERIC_READ | GENERIC_WRITE, //Request Read and Write Acess
0, //Block others from sharing Acess
NULL, //Disable Security features
OPEN_EXISTING, //Only open existing device
FILE_ATTRIBUTE_NORMAL, //Used to set atributes and flags
NULL);
//Handle to
if(prog_com_port == INVALID_HANDLE_VALUE)
{
printf("Opening COM port failed - INVALID_HANDLE_VALUE\n");
CloseHandle(prog_com_port);
return 1;
}
else
printf("COM port was opened successfully \n");
SetupCommState(prog_com_port);
Sleep(2);
#define wm_size 25
int messageLength = 2;
char W_message[wm_size] = {0x01,0x01};
long unsigned int * bytes_sent;
BOOL Status;
Status = WriteFile(prog_com_port, // Handle to the Serial port
&W_message, // Pointer to message buffer
messageLength, // No of bytes to write
bytes_sent, // Pointer to number of bytes written
NULL);
if(!Status)
{
printf("Failed to write to COM port - 0x00 \n");
CloseHandle(prog_com_port);
return 2;
}
CloseHandle(prog_com_port);
My logic tells me that setting wm_size = 2 is enough but apparently that is wrong. Can someone tell me why?
I played around with the size of wm_size and found experiemtally that 25 fixed the problem.
wm_size = 2 is enough, the problem is elsewhere: bytes_sent is a pointer that points nowhere.
Your "fix" didn't fix anything. You are experiencing undefined behaviour (which includes apparently working fine).
You want this (all comments are mine):
DWORD messageLength = 2; // use DWORD
DWORD bytes_sent; // use DWORD
char W_message[] = {0x01,0x01}; // you don't need wm_size
Status = WriteFile(prog_com_port,
W_message, // remove &, W_message decays into a pointer
messageLength,
&bytes_sent, // put &, you need a pointer here
NULL);
or even better: you don't need messageLength:
Status = WriteFile(prog_com_port,
W_message, // remove &
sizeof(W_message), // assuming W_message contains chars
&bytes_sent, // put &
NULL);
// now bytes_sent contains the number of bytes sent (hopefully 2),
// providing WriteFile succeeded (Status is TRUE)
The usage of DWORD is highly recommended, so the types of the arguments passed to to WriteFile actually match the declaration (and the documentation). Also be aware that LPDWORD in all Microsoft documentation and header files is is the
same thing as DWORD*.

Is it legal to read a file descriptor into NULL?

Recently, I've been fixing the timestep for the sake of a library that I am writing. Following some research, suppose that I ended up with this prototype, precise and easy to combine with the generic event system of my library:
#include <stdio.h>
#include <unistd.h>
#include <sys/timerfd.h>
#include <poll.h>
struct pollfd fds[1];
struct itimerspec its;
int main(void) {
fds[0] = (struct pollfd) {timerfd_create(CLOCK_MONOTONIC, 0), POLLIN, 0}; //long live clarity
its.it_interval = (struct timespec) {0, 16666667};
its.it_value = (struct timespec) {0, 16666667};
timerfd_settime(fds[0].fd, 0, &its, NULL);
while(1) {
poll(fds, 1, -1);
if(fds[0].revents == POLLIN) {
long long buffer;
read(fds[0].fd, &buffer, 8);
printf("ROFL\n");
} else {
printf("BOOM\n");
break;
}
}
close(fds[0].fd);
return 0;
}
However, it severely hurt me that I've had to pollute my CPU caches with a whole precious 8 bytes of data in order to make the timer's file descriptor reusable. Because of that, I've tried to replace the read() call with lseek(), as follows:
lseek(fds[0].fd, 0, SEEK_END);
Unfortunately, both that and even lseek(fds[0].fd, 8, SEEK_CUR); gave me ESPIPE errors and would not work. But then, I found out that the following actually did its job, despite of giving EFAULTs:
read(fds[0].fd, NULL, 8);
Is it legal, defined behavior to offset the file descriptor like this? If it is not (as the EFAULTs suggested to me, strongly enough to refrain from using that piece of genius), does there exist a function that would discard the read data, without ever writing it down, or otherwise offset my timer's file descriptor?
The POSIX specification of read(2) does not specify the consequences of passing a null pointer as the buffer argument. No specific error code is given, nor does it say whether any data will be read from the descriptor.
The Linux man page has this error, though:
EFAULT buf is outside your accessible address space.
It doesn't say that it will read the 8 bytes and discard them when this happens, though.
So I don't think you can depend on this working as you desire.

Linux select() not blocking

I'm trying to understand the difference between select() and poll() better. For this I tried to implement a simple program that will open a file as write-only, add its file descriptor to the read set and than execute select in hopes that the function will block until the read permission is granted.
As this didnt work (and as far as I understood, this is intended behaviour) I tried to block access to the file using flock before the select() executen. Still, the program did not block its execution.
My sample code is as follows:
#include <stdio.h>
#include <poll.h>
#include <sys/file.h>
#include <errno.h>
#include <sys/select.h>
int main(int argc, char **argv)
{
printf("[+] Select minimal example\n");
int max_number_fds = FOPEN_MAX;
int select_return;
int cnt_pollfds;
struct pollfd pfds_array[max_number_fds];
struct pollfd *pfds = pfds_array;
fd_set fds;
int fd_file = open("./poll_text.txt", O_WRONLY);
struct timeval tv;
tv.tv_sec = 10;
tv.tv_usec = 0;
printf("\t[+] Textfile fd: %d\n", fd_file);
//create and set fds set
FD_ZERO(&fds);
FD_SET(fd_file, &fds);
printf("[+] Locking file descriptor!\n");
if(flock(fd_file,LOCK_EX) == -1)
{
int error_nr = errno;
printf("\t[+] Errno: %d\n", error_nr);
}
printf("[+] Executing select()\n");
select_return = select(fd_file+1, &fds, NULL, NULL, &tv);
if(select_return == -1){
int error_nr = errno;
printf("[+] Select Errno: %d\n", error_nr);
}
printf("[+] Select return: %d\n", select_return);
}
Can anybody see my error in this code? Also: I first tried to execute this code with two FDs added to the read list. When trying to lock them I had to use flock(fd_file,LOCK_SH) as I cannot exclusively lock two FDs with LOCK_EX. Is there a difference on how to lock two FDs of the same file (compared to only one fd)
I'm also not sure why select will not block when a file, that is added to the Read-set is opened as Write-Only. The program can never (without a permission change) read data from the fd, so in my understanding select should block the execution, right?
As a clarification: My "problem" I want to solve is that I have to check if I'm able to replace existing select() calls with poll() (existing in terms of: i will not re-write the select() call code, but will have access to the arguments of select.). To check this, I wanted to implement a test that will force select to block its execution, so I can later check if poll will act the same way (when given similar instructions, i.e. the same FDs to check).
So my "workflow" would be: write tests for different select behaviors (i.e. block and not block), write similar tests for poll (also block, not block) and check if/how poll can be forced do exactly what select is doing.
Thank you for any hints!
When select tells you that a file descriptor is ready for reading, this doesn't necessarily mean that you can read data. It only means that a read call will not block. A read call will also not block when it returns an EOF or error condition.
In your case I expect that read will immediately return -1 and set errno to EBADF (fd is not a valid file descriptor or is not open for reading) or maybe EINVAL (fd is attached to an object which is unsuitable for reading...)
Edit: Additional information as requested in a comment:
A file can be in a blocking state if a physical operation is needed that will take some time, e.g. if the read buffer is empty and (new) data has to be read from the disk, if the file is connected to a terminal and the user has not yet entered any (more) data or if the file is a socket or a pipe and a read would have to wait for (new) data to arrive...
The same applies for write: If the send buffer is full, a write will block. If the remaining space in the send buffer is smaller than your amount of data, it may write only the part that currently fits into the buffer.
If you set a file to non-blocking mode, a read or write will not block but tell you that it would block.
If you want to have a blocking situation for testing purposes, you need control over the process or hardware that provides or consumes the data. I suggest to use read from a terminal (stdin) when you don't enter any data or from a pipe where the writing process does not write any data. You can also fill the write buffer on a pipe when the reading process does not read from it.

Why does MapViewOfFile fail with ERROR_ACCESS_DENIED?

I came across this situation with WinAPI's MapViewOfFile function. An Internet search didn't turn up any apparent fixes, so I will share my problem and solution here.
Consider the following snippet:
const char *name = "Global\\Object_Name";
unsigned long size = get_object_size();
HANDLE handle = CreateFileMapping(INVALID_HANDLE_VALUE,
NULL,
PAGE_READWRITE,
0,
size,
name);
if (!handle || handle == INVALID_HANDLE_VALUE)
exit(GetLastError());
bool created = GetLastError() == 0;
void *block = MapViewOfFile( handle,
FILE_MAP_ALL_ACCESS,
0,
0,
size);
if (block == NULL)
exit(GetLastError());
In one particular case, CreateFileMapping was successfully returning a handle. GetLastError was returning ERROR_ALREADY_EXISTS, so created == false. Now, the call to MapViewOfFile, using the same size that I passed to CreateFileMapping, returns NULL and GetLastError returns 0x05: ERROR_ACCESS_DENIED. The process was running with administrator privileges.
The MSDN documentation doesn't really mention any reason why this situation would occur. So why does CreateFileMapping succeed, but MapViewOfFile fail?
After a lot of suffer, I finally found what was causing this error in my application, in case someone else is struggling with the same, the problem is not with the MapViewOfFile method, but with the CreateFileMapping, the size of the createFileMapping should be the size of the file, not the size of the element to read, if you don't know the size then it should be 0, this does not apply to the MapViewOfFile as the value to pass as size is the length of the block you want to read/write.
Your code working will look like this:
const char *name = "Global\\Object_Name";
unsigned long size = get_object_size();
HANDLE handle = CreateFileMapping(INVALID_HANDLE_VALUE,
NULL,
PAGE_READWRITE,
0,
0,
name);
if (!handle || handle == INVALID_HANDLE_VALUE)
exit(GetLastError());
bool created = GetLastError() == 0;
void *block = MapViewOfFile( handle,
FILE_MAP_ALL_ACCESS,
0,
0,
size);
if (block == NULL)
exit(GetLastError());
A just putting this here to document what I found, unfortunately is hard to search for this error when you don't know what is causing it. I hope this saves a couple of hours to someone else.
I'm sure there are many reasons why ERROR_ACCESS_DENIED could occur from a call to MapViewOfFile. In my particular situation, it was due to the size argument.
The hint is in the fact that created == false. It shows that the object "Global\\Object_Name" has already been created. For whatever reason, the creating call initialised the section with a smaller size. For what seems like an oversight, the second call to CreateFileMapping will happily give you a handle to the already-existing object, even if you asked for a bigger mapping.
The call to MapViewOfFile now fails, because it's requesting a view that is bigger than the actual section.
So, if you're in a similar situation where the second call to MapViewOfFile fails, check the size that you're trying to map to.
It could be that the second project is compiling with a different structure alignment, resulting in the sizeof() operator determining different values, or some other size-determining function is not behaving as expected.

Why is Windows's CreateFile(<no share access>) lying to me?

I'm trying to prevent a third-party DLL in my process from reading a file I've opened, and I've found it to be... well, impossible.
No matter what I do, no matter what share flags I specify, their call always seems to succeed!
Here is the screenshot from Process Monitor -- the first CreateFile call is mine, and the rest are theirs:
How is this even possible? Why is the "Share Mode: None" lying to me, and how can I prevent this?
This code below is an example that reproduces the problem:
#include <stdio.h>
#include <Windows.h>
int main()
{
LPCTSTR file = TEXT("C:\\Test1234.xml");
HANDLE hFile1 =
CreateFile(file, FILE_READ_ATTRIBUTES, 0, NULL, OPEN_ALWAYS, 0, NULL);
HANDLE hFile2 =
CreateFile(file, FILE_READ_DATA, 0, NULL, OPEN_ALWAYS, 0, NULL);
DWORD n;
BYTE buf[1];
printf("%d\n", ReadFile(hFile2, buf, sizeof(buf), &n, NULL));
CloseHandle(hFile1);
CloseHandle(hFile2);
DeleteFile(file);
}
Share modes are enforced for actually reading and writing the DATA of the file. Attributes (like file size, timestamps, etc) are not covered by the sharing rules and there is no way to prevent their access short of ACLs.
The best you can to is open the file for R/W/D access and not specify SHARE_READ|WRITE|DELETE.
Weird, but true.

Resources