out-of-band message causing read on socket to be corrupted.

out-of-band message causing read on socket to be corrupted.

Post by Audrey Won » Thu, 12 Apr 2001 04:00:08



This is my problem:

My server program is continually sending the client a whole lot of
messages.

The client sends the server an MSG_OOB(out-of-band) message, goes to
sleeps in a loop and waits for the server to reply.  

The server's reply to this message will raise the signal SIGURG, which
wakes up the client.

The client then proceeds to read the reply and continues to process the
rest of the messages. But the messages that it reads after that are all
corrupted.

Does anyone know why this is?  This only happens on linux (2.2.16, 2.2.17,
2.4.1) but not irix or suns.

thanks
audrey

ps: i've enclosed my simple test case below.
-----------------------------------
/* client.c */

#include "tcpDefs.h"

static void
sigUrgHandler(int sig)
{
    fprintf(stderr, " \n!!!sigUrgHandler!!!!\n");
    signal(SIGURG, sigUrgHandler);

}

static int
getOOBReply( int sd ) {

    int rv;
    char msg;

    fprintf(stderr, " -> getOOBReply! ");
    for (;;) {

        rv = recv( sd, &msg, sizeof( msg ), MSG_OOB );
        fprintf(stderr, ".");
        if (rv == sizeof(msg)) {
            fprintf(stderr, " rv= %d \n", rv);
            return msg;
        }
        sleep(1);
    }

}

void sendOOBMsg(int sd) {

    fprintf(stderr, " -> SendOOBMsg \n");
    if (!SendMsg( sd, CP_EH_DELETEQ ))
        return;
    getOOBReply(sd);

}

void getNextMsg(int sd) {

    int cnt=0;
    int br, rr, flag;
    CpMsg msg;
    fd_set fdset;
    struct timeval timeout;

    fprintf(stderr, " ------ GetNextMsg! ------ \n");
    for (;;) {

        FD_ZERO(&fdset);
        FD_SET(sd, &fdset);
        timeout.tv_sec = 0;
        timeout.tv_usec = 0;

        /* see if there are any events to read. */
        flag = select(sd+1, &fdset, 0, 0, &timeout);
        if (flag <= 0)
            continue; /* no events to read, sorry. */

        if (ReadMsg(sd, &msg)) {
            fprintf(stderr, " Msg= (%s %c)\n", PrintMsgId(msg.id), msg.data);

            if (msg.id == CP_EH_LUXO_DONE) {
                fprintf(stderr, " quitting!\n");
                return;
            }

            if (msg.id == CP_EH_HELLO) {
                SendMsg(sd, CP_EH_HELLO);
                continue;
            }
            cnt++;
            if ( cnt >= 5)
                sendOOBMsg(sd);
        }
    }

}

int main (int argc, char *argv[]) {

    struct sockaddr_in localAddr, servAddr;    
    struct utsname host;
    struct hostent *hp;

    int one = 1;
    int p_proto;

    int sd, rc, i, pid;

    hp = gethostbyname(argv[1]);
    if(hp==NULL) {
        printf("%s: unknown host'\n");
        return -1;
    } else
        fprintf(stderr, " Host= %s\n", argv[1]);

    /* create socket */
    sd = socket(AF_INET, SOCK_STREAM, 0);
    if(sd<0) {
        perror("cannot open socket ");
        return -1;
    } else
        fprintf(stderr, " creating socket! sd=%d\n", sd);

    /* bind any port number */
    memset((caddr_t) &localAddr, 0, sizeof(localAddr));
    localAddr.sin_family = AF_INET;
    localAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    localAddr.sin_port = htons(0);

    rc = bind(sd, (struct sockaddr *) &localAddr, sizeof(localAddr));
    if(rc<0) {
        fprintf(stderr, "%s: cannot bind port TCP \n");
        exit(1);
    }

    servAddr.sin_port = htons(CP_EH_PORT);
    servAddr.sin_family = hp->h_addrtype;
    memcpy((char *) &servAddr.sin_addr.s_addr, hp->h_addr_list[0], hp->h_length);

    /* connect to server */
    rc = connect(sd, (struct sockaddr *) &servAddr, sizeof(servAddr));
    if(rc<0) {
        fprintf(stderr, "cannot connect ");
        return -1;
    }

    p_proto = getprotobyname("tcp")->p_proto;
    if ( setsockopt( sd, p_proto, TCP_NODELAY, (char *)&one, sizeof(one) )
         < 0 ) {
        fprintf(stderr, "cannot setsockopt\n");
        return -1;
    }

    pid = getpid();
    if ( fcntl(sd, F_SETOWN, pid) < 0)
        fprintf(stderr, " fcntl didnt succeed\n");

    signal( SIGURG, sigUrgHandler);

    usleep(900);
    getNextMsg(sd);

    return 0;

}

---------------------------
/* server.c */

#include "tcpDefs.h"

int client_fd = -1;

int ProcessMsg( int fd, CpMsg *msg) {
    int i;
    char rv = 1;
    switch (msg->id) {
    case CP_EH_LUXO_DONE:
        fprintf(stderr, " quitting!\n");
        return -1;
    case CP_EH_HELLO: {
        fprintf(stderr, "Sending 10 messg!\n");
        for (i=0; i<20; i++) {
          SendMsg(fd, CP_EH_SEND_EVENT);
        }
        break; }
    case CP_EH_DELETEQ:
        fprintf(stderr, " sending client OOB message!\n");
        send(fd, &rv, sizeof(rv), MSG_OOB);
        break;
    }
        return 1;

}

static void Quit() {
        fprintf(stderr, " .. quiting .. \n");
        SendMsg(client_fd, CP_EH_LUXO_DONE);
        exit(1);

}

int main (int argc, char *argv[]) {

    CpMsg msg;
    int i, sd, newSd, cliLen, flag;
    int hiFd;
    fd_set fdset, readfdset;
    struct timeval timeout;
    struct sockaddr_in cliAddr, servAddr;

    /* create socket */
    sd = socket(AF_INET, SOCK_STREAM, 0);
    if(sd<0) {
        perror("cannot open socket ");
        return -1;
    }
        hiFd = sd;
    /* bind server port */
    servAddr.sin_family = AF_INET;
    servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servAddr.sin_port = htons(CP_EH_PORT);

    if(bind(sd, (struct sockaddr *) &servAddr, sizeof(servAddr))<0) {
        perror("cannot bind port ");
        return -1;
    }

    listen(sd,5);

    printf("waiting for data on port TCP %u\n",CP_EH_PORT);
    signal(SIGQUIT, Quit);

    cliLen = sizeof(cliAddr);
        newSd = accept(sd, (struct sockaddr *) &cliAddr, &cliLen);
        if(newSd<0) {
            perror("cannot accept connection ");
            return -1;
        } else {
                fprintf(stderr, " NewConnection %d\n", newSd);
                client_fd = newSd;
                SendMsg(client_fd, CP_EH_HELLO);
                if (newSd > hiFd)
                    hiFd = newSd;
        }

        FD_ZERO(&readfdset);
        FD_SET(client_fd, &readfdset);

    while (1) {
        timeout.tv_sec = 0;
        timeout.tv_usec = 0;

        /* see if there are any events to read. */
        fdset = readfdset;
        flag = select(hiFd+1, &fdset, 0, 0, &timeout);
        if (flag <= 0)
                continue;

        if (FD_ISSET(client_fd, &fdset) && ReadMsg(client_fd, &msg)) {
              if ( ProcessMsg(client_fd, &msg) == -1)
                break;
        }
    } /* while (1) */

}

-----------------------------
/* tcpDefs.h  */

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/utsname.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include <sys/file.h>
#include <string.h>
#include <netinet/in.h>
#include <netdb.h>
#include <fcntl.h>
#include <errno.h>

#define CP_EH_PORT 7012
#define MAX_MSG 100
#define MSGSIZE 8

typedef enum CpMsgId {
    CP_EH_HELLO,        
    CP_EH_EXPRESS_INTEREST,    
    CP_EH_REVOKE_INTEREST,
    CP_EH_SEND_EVENT,  
    CP_EH_POLL,
    CP_EH_CURSORON,    
    CP_EH_CURSOROFF,
    CP_EH_SETCURSOR,
    CP_EH_SETTABMAP,
    CP_EH_PRINTINTERESTS,      
    CP_EH_GETTABMAP,    
    CP_EH_REGISTER,
    CP_EH_DEREGISTER,  
    CP_EH_DELETEQ,
    CP_EH_DIE,  
    CP_EH_PRINTRESOURCES,      
    CP_EH_SAVE_CANVAS,  
    CP_EH_GET_CANVASES,
    CP_EH_EVENT,
    CP_EH_GOOD_STATUS,  
    CP_EH_BAD_STATUS,  
    CP_EH_GETTABMAP_REPLY,
    CP_EH_PRINT_REPLY,    
    CP_EH_GRAB,        
    CP_EH_UNGRAB,      
    CP_EH_READ_CANVAS,  
    CP_EH_FREE_TEXTURE,  
    CP_EH_LUXO_DONE  

} CpMsgId;

typedef struct {
    CpMsgId id;
    char data;

} CpMsg;

int ReadMsg(int sd, CpMsg *msg) {
    int br, rr;
    char *p = (char*) msg;

    br =0;
    fprintf(stderr, " reading msg: %d:", sd);
    while ( br < MSGSIZE ) {
        rr = read(sd, p, MSGSIZE);
        if (rr < 0) {
            fprintf(stderr, " no mesg read!\n");
            return -1;
        }
        fprintf(stderr, "%d.", rr);
        br += rr;
        p += rr;
    }
    fprintf(stderr, "\n");
    return 1;

}

char* PrintMsgId(int msgId) {
    switch(msgId)  {
    case CP_EH_HELLO:
        return "CP_EH_HELLO";
    case CP_EH_SEND_EVENT:
        return "CP_EH_SEND_EVENT";
    case CP_EH_DELETEQ:
        return "CP_EH_DELETEQ";
    case CP_EH_LUXO_DONE:
        return "CP_EH_LUXO_DONE";
    default:
        fprintf(stderr, "unknown msg id %d", msgId);
        return "Unknown";    
    }

}

int SendMsg(int sd, int msgId) {

    CpMsg msg;
    int bw=0, wr;
    char *p;

    msg.id = msgId;
    msg.data = 'k';

    p = (char*)&msg;

    fprintf(stderr, " sending msg (%s,%c) to %d: ",
                PrintMsgId(msgId), msg.data, sd);
    while (bw < sizeof(CpMsg)) {
        wr = write(sd, p, sizeof(msg) -bw);
        fprintf(stderr, ".%d.", wr);
        if (wr < 0) {
            fprintf(stderr, " write error! \n");
            return 0;
        }
        bw += wr;
        p += wr;
    }
    fprintf(stderr, "\n");
    return 1;

}

------------

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

 
 
 

1. Out-of-band data on sockets - how to detect "true" exceptions ?

Hello,

I have a question regarding the use of "select" system call to detect
the exception condition caused by arrival of "out-of-band" data.
I am running into the following problem (item 4 below describes the
actual problem)

(1) A signal handler is associated with the SIGURG signal. Thus,
    when an out-of-band data arrives, the signal handler is called.
    The signal handler uses the "select" system call to determine
    which sockets have exception conditions. It reads an out-of-band
    byte on each socket that has the exception.
    (using recv(fd, &data, 1, MSG_OOB))
(2) process A and B both send one byte of out-of-band data
    to process C (using send(fd, &data, 1, MSG_OOB)).
(3) The out-of-band data from A arrives first and causes
    the signal handler to be called.
    The socket (say, Sa) connecting C and A is detected to have
    an exception. The signal handler reads a byte (out-of-order)
    from that socket. No exception is detected on the socket
    (say Sb) connecting B and C.

(4) The signal handler is called again when the out-of-band data
    arrives from B to process C.
    There cannot be any pending out-of-order data from A on socket Sa.
    However, when "select" is called, it indicates that BOTH
    sockets Sa and Sb have an exception condition.
    An attempt to recv(fd, &data, 1, MSG_OOB) on socket Sa returns
    error EINVAL (as there is no out-of-band data on that socket).

Should socket Sa show an exception condition when the out-of-band
data has already been read ?
Or, do I have to do something to "clear" the exception condition
after the out-of-band data is read ?

I would appreciate your reply. Please send your reply

- nitin vaidya

2. How to setup the DNS server?

3. BSD Sockets and Out-of-Band data

4. Linux Reboot Problem

5. select & out-of-band socket data

6. IPMasq and FTP Ports?

7. HELP with Sockets using OOB data (Out-Of-Band)

8. PAS16 Mixer + RedHat 6.1

9. socket out-of-band data

10. sockets and out-of-band data

11. out-of-band data on tcp-sockets

12. Disable out-of-band message

13. Need help with out of band messaging on socket