/** Read a datagram from an outbound socket. * * @param[in] socklist - The list of sockets being monitored. * @param[in] sock - The socket to be read from. */ void OutgoingDatagramRead(SLPList * socklist, SLPDSocket * sock) { int bytesread; socklen_t peeraddrlen = sizeof(struct sockaddr_storage); (void)socklist; bytesread = recvfrom(sock->fd, (char*)sock->recvbuf->start, G_SlpdProperty.MTU, 0, (struct sockaddr *)&sock->peeraddr, &peeraddrlen); if (bytesread > 0) { sock->recvbuf->end = sock->recvbuf->start + bytesread; 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); SLPDProcessMessage(&sock->peeraddr, &sock->localaddr, sock->recvbuf, &sock->sendbuf, &sock->sendlist); /* Completely ignore the message */ } }
/*-------------------------------------------------------------------------*/ void IncomingDatagramRead(SLPList* socklist, SLPDSocket* sock) /*-------------------------------------------------------------------------*/ { int bytesread; int bytestowrite; int byteswritten; int peeraddrlen = sizeof(struct sockaddr_in); bytesread = recvfrom(sock->fd, sock->recvbuf->start, SLP_MAX_DATAGRAM_SIZE, 0, (struct sockaddr *) &(sock->peeraddr), &peeraddrlen); if (bytesread > 0) { sock->recvbuf->end = sock->recvbuf->start + bytesread; 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: break; default: /* check to see if we should send anything */ bytestowrite = sock->sendbuf->end - sock->sendbuf->start; if (bytestowrite > 0) { byteswritten = sendto(sock->fd, sock->sendbuf->start, bytestowrite, 0, (struct sockaddr *)&(sock->peeraddr), sizeof(struct sockaddr_in)); if (byteswritten != bytestowrite) { SLPDLog("NETWORK_ERROR - %d replying %s\n", errno, inet_ntoa(sock->peeraddr.sin_addr)); } } } } }
/*-------------------------------------------------------------------------*/ void HandleDatagramRead(SLPDSocketList* list, SLPDSocket* sock) /*-------------------------------------------------------------------------*/ { int bytesread; int bytestowrite; bytesread = recvfrom(sock->fd, sock->recvbuf->start, SLP_MAX_DATAGRAM_SIZE, 0, &(sock->peerinfo.peeraddr), &(sock->peerinfo.peeraddrlen)); if(bytesread > 0) { sock->recvbuf->end = sock->recvbuf->start + bytesread; if(SLPDProcessMessage(&(sock->peerinfo), sock->recvbuf, sock->sendbuf) == 0) { /* check to see if we should send anything */ bytestowrite = sock->sendbuf->end - sock->sendbuf->start; if(bytestowrite > 0) { sendto(sock->fd, sock->sendbuf->start, sock->sendbuf->end - sock->sendbuf->start, 0, &(sock->peerinfo.peeraddr), sock->peerinfo.peeraddrlen); } } else { SLPLog("An error occured while processing message from %s\n", inet_ntoa(sock->peerinfo.peeraddr.sin_addr)); } } }
/*-------------------------------------------------------------------------*/ void OutgoingDatagramRead(SLPList* socklist, SLPDSocket* sock) /*-------------------------------------------------------------------------*/ { int bytesread; int peeraddrlen = sizeof(struct sockaddr_in); bytesread = recvfrom(sock->fd, sock->recvbuf->start, SLP_MAX_DATAGRAM_SIZE, 0, (struct sockaddr *) &(sock->peeraddr), &peeraddrlen); if ( bytesread > 0 ) { sock->recvbuf->end = sock->recvbuf->start + bytesread; SLPDProcessMessage(&(sock->peeraddr), sock->recvbuf, &(sock->sendbuf)); /* Completely ignore the message */ } }
/*-------------------------------------------------------------------------*/ 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; } } }
/*-------------------------------------------------------------------------*/ 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; } } } }
/** Read an inbound datagram. * * @param[in] socklist - The list of monitored sockets. * @param[in] sock - The socket to be read. * * @internal */ static void IncomingDatagramRead(SLPList * socklist, SLPDSocket * sock) { int bytesread; int byteswritten; socklen_t peeraddrlen = sizeof(struct sockaddr_storage); char addr_str[INET6_ADDRSTRLEN]; sockfd_t sendsock = SLP_INVALID_SOCKET; (void)socklist; bytesread = recvfrom(sock->fd, (char*)sock->recvbuf->start, G_SlpdProperty.MTU, 0, (struct sockaddr *)&sock->peeraddr, &peeraddrlen); if (bytesread > 0) { sock->recvbuf->end = sock->recvbuf->start + bytesread; 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: break; default: #ifdef DARWIN /* If the socket is a multicast socket, find the designated UDP output socket for sending */ if (sock->state == DATAGRAM_MULTICAST) if ((sendsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) != SLP_INVALID_SOCKET) SLPNetworkSetSndRcvBuf(sendsock); #endif if (sendsock == SLP_INVALID_SOCKET) sendsock = sock->fd; /* check to see if we should send anything, breaking up individual packets in the buffer into different sendto calls (should only be an issue with the loopback DA response)*/ if (sock->sendbuf) { sock->sendbuf->curpos = sock->sendbuf->start; while (sock->sendbuf->curpos < sock->sendbuf->end) { int packetbytes = AS_UINT24(sock->sendbuf->curpos + 2); byteswritten = sendto(sendsock, (char*)sock->sendbuf->curpos, packetbytes, 0, (struct sockaddr *)&sock->peeraddr, SLPNetAddrLen(&sock->peeraddr)); if (byteswritten != packetbytes) { /* May be an overflow reply */ int flags = AS_UINT16(sock->sendbuf->curpos + 5); if ((byteswritten == -1) && #ifdef _WIN32 (WSAGetLastError() == WSAEMSGSIZE) && #else (errno == EMSGSIZE) && #endif (flags & SLP_FLAG_OVERFLOW)) { int byteswrittenmax = sendto(sendsock, (char*)sock->sendbuf->curpos, G_SlpdProperty.MTU, 0, (struct sockaddr *)&sock->peeraddr, SLPNetAddrLen(&sock->peeraddr)); if (byteswrittenmax == G_SlpdProperty.MTU) byteswritten = packetbytes; } } if (byteswritten != packetbytes) SLPDLog("NETWORK_ERROR - %d replying %s\n", errno, SLPNetSockAddrStorageToString(&(sock->peeraddr), addr_str, sizeof(addr_str))); sock->sendbuf->curpos += packetbytes; } /* Only close if we allocated a new socket */ if (sendsock != sock->fd) closesocket(sendsock); } break; } } }
/** 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); } } }