/** A callback routine that tests each DA discovered from DHCP. * * Each DA that passes is added to the DA cache. * * @param[in] tag - The DHCP option tag for this call. * @param[in] optdata - A pointer to the DHCP option data for this call. * @param[in] optdatasz - The size of @p optdata. * @param[in] context - Callback context data. For this callback routine * this parameter is actually a pointer to DHCPContext data. * * @return Zero on success, or a non-zero value to stop the caller from * continuing to parse the buffer and call this routine. */ int DHCPParseSLPTags(int tag, void * optdata, size_t optdatasz, void * context) { size_t cpysz, bufsz, dasize; DHCPContext * ctxp = (DHCPContext *)context; unsigned char * p = (unsigned char *)optdata; unsigned char flags; int encoding; /* filter out zero length options */ if (!optdatasz) return 0; switch(tag) { case TAG_SLP_SCOPE: /* Draft 3 format is only supported for ASCII and UNICODE * character encodings - UTF8 encodings must use rfc2610 format. * To determine the format, we parse 2 bytes and see if the result * is a valid encoding. If so it's draft 3, otherwise rfc2610. */ encoding = (optdatasz > 1)? AS_UINT16(p): 0; if (encoding != CT_ASCII && encoding != CT_UNICODE) { /* rfc2610 format */ if (optdatasz == 1) break; /* UA's should ignore statically configured * scopes for this interface - * add code to handle this later... */ flags = *p++; /* pick up the mandatory flag... */ optdatasz--; if (flags) ; /* ...and add code to handle it later... */ /* copy utf8 string into return buffer */ ctxp->scopelistlen = optdatasz < sizeof(ctxp->scopelist)? optdatasz: sizeof(ctxp->scopelist); strncpy(ctxp->scopelist, (char*)p, ctxp->scopelistlen); ctxp->scopelist[sizeof(ctxp->scopelist) - 1] = 0; } else { /* Draft 3 format: defined to configure scopes for SA's only * so we should flag the scopes to be used only as registration * filter scopes - add code to handle this case later... * * offs len name description * 0 2 encoding character encoding used * 2 n scopelist list of scopes as asciiz string. * */ optdatasz -= 2; /* skip encoding bytes */ p += 2; /* if UNICODE encoding is used convert to utf8 */ if (encoding == CT_UNICODE) wcstombs(ctxp->scopelist, (wchar_t*)p, sizeof(ctxp->scopelist)); else { ctxp->scopelistlen = optdatasz < sizeof(ctxp->scopelist)? optdatasz: sizeof(ctxp->scopelist); strncpy(ctxp->scopelist, (char*)p, ctxp->scopelistlen); ctxp->scopelist[sizeof(ctxp->scopelist) - 1] = 0; } } break; case TAG_SLP_DA: flags = *p++; optdatasz--; /* If the flags byte has the high bit set, we know we are * using draft 3 format, otherwise rfc2610 format. */ if (!(flags & DA_NAME_PRESENT)) { /* rfc2610 format */ if (flags) { /* If the mandatory byte is non-zero, indicate that * multicast is not to be used to dynamically discover * directory agents on this interface by setting the * LACBF_STATIC_DA flag in the LACB for this interface. */ /* skip this for now - deal with it later... */ } bufsz = sizeof(ctxp->addrlist) - ctxp->addrlistlen; cpysz = optdatasz < bufsz? optdatasz: bufsz; memcpy(ctxp->addrlist + ctxp->addrlistlen, p, cpysz); ctxp->addrlistlen += cpysz; } else { /* pre-rfc2610 (draft 3) format: * offs len name description * 0 1 flags contains 4 flags (defined above) * 1 1 dasize name or addr length * 2 dasize daname da name or ip address (flags) */ dasize = *p++; optdatasz--; if (dasize > optdatasz) dasize = optdatasz; if (flags & DA_NAME_IS_DNS) ; /* DA name contains dns name - we have to resolve - later... */ else { /* DA name is one 4-byte ip address */ if (dasize < 4) break; /* oops, bad option format */ dasize = 4; bufsz = sizeof(ctxp->addrlist) - ctxp->addrlistlen; cpysz = dasize < bufsz? dasize: bufsz; memcpy(ctxp->addrlist + ctxp->addrlistlen, p, cpysz); ctxp->addrlistlen += cpysz; } if (flags & DISABLE_DA_MCAST) ; /* this is the equivalent of the rfc2610 mandatory bit */ } break; } return 0; }
/** 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; } } }