Re: select + stderr

From: Thomas Beneke (thomas.beneke_at_web.de)
Date: 01/21/05


Date: Fri, 21 Jan 2005 16:20:43 +0100

Jens.Toerring@physik.fu-berlin.de wrote:

> Thomas Beneke <thomas.beneke@web.de> wrote:
>
>>I have a client - server, but this works only for stdout.
>
>
> What works? What means stdout in the context of a server-client pair?
>
>
>> What do I have
>>to change . If I send a 'ls' to the server, I get the correct response
>>on the client side. If I send a 'ls /sdfdsfdlfsdl' ( a non existing
>>file), I get the error message on server side on stderr, but on client
>>side on stdout.
>
>
>>while (FD_ISSET(sockfd, &rfdset))
>
>
> I don't understand what this is good for - using the FD_ISSET macro
> only really makes sense *after* you called select().
>
>
>>{
>> if (select( fd+1 , &rfdset, NULL, NULL, NULL) < 0) {
>> if (errno != EINTR) {
>> fprintf(stderr,"select failed\n");
>> exit(1);
>> }
>> }
>> if (FD_ISSET(sockfd, &rfdset)) {
>> if ( (numbytes = recv(sockfd, buffer, sizeof(buf), MSG_WAITALL))
>>< 0 )
>
>
> Are you sure the MSG_WAITALL is appropriate here? What is supposd to
> happen when the message sent by the server is less than sizeof(buf)
> bytes?
>
>
>> {
>> fprintf(stderr,"recv failed.\n");
>> exit(1);
>> }
>> if ( numbytes ) {
>> if ( (write(STDOUT_FILENO, buffer, numbytes)) <0) {
>> fprintf(stderr,"send stdout failed\n");
>> exit(1);
>> }
>> }
>> else if (numbytes == 0 || errno != EWOULDBLOCK)
>
>
> If recv() didn't return -1 the value of errno doesn't tell you anything,
> you are never supposed to do anything with errno's value unless an error
> happened. If you feel like checking for EWOULDBLOCK (BTW, it could also
> be EAGAIN according to SUSv3) you need to do that further up where you
> check 'numbytes' for a negative value.
>
>
>> FD_CLR(sockfd, &rfdset);
>
>
> If you call select() with a cleared fdset you tell it to wait for *no*
> file descriptors to become ready for reading. I guess you do that because
> of the bogus while loop condition at the start. You better make the while
> loop an infinite loop (i.e. use "while(1)" and break from it once you find
> that you recv() returned 0 (telling you that the other side closed the
> socket).
>
>
>> }
>
>
> Before you call select() again you must set up the fdset anew - other-
> wise the case that select() did return -1 with errno being set to EINTR
> won't be dealt with correctly (or if you're dealing with more than a
> single file descriptor you call select() on).
>
>
>> }
>
>
> If I guess correctly that you want to have your client send a shell
> command to the server, have the server execute it by fork()ing and
> exec()ing a shell and send back both what the server received from
> both the stdout and stderr of the shell it spawned separately, then
> you need two logical channels between the server and the client -
> one for sending back the result from stdout and one for sending what
> appeared on stderr. For that you need either two sockets or you must
> develop some kind of protocol that allows the client to figure out
> what was what. There's nothing magical about stdout and stderr, they
> are just two different file descriptor - and when you have the server
> send what it read from both these channels intermixed via a single
> channel to the client, the client won't be able to untangle them.
>
> The simplest solution is probably to open two sockets and have the
> server write what it got from the stdout of the shell via one of the
> sockets and what it read from stderr of the shell to the other one.
> The client then listens on both these sockets, writing out what it
> receives from the first one to its stdout and what it receives from
> the second one to its stderr.
> Regards, Jens
>
> PS: I hope you're aware of the security implications of such a server
> running on your machine and have access to that server secured by a
> password (which you better don't send unencrypted over the net!).

Thank you for your reply. I've changed the select() block in my client.
Now I've added on client a second socket()

errfd = socket(AF_INET, SOCK_STREAM, 0)

a second connect()

connect(errfd, (struct sockaddr *)&server, sizeof(struct sockaddr))

and a FD_ISSET for errfd

if (FD_ISSET(errfd, &rfdset)) {
    if ( (numbytes = read(errfd, buffer, sizeof(buf))) <= 0 )
.

On my server i've added a second getpeername()

getpeername(err_fd, (struct sockaddr *)&client, &client_len)

the pipe(), fork() and exec()

if (pipe(pipe_out) == -1 || pipe(pipe_err) == -1 )
    exit;

   switch (fork()) {
         case -1:
                 fprintf(stderr, "fork failed.\n");
                 _exit(1);

         case 0:
                 /* child */

                  /* stdout. */
                 close(pipe_out[0]);
                 if (dup2(pipe_out[1], 1) == -1)
                    fprintf(stderr, "aasapd: dup2(pipe_out).\n");
                 close(pipe_out[1]);

                 /* stderr. */
                 close(pipe_err[0]);
                 if (dup2(pipe_err[1], 2) == -1)
                    fprintf(stderr, "aasapd: dup2(pipe_err).\n");
                 close(pipe_err[1]);

                 execl("/bin/sh", "sh", "-c", buffer, (char *) 0);
                 _exit(1);
         default:
         default:
                 /* parent */
         close(pipe_out[1]);
         close(pipe_err[1]);
   }

/* only for test */
  numbytes = read(pipe_err[0], buffer, sizeof(buf));
   write(err_fd, buffer, numbytes);
  numbytes = read(pipe_out[0], buffer, sizeof(buf));
   write(client_fd, buffer, numbytes);

The Problem now is that both outputs using stdin on my client. Why ?

Thanks,
Thomas



Relevant Pages

  • Reidrect stderr of child process
    ... I have inherited the maintenance of a client app and the associated server. ... Simply, the server waits for the client to trigger it; ... Save current STDERR, to be restored later. ...
    (microsoft.public.win32.programmer.networks)
  • Re: How to display binary file contents if it is stored in an integer array?
    ... a file to the server, then the server should display the content of ... What do you expect to display on stdout? ...
    (comp.lang.c)
  • Re: select + stderr
    ... > I have a client - server, but this works only for stdout. ... > file), I get the error message on server side on stderr, but on client ...
    (comp.unix.programmer)
  • Re: [QUIZ] Space Merchant (#71)
    ... Could you have the client pass you $stdout and $stdin, ... station (which causes the server to wait for input!) :-( ...
    (comp.lang.ruby)
  • Re: Writting a UDP server program under inetd/xinetd
    ... >> message to server, but server cannot send response by simply printf the ... >> message to stdout. ... >'printf' because it doesn't give you appropriate control. ... to opinions held by my employer, Sun Microsystems. ...
    (comp.unix.programmer)