I am new to C++ programming and I am trying to use mkfifo command to create a named pipe that I can read from my java program. Here is my code:
int main(int, char **)
{
std::cout << "START" << std::endl;
int fd;
// FIFO file path
char *myfifo = "/sdcard/tempFifo";
// Creating the named file(FIFO)
// mkfifo(<pathname>, <permission>)
int ret = mkfifo(myfifo, 0666);
std::cout << "mkfifo ret " << ret << std::endl;
std::cout << "errno " << errno << std::endl;
std::cout << "errno str::" << std::strerror(errno) << std::endl;
char arr1[80];
int startCount = 0;
while (1)
{
// Open FIFO for Read only
std::cout << "Opening FIFO.." << std::endl;
fd = open(myfifo, O_RDONLY);
// Read from FIFO
std::cout << "Start reading.." << std::endl;
read(fd, arr1, sizeof(arr1));
if (strcmp(arr1, "start") == 0)
{
if (startCount == 1)
{
std::cout << "Start count is greater than one so exit." << std::endl;
return 0;
}
startCount++;
std::cout << "Start received" << std::endl;
}
sleep(5000);
close(fd);
}
std::cout << "STOP" << std::endl;
return 0;
}
To write "start" on the target pipe, I am using a java code as:
File file = new File("/sdcard/tempFifo");
FileOutputStream fileOutputStream = new FileOutputStream(file);
PrintWriter printWriter = new PrintWriter(fileOutputStream);
printWriter.print("start");
printWriter.flush();
printWriter.close();
I am getting Exception: /sdcard/tempFifo: open failed: ENOENT (No such file or directory) in java applicatoin and when I have executed ls -l /sdcard/tempFifo on adb shell then I am not able to see any tempFifo file on my sdcard of rooted phone.
Does anyone know what is the problem in my code?
Update on errno
mkfifo ret -1
errno 22
errno str::Invalid argument
Android doesn't allow creating pipes on /sdcard so, I have used /system/tempFifo instead of /sdcard/tempFifo to make it work.
Related
I did two months search on the web for a proper file locking mechanism to be used in a C++ program.
I found a lot on "C and fnctl" which I could proof to work. But all really proper working locking mechanism, that I could proof to work in Linux are only based on file descriptors.
As this seems to be something really old fashined and in actual C++17 style of writing C++ code with file- and ip-streams not using that mechanism, I only came up with something that works with using what was presented here:
Not able to ofstream using __gnu_cxx::stdio_filebuf
My Question is, is this really the only mechanism working? To connect both worlds?
I looked in all these books to find anything about fcntl and C++, but was not successful:
[Der C++ Programmierer Cxx20]
(https://www.hanser-elibrary.com/doi/book/10.3139/9783446465510)
[The C++ Programming Language] (https://www.stroustrup.com/C++.html)
[C++ Das Umfassende Handbuch]
(https://www.rheinwerk-verlag.de/c-plusplus-das-umfassende-handbuch/)
[Modern C++ Programming Cookbook Second Edition]
(https://www.packtpub.com/product/modern-c-programming-cookbook-second-edition/9781800208988)
My question to the C++ gurus here is, if I missed something, or if the following code is, today, begin of 2021 the best we could do.
Short explanation of what the code is a proof for:
We have a C++ Code which adds usernames and its LSF-processes to a conf-file, which is read by SSH-server to allow user access to that machine. As at the same time two or more running processes of this code could lead to concurrent attempts of adding or deleting users from this file could occur, we have to proof that proper file locking is preventing that. Without using an extra "access" file, which also could be a solution.
This is some example code I tested:
#include <iostream>
#include <string>
#include <thread>
#include <chrono>
#include <fcntl.h>
#include <unistd.h>
#include <ext/stdio_filebuf.h>
using namespace std::this_thread; // for sleep_for
int main( ) {
// set unbuffered concole output
std::cout.setf(std::ios::unitbuf);
const char* filename {"testfile.txt"};
// get input from input_from_user
std::string input_from_user_string;
std::cout << "Please give input to change in the file: ";
std::cin >> input_from_user_string;
int add_1_del_2 = 0;
std::cout << "Please give 1 if you want to add to the file or 2 if you want to delete from file: ";
std::cin >> add_1_del_2;
int input_from_user_time;
std::cout << "Please give seconds to wait: ";
std::cin >> input_from_user_time;
// opening file
std::cout << "Opening File" << std::endl;
mode_t mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH; //664
int fd;
fd = open(filename, O_RDWR | O_CREAT, mode);
// printing out information about file descriptor
std::cout << " Dexc:" << fd << std::endl;
// generating C++-streams on filedescriptor
__gnu_cxx::stdio_filebuf<char> sourcebufin(fd, std::ios::in);
__gnu_cxx::stdio_filebuf<char> sourcebufout(fd, std::ios::out);
std::istream myfilein(&sourcebufin);
std::ostream myfileout(&sourcebufout);
// -----------
// check for file Locking or exit
// -----------
// creating structure for file locking
struct flock fl;
fl.l_type = F_RDLCK;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len = 0;
// set file locking for read
fl.l_type = F_RDLCK;
std::cout << "Checking for Lock on file" << std::endl;
// check for file locking on file for read only once
(void) fcntl(fd, F_GETLK, &fl);
if (fl.l_type != F_UNLCK) {
std::cout << "File is locked for reading by process "
<< fl.l_pid
<< ", in status"
<< ((fl.l_type == F_WRLCK) ? 'W' : 'R')
<< ", start="
<< fl.l_start
<< ", end="
<< fl.l_len
<< std::endl;
}
else {
(void) printf("File is unlocked for reading\n");
}
// set file locking for write
fl.l_type = F_WRLCK;
// check for file locking on file for write in a loop
for (int i = 1; i < 11; i++) {
//printf("Checking for lock %d of 10 times...\n", i);
std::cout << "Checking for lock "
<< i
<< " of 10 times..."
<< std::endl;
(void) fcntl(fd, F_GETLK, &fl);
if (fl.l_type != F_UNLCK) {
//(void) printf("File is locked by process %d, in status %c, start=%8ld, end=%8ld\n", fl.l_pid,
// , fl.l_start, fl.l_len);
std::cout << "File is locked by process "
<< fl.l_pid
<< ", in status"
<< ((fl.l_type == F_WRLCK) ? 'W' : 'R')
<< ", start="
<< fl.l_start
<< ", end="
<< fl.l_len
<< std::endl;
sleep(10);
}
else {
(void) printf("File is unlocked\n");
break;
}
}
// -----------
// apply lock for write on file
// -----------
// locking file
std::cout << "Locking file for write" << std::endl;
// set file locking for write again, as checking on lock resets it
fl.l_type = F_WRLCK;
if (fcntl(fd, F_SETLKW, &fl) == -1) {
perror("fcntl");
abort();
}
// -----------
// wait some time
// -----------
std::cout << "Now waiting for " << input_from_user_time << " seconds, keeping the file locked..." << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(input_from_user_time));
// -----------
// read from file
// -----------
std::cout << "Reading from file... " << std::endl;
myfilein.seekg(0, std::ios::end);
size_t size_before = myfilein.tellg();
myfilein.seekg(0);
std::string filecontent{""};
filecontent.reserve(size_before);
std::cout << "Length of file is: " << size_before << std::endl;
// read full content of file in string "filecontent"
filecontent.assign((std::istreambuf_iterator<char>(myfilein)),
std::istreambuf_iterator<char>());
// -----------
// print output about read data
// -----------
std::cout << "Length of filecontent-string: " << filecontent.size() << std::endl;
std::cout << "Content of File begin" << std::endl;
std::cout << "----------" << std::endl;
std::cout << filecontent << std::endl;
std::cout << "----------" << std::endl;
// -----------
// Apply changes on read in data depending on given input
// -----------
if (add_1_del_2 == 2) {
std::cout << "Runmode: Del" << std::endl;
std::string string_to_delete = input_from_user_string+"\n";
std::string::size_type pos_of_found_substring = filecontent.find(string_to_delete);
if (pos_of_found_substring != std::string::npos) {
filecontent.erase(pos_of_found_substring, string_to_delete.length());
}
else {
}
}
if (add_1_del_2 == 1) {
std::cout << "Runmode: Append" << std::endl;
filecontent.append(input_from_user_string);
}
std::cout << "Content of String after change" << std::endl;
std::cout << "----------" << std::endl;
std::cout << filecontent << std::endl;
std::cout << "----------" << std::endl;
// -----------
// write out to file, truncate before to length of new string
// -----------
std::cout << "Now starting the write out..." << std::endl;
myfilein.seekg(0);
ftruncate(fd,filecontent.length());
myfileout.seekp(0);
myfileout << filecontent;
myfileout.flush();
myfileout.clear();
// -----------
// read from file for a second time and printout content
// -----------
std::cout << "Reading from file again... " << std::endl;
myfilein.seekg(0, std::ios::end);
size_t size_after = myfilein.tellg();
myfilein.seekg(0);
std::string filecontent_after{""};
filecontent_after.reserve(size_after);
std::cout << "Length of file is now: " << size_after << std::endl;
// read full content of file in string "filecontent"
filecontent_after.assign((std::istreambuf_iterator<char>(myfilein)),
std::istreambuf_iterator<char>());
std::cout << "Length of filecontent_after-string: " << filecontent_after.size() << std::endl;
std::cout << "Content of File end" << std::endl;
std::cout << "----------" << std::endl;
std::cout << filecontent_after << std::endl;
std::cout << "----------" << std::endl;
// -----------
// unlocking file and close file
// -----------
printf("Unlocking...\n");
fl.l_type = F_UNLCK;
if (fcntl(fd, F_SETLK, &fl) == -1) {
perror("fcntl");
abort();
}
close(fd);
// -----------
// done
// -----------
std::cout << "done" << std::endl;
exit(0);
}
I ask for your comments on this or perhaps how to improve.
Alexander Bruns
I need to receive a HTTP request from my browser, when I run localhost:8228 it works fine, I receive the header in the buffer and am able to write it to the console and even echo send it back to the browser. But when I try reading a request from a actual webpage, buffer is empty, it prints nothing.
I have a simple main that looks like this:
int main (int argc, char *argv[]) {
char buffer[1024*1024] = {0};
int port_number = 8228;
if (argc == 1)
std::cout << "Using default port number, 8228." << std::endl;
else if (argc == 3) {
port_number = atoi(argv[2]);
} else {
std::cout << "::Error::" << std::endl;
std::cout << "Wrong number of arguments." << std::endl;
exit[0];
}
AppSocket app;
app.Start((int)port_number);
app.AcceptCall();
int request_size = app.ReceiveRequest(buffer, sizeof(buffer));
return 0;
}
My AppSocket functions would be:
void AppSocket::Start(int port) {
// Create a socket
listening_fd = socket(AF_INET, SOCK_STREAM, 0);
if (listening_fd == -1) {
std::cerr << "Could not create a socket." << std::endl;
exit(-1);
}
app_hint.sin_family = AF_INET;
app_hint.sin_port = htons(port);
inet_pton(AF_INET, "127.0.0.1", &app_hint.sin_addr);
if (bind(listening_fd, (sockaddr*)&app_hint, sizeof(app_hint))< 0) {
std::cerr << "Cannot bind to IP/port." << std::endl;
exit(-2);
}
std::cout << "Socket has been bound." << std::endl;
if (listen(listening_fd, SOMAXCONN) == -1) {
std::cerr << "Cannot listen." << std::endl;
exit(-3);
}
std::cout << "Listening to port " << port << std::endl;
std::cout << "Your socket is: " << listening_fd << std::endl;
}
void AppSocket::AcceptCall() {
client_size = sizeof(client_addr);
client_fd =
accept(listening_fd, (sockaddr *)&client_addr, &client_size);
if (client_fd < 0) {
std::cerr << "Error connecting to client." << std::endl;
exit(-4);
}
std::cout << inet_ntoa(client_addr.sin_addr)
<< " connected to port "
<< ntohs(client_addr.sin_port) << std::endl;
close(listening_fd);
}
int AppSocket::ReceiveRequest(char *buffer, int max) {
std::cout << "Client is: " << client_fd << std::endl;
memset(buffer, 0, buff_size); //clear buffer
int n = recv(client_fd, buffer, buff_size, 0);
if (n < 0)
std::cerr << "A connection issue has occured." << std::endl;
if (n == 0)
std::cout << "Client disconected." << std::endl;
std::cout << "recv return " << n << std::endl;
std::cout << buffer << std::endl;
return n;
}
When I run and access a webpage I get this:
Using default port number, 8228.
Socket has been bound.
Listening to port 8228
Your socket is: 3
127.0.0.1 connected to port 37522
Client is: 4
recv return 3
None of the questions I've read seem to work for me...
edit: sorry one of the lines in the main code wasn't copied.
How can I receive repeatedly? A while loop? I tried that and just kept receiving nothing.
The code works, what was happening is that the firefox proxy settings were wrong, when I ran localhosts it worked fine because it was actually working as the server due to the port it was using but when trying to access a "real" website it didn't. After configuring it correctly it did just what it's supposed to do.
When using a FIFO on a single process, it looks like after both ends have been opened and one is then closed, it is not possible to reuse the FIFO. Any attempt to reopen the closed end fails or the returned file descriptor is useless.
Is it possible to work around this behavior, or do we have to keep both ends of the FIFO open until we are absolutely sure we don't need it anymore?
Here is some test code that shows and attempt to reopen a closed write end of a FIFO:
#include <iostream>
#include <cstdio>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
using namespace std;
int main(int argc, const char **argv)
{
cout << "Creating an instance of a named pipe..." << endl;
mode_t prevMask = umask(0);
if (mknod("my_pipe", S_IFIFO | 0666, 0))
return -1;
umask(prevMask);
cout << "Opening Read end..." << endl;
int fdM = open("my_pipe", O_RDONLY | O_NONBLOCK);
if (fdM == -1)
return -1;
cout << "Opening Write end..." << endl;
int fdS = open("my_pipe", O_WRONLY | O_NONBLOCK);
if (fdS == -1)
return -1;
cout << "Sending data to pipe..." << endl;
const char *data = "Hello my friend!";
ssize_t NbOfBytesWritten = write(fdS, data, strlen(data));
if (NbOfBytesWritten < 0)
return -1;
cout << "Number of bytes sent: " << NbOfBytesWritten << endl;
cout << "Closing Write end..." << endl;
if (close(fdS))
return -1;
cout << "Reopening Write end..." << endl;
fdS = open("my_pipe", O_WRONLY | O_NONBLOCK);
if (fdS == -1)
{
cout << "open() - failed("<< errno << "): " << strerror(errno) << '.';
remove("my_pipe");
return -1;
}
cout << "Sending some more data to pipe..." << endl;
data = "What's up?";
NbOfBytesWritten = write(fdS, data, strlen(data));
if (NbOfBytesWritten < 0)
return -1;
cout << "Number of bytes sent: " << NbOfBytesWritten << endl;
cout << "Reading data from pipe..." << endl;
char buff[128];
ssize_t numBytesRead = read(fdM, buff, 127);
if (NbOfBytesWritten < 0)
return -1;
buff[numBytesRead] = '\0'; // null terminate the string
cout << "Number of bytes read: " << numBytesRead << endl;
cout << "Message: " << buff << endl;
cout << "Closing Write end..." << endl;
if (close(fdS))
return -1;
cout << "Closing Read end..." << endl;
if (close(fdM))
return -1;
cout << "Deleting pipe..." << endl;
if (remove("my_pipe"))
return -1;
return 0;
}
Here is the output:
Creating an instance of a named pipe...
Opening Read end...
Opening Write end...
Sending data to pipe...
Number of bytes sent: 16
Closing Write end...
Reopening Write end...
open() - failed(6): No such device or address.
I also tested similar code trying to reopen a closed read end (While the write end was kept open). In that case the open() function succeed, but the read() function using the file descriptor returned by open() fails with:
Communication error on send. (70)
EDIT:
I'm using CYGWIN.
You code works fine on Linux. I think the issue you are running into is that named pipes on CYGWIN don't work very well and fail to follow POSIX semantics. See FIFO (named pipe) is broken on Cygwin. Likely the same problem you have.
So I have an issue trying to iterate through my container in c++ with visual studio Community 2015.
I'm trying to write a server/client on windows using select() and I get the error:
vector iterator not incrementable
I'm not calling a vector::erase() or such, although I do use a vector::push_back()
void MGKServer::mainLoop()
{
MGKServerSocket *mgk;
std::vector<User *> users;
int actual = 0;
char buffer[1024];
mgk = new WindowsServerSocket();
mgk->init("127.0.0.1", 4242, "TCP");
int sock = mgk->getSock();
std::cout << "sock is: " << mgk->getSock() << std::endl;
while (1)
{
this->setFd(sock, &users); // FD_ZERO(&_readfd) and FD_SET for each user's socket and the server socket
std::cout << "there is currently " << users.size() << " user(s) connected" << std::endl;
if (select(FD_SETSIZE + 1, &this->_readfd, NULL, NULL, NULL) == -1)
exit(errno);
// When a user connects
if (FD_ISSET(sock, &this->_readfd))
{
// addNewUser creates a pointer to an object User , set his socket to the given one and push it in the vector
if (this->addNewUser(sock, &users) == -1)
std::cout << "Can't add newUser" << std::endl;
}
// When a user sends a message to the server
else
{
int debug = 0;
std::vector<User *>::iterator it = users.begin();
while (it != users.end())
{
if (it == users.end())
std::cout << "Test if something went wrong with iterations" << std::endl;
if (FD_ISSET((*it)->getSocket(), &this->_readfd))
{
// RecvUser will just call recv with the client socket and store the message in buffer.
int c = mgk->recvUser((*it)->getSocket(), buffer);
// Means the user disconnected so i close his socket
if (c == 0)
{
std::cout << "user with socket: " << (*it)->getSocket() << "disconnected" << std::endl;
closesocket((*it)->getSocket());
}
// Means he sends an instruction
else
std::cout << "ok" << std::endl;
}
std::cout << "Debug = " << debug << std::endl;
++debug;
it++; // <- This small line seems to be the problem
}
std::cout << "Out of For loop" << std::endl;
}
std::cout << "found something on socket" << std::endl;
}
}
here is what i do in addNewUser:
int MGKServer::addNewUser(int socket, std::vector<User *> *users)
{
std::cout << "----NEW USER----" << std::endl;
SOCKADDR_IN usin = { 0 };
User *u;
int size;
int usock;
size = sizeof(usin);
std::cout << "New user is trying to connect, socket is: ";
usock = accept(socket, (SOCKADDR *)&usin, &size);
if (usock == SOCKET_ERROR)
{
std::cout << "socket error occured" << std::endl;
return (-1);
}
std::cout << usock << std::endl;
FD_SET(usock, &this->_readfd);
u = new User();
u->setSocket(usock);
users->push_back(u);
return (0);
}
My object User only contains a socket with get&set methods for now.
My MGKServerSocket is just an abstration for windows/linux socket. It contain basic function for initializing my socket and send & recv data to users.
So at first I had a list container but I've got the same error. So I switched to try with vector instead but nothing changed.
In the beginning, I also used a for loop instead of my current while loop but, once again, nothing changed.
I know that there's already many questions for this error, but they usually use erase, insert inside the for loop or create the iterator when the list is empty which I don't. So my question is, why do I get this error ?
I have the following code which ends up forever reading '/proc/cpuinfo' as it keeps getting the same result every read. Why doesn't the file pointer get advanced and reach eof ever? Seems this special file has different semantics.
const int bufSize = 4096;
char buf[bufSize + 1];
const string cpuInfo = "/proc/cpuinfo";
int cpuFD = ::open(cpuInfo.c_str(), O_RDONLY);
if (cpuFD == -1) {
logOutputStream << "Failed attempt to open '" << cpuInfo << "': "
<< strerror(errno) << endl;
} else {
assert(bufSize <= SSIZE_MAX);
logOutputStream << "Contents of: '" << cpuInfo << "'.\n";
for (int nRead = ::read(cpuFD, buf, bufSize); nRead != 0;) {
if (nRead == -1) {
logOutputStream << "Failed attempt to read '" << cpuInfo << "': "
<< strerror(errno) << endl;
break;
} else {
buf[nRead] = '\0';
logOutputStream << buf;
}
}
if (::close(cpuFD) == -1) {
logOutputStream << "Failed attempt to close '" << cpuInfo << "': "
<< strerror(errno) << endl;
}
}
for (int nRead = ::read(cpuFD, buf, bufSize); nRead != 0;) {
is wrong. You're using read as an initializer, so read is only being called once, not once per loop. After that, you're just looping forever printing it out (because nothing is changing nRead).
What happens if you try dumping the content into an actual text file with something like
cat /proc/cpuinfo > cpuinfo.txt
and then reading that file ?