/*-------------------------------------------------------------------------*/ int ParseHeader(SLPBuffer buffer, SLPHeader* header) /* */ /* Returns - Zero on success, SLP_ERROR_VER_NOT_SUPPORTED, or */ /* SLP_ERROR_PARSE_ERROR. */ /*-------------------------------------------------------------------------*/ { header->version = *(buffer->curpos); header->functionid = *(buffer->curpos + 1); header->length = AsUINT24(buffer->curpos + 2); header->flags = AsUINT16(buffer->curpos + 5); header->extoffset = AsUINT24(buffer->curpos + 7); header->xid = AsUINT16(buffer->curpos + 10); header->langtaglen = AsUINT16(buffer->curpos + 12); header->langtag = buffer->curpos + 14; if(header->version != 2) { return SLP_ERROR_VER_NOT_SUPPORTED; } if(header->functionid > SLP_FUNCT_SAADVERT) { /* invalid function id */ return SLP_ERROR_PARSE_ERROR; } if(header->length != buffer->end - buffer->start || header->length < 18) { /* invalid length 18 bytes is the smallest v2 message*/ return SLP_ERROR_PARSE_ERROR; } if(header->flags & 0x1fff) { /* invalid flags */ return SLP_ERROR_PARSE_ERROR; } buffer->curpos = buffer->curpos + header->langtaglen + 14; return 0; }
/*-------------------------------------------------------------------------*/ int ParseHeader(SLPBuffer buffer, SLPHeader* header) /* */ /* Returns - Zero on success, SLP_ERROR_VER_NOT_SUPPORTED, or */ /* SLP_ERROR_PARSE_ERROR. */ /*-------------------------------------------------------------------------*/ { header->version = *(buffer->curpos); header->functionid = *(buffer->curpos + 1); #if defined(ENABLE_SLPv1) if(header->version == 1) { return v1ParseHeader(buffer, header); } #endif if(header->version != 2) { return SLP_ERROR_VER_NOT_SUPPORTED; } header->length = AsUINT24(buffer->curpos + 2); header->flags = AsUINT16(buffer->curpos + 5); header->encoding = 0; /* not used for SLPv2 */ header->extoffset = AsUINT24(buffer->curpos + 7); header->xid = AsUINT16(buffer->curpos + 10); header->langtaglen = AsUINT16(buffer->curpos + 12); header->langtag = buffer->curpos + 14; /* check for invalid function id */ if(header->functionid > SLP_FUNCT_SAADVERT) { return SLP_ERROR_PARSE_ERROR; } /* check for invalid length 18 bytes is the smallest v2 message*/ if(header->length != buffer->end - buffer->start || header->length < 18) { return SLP_ERROR_PARSE_ERROR; } /* check for invalid flags */ if(header->flags & 0x1fff) { return SLP_ERROR_PARSE_ERROR; } buffer->curpos = buffer->curpos + header->langtaglen + 14; /* check for invalid langtaglen */ if((void*)(header->langtag + header->langtaglen) > (void*)buffer->end) { return SLP_ERROR_PARSE_ERROR; } /* check for invalid ext offset */ if(buffer->start + header->extoffset > buffer->end) { return SLP_ERROR_PARSE_ERROR; } return 0; }
/*-------------------------------------------------------------------------*/ void OutgoingStreamRead(SLPList* socklist, SLPDSocket* sock) /*-------------------------------------------------------------------------*/ { int bytesread; char peek[16]; int peeraddrlen = sizeof(struct sockaddr_in); if ( sock->state == STREAM_READ_FIRST ) { /*---------------------------------------------------*/ /* take a peek at the packet to get size information */ /*---------------------------------------------------*/ bytesread = recvfrom(sock->fd, peek, 16, MSG_PEEK, (struct sockaddr *)&(sock->peeraddr), &peeraddrlen); if ( bytesread > 0 ) { /* allocate the recvbuf big enough for the whole message */ sock->recvbuf = SLPBufferRealloc(sock->recvbuf,AsUINT24(peek+2)); if ( sock->recvbuf ) { sock->state = STREAM_READ; } else { SLPDLog("INTERNAL_ERROR - out of memory!\n"); sock->state = SOCKET_CLOSE; } } else { #ifdef WIN32 if ( WSAEWOULDBLOCK != WSAGetLastError() ) #else if ( errno != EWOULDBLOCK ) #endif { /* Error occured or connection was closed. Try to reconnect */ /* Socket will be closed if connect times out */ OutgoingStreamReconnect(socklist,sock); } } } if ( sock->state == STREAM_READ ) { /*------------------------------*/ /* recv the rest of the message */ /*------------------------------*/ bytesread = recv(sock->fd, sock->recvbuf->curpos, sock->recvbuf->end - sock->recvbuf->curpos, 0); if ( bytesread > 0 ) { /* reset age because of activity */ sock->age = 0; /* move buffer pointers */ sock->recvbuf->curpos += bytesread; /* check to see if everything was read */ if ( sock->recvbuf->curpos == sock->recvbuf->end ) { switch ( SLPDProcessMessage(&(sock->peeraddr), sock->recvbuf, &(sock->sendbuf)) ) { case SLP_ERROR_DA_BUSY_NOW: sock->state = STREAM_WRITE_WAIT; break; case SLP_ERROR_PARSE_ERROR: case SLP_ERROR_VER_NOT_SUPPORTED: sock->state = SOCKET_CLOSE; break; default: /* End of outgoing message exchange. Unlink */ /* send buf from to do list and free it */ SLPBufferFree((SLPBuffer)SLPListUnlink(&(sock->sendlist),(SLPListItem*)(sock->sendbuf))); sock->state = STREAM_WRITE_FIRST; /* clear the reconnection count since we actually * transmitted a successful message exchange */ sock->reconns = 0; break; } } } else { #ifdef WIN32 if ( WSAEWOULDBLOCK != WSAGetLastError() ) #else if ( errno != EWOULDBLOCK ) #endif { /* Error occured or connection was closed. Try to reconnect */ /* Socket will be closed if connect times out */ OutgoingStreamReconnect(socklist,sock); } } } }
/*-------------------------------------------------------------------------*/ void IncomingStreamRead(SLPList* socklist, SLPDSocket* sock) /*-------------------------------------------------------------------------*/ { int bytesread, recvlen = 0; char peek[16]; int peeraddrlen = sizeof(struct sockaddr_in); if (sock->state == STREAM_READ_FIRST) { /*---------------------------------------------------*/ /* take a peek at the packet to get size information */ /*---------------------------------------------------*/ bytesread = recvfrom(sock->fd, peek, 16, MSG_PEEK, (struct sockaddr *)&(sock->peeraddr), &peeraddrlen); if (bytesread > 0) { if (*peek == 2) recvlen = AsUINT24(peek + 2); else if (*peek == 1) /* SLPv1 packet */ recvlen = AsUINT16(peek + 2); /* allocate the recvbuf big enough for the whole message */ sock->recvbuf = SLPBufferRealloc(sock->recvbuf,recvlen); if (sock->recvbuf) { sock->state = STREAM_READ; } else { SLPDLog("INTERNAL_ERROR - out of memory!\n"); sock->state = SOCKET_CLOSE; } } else { sock->state = SOCKET_CLOSE; return; } } if (sock->state == STREAM_READ) { /*------------------------------*/ /* recv the rest of the message */ /*------------------------------*/ bytesread = recv(sock->fd, sock->recvbuf->curpos, sock->recvbuf->end - sock->recvbuf->curpos, 0); if (bytesread > 0) { /* reset age to max because of activity */ sock->age = 0; sock->recvbuf->curpos += bytesread; if (sock->recvbuf->curpos == sock->recvbuf->end) { switch (SLPDProcessMessage(&sock->peeraddr, sock->recvbuf, &(sock->sendbuf))) { case SLP_ERROR_PARSE_ERROR: case SLP_ERROR_VER_NOT_SUPPORTED: case SLP_ERROR_MESSAGE_NOT_SUPPORTED: sock->state = SOCKET_CLOSE; break; default: sock->state = STREAM_WRITE_FIRST; IncomingStreamWrite(socklist, sock); } } } else { /* error in recv() */ sock->state = SOCKET_CLOSE; } } }
/*=========================================================================*/ int SLPXcastRecvMessage(const SLPXcastSockets* sockets, SLPBuffer* buf, struct sockaddr_in* peeraddr, struct timeval* timeout) /* Description: �* � �Receives datagram messages from one of the sockets in the specified � �* � �SLPXcastsSockets structure �* � �* Parameters: �* � �sockets (IN) Pointer to the SOPXcastSockets structure that describes �* � � � � � � � � which sockets to read messages from. �* � �buf � � (OUT) Pointer to SLPBuffer that will contain the message upon �* � � � � � � � � �successful return. �* � �peeraddr (OUT) Pointer to struc sockaddr_in that will contain the �* � � � � � � � � � address of the peer that sent the received message. �* � �timeout (IN/OUT) pointer to the struct timeval that indicates how much �* � � � � � � � � � � time to wait for a message to arrive �* �* Returns: �* � �Zero on success, non-zero with errno set on failure. �*========================================================================*/ { fd_set readfds; int highfd; int i; int readable; size_t bytesread; int recvloop; int peeraddrlen = sizeof(struct sockaddr_in); char peek[16]; int result; /* recv loop */ recvloop = 1; while(recvloop) { /* Set the readfds */ FD_ZERO(&readfds); highfd = 0; for (i=0; i<sockets->sock_count; i++) { FD_SET(sockets->sock[i],&readfds); if(sockets->sock[i] > highfd) { highfd = sockets->sock[i]; } } /* Select */ readable = select(highfd + 1,&readfds,NULL,NULL,timeout); if(readable > 0) { /* Read the datagram */ for (i=0; i<sockets->sock_count; i++) { if(FD_ISSET(sockets->sock[i],&readfds)) { /* Peek at the first 16 bytes of the header */ bytesread = recvfrom(sockets->sock[i], peek, 16, MSG_PEEK, (struct sockaddr *)peeraddr, &peeraddrlen); if(bytesread == 16) { if(AsUINT24(peek + 2) <= SLP_MAX_DATAGRAM_SIZE) { *buf = SLPBufferRealloc(*buf, AsUINT24(peek + 2)); bytesread = recv(sockets->sock[i], (*buf)->curpos, (*buf)->end - (*buf)->curpos, 0); if(bytesread != AsUINT24(peek + 2)) { /* This should never happen but we'll be paranoid*/ (*buf)->end = (*buf)->curpos + bytesread; } /* Message read. We're done! */ result = 0; recvloop = 0; break; } else { /* we got a bad message, or one that is too big! */ } } else { /* Not even 16 bytes available */ } } } } else if(readable == 0) { result = -1; errno = ETIMEDOUT; recvloop = 0; } else { result = -1; recvloop = 0; } } return result; }
/*=========================================================================*/ int SLPNetworkRecvMessage(int sockfd, int socktype, SLPBuffer* buf, struct sockaddr_in* peeraddr, struct timeval* timeout) /* Receives a message */ /* */ /* Returns - zero on success, non-zero on failure */ /* */ /* errno ENOTCONN error during read */ /* ETIME read timed out */ /* ENOMEM out of memory */ /* EINVAL parse error */ /*=========================================================================*/ { int xferbytes; fd_set readfds; char peek[16]; int peeraddrlen = sizeof(struct sockaddr_in); /*---------------------------------------------------------------*/ /* take a peek at the packet to get version and size information */ /*---------------------------------------------------------------*/ FD_ZERO(&readfds); FD_SET(sockfd, &readfds); xferbytes = select(sockfd + 1, &readfds, 0 , 0, timeout); if(xferbytes > 0) { if(socktype == SOCK_DGRAM) { xferbytes = recvfrom(sockfd, peek, 16, MSG_PEEK, (struct sockaddr *)peeraddr, &peeraddrlen); } else { xferbytes = recv(sockfd, peek, 16, MSG_PEEK); } if(xferbytes <= 0) { #ifdef WIN32 if(WSAGetLastError() != WSAEMSGSIZE) { errno = ENOTCONN; return -1; } #else errno = ENOTCONN; return -1; #endif } } else if(xferbytes == 0) { errno = ETIMEDOUT; return -1; } else { errno = ENOTCONN; return -1; } /*------------------------------*/ /* Read the rest of the message */ /*------------------------------*/ /* check the version */ if(*peek == 2) { /* allocate the recvmsg big enough for the whole message */ *buf = SLPBufferRealloc(*buf, AsUINT24(peek + 2)); if(*buf) { while((*buf)->curpos < (*buf)->end) { FD_ZERO(&readfds); FD_SET(sockfd, &readfds); xferbytes = select(sockfd + 1, &readfds, 0 , 0, timeout); if(xferbytes > 0) { xferbytes = recv(sockfd, (*buf)->curpos, (*buf)->end - (*buf)->curpos, 0); if(xferbytes > 0) { (*buf)->curpos = (*buf)->curpos + xferbytes; } else { errno = ENOTCONN; return -1; } } else if(xferbytes == 0) { errno = ETIMEDOUT; return -1; } else { errno = ENOTCONN; return -1; } } /* end of main read while. */ } else { errno = ENOMEM; return -1; } } else { errno = EINVAL; return -1; } return 0; }
/*-------------------------------------------------------------------------*/ void HandleStreamRead(SLPDSocketList* list, SLPDSocket* sock) /*-------------------------------------------------------------------------*/ { int fdflags; int bytesread; char peek[16]; if(sock->state == STREAM_FIRST_READ) { fdflags = fcntl(sock->fd, F_GETFL, 0); fcntl(sock->fd,F_SETFL, fdflags | O_NONBLOCK); /*---------------------------------------------------------------*/ /* take a peek at the packet to get version and size information */ /*---------------------------------------------------------------*/ bytesread = recvfrom(sock->fd, peek, 16, MSG_PEEK, &(sock->peerinfo.peeraddr), &(sock->peerinfo.peeraddrlen)); if(bytesread > 0) { /* check the version */ if(*peek == 2) { /* allocate the recvbuf big enough for the whole message */ sock->recvbuf = SLPBufferRealloc(sock->recvbuf,AsUINT24(peek+2)); if(sock->recvbuf) { sock->state = STREAM_READ; } else { SLPLog("Slpd is out of memory!\n"); sock->state = SOCKET_CLOSE; } } else { SLPLog("Unsupported version %i received from %s\n", *peek, inet_ntoa(sock->peerinfo.peeraddr.sin_addr)); sock->state = SOCKET_CLOSE; } } else { if(errno != EWOULDBLOCK) { sock->state = SOCKET_CLOSE; return; } } /*------------------------------*/ /* recv the rest of the message */ /*------------------------------*/ bytesread = recv(sock->fd, sock->recvbuf->curpos, sock->recvbuf->end - sock->recvbuf->curpos, 0); if(bytesread > 0) { /*------------------------------*/ /* Reset the timestamp */ /*------------------------------*/ time(&(sock->timestamp)); sock->recvbuf->curpos += bytesread; if(sock->recvbuf->curpos == sock->recvbuf->end) { if(SLPDProcessMessage(&sock->peerinfo, sock->recvbuf, sock->sendbuf) == 0) { sock->state = STREAM_FIRST_WRITE; } else { /* An error has occured in SLPDProcessMessage() */ SLPLog("An error while processing message from %s\n", inet_ntoa(sock->peerinfo.peeraddr.sin_addr)); sock->state = SOCKET_CLOSE; } } } else { if(errno != EWOULDBLOCK) { /* error in recv() */ sock->state = SOCKET_CLOSE; } } } }
/*=========================================================================*/ SLPError NetworkRecvMessage(int sockfd, SLPBuffer buf, struct timeval* timeout, struct sockaddr* peeraddr, int* peeraddrlen) /* Receives a message */ /* */ /* Returns - SLP_OK, SLP_NETWORK_TIMEOUT, SLP_NETWORK_ERROR, or */ /* SLP_PARSE_ERROR. */ /*=========================================================================*/ { SLPError result = SLP_OK; int xferbytes; fd_set readfds; char peek[16]; /*---------------------------------------------------------------*/ /* take a peek at the packet to get version and size information */ /*---------------------------------------------------------------*/ FD_ZERO(&readfds); FD_SET(sockfd, &readfds); xferbytes = select(sockfd + 1, &readfds, 0 , 0, timeout); if(xferbytes > 0) { xferbytes = recvfrom(sockfd, peek, 16, MSG_PEEK, peeraddr, peeraddrlen); if(xferbytes <= 0) { result = SLP_NETWORK_ERROR; } } else if(xferbytes == 0) { result = SLP_NETWORK_TIMED_OUT; } else { result = SLP_NETWORK_ERROR; } /*---------------------------------------*/ /* return now if peek was not successful */ /*---------------------------------------*/ if(result) return result; /*------------------------------*/ /* Read the rest of the message */ /*------------------------------*/ /* check the version */ if(*peek == 2) { /* allocate the recvmsg big enough for the whole message */ if(SLPBufferRealloc(buf, AsUINT24(peek + 2))) { while(buf->curpos < buf->end) { FD_ZERO(&readfds); FD_SET(sockfd, &readfds); xferbytes = select(sockfd + 1, &readfds, 0 , 0, timeout); if(xferbytes > 0) { xferbytes = recv(sockfd, buf->curpos, buf->end - buf->curpos, 0); if(xferbytes > 0) { buf->curpos = buf->curpos + xferbytes; } else { result = SLP_NETWORK_ERROR; break; } } else if(xferbytes == 0) { result = SLP_NETWORK_TIMED_OUT; break; } else { result = SLP_NETWORK_ERROR; break; } } /* end of main read while. */ } else { result = SLP_MEMORY_ALLOC_FAILED; } } else { result = SLP_PARSE_ERROR; } return result; }