/*-------------------------------------------------------------------------*/ 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; } } }
/*=========================================================================*/ void SLPDIncomingHandler(int* fdcount, fd_set* readfds, fd_set* writefds) /* Handles all outgoing requests that are pending on the specified file */ /* discriptors */ /* */ /* fdcount (IN/OUT) number of file descriptors marked in fd_sets */ /* */ /* readfds (IN) file descriptors with pending read IO */ /* */ /* writefds (IN) file descriptors with pending read IO */ /*=========================================================================*/ { SLPDSocket* sock; sock = (SLPDSocket*) G_IncomingSocketList.head; while (sock && *fdcount) { if (FD_ISSET(sock->fd,readfds)) { switch (sock->state) { case SOCKET_LISTEN: IncomingSocketListen(&G_IncomingSocketList,sock); break; case DATAGRAM_UNICAST: case DATAGRAM_MULTICAST: case DATAGRAM_BROADCAST: IncomingDatagramRead(&G_IncomingSocketList,sock); break; case STREAM_READ: case STREAM_READ_FIRST: IncomingStreamRead(&G_IncomingSocketList,sock); break; default: break; } *fdcount = *fdcount - 1; } else if (FD_ISSET(sock->fd,writefds)) { switch (sock->state) { case STREAM_WRITE: case STREAM_WRITE_FIRST: IncomingStreamWrite(&G_IncomingSocketList,sock); break; default: break; } *fdcount = *fdcount - 1; } sock = (SLPDSocket*)sock->listitem.next; } }
/** Read inbound stream data. * * @param[in] socklist - The list of monitored sockets. * @param[in] sock - The socket to be read. * * @internal */ static void IncomingStreamRead(SLPList * socklist, SLPDSocket * sock) { int bytesread; size_t recvlen = 0; char peek[16]; socklen_t peeraddrlen = sizeof(struct sockaddr_storage); if (sock->state == STREAM_READ_FIRST) { /*---------------------------------------------------*/ /* take a peek at the packet to get size information */ /*---------------------------------------------------*/ bytesread = recvfrom(sock->fd, (char *)peek, 16, MSG_PEEK, (struct sockaddr *)&sock->peeraddr, &peeraddrlen); if (bytesread > 0 && bytesread >= (*peek == 2? 5: 4)) { recvlen = PEEK_LENGTH(peek); /* 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, (char *)sock->recvbuf->curpos, (int)(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) { if (!sock->sendbuf) /* Some of the error handling code expects a sendbuf to be available * to be emptied, so make sure there is at least a minimal buffer */ sock->sendbuf = SLPBufferAlloc(1); switch (SLPDProcessMessage(&sock->peeraddr, &sock->localaddr, sock->recvbuf, &sock->sendbuf, 0)) { case SLP_ERROR_PARSE_ERROR: case SLP_ERROR_VER_NOT_SUPPORTED: case SLP_ERROR_MESSAGE_NOT_SUPPORTED: sock->state = SOCKET_CLOSE; break; default: if (!sock->sendbuf || sock->sendbuf->end == sock->sendbuf->start) { /* no answer available, just close socket */ sock->state = SOCKET_CLOSE; break; } /* some clients cannot cope with the OVERFLOW * bit set on a TCP stream, so always clear it */ if (sock->sendbuf->end - sock->sendbuf->start > 5) { if (sock->sendbuf->start[0] == 1) sock->sendbuf->start[4] &= ~SLPv1_FLAG_OVERFLOW; else sock->sendbuf->start[5] &= ~(SLP_FLAG_OVERFLOW >> 8); } sock->state = STREAM_WRITE_FIRST; IncomingStreamWrite(socklist, sock); } } }