I'm trying to write in a named pipe and read back the same thing. Consider the following code snippet (the error handling is stripped for brevity):
const char * pipeName = "\\\\.\\pipe\\pipe";
const char * buffWrite = "SOME TEXT";
unsigned buffLength = strlen(buffWrite);
char buffRead[1024];
DWORD nWritten, nRead;
HANDLE hPipe = CreateNamedPipe(pipeName,
PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 1024, 1024, 0, 0);
HANDLE hFile = CreateFile(pipeName, GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
WriteFile(hFile, buffWrite, buffLength, &nWritten, 0);
CloseHandle(hFile);
//the next line fails with >>All pipe instances are busy.<<
hFile = CreateFile(pipeName, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);
ReadFile(hFile, buffRead, buffLength, &nRead, 0);
...
However when I try reopen the pipe for reading the CreateFile call fails with "All pipes are busy."
What am I missing here?
EDIT.
Peeking works fine, i.e.
DWORD nRead, nTotal, nLeft;
PeekNamedPipe(hPipe, buffRead, buffLength, &nRead, &nTotal, &nLeft);
returns the written data correctly.
REMARK.
This is a proof of concept for something larger. No new threads and processes will be involved.
The reason you're getting that specific error code is that you only created one instance of the named pipe, and you've already used it. (You can create a new instance by calling CreateNamedPipe a second time, or you can reuse an existing instance by calling DisconnectNamedPipe.)
However, based on your commentary, I believe you want the call to ReadFile to retrieve the data written by the call to WriteFile, i.e., you want the same instance of the pipe, not a new one.
To do that, do not open a new handle. Use the existing handle, hPipe.
(Note that each pipe instance has two ends; a server end and a client end. The handle from CreateNamedPipe is always to the server end, and the handle from CreateFile is always to the client end. Data written to the server end can only be read from the client end, and vice-versa.)
You are trying to use named pipe as some kind of buffer - client connects to it, puts some data, then disconnects, after that other client connects and retrieves this data. This is invalid approach, named pipe is just that - a pipe, it has two sides - server side and client side, server and client could communicate through it. Usual pipe usage scenario:
Server creates named pipe using CreateNamedPipe function;
Server begin waiting for the client connections using ConnectNamedPipe method;
Client creates its side of the pipe using CreateFile API call;
Server and client communicate using ReadFile/WriteFile;
Pipe is closed with DisconnectNamedPipe and could be reactivated again with ConnectNamedPipe.
You could see complete example in the MSDN here.
It is because both extremities of the pipe have allready be opened (*)...
First was opened with the CreatePipe call, the other was with the first CreateFile call. You should not try to open one time more the pipe, but simply read from the hPipe HANDLE :
const char * pipeName = "\\\\.\\pipe\\pipe";
const char * buffWrite = "SOME TEXT";
unsigned buffLength = strlen(buffWrite);
char buffRead[1024];
DWORD nWritten, nRead;
HANDLE hPipe = CreateNamedPipe(pipeName,
PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 1024, 1024, 0, 0);
HANDLE hFile = CreateFile(pipeName, GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
WriteFile(hFile, buffWrite, buffLength, &nWritten, 0);
CloseHandle(hFile);
ReadFile(hPipe, buffRead, buffLength, &nRead, 0); // nRead=9, buffRead="SOME TEXT"
...
(*) You did specify PIPE_UNLIMITED_INSTANCES for the nMaxInstances parameter in CreateNamedPipe call, but as you never called ConnectNamedPipe to create other endpoints, only one CreateFile was allowed.
Related
I am developing a uri scheme registering library in C. I need to redirect the second call of the application to the first one so that only one is opened at a time. I decided to use windows named pipes for that. When I start the second instance like start testuri://example it works fine and the first instance receives the value testuri://example. However, when I start it like explorer testuri://example it fails to open the pipe to write.
This is my code for pipes (it is a wrapper for the winapi since I want the code to be cross platform and a Linux version also exists)
#include <windows.h>
#define READONLY GENERIC_READ
#define WRITEONLY GENERIC_WRITE
#define READWRITE GENERIC_WRITE | GENERIC_READ
#define CREATE_EXCLUSIVE CREATE_NEW
#define CREATE CREATE_ALWAYS
typedef struct file_desc {
char* name;
HANDLE hPipe;
int isReadPipe;
} file_desc;
void pipe_create(file_desc* pipe, const char* name) {
pipe->name = (char*) malloc(strlen(name) + 10);
memcpy(pipe->name, "\\\\.\\pipe\\", 10);
strcat(pipe->name, name);
pipe->hPipe = CreateNamedPipe(
TEXT(pipe->name),
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
1,
1024 * 16,
1024 * 16,
NMPWAIT_USE_DEFAULT_WAIT,
NULL
);
}
int pipe_open(file_desc* pipe, int mode) {
if (mode == READONLY) {
pipe->isReadPipe = TRUE;
return ConnectNamedPipe(pipe->hPipe, NULL);
} return file_open(pipe, pipe->name, mode, 1);
}
void pipe_close(file_desc* pipe) {
if (pipe->isReadPipe) {
DisconnectNamedPipe(pipe->hPipe);
} else file_close(pipe);
}
int file_open(file_desc* pipe, const char* name, int mode, int lock) {
if (!lock) pipe->hPipe = CreateFile(TEXT(name), mode, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_ALWAYS, 0, NULL);
else pipe->hPipe = CreateFile(TEXT(name), mode, 0, NULL, OPEN_ALWAYS, 0, NULL);
return pipe->hPipe != INVALID_HANDLE_VALUE;
}
char* file_read(file_desc* pipe, char buf[], unsigned int size) {
DWORD dwRead;
ReadFile(pipe->hPipe, buf, size, &dwRead, NULL);
}
void file_write(file_desc* pipe, const char* str) {
DWORD dwWritten;
WriteFile(pipe->hPipe,str, strlen(str) + 1, &dwWritten, NULL);
}
void file_close(file_desc* pipe) {
CloseHandle(pipe->hPipe);
}
The way I create the pipes is something like this
file_desc* pipe;
pipe_create(pipe, "mypipe");
if (firstInstance) {
pipe_open(pipe, READONLY);
char buf[200];
file_read(pipe, buf, 200);
pipe_close(pipe);
} else {
pipe_open(pipe, WRITEONLY);
file_write(pipe, "test");
pipe_close(pipe);
}
Full code is at https://github.com/germaniuss/libschemehandler just create an obj folder and execute make in MinGW. Then run myapp.exe
I found a solution!
I tried looking at the error code at it returned error 5, access is denied. I found the problem. When opening the first instance I did that with elevated privileges, however, when opening an app using explorer testuri://example a new terminal window without elevated privileges pops up. This causes a problem since the pipe was created as administrator and is being accessed without.
I looked for info on this topic and found this forum exchange https://forums.codeguru.com/showthread.php?548311-RESOLVED-Writing-to-a-named-pipe-coming-from-a-service-(session-0)-without-admin-rights which was exactly what I needed. I just needed to create an all access security descriptor for the named pipe.
I feel like the fact that the pipe is created by default as with admin only access should be more clearly stated, since it says full access is granted by default
A pointer to a SECURITY_ATTRIBUTES structure that specifies a security
descriptor for the new named pipe and determines whether child
processes can inherit the returned handle. If lpSecurityAttributes is
NULL, the named pipe gets a default security descriptor and the handle
cannot be inherited. The ACLs in the default security descriptor for a
named pipe grant full control to the LocalSystem account,
administrators, and the creator owner. They also grant read access to
members of the Everyone group and the anonymous account.
Source MSDN
In the end my pipe_open functions ended up like so
void pipe_create(file_desc* pipe, const char* name) {
// all access secutrity descriptor
PSECURITY_DESCRIPTOR psd = NULL;
BYTE sd[SECURITY_DESCRIPTOR_MIN_LENGTH];
psd = (PSECURITY_DESCRIPTOR)sd;
InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(psd, TRUE, (PACL)NULL, FALSE);
SECURITY_ATTRIBUTES sa = {sizeof(sa), psd, FALSE};
pipe->name = (char*) malloc(strlen(name) + 10);
memcpy(pipe->name, "\\\\.\\pipe\\", 10);
strcat(pipe->name, name);
pipe->hPipe = CreateNamedPipe(
TEXT(pipe->name),
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
1,
1024 * 16,
1024 * 16,
NMPWAIT_USE_DEFAULT_WAIT,
&sa
);
}
I encountered code similar to this (stripped down for MCVE):
HANDLE hFile = CreateFileW(argv[1], GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
// Note: FILE_FLAG_NO_BUFFERING and FILE_FLAG_WRITE_THROUGH are not present
DWORD dwWritten;
WCHAR wBOM = 0xFEFF, wString[100] = L"Hello World!";
SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
WriteFile(hFile, &wBOM, sizeof(WCHAR), &dwWritten, NULL);
WriteFile(hFile, wString, wcslen(wString) * sizeof(WCHAR), &dwWritten, NULL);
FlushFileBuffers(hFile);
CloseHandle(hFile);
The last part struck me as pedantic since I had the impression that calling CloseHandle would flush any buffered output to disk (similar to fclose(FILE *), where it is explicitly documented by the C Standard that buffers will be flushed). However, I wasn't able to find this information in the documentation for CloseHandle on MSDN.
So, is the call to FlushFileBuffers immediately before closing the file handle necessary to avoid discarding buffered output?
Closing the handle does not discard unflushed updates, but it does not flush them either.
FlushFileBuffers() is useful if you want to force flushing before CloseHandle() because the latter does not flush the buffers automatically. However, if you really need direct writes, you must open the handle with FILE_FLAG_WRITE_THROUGH.
If you do not read direct writes, then flushing is not necessary either before closing the handle or at any point of the life of the handle.
I have two processes communicating via a pty, nonblocking. Problem is that the fread() on the master fails when there is no data available to process.
How can I ignore the "no reader/data present" case when reading from the unconnected file descriptor on the master side? I suspect there is some flag for open() or fcntl() which I skipped during reading?
// initialization:
int pty_fd = posix_openpt(O_RDWR | O_NOCTTY);
int rc = grantpt(pty_fd);
rc = unlockpt(pty_fd);
fcntl(pty_fd, F_SETFL, O_NONBLOCK);
fd_read = fdopen(pty_fd, "r");
// now, trying to read will fail if no data is present:
char buf[100];
int count = sizeof(buf);
size_t bytesRead = fread(buf, sizeof(char), count, fd_read);
if ((bytesRead == 0) && (ferror(fd_read)) {
printf("fail...\n");
}
Sure, I can ignore the return value of ferror(), but I suppose this is not the right way to use this function.
Ah, one thing: I found the POLLHUP trick on stackoverflowz. It works but is racy and hence not suitable for my case...
Greetings
I have a client and server, and the client runs a select loop to multiplex between a TCP and a UDP connection. I'm trying to add my TCP connection file descriptor to both the read and the write set and then initiate one message exchange using write set and one using read set. My message communication with the write set works fine but with the read set I'm unable to do so.
Client Code:
char buf[256] = {};
char buf_to_send[256] = {};
int nfds, sd, r;
fd_set rd, wr;
int connect_init = 1;
/* I do the Connect Command here */
FD_ZERO(&rd);
FD_ZERO(&wr);
FD_SET(sd, &rd);
FD_SET(sd, &wr);
nfds = sd;
for(; ;){
r = select(nfds + 1, &rd, &wr, NULL, NULL);
if(connect_init == 0){
if(FD_ISSET(sd, &rd)){ // this is not working, if I change rd to wr, it works!
r = recv(sd, buf, sizeof(buf),0);
printf("received buf = %s", buf);
sprintf(buf, "%s", "client_reply\n");
send(sd, buf, strlen(buf), 0);
}
}
/* Everything below this works correctly */
if (connect_init){
if(FD_ISSET(sd, &wr)){
sprintf(buf_to_send, "%s", "Client connect request");
write(sd, buf_to_send, strlen(buf_to_send));
recv(sd, buf, sizeof(buf), 0);
printf("Server said = %s", buf);
sprintf(buf_to_send, "Hello!\n"); // client Hellos back
send(sd, buf_to_send, strlen(buf_to_send), 0);
}
connect_init = 0;
}
} // for loops ends
You need to initialize the sets in the loop, every time before calling select. This is needed because select modifies them. Beej's Guide to Network Programming has a comprehensive example on one way to use select.
So in your code, it seems select returns first with writing allowed, but reading not, which has the read bit reset to 0, and then there's nothing to set it back to 1, because from then on select will not touch it, because it is already 0.
If select API bothers you, look at poll, it avoids this (note that there's probably no practical/efficiency difference, it basically boils down to personal preference). On a "real" code with many descriptors (such as a network server with many clients), where performance matters, you should use some other mechanism though, probably some higher level event library, which then uses the OS specific system API, such as Linux's epoll facility. But checking just a few descriptors, select is the tried and true and relatively portable choice.
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?