int receive_msg()

in src/generic/messages.c [322:435]


int receive_msg(Tcl_Channel f, int *command, int *flags, int *size,
		void **data)
{

    /* fd_set rfs;
       struct timeval timeout; */
    int ret, maxsize;
    u_long magic;
    u_long version;
    MsgHeader mh;

    /* timeout.tv_usec=0;
       timeout.tv_sec=WMSG_TIMEOUT; */
    magic = 0;
    if (*data == NULL) {
	maxsize = 0;
    }
    else {
	maxsize = *size;
    }
    /* read from socket until timeout or magic header word appears */
    while (magic != WMSG_MAGIC) {
	ret = Tcl_Read(f, (char *) &magic, sizeof(u_long));
	magic = ntohl(magic);
	if (ret == -1) {
#ifdef MSGDEBUG
	    printf("Error reading socket\n");
#endif
	    return (-1);	/* some error */
	}
	if (ret != sizeof(u_long)) {
#ifdef MSGDEBUG
	    printf("incomplete read or client disconnected\n");
#endif
	    errno = EIO;
	    return (-1);	/* incomplete read */
	}
    }
    /* get rest of message header */
    ret =
	Tcl_Read(f, (char *) &mh.version, sizeof(MsgHeader) - sizeof(u_long));
    if (ret == -1) {
#ifdef MSGDEBUG
	printf("Error reading socket\n");
#endif
	return (-1);		/* some error */
    }
    if (ret != sizeof(MsgHeader) - sizeof(u_long)) {
#ifdef MSGDEBUG
	printf("Incomplete header read: %d but expected %d\n", ret,
	       sizeof(MsgHeader) - sizeof(u_long));
#endif
	errno = EIO;
	return (-1);		/* incomplete read */
    }

    version = (int) ntohl(mh.version);
    if (version > WMSG_VERSION) {
#ifdef MSGDEBUG
	printf("Got unknown version %d\n", version);
#endif

#ifdef EPROTONOSUPPORT
        errno = EPROTONOSUPPORT;
#else
        errno = EIO;
#endif
	return (-1);		/* unknown version */
    }

    *command = (int) ntohl(mh.command);
    *flags = (*command & 0xffff0000);
    *command &= 0xffff;
    *size = (int) ntohl(mh.size);	/* +1 = zero terminate block */

    if (*data == NULL) {	/*alloc a buffer */
	*data = Tcl_Alloc(*size + 1);
	if (*data == NULL) {
	    errno = ENOMEM;
	    return (-1);	/* no more memory */
	}
	maxsize = *size + 1;
    }

    if ((*size + 1) > maxsize) {	/* problem: incoming msg larger than buffer */
#ifdef MSGDEBUG
	printf("Message larger than receive buffer, reallocating memory\n");
#endif
	*data = Tcl_Realloc(*data, *size + 1);
	if (*data == NULL) {
	    errno = ENOMEM;
	    return (-1);	/* no more memory */
	}
    }
    if ((*size) != 0) {
	ret = Tcl_Read(f, (char *) *data, (*size));
	if (ret == -1) {
#ifdef MSGDEBUG
	    printf("Error reading data section of message\n");
#endif
	    return (-1);
	}
	if (ret != *size) {
#ifdef MSGDEBUG
	    printf("Incomplete data read: expected %d got %d (%d)\n", *size, ret, Tcl_Eof(f));
#endif
	    errno = EIO;
	    return (-1);	/* incomplete read */
	}
    }
    /* zero terminate */
    ((char *) *data)[*size] = '\0';
    return (0);
}