Code Comments
Programming Forum and web based access to our favorite programming groups.Hello again comp.unix.programmer folks :). I have been reading UNIX Network Programming, Volume 1, Second Edition: Networking APIs: Sockets and XTI, Prentice Hall, 1998, ISBN 0-13-490012-X. <http://www.kohala.com/start/unpv12e.html> In figure 16.3 the author has the following implementation of a function called str_cli() which takes two arguments, a socket descriptor and a file stream. Because of the functions length, I'll just describe what I *think* (because I'm not sure if I'm correct, thus why asking here) it does wrong here. The code in question is in nonblock/strclinonb.c, which you'll find in <http://www.kohala.com/start/unpv12e/unpv12e.tar.gz> (226K) It reads from the file stream and then writes to the socket descriptor using FD_SET and select(). When the function encounters EOF in the stream, it sends a FIN with shutdown() SHUT_WR, and keeps reading from the socket until bytes read <= 0. It also uses some sort of buffering: If data is available to be read from the stream, but the socket is not ready to be sent data, it reads the data and adds it to the buffer. The problem(s) are: 1) The way it uses the buffering looks like this n = read(fd, bufptr, &buf[MAXLINE] - bufptr); bufptr is a pointer to buf + the bytes already read. (it gets reset to bufptr = buf when the bytes are sent to the socket) Now, the code performs the following checks after that if(n == -1) /* error unless errno == EWOULDBLOCK */ else if(n == 0) /* EOF */ else /* other stuff */ Now, n being 0 does not certainly mean the stream has reached EOF. It could be that the buffer is full and &buf[MAXLINE] - bufptr equals 0. read() when the third argument is 0 does nothing and returns 0. 2) The code doesn't even use the stream. Instead it uses STDIN_FILENO, and the stream is not used at all! I'd like to know what you think, and please if I'm blatantly incorrect, don't flame much :).
Post Follow-up to this message> The problem(s) are: > > 1) The way it uses the buffering looks like this > n = read(fd, bufptr, &buf[MAXLINE] - bufptr); > bufptr is a pointer to buf + the bytes already read. (it gets reset to > bufptr = buf when the bytes are sent to the socket) > Now, the code performs the following checks after that > if(n == -1) /* error unless errno == EWOULDBLOCK */ > else if(n == 0) /* EOF */ > else /* other stuff */ > Now, n being 0 does not certainly mean the stream has reached EOF. It > could be that the buffer is full and &buf[MAXLINE] - bufptr equals 0. > read() when the third argument is 0 does nothing and returns 0. Can you quote the code you are talking about please ? So far the for(;;) seems ok to me since bufptr == &buf[MAXLINE] will never happen. The read is done only if it is part of the reading set. And the fd is added to the set only if there is room in the buffer. I may be wrong though, but since you did not quote any code ... ;-) cheers, -- paulo
Post Follow-up to this messageOn Mar 24, 4:00 pm, ppi <vod...@gmail.com> wrote:
>
>
> Can you quote the code you are talking about please ?
Sure,
-- strclinonb.c --
/* include nonb1 */
#include "unp.h"
void str_cli(FILE * fp, int sockfd)
{
int maxfdp1, val, stdineof;
ssize_t n, nwritten;
fd_set rset, wset;
char to[MAXLINE], fr[MAXLINE];
char *toiptr, *tooptr, *friptr, *froptr;
val = Fcntl(sockfd, F_GETFL, 0);
Fcntl(sockfd, F_SETFL, val | O_NONBLOCK);
val = Fcntl(STDIN_FILENO, F_GETFL, 0);
Fcntl(STDIN_FILENO, F_SETFL, val | O_NONBLOCK);
val = Fcntl(STDOUT_FILENO, F_GETFL, 0);
Fcntl(STDOUT_FILENO, F_SETFL, val | O_NONBLOCK);
toiptr = tooptr = to; /* initialize buffer pointers */
friptr = froptr = fr;
stdineof = 0;
maxfdp1 = max(max(STDIN_FILENO, STDOUT_FILENO), sockfd) + 1;
for (;;) {
FD_ZERO(&rset);
FD_ZERO(&wset);
if (stdineof == 0 && toiptr < &to[MAXLINE])
FD_SET(STDIN_FILENO, &rset); /* read from stdin */
if (friptr < &fr[MAXLINE])
FD_SET(sockfd, &rset); /* read from socket */
if (tooptr != toiptr)
FD_SET(sockfd, &wset); /* data to write to socket */
if (froptr != friptr)
FD_SET(STDOUT_FILENO, &wset); /* data to write to stdout */
Select(maxfdp1, &rset, &wset, NULL, NULL);
/* end nonb1 */
/* include nonb2 */
if (FD_ISSET(STDIN_FILENO, &rset)) {
if ((n =
read(STDIN_FILENO, toiptr, &to[MAXLINE] - toiptr)) < 0) {
if (errno != EWOULDBLOCK)
err_sys("read error on stdin");
} else if (n == 0) {
#ifdef VOL2
fprintf(stderr, "%s: EOF on stdin\n", gf_time());
#endif
stdineof = 1; /* all done with stdin */
if (tooptr == to)
Shutdown(sockfd, SHUT_WR); /* send FIN */
} else {
#ifdef VOL2
fprintf(stderr, "%s: read %d bytes from stdin\n",
gf_time(), n);
#endif
toiptr += n; /* # just read */
FD_SET(sockfd, &wset); /* try and write to socket below */
}
}
if (FD_ISSET(sockfd, &rset)) {
if ((n = read(sockfd, friptr, &fr[MAXLINE] - friptr)) < 0) {
if (errno != EWOULDBLOCK)
err_sys("read error on socket");
} else if (n == 0) {
#ifdef VOL2
fprintf(stderr, "%s: EOF on socket\n", gf_time());
#endif
if (stdineof)
return; /* normal termination */
else
err_quit("str_cli: server terminated prematurely");
} else {
#ifdef VOL2
fprintf(stderr, "%s: read %d bytes from socket\n",
gf_time(), n);
#endif
friptr += n; /* # just read */
FD_SET(STDOUT_FILENO, &wset); /* try and write below */
}
}
/* end nonb2 */
/* include nonb3 */
if (FD_ISSET(STDOUT_FILENO, &wset) && ((n = friptr - froptr) > 0)) {
if ((nwritten = write(STDOUT_FILENO, froptr, n)) < 0) {
if (errno != EWOULDBLOCK)
err_sys("write error to stdout");
} else {
#ifdef VOL2
fprintf(stderr, "%s: wrote %d bytes to stdout\n",
gf_time(), nwritten);
#endif
froptr += nwritten; /* # just written */
if (froptr == friptr)
froptr = friptr = fr; /* back to beginning of buffer */
}
}
if (FD_ISSET(sockfd, &wset) && ((n = toiptr - tooptr) > 0)) {
if ((nwritten = write(sockfd, tooptr, n)) < 0) {
if (errno != EWOULDBLOCK)
err_sys("write error to socket");
} else {
#ifdef VOL2
fprintf(stderr, "%s: wrote %d bytes to socket\n",
gf_time(), nwritten);
#endif
tooptr += nwritten; /* # just written */
if (tooptr == toiptr) {
toiptr = tooptr = to; /* back to beginning of buffer */
if (stdineof)
Shutdown(sockfd, SHUT_WR); /* send FIN */
}
}
}
}
}
/* end nonb3 */
-- strclinonb.c --
<snip>
Post Follow-up to this message> FD_ZERO(&rset); > FD_ZERO(&wset); > if (stdineof == 0 && toiptr < &to[MAXLINE]) > FD_SET(STDIN_FILENO, &rset); /* read from stdin */ > if (friptr < &fr[MAXLINE]) > FD_SET(sockfd, &rset); /* read from socket */ > if (tooptr != toiptr) > FD_SET(sockfd, &wset); /* data to write to socket */ > if (froptr != friptr) > FD_SET(STDOUT_FILENO, &wset); /* data to write to stdout */ Thanks for posting the code. So yes, &buff[MAXLINE] will never be equal to buffptr in the read() call. The STDIN_FILENO and sockfd fds are not inserted in the list of fds to be checked for incoming data i.e. buffer is full hence the reading from these streams is delayed until the buffptr is updated i.e. some data is sent. So yes, 0 returned by read is really end of file. cheers, -- paulo
Post Follow-up to this messageOn Mar 24, 5:44 pm, ppi <vod...@gmail.com> wrote: > > Thanks for posting the code. > So yes, &buff[MAXLINE] will never be equal to buffptr in the read() > call. > The STDIN_FILENO and sockfd fds are not inserted in the list of fds to > be checked for incoming data i.e. buffer is full hence the reading > from these streams is delayed until the buffptr is updated i.e. some > data is sent. > > So yes, 0 returned by read is really end of file. Ah yes, now I see it too, thanks a lot.
Post Follow-up to this message
Show a Printable Version
Email This Page to Someone!
Receive updates to this thread
Powered by vBulletin
Copyright 2000-2006 Jelsoft Enterprises Limited.