简体   繁体   中英

Named pipe file descriptor

Currently I am making a C/C++ program for the Linux Operating system. I want to use a named pipe to communicate a PID (process ID) between two programs. The pipe has been created and is visible in the directory.

The Get PID program says that the file descriptor returns 3, while it should return 0 if it could open the pipe. What am I doing wrong?

// Several includes
using namespace std;

int main(int argc, char *argv[]) {
  pid_t pid;
  int sig = 22;
  int succesKill;
  int iFIFO;
  char sPID[5] = {0,1,2,3,'\0'};
  iFIFO = open("IDpipe" , O_RDONLY);
  if(iFIFO != 0)
    {
    cerr << "File descriptor does not return 0, but: " <<  iFIFO << endl;
    return EXIT_FAILURE;
    } 
  read(iFIFO, sPID, strlen(sPID));
  cerr << "In sPID now is: " << sPID << endl;
  close(iFIFO);
  pid = atoi(sPID);
  cout << "The PID I will send signals to is: " << pid << "." << endl;
  while(1)
    {
    succesKill = kill(pid, sig);
    cout << "Tried to send signal" << endl;
    sleep(5);
    }
  return EXIT_SUCCESS;
}

// Several includes
using namespace std;

void catch_function(int signo);

volatile sig_atomic_t iAmountSignals = 0;

int main(void) {
    pid_t myPID;
    int iFIFO;
    char sPID[5] = {'l','e','e','g','\0'};
    myPID = getpid();
    sprintf(sPID, "%d",myPID);
    cout << "My PID is: " << sPID << endl;
    iFIFO = open("IDpipe" , O_WRONLY);
    if(iFIFO == -1)
      {
      cerr << "Pipe can't be opened for writing, error: " << errno << endl;
      return EXIT_FAILURE;
      }
    write(iFIFO, sPID, strlen(sPID));
    close(iFIFO);
    if (signal(22, catch_function) == SIG_ERR) {
        cerr << "An error occurred while setting a signal handler." << endl;
        return EXIT_FAILURE;
    }
    cout << "Raising the interactive attention signal." << endl;
    if (raise(22) != 0) {
        cerr << "Error raising the signal." << endl;
        return EXIT_FAILURE;
    }
    while(1)
    {
        cout << "iAmountSignals is: " << iAmountSignals << endl;
        sleep(1);
    }
    cout << "Exit." << endl;
    return EXIT_SUCCESS;
}

void catch_function(int signo) {
    switch(signo) {
    case 22:
        cout << "Caught a signal 22" << endl;
        if(iAmountSignals == 9)
          {iAmountSignals = 0;}
        else
          {++iAmountSignals;}
        break;
    default:
        cerr << "Thats the wrong signal.." << endl;
        break;
    }
}

Output

Your logic appears to be incorrect.

if(iFIFO != 0)

should be

if(iFIFO == -1)

since open returns -1 on error. Otherwise it returns a valid file descriptor.

open() returns the newly created file descriptor. It cannot return 0 for the simple reason that the new process already has a file descriptor 0. That would be standard input.

The return value of 3 is the expected result from open() , in this case, because that would be the next available file descriptor after standard input, output, and error. If open() couldn't open the file descriptor, it would return -1.

But besides that, your code also has a bunch of other bugs:

sprintf(sPID, "%d",myPID);

// ...

write(iFIFO, sPID, strlen(sPID));

If your process ID happens to be only 3 digits long (which is possible), this will write three bytes to the pipe.

If your process ID happens to be five digits long (which is even more possible), this will write 5 bytes plus the '\\0' byte, for a total of six bytes written to the five byte-long sPID buffer, overrunning the array and resulting in undefined behavior.

The actual results are, of course, are undefined, but a typical C++ implementation will end up clobbering the first byte of whatever is the next variable on the stack, which is:

int iFIFO;

which is your file descriptor. So, if your luck runs out and your new process gets a five-digit process id, and this is a little-endian C++ implementation, there is no padding, then the low order byte of iFIFO gets set to 0, and if the code got compiled without any optimizations, the iFIFO file descriptor gets set to 0. Hillarity ensues.

Furthermore, on the other side of the pipe:

char sPID[5] = {0,1,2,3,'\0'};

// ...

read(iFIFO, sPID, strlen(sPID));

Because the first byte of SPID is always set to 0, this will always execute read(iFIFO, sPID, 0) , and not read anything.

After that:

pid = atoi(sPID);

atoi() expects a '\\0'-terminated string. read() only reads whatever it reads, it will not '\\0'-terminate whatever it ends up reading. It is your responsibility to place a '\\0' that terminates the read input (and, of course, making sure that the read buffer is big enough), before using atoi() .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM