Linux Fcntl - Unsetting Flag

linux fcntl - unsetting flag

int oldfl;
oldfl = fcntl(sockfd, F_GETFL);
if (oldfl == -1) {
/* handle error */
}
fcntl(sockfd, F_SETFL, oldfl & ~O_NONBLOCK);

Untested, but hope this helps. :-)

cannot switch to blocking mode using fcntl in linux

The behavior you are seeing is expected. You've done the following:

  1. Opened the read end of the FIFO using O_NONBLOCK, so that a writer need not be present on the FIFO. This guarantees that the open() will immediately succeed.
  2. Disabled O_NONBLOCK before subsequent reads. You've now taken yourself back to a position that is equivalent to the standard (blocking) case where a FIFO had a reader and writer, but the writer closed the FIFO. At that point, the reader should see end-of-file, which is what you are seeing.

What does the FD_CLOEXEC fcntl() flag do?

It sets the close-on-exec flag for the file descriptor, which causes the file descriptor to be automatically (and atomically) closed when any of the exec-family functions succeed.

It also tests the return value to see if the operation failed, which is rather useless if the file descriptor is valid, since there is no condition under which this operation should fail on a valid file descriptor.

Why fcntl() flag values are defined in Octal format & how this function works for blocking/non-blocking sockets?

"Why fcntl() flag values are defined in Octal format"

As many of the users have suggested, it's purely because of historical reasons. Apparently Octal format was more popular than Hex format.

"Is this answer the correct way to make non-blocking to blocking socket?"

Yes. The answer is correct, as it serves the purpose of setting the flags with keeping various scenario in consideration. However, error checking would have been more helpful, which is trivial.

"Is there a difference between fcntl(socket, F_GETFL, 0) and fcntl(socket, F_GETFL)?"

No difference. The man page for fcntl(2) suggest the same.

F_GETFL (void) -- Get the file access mode and the file status flags; arg is ignored.

SSL connection with non-blocking socket

This is a little tricky part, where I was facing problem. A typical blocking call on SSL will look like this:

int result = ::SSL_connect(pSSL);  // <0: failed, 0: disconnected, 0<: pass

Now, the natural non-blocking alternative, we may assume as:

::fcntl(socketfd, F_SETFL, m_fcntl);
::connect(socketfd, ...);
int result == ::SSL_connect(pSSL);
// put the FD_SET() etc.
result = select(...);
if(result == 0) ... // SSL timed out
else if(result < 0) ... // SSL error
else ... // success

However, it doesn't work as simple as that. SSL is a bit complicated process, where messages are exchanged back and forth. Hence, we have to run ::SSL_Connect() in a loop to capture SSL_want_read, SSL_want_write. In a simplistic manner, the code may look like this:

::fcntl(socketfd, F_SETFL, m_fcntl);
::connect(socketfd, ...);
int result; // looping for various handshakes & to/from messages
while((result = ::SSL_connect(pSSL)) < 0) {
// put the FD_SET() etc.
if(select(...) <= 0)
break;
}
if(result == 0) ... // SSL timed out
else if(result < 0) ... // SSL error
else ... // success

I was able to fix my SSL issue with above (pseudo) code.

This answer is based on useful comments & my findings.

How to get flags of opened fd in C?

You should use F_GETFL instead of F_GETFD. Also remember to print in octal to compare.

One important thing is not all flags are returned by fcntl. Only the access mode flags are remembered, like O_RDWR. However O_CREATE/O_TRUNC etc. are operating mode or open-time flags which are not remembered by the system and hence not returned.

Here is your modified code

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

#define XSZ(x) (int)(sizeof(x)*2)

int main()
{
int ret;
int fd = open("test.txt", O_RDWR | O_APPEND | O_CREAT, 0777);
if(fd < 0)
{
perror("open");
return -1;
}
printf("fd = %d\n", fd);
ret = fcntl(fd, F_GETFL);
perror("fcntl");
printf("flag:%o\n",ret);
printf("flag:%o\n",O_RDWR|O_APPEND);
write(fd, "hello c program\n", strlen("hello c program!\n"));

return 0;
}

here is the output of the above code

fd = 3
fcntl: Success
flag:102002
flag:2002

when is the arg for F_GETFL fcntl command required?

Look at the rest of the fcntl commands. Notice how some of them (F_DUPFD, F_SETFL, and others) tell you what the third arg is used for. You need to provide the third arg when using one of those. Not when using F_GETFL or F_GETFD.

In the SYNOPSIS you can see that the fcntl takes 2 args plus a ... which means the third arg can be omitted when it's not going to be used.

After doing some more research, I found that there are some old man pages (from around the time of the first APUE) in which the SYNOPSIS implies that all 3 arguments are required. Example: http://www.freebsd.org/cgi/man.cgi?query=fcntl&manpath=FreeBSD+2.2.7-RELEASE

SYNOPSIS
#include <fcntl.h>

int
fcntl(int fd, int cmd, int arg);

I can't find any evidence that it was ever actually declared that way in the header, but if it was, then compilation would fail when it was called with only 2 arguments. That would be a good reason to include the extra 0 argument in your code.

If my guess is correct and this is the actual reason for the historical use of 3-arg F_GETFL then it is a useless fossil from a time when function prototypes were new and scary and OS vendors were getting them wrong.

MACOSX (BSD) equivalent for F_NOTIFY flag for fcntl() function

There is no exact equivalent; kqueue()/kevent() with an EVFILT_VNODE event filter is the substitute on OS X.

Note that even in Linux, F_NOTIFY has been superceded by inotify.



Related Topics



Leave a reply



Submit