/*=========================================================================*/ void SLPDSocketFree(SLPDSocket* sock) /* Frees memory associated with the specified SLPDSocket */ /* */ /* sock (IN) pointer to the socket to free */ /*=========================================================================*/ { /* close the socket descriptor */ CloseSocket(sock->fd); /* free receive buffer */ if(sock->recvbuf) { SLPBufferFree(sock->recvbuf); } /* free send buffer(s) */ if(sock->sendlist.count) { while(sock->sendlist.count) { SLPBufferFree((SLPBuffer)SLPListUnlink(&(sock->sendlist), sock->sendlist.head)); } } else if(sock->sendbuf) { SLPBufferFree(sock->sendbuf); } /* free the actual socket structure */ xfree(sock); }
/*-------------------------------------------------------------------------*/ void HandleSocketClose(SLPDSocketList* list, SLPDSocket* sock) /*-------------------------------------------------------------------------*/ { SLPDSocketListRemove(list,sock); close(sock->fd); if(sock->recvbuf) SLPBufferFree(sock->recvbuf); if(sock->sendbuf) SLPBufferFree(sock->sendbuf); free(sock); }
main() { SLPIfaceInfo ifaceinfo; SLPXcastSockets socks; SLPBuffer buffer; buffer = SLPBufferAlloc(SLP_MAX_DATAGRAM_SIZE); if(buffer) { strcpy(buffer->start,"testdata"); SLPIfaceGetInfo(NULL,&ifaceinfo); if (SLPBroadcastSend(&ifaceinfo, buffer,&socks) !=0) printf("\n SLPBroadcastSend failed \n"); SLPXcastSocketsClose(&socks); if (SLPMulticastSend(&ifaceinfo, buffer, &socks) !=0) printf("\n SLPMulticast failed \n"); SLPXcastSocketsClose(&socks); printf("Success\n"); SLPBufferFree(buffer); } }
int main(void) { SLPIfaceInfo ifaceinfo; SLPIfaceInfo ifaceinfo6; SLPXcastSockets socks; SLPBuffer buffer; /* multicast srvloc address */ uint8_t v6Addr[] = {0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x16}; struct sockaddr_storage dst; int mtu; #ifdef _WIN32 WSADATA wsadata; WSAStartup(MAKEWORD(2, 2), &wsadata); #endif mtu = SLPPropertyGetMTU(); //const struct in6_addr in6addr; buffer = SLPBufferAlloc(mtu); if (buffer) { strcpy((char *)buffer->start, "testdata"); SLPIfaceGetInfo(NULL,&ifaceinfo, AF_INET); SLPIfaceGetInfo(NULL,&ifaceinfo6, AF_INET6); if (SLPBroadcastSend(&ifaceinfo, buffer, &socks) !=0) printf("\n SLPBroadcastSend failed \n"); SLPXcastSocketsClose(&socks); /* for v6 */ if (SLPBroadcastSend(&ifaceinfo6, buffer,&socks) !=0) printf("\n SLPBroadcastSend failed for ipv6\n"); SLPXcastSocketsClose(&socks); if (SLPMulticastSend(&ifaceinfo, buffer, &socks, 0) !=0) printf("\n SLPMulticast failed \n"); SLPXcastSocketsClose(&socks); /* set up address and scope for v6 multicast */ SLPNetSetAddr(&dst, AF_INET6, 0, (uint8_t *)v6Addr); if (SLPMulticastSend(&ifaceinfo6, buffer, &socks, &dst) !=0) printf("\n SLPMulticast failed for ipv\n"); SLPXcastSocketsClose(&socks); printf("Success\n"); SLPBufferFree(buffer); } #ifdef _WIN32 WSACleanup(); #endif return 0; }
int CheckAndResizeBuffer(SLPBuffer * sendbuf, SLPBuffer tmp, size_t grow_size) { int retVal = 0; if( (*sendbuf)->curpos + (tmp->end - tmp->start) > ( (*sendbuf)->start + (*sendbuf)->allocated) ) { /* Grow the sendbuf buffer - note that SLPBufferRealloc may potentially do a memset if the DEBUG flag is set Therefore we have to copy the old contents into the buffer afterwards to be sure */ #ifdef DEBUG SLPBuffer duplicate = SLPBufferDup( (*sendbuf) ); #endif /* store how far we are from the start of the buffer */ size_t currentPosFromStart = (*sendbuf)->curpos - (*sendbuf)->start; /* check to make sure we're growing by at least the size of the tmp buffer */ *sendbuf = SLPBufferRealloc( (*sendbuf), ((*sendbuf)->allocated + ((size_t)(tmp->end - tmp->start) > grow_size?(tmp->end - tmp->start):grow_size)) ); if (*sendbuf == 0) { retVal = SLP_ERROR_INTERNAL_ERROR; } else { /* update the current position to what it was before */ (*sendbuf)->curpos = (*sendbuf)->start + currentPosFromStart; #ifdef DEBUG memcpy( (*sendbuf)->start, duplicate->start, duplicate->end - duplicate->start ); #endif } #ifdef DEBUG SLPBufferFree(duplicate); duplicate = 0; #endif } return retVal; }
/*-------------------------------------------------------------------------*/ SLPError ProcessSrvDeReg(PSLPHandleInfo handle) /*-------------------------------------------------------------------------*/ { struct timeval timeout; struct sockaddr peeraddr; int peeraddrlen = sizeof(peeraddr); int size = 0; SLPError error = 0; SLPBuffer buf = 0; SLPMessage msg = 0; int xid = XidGenerate(); /*-----------------------*/ /* allocate a SLPMessage */ /*-----------------------*/ msg = SLPMessageAlloc(); if(msg == 0) { error = SLP_MEMORY_ALLOC_FAILED; goto FINISHED; } /*-------------------------------------------------------------*/ /* ensure the buffer is big enough to handle the whole srvreg */ /*-------------------------------------------------------------*/ size = handle->langtaglen + 14; /* 14 bytes for header */ size += handle->params.dereg.scopelistlen + 2; /* 2 bytes for len field*/ size += handle->params.dereg.urllen + 8; /* 1 byte for reserved */ /* 2 bytes for lifetime */ /* 2 bytes for urllen */ /* 1 byte for authcount */ size += 2; /* 2 bytes for taglistlen*/ /* TODO: Fix this for authentication */ buf = SLPBufferAlloc(size); if(buf == 0) { error = SLP_MEMORY_ALLOC_FAILED; goto FINISHED; } /*----------------*/ /* Add the header */ /*----------------*/ /*version*/ *(buf->start) = 2; /*function id*/ *(buf->start + 1) = SLP_FUNCT_SRVDEREG; /*length*/ ToUINT24(buf->start + 2,size); /*flags*/ ToUINT16(buf->start + 5, 0); /*ext offset*/ ToUINT24(buf->start + 7,0); /*xid*/ ToUINT16(buf->start + 10,xid); /*lang tag len*/ ToUINT16(buf->start + 12,handle->langtaglen); /*lang tag*/ memcpy(buf->start + 14, handle->langtag, handle->langtaglen); /*--------------------------*/ /* Add rest of the SrvDeReg */ /*--------------------------*/ buf->curpos = buf->curpos + handle->langtaglen + 14; /* scope list */ ToUINT16(buf->curpos,handle->params.dereg.scopelistlen); buf->curpos = buf->curpos + 2; memcpy(buf->curpos, handle->params.dereg.scopelist, handle->params.dereg.scopelistlen); buf->curpos = buf->curpos + handle->params.dereg.scopelistlen; /* url-entry reserved */ *buf->curpos = 0; buf->curpos = buf->curpos + 1; /* url-entry lifetime */ ToUINT16(buf->curpos, 0); buf->curpos = buf->curpos + 2; /* url-entry urllen */ ToUINT16(buf->curpos,handle->params.dereg.urllen); buf->curpos = buf->curpos + 2; /* url-entry url */ memcpy(buf->curpos, handle->params.dereg.url, handle->params.dereg.urllen); buf->curpos = buf->curpos + handle->params.dereg.urllen; /* url-entry authcount */ *buf->curpos = 0; buf->curpos = buf->curpos + 1; /* TODO: put in urlentry authentication stuff too */ /* TODO: put tag list stuff in*/ ToUINT16(buf->curpos,0); /*------------------------*/ /* Send the SrvDeReg */ /*------------------------*/ timeout.tv_sec = atoi(SLPGetProperty("net.slp.unicastMaximumWait")) / 1000; timeout.tv_usec = 0; buf->curpos = buf->start; error = NetworkSendMessage(handle->slpdsock, buf, &timeout, &(handle->slpdaddr), sizeof(handle->slpdaddr)); if(error == SLP_OK) { /* Recv the SrvAck */ error = NetworkRecvMessage(handle->slpdsock, buf, &timeout, &peeraddr, &peeraddrlen); if(error == SLP_OK) { /* parse the SrvAck message */ error = SLPMessageParseBuffer(buf,msg); if(error == SLP_OK) { if(msg->header.xid == xid && msg->header.functionid == SLP_FUNCT_SRVACK) { /* map and use errorcode from message */ error = -(msg->body.srvack.errorcode); } else { error = SLP_NETWORK_ERROR; } } } } FINISHED: /* call callback function */ handle->params.dereg.callback((SLPHandle)handle, error, handle->params.dereg.cookie); /* free resources */ SLPBufferFree(buf); SLPMessageFree(msg); return 0; }
/** Read service registrations from a text file. * * A really big and nasty function that reads service registrations from * from a file. Don't look at this too hard or you'll be sick. This is by * far the most horrible code in OpenSLP. Please volunteer to rewrite it! * * "THANK GOODNESS this function is only called at startup" -- Matt * * @param[in] fd - The file to read from. * @param[out] msg - A message describing the SrvReg in buf. * @param[out] buf - The buffer used to hold @p message data. * * @return Zero on success. A value greater than zero on error. A value * less than zero on EOF. * * @note Eventually the caller needs to call SLPBufferFree and * SLPMessageFree to free memory. */ int SLPDRegFileReadSrvReg(FILE * fd, SLPMessage ** msg, SLPBuffer * buf) { char * slider1; char * slider2; char line[4096]; struct sockaddr_storage peer; int result = 0; size_t bufsize = 0; size_t langtaglen = 0; char * langtag = 0; size_t scopelistlen = 0; char * scopelist = 0; size_t urllen = 0; char * url = 0; int lifetime = 0; size_t srvtypelen = 0; char * srvtype = 0; size_t attrlistlen = 0; char * attrlist = 0; SLPBuffer tmp; #ifdef ENABLE_SLPv2_SECURITY unsigned char * urlauth = 0; int urlauthlen = 0; unsigned char * attrauth = 0; int attrauthlen = 0; #endif /* give the out params an initial NULL value */ *buf = 0; *msg = 0; /* read the next non-white non-comment line from the stream */ do { slider1 = RegFileReadLine(fd, line, 4096); if (slider1 == 0) return -1; } while (*slider1 == 0x0d || *slider1 == 0x0a); /* Parse the url-props */ slider2 = strchr(slider1, ','); if (slider2) { /* srvurl */ *slider2 = 0; /* squash comma to null terminate srvurl */ url = xstrdup(TrimWhitespace(slider1)); if (url == 0) { result = SLP_ERROR_INTERNAL_ERROR; goto CLEANUP; } urllen = strlen(url); /* derive srvtype from srvurl */ srvtype = strstr(slider1, "://"); if (srvtype == 0) { result = SLP_ERROR_INVALID_REGISTRATION; goto CLEANUP; } *srvtype = 0; srvtype=xstrdup(TrimWhitespace(slider1)); if (srvtype == 0) { result = SLP_ERROR_INTERNAL_ERROR; goto CLEANUP; } srvtypelen = strlen(srvtype); slider1 = slider2 + 1; /*lang*/ slider2 = strchr(slider1, ','); if (slider2) { *slider2 = 0; /* squash comma to null terminate lang */ langtag = xstrdup(TrimWhitespace(slider1)); if (langtag == 0) { result = SLP_ERROR_INVALID_REGISTRATION; goto CLEANUP; } langtaglen = strlen(langtag); slider1 = slider2 + 1; } else { result = SLP_ERROR_INVALID_REGISTRATION; goto CLEANUP; } /* ltime */ slider2 = strchr(slider1,','); if (slider2) { *slider2 = 0; /* squash comma to null terminate ltime */ lifetime = atoi(slider1); slider1 = slider2 + 1; } else { lifetime = atoi(slider1); slider1 = slider2; } if (lifetime < 1 || lifetime > SLP_LIFETIME_MAXIMUM) { result = SLP_ERROR_INVALID_REGISTRATION; goto CLEANUP; } /* get the srvtype if one was not derived by the srvurl */ if (srvtype == 0) { srvtype = xstrdup(TrimWhitespace(slider1)); if (srvtype == 0) { result = SLP_ERROR_INTERNAL_ERROR; goto CLEANUP; } srvtypelen = strlen(srvtype); if (srvtypelen == 0) { result = SLP_ERROR_INVALID_REGISTRATION; goto CLEANUP; } } } else { result = SLP_ERROR_INVALID_REGISTRATION; goto CLEANUP; } /* read all the attributes including the scopelist */ *line=0; while (1) { slider1 = RegFileReadLine(fd,line,4096); if (slider1 == 0) { result = -1; break; } if (*slider1 == 0x0d || *slider1 == 0x0a) break; /* Check to see if it is the scopes line */ /* FIXME We can collapse the scope stuff into the value getting and just make it a special case (do strcmp on the tag as opposed to the line) of attribute getting. */ if (strncasecmp(slider1,"scopes", 6) == 0) { /* found scopes line */ slider2 = strchr(slider1,'='); if (slider2) { slider2++; if (*slider2) { /* just in case some idiot puts multiple scopes lines */ if (scopelist) { result = SLP_ERROR_SCOPE_NOT_SUPPORTED; goto CLEANUP; } /* make sure there are no spaces in the scope list NOTE: There's nothing in the spec that indicates that scopes can't contain spaces. Commenting out for now. --jmc if (strchr(slider2, ' ')) { result = SLP_ERROR_SCOPE_NOT_SUPPORTED; goto CLEANUP; } */ scopelist = xstrdup(TrimWhitespace(slider2)); if (scopelist == 0) { result = SLP_ERROR_INTERNAL_ERROR; goto CLEANUP; } scopelistlen = strlen(scopelist); } } } else { /* line contains an attribute (slow but it works)*/ /* TODO Fix this so we do not have to realloc memory each time! */ TrimWhitespace(slider1); if (attrlist == 0) { attrlistlen += strlen(slider1) + 2; attrlist = xmalloc(attrlistlen + 1); if (attrlist == 0) { result = SLP_ERROR_INTERNAL_ERROR; goto CLEANUP; } *attrlist = 0; } else { char * tmp_attrlist; attrlistlen += strlen(slider1) + 3; if ((tmp_attrlist = xrealloc(attrlist, attrlistlen + 1)) == 0) { xfree(attrlist); result = SLP_ERROR_INTERNAL_ERROR; goto CLEANUP; } attrlist = tmp_attrlist; strcat(attrlist, ","); } if (attrlist == 0) { result = SLP_ERROR_INTERNAL_ERROR; goto CLEANUP; } /* we need special case for keywords (why do we need these) they seem like a waste of code. Why not just use booleans */ if (strchr(slider1, '=')) { /* normal attribute (with '=') */ strcat(attrlist, "("); strcat(attrlist, slider1); strcat(attrlist, ")"); } else { /* keyword (no '=') */ attrlistlen -= 2; /* subtract 2 bytes for no '(' or ')' */ strcat(attrlist, slider1); } } } /* Set the scope set in properties if not is set */ if (scopelist == 0) { scopelist = xstrdup(G_SlpdProperty.useScopes); if (scopelist == 0) { result = SLP_ERROR_INTERNAL_ERROR; goto CLEANUP; } scopelistlen = G_SlpdProperty.useScopesLen; } #ifdef ENABLE_SLPv2_SECURITY /* generate authentication blocks */ if (G_SlpdProperty.securityEnabled) { SLPAuthSignUrl(G_SlpdSpiHandle, 0, 0, urllen, url, &urlauthlen, &urlauth); SLPAuthSignString(G_SlpdSpiHandle, 0, 0, attrlistlen, attrlist, &attrauthlen, &attrauth); } #endif /* allocate buffer for the SrvReg Message */ bufsize = 14 + langtaglen; /* 14 bytes for header */ bufsize += urllen + 6; /* 1 byte for reserved */ /* 2 bytes for lifetime */ /* 2 bytes for urllen */ /* 1 byte for authcount */ bufsize += srvtypelen + 2; /* 2 bytes for len field */ bufsize += scopelistlen + 2; /* 2 bytes for len field */ bufsize += attrlistlen + 2; /* 2 bytes for len field */ bufsize += 1; /* 1 byte for authcount */ #ifdef ENABLE_SLPv2_SECURITY bufsize += urlauthlen; bufsize += attrauthlen; #endif tmp = *buf = SLPBufferAlloc(bufsize); if (tmp == 0) { result = SLP_ERROR_INTERNAL_ERROR; goto CLEANUP; } /* now build the SrvReg Message */ /* version */ *tmp->curpos++ = 2; /* function id */ *tmp->curpos++ = SLP_FUNCT_SRVREG; /* length */ PutUINT24(&tmp->curpos, bufsize); /* flags */ PutUINT16(&tmp->curpos, 0); /* ext offset */ PutUINT24(&tmp->curpos, 0); /* xid */ PutUINT16(&tmp->curpos, 0); /* lang tag len */ PutUINT16(&tmp->curpos, langtaglen); /* lang tag */ memcpy(tmp->curpos, langtag, langtaglen); tmp->curpos += langtaglen; /* url-entry reserved */ *tmp->curpos++ = 0; /* url-entry lifetime */ PutUINT16(&tmp->curpos, lifetime); /* url-entry urllen */ PutUINT16(&tmp->curpos, urllen); /* url-entry url */ memcpy(tmp->curpos, url, urllen); tmp->curpos += urllen; /* url-entry authblock */ #ifdef ENABLE_SLPv2_SECURITY if (urlauth) { /* authcount */ *tmp->curpos++ = 1; /* authblock */ memcpy(tmp->curpos, urlauth, urlauthlen); tmp->curpos += urlauthlen; } else #endif *tmp->curpos++ = 0; /* service type */ PutUINT16(&tmp->curpos, srvtypelen); memcpy(tmp->curpos, srvtype, srvtypelen); tmp->curpos += srvtypelen; /* scope list */ PutUINT16(&tmp->curpos, scopelistlen); memcpy(tmp->curpos, scopelist, scopelistlen); tmp->curpos += scopelistlen; /* attr list */ PutUINT16(&tmp->curpos, attrlistlen); memcpy(tmp->curpos, attrlist, attrlistlen); tmp->curpos += attrlistlen; /* attribute auth block */ #ifdef ENABLE_SLPv2_SECURITY if (attrauth) { /* authcount */ *tmp->curpos++ = 1; /* authblock */ memcpy(tmp->curpos, attrauth, attrauthlen); tmp->curpos += attrauthlen; } else #endif *tmp->curpos++ = 0; /* okay, now comes the really stupid (and lazy part) */ *msg = SLPMessageAlloc(); if (*msg == 0) { SLPBufferFree(*buf); *buf = 0; result = SLP_ERROR_INTERNAL_ERROR; goto CLEANUP; } /* this should be ok even if we are not supporting IPv4, * since it's a static service */ memset(&peer, 0, sizeof(struct sockaddr_in)); peer.ss_family = AF_UNSPEC; ((struct sockaddr_in *)&peer)->sin_addr.s_addr = htonl(INADDR_LOOPBACK); result = SLPMessageParseBuffer(&peer, &peer, *buf, *msg); (*msg)->body.srvreg.source = SLP_REG_SOURCE_STATIC; CLEANUP: /* check for errors and free memory */ switch(result) { case SLP_ERROR_INTERNAL_ERROR: SLPDLog("\nERROR: Out of memory one reg file line:\n %s\n", line); break; case SLP_ERROR_INVALID_REGISTRATION: SLPDLog("\nERROR: Invalid reg file format near:\n %s\n", line); break; case SLP_ERROR_SCOPE_NOT_SUPPORTED: SLPDLog("\nERROR: Duplicate scopes or scope list with " "embedded spaces near:\n %s\n", line); break; default: break; } xfree(langtag); xfree(scopelist); xfree(url); xfree(srvtype); xfree(attrlist); #ifdef ENABLE_SLPv2_SECURITY xfree(urlauth); xfree(attrauth); #endif return result; }
/*-------------------------------------------------------------------------*/ 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); } } } }
/** Process a DA service request message. * * @param[in] message - The message to process. * @param[out] sendbuf - The response buffer to fill. * @param[in] errorcode - The error code from the client request. * * @return Zero on success, or a non-zero SLP error on failure. * * @internal */ static int ProcessDASrvRqst(SLPMessage * message, SLPBuffer * sendbuf, int errorcode) { SLPBuffer tmp = 0; SLPMessage * msg = 0; void * eh = 0; /* TODO should really be a configurable property, maybe G_SlpdProperty.MTU? Left at 4096 to retain same behaviour */ size_t initial_buffer_size = 4096; size_t grow_size = initial_buffer_size; /* Special case for when libslp asks slpd (through the loopback) about a known DAs. Fill sendbuf with DAAdverts from all known DAs. */ if (SLPNetIsLoopback(&message->peer)) { *sendbuf = SLPBufferRealloc(*sendbuf, initial_buffer_size); if (*sendbuf == 0) return SLP_ERROR_INTERNAL_ERROR; if (errorcode == 0) { /* Note: The weird *sendbuf code is making a single SLPBuffer that contains multiple DAAdverts. This is a special process that only happens for the DA SrvRqst through loopback to the SLPAPI */ /*If we are a DA, always have ourself at the start of the list, so the lib requests can be handled locally for speed */ if(G_SlpdProperty.isDA) { struct sockaddr_storage loaddr; if(SLPNetIsIPV4()) { int addr = INADDR_LOOPBACK; SLPNetSetAddr(&loaddr, AF_INET, G_SlpdProperty.port, &addr); } else { SLPNetSetAddr(&loaddr, AF_INET6, G_SlpdProperty.port, &slp_in6addr_loopback); } if(0 == SLPDKnownDAGenerateMyDAAdvert(&loaddr, 0, 0, 0, message->header.xid, &tmp)) { memcpy((*sendbuf)->curpos, tmp->start, tmp->end - tmp->start); (*sendbuf)->curpos = ((*sendbuf)->curpos) + (tmp->end - tmp->start); SLPBufferFree(tmp); tmp = 0; } else { SLPDLog("Unable to add initial DAAdvert due to error\n"); } } eh = SLPDKnownDAEnumStart(); if (eh) { while (1) { /* iterate over all database entries */ if (SLPDKnownDAEnum(eh, &msg, &tmp) == 0) { break; } /* if we resize succesfully.. */ if( CheckAndResizeBuffer(sendbuf, tmp, grow_size) == 0 ) { /* buffer should now be resized to an appropriate size to handle all current database entries */ /* TRICKY: Fix up the XID and clear the flags. */ tmp->curpos = tmp->start + 10; TO_UINT16(tmp->curpos, message->header.xid); if (*(tmp->start) == 1) *(tmp->start + 4) = 0; else TO_UINT16(tmp->start + 5, 0); /* copy all data out of tmp into the sendbuf */ memcpy((*sendbuf)->curpos, tmp->start, tmp->end - tmp->start); /* increment the current position in sendbuf */ (*sendbuf)->curpos = ((*sendbuf)->curpos) + (tmp->end - tmp->start); } else { errorcode = SLP_ERROR_INTERNAL_ERROR; } } SLPDKnownDAEnumEnd(eh); } /* tmp can store database entries which should not be freed by anyone else so reset the pointer to prevent double deletion */ tmp = 0; /* Tack on a "terminator" DAAdvert Note that this function *always* returns the error code passed as its second parameter (or SLP_ERROR_INTERNAL_ERROR if the buffer fails to resize) The errorcode is also inserted into the srvrply header by this function */ SLPDKnownDAGenerateMyDAAdvert(&message->localaddr, SLP_ERROR_INTERNAL_ERROR, 0, 0, message->header.xid, &tmp); /* if we resize succesfully.. */ if ( CheckAndResizeBuffer(sendbuf, tmp, grow_size) == 0 ) { memcpy((*sendbuf)->curpos, tmp->start, tmp->end - tmp->start); (*sendbuf)->curpos = ((*sendbuf)->curpos) + (tmp->end - tmp->start); /* mark the end of the sendbuf */ (*sendbuf)->end = (*sendbuf)->curpos; } else { errorcode = SLP_ERROR_INTERNAL_ERROR; } SLPBufferFree(tmp); tmp = 0; } return errorcode; } /* Normal case where a remote Agent asks for a DA */ *sendbuf = SLPBufferRealloc(*sendbuf, G_SlpdProperty.MTU); if (*sendbuf == 0) return SLP_ERROR_INTERNAL_ERROR; if (G_SlpdProperty.isDA) { if (message->body.srvrqst.scopelistlen == 0 || SLPIntersectStringList(message->body.srvrqst.scopelistlen, message->body.srvrqst.scopelist, G_SlpdProperty.useScopesLen, G_SlpdProperty.useScopes)) { errorcode = SLPDKnownDAGenerateMyDAAdvert(&message->localaddr, errorcode, 0, 0, message->header.xid, sendbuf); } else errorcode = SLP_ERROR_SCOPE_NOT_SUPPORTED; } else errorcode = SLP_ERROR_MESSAGE_NOT_SUPPORTED; /* don't return errorcodes to multicast messages */ if (errorcode != 0) { if (message->header.flags & SLP_FLAG_MCAST || SLPNetIsMCast(&(message->peer))) (*sendbuf)->end = (*sendbuf)->start; } return errorcode; }
/** Processes the recvbuf and places the results in sendbuf * * @param[in] peerinfo - The remote address the message was received from. * @param[in] localaddr - The local address the message was received on. * @param[in] recvbuf - The message to process. * @param[out] sendbuf - The address of storage for the results of the * processed message. * @param[out] sendlist - if non-0, this function will prune the message * with the processed xid from the sendlist. * * @return Zero on success if @p sendbuf contains a response to send, * or a non-zero value if @p sendbuf does not contain a response * to send. */ int SLPDProcessMessage(struct sockaddr_storage * peerinfo, struct sockaddr_storage * localaddr, SLPBuffer recvbuf, SLPBuffer * sendbuf, SLPList * psendlist) { SLPHeader header; SLPMessage * message = 0; int errorcode = 0; #ifdef DEBUG char addr_str[INET6_ADDRSTRLEN]; #endif SLPDLogMessage(SLPDLOG_TRACEMSG_IN, peerinfo, localaddr, recvbuf); /* set the sendbuf empty */ if (*sendbuf) (*sendbuf)->end = (*sendbuf)->start; /* zero out the header before parsing it */ memset(&header, 0, sizeof(header)); /* Parse just the message header */ recvbuf->curpos = recvbuf->start; errorcode = SLPMessageParseHeader(recvbuf, &header); /* Reset the buffer "curpos" pointer so that full message can be parsed later */ recvbuf->curpos = recvbuf->start; #if defined(ENABLE_SLPv1) /* if version == 1 and the header was correct then parse message as a version 1 message */ if ((errorcode == 0) && (header.version == 1)) errorcode = SLPDv1ProcessMessage(peerinfo, recvbuf, sendbuf); else #endif if (errorcode == 0) { /* TRICKY: Duplicate SRVREG recvbufs *before* parsing them * we do this because we are going to keep track of in the * registration database. */ if (header.functionid == SLP_FUNCT_SRVREG || header.functionid == SLP_FUNCT_DAADVERT) { recvbuf = SLPBufferDup(recvbuf); if (recvbuf == 0) return SLP_ERROR_INTERNAL_ERROR; } /* Allocate the message descriptor */ message = SLPMessageAlloc(); if (message) { /* Parse the message and fill out the message descriptor */ errorcode = SLPMessageParseBuffer(peerinfo, localaddr, recvbuf, message); if (errorcode == 0) { /* Process messages based on type */ switch (message->header.functionid) { case SLP_FUNCT_SRVRQST: errorcode = ProcessSrvRqst(message, sendbuf, errorcode); break; case SLP_FUNCT_SRVREG: errorcode = ProcessSrvReg(message, recvbuf, sendbuf, errorcode); if (errorcode == 0) SLPDKnownDAEcho(message, recvbuf); break; case SLP_FUNCT_SRVDEREG: errorcode = ProcessSrvDeReg(message, sendbuf, errorcode); if (errorcode == 0) SLPDKnownDAEcho(message, recvbuf); break; case SLP_FUNCT_SRVACK: errorcode = ProcessSrvAck(message, sendbuf, errorcode); break; case SLP_FUNCT_ATTRRQST: errorcode = ProcessAttrRqst(message, sendbuf, errorcode); break; case SLP_FUNCT_DAADVERT: errorcode = ProcessDAAdvert(message, recvbuf, sendbuf, errorcode); break; case SLP_FUNCT_SRVTYPERQST: errorcode = ProcessSrvTypeRqst(message, sendbuf, errorcode); break; case SLP_FUNCT_SAADVERT: errorcode = ProcessSAAdvert(message, sendbuf, errorcode); break; default: /* Should never happen... but we're paranoid */ errorcode = SLP_ERROR_PARSE_ERROR; break; } } else SLPDLogParseWarning(peerinfo, recvbuf); /*If there was a send list, prune the xid, since the request has been processed*/ if(psendlist) { SLPHeader bufhead; SLPBuffer pnext; SLPBuffer pbuf = (SLPBuffer) psendlist->head; while(pbuf) { pnext = (SLPBuffer) pbuf->listitem.next; if((0 == SLPMessageParseHeader(pbuf, &bufhead)) && (bufhead.xid == header.xid)) SLPBufferFree((SLPBuffer)SLPListUnlink(psendlist, (SLPListItem*)pbuf)); else pbuf->curpos = pbuf->start; /*We parsed the buffer enough to attempt the xid check, we need to reset it for the next parse*/ pbuf = pnext; } } if (header.functionid == SLP_FUNCT_SRVREG || header.functionid == SLP_FUNCT_DAADVERT) { /* TRICKY: If this is a reg or daadvert message we do not free * the message descriptor or duplicated recvbuf because they are * being kept in the database! */ if (errorcode == 0) goto FINISHED; /* TRICKY: If there is an error we need to free the * duplicated recvbuf */ SLPBufferFree(recvbuf); } SLPMessageFree(message); } else errorcode = SLP_ERROR_INTERNAL_ERROR; /* out of memory */ } else SLPDLogParseWarning(peerinfo,recvbuf); FINISHED: #ifdef DEBUG if (errorcode) SLPDLog("\n*** DEBUG *** errorcode %i during processing " "of message from %s\n", errorcode, SLPNetSockAddrStorageToString( peerinfo, addr_str, sizeof(addr_str))); #endif /* Log message silently ignored because of an error */ if (errorcode) if (*sendbuf == 0 || (*sendbuf)->end == (*sendbuf)->start) SLPDLogMessage(SLPDLOG_TRACEDROP,peerinfo,localaddr,recvbuf); /* Log trace message */ SLPDLogMessage(SLPDLOG_TRACEMSG_OUT, peerinfo, localaddr, *sendbuf); return errorcode; }
/*-------------------------------------------------------------------------*/ SLPBoolean KnownDADiscoveryCallback(SLPError errorcode, struct sockaddr_in* peerinfo, SLPBuffer rplybuf, void* cookie) /*-------------------------------------------------------------------------*/ { SLPMessage replymsg; SLPBuffer dupbuf; struct hostent* he; SLPSrvURL* srvurl; int* count; SLPBoolean result = SLP_TRUE; count = (int*)cookie; if(errorcode == 0) { dupbuf = SLPBufferDup(rplybuf); if(dupbuf) { replymsg = SLPMessageAlloc(); if(replymsg) { if(SLPMessageParseBuffer(peerinfo,dupbuf,replymsg) == 0 && replymsg->header.functionid == SLP_FUNCT_DAADVERT) { if(replymsg->body.daadvert.errorcode == 0) { /* TRICKY: NULL terminate the DA url */ ((char*)(replymsg->body.daadvert.url))[replymsg->body.daadvert.urllen] = 0; if(SLPParseSrvURL(replymsg->body.daadvert.url, &srvurl) == 0) { he = gethostbyname(srvurl->s_pcHost); SLPFree(srvurl); if(he) { /* Reset the peer to the one in the URL */ replymsg->peer.sin_addr.s_addr = *((unsigned int*)(he->h_addr_list[0])); (*count) += 1; KnownDAAdd(replymsg,dupbuf); if(replymsg->header.flags & SLP_FLAG_MCAST) { return SLP_FALSE; } return SLP_TRUE; } } } else if(replymsg->body.daadvert.errorcode == SLP_ERROR_INTERNAL_ERROR) { /* SLP_ERROR_INTERNAL_ERROR is a "end of stream" */ /* marker for looppack IPC */ result = SLP_FALSE; } } SLPMessageFree(replymsg); } SLPBufferFree(dupbuf); } } return result; }
/*-------------------------------------------------------------------------*/ int ProcessDASrvRqst(struct sockaddr_in* peeraddr, SLPMessage message, SLPBuffer* sendbuf, int errorcode) /*-------------------------------------------------------------------------*/ { SLPDAEntry daentry; SLPBuffer tmp = 0; SLPDAEntry* entry = 0; void* i = 0; /* set up local data */ memset(&daentry,0,sizeof(daentry)); /*---------------------------------------------------------------------*/ /* Special case for when libslp asks slpd (through the loopback) about */ /* a known DAs. Fill sendbuf with DAAdverts from all known DAs. */ /*---------------------------------------------------------------------*/ if(ISLOCAL(peeraddr->sin_addr)) { /* TODO: be smarter about how much memory is allocated here! */ /* 4096 may not be big enough to handle all DAAdverts */ *sendbuf = SLPBufferRealloc(*sendbuf, 4096); if(*sendbuf == 0) { return SLP_ERROR_INTERNAL_ERROR; } if(errorcode == 0) { /* Note: The weird *sendbuf code is making a single SLPBuffer */ /* that contains multiple DAAdverts. This is a special */ /* process that only happens for the DA SrvRqst through */ /* loopback to the SLPAPI */ while(SLPDKnownDAEnum(&i,&entry) == 0) { if(SLPDKnownDAEntryToDAAdvert(errorcode, message->header.xid, entry, &tmp) == 0) { if(((*sendbuf)->curpos) + (tmp->end - tmp->start) > (*sendbuf)->end) { break; } memcpy((*sendbuf)->curpos, tmp->start, tmp->end - tmp->start); (*sendbuf)->curpos = ((*sendbuf)->curpos) + (tmp->end - tmp->start); } } /* Tack on a "terminator" DAAdvert */ SLPDKnownDAEntryToDAAdvert(SLP_ERROR_INTERNAL_ERROR, message->header.xid, &daentry, &tmp); if(((*sendbuf)->curpos) + (tmp->end - tmp->start) <= (*sendbuf)->end) { memcpy((*sendbuf)->curpos, tmp->start, tmp->end - tmp->start); (*sendbuf)->curpos = ((*sendbuf)->curpos) + (tmp->end - tmp->start); } /* mark the end of the sendbuf */ (*sendbuf)->end = (*sendbuf)->curpos; if(tmp) { SLPBufferFree(tmp); } } return errorcode; } /*---------------------------------------------------------------------*/ /* Normal case where a remote Agent asks for a DA */ /*---------------------------------------------------------------------*/ if(G_SlpdProperty.isDA) { if(message->body.srvrqst.scopelistlen == 0 || SLPIntersectStringList(message->body.srvrqst.scopelistlen, message->body.srvrqst.scopelist, G_SlpdProperty.useScopesLen, G_SlpdProperty.useScopes)) { /* fill out real structure */ G_SlpdProperty.DATimestamp += 1; daentry.bootstamp = G_SlpdProperty.DATimestamp; daentry.langtaglen = G_SlpdProperty.localeLen; daentry.langtag = (char*)G_SlpdProperty.locale; daentry.urllen = G_SlpdProperty.myUrlLen; daentry.url = (char*)G_SlpdProperty.myUrl; daentry.scopelistlen = G_SlpdProperty.useScopesLen; daentry.scopelist = (char*)G_SlpdProperty.useScopes; daentry.attrlistlen = 0; daentry.attrlist = 0; daentry.spilistlen = 0; daentry.spilist = 0; } else { errorcode = SLP_ERROR_SCOPE_NOT_SUPPORTED; } } else { errorcode = SLP_ERROR_MESSAGE_NOT_SUPPORTED; } /* don't return errorcodes to multicast messages */ if(errorcode != 0) { if(message->header.flags & SLP_FLAG_MCAST || ISMCAST(peeraddr->sin_addr)) { (*sendbuf)->end = (*sendbuf)->start; return errorcode; } } errorcode = SLPDKnownDAEntryToDAAdvert(errorcode, message->header.xid, &daentry, sendbuf); return errorcode; }
/*=========================================================================*/ int SLPDv1ProcessMessage(struct sockaddr_in* peeraddr, SLPBuffer recvbuf, SLPBuffer* sendbuf) /* Processes the SLPv1 message and places the results in sendbuf */ /* */ /* peeraddr - the socket the message was received on */ /* */ /* recvbuf - message to process */ /* */ /* sendbuf - results of the processed message */ /* */ /* Returns - zero on success SLP_ERROR_PARSE_ERROR or */ /* SLP_ERROR_INTERNAL_ERROR on ENOMEM. */ /*=========================================================================*/ { SLPHeader header; SLPMessage message; int errorcode = 0; if (!G_SlpdProperty.isDA) { /* SLPv1 messages are handled only by DAs */ errorcode = SLP_ERROR_VER_NOT_SUPPORTED; } /* Parse just the message header the reset the buffer "curpos" pointer */ recvbuf->curpos = recvbuf->start; errorcode = SLPv1MessageParseHeader(recvbuf, &header); /* TRICKY: Duplicate SRVREG recvbufs *before* parsing them */ /* it because we are going to keep them in the */ if (header.functionid == SLP_FUNCT_SRVREG) { recvbuf = SLPBufferDup(recvbuf); if (recvbuf == NULL) { return SLP_ERROR_INTERNAL_ERROR; } } /* Allocate the message descriptor */ message = SLPMessageAlloc(); if (message) { /* Parse the message and fill out the message descriptor */ errorcode = SLPv1MessageParseBuffer(peeraddr,recvbuf, message); if (errorcode == 0) { /* Process messages based on type */ switch (message->header.functionid) { case SLP_FUNCT_SRVRQST: errorcode = v1ProcessSrvRqst(peeraddr, message, sendbuf, errorcode); break; case SLP_FUNCT_SRVREG: errorcode = v1ProcessSrvReg(peeraddr, message, recvbuf, sendbuf, errorcode); if (errorcode == 0) { SLPDKnownDAEcho(message, recvbuf); } break; case SLP_FUNCT_SRVDEREG: errorcode = v1ProcessSrvDeReg(peeraddr, message, sendbuf, errorcode); if (errorcode == 0) { SLPDKnownDAEcho(message, recvbuf); } break; case SLP_FUNCT_ATTRRQST: errorcode = v1ProcessAttrRqst(peeraddr, message, sendbuf, errorcode); break; case SLP_FUNCT_SRVTYPERQST: errorcode = v1ProcessSrvTypeRqst(peeraddr, message, sendbuf, errorcode); break; case SLP_FUNCT_DAADVERT: /* we are a SLPv2 DA, ignore other v1 DAs */ (*sendbuf)->end = (*sendbuf)->start; break; default: /* Should never happen... but we're paranoid */ errorcode = SLP_ERROR_PARSE_ERROR; break; } } if (header.functionid == SLP_FUNCT_SRVREG) { /* TRICKY: Do not free the message descriptor for SRVREGs */ /* because we are keeping them in the database */ /* unless there is an error then we free memory */ if (errorcode) { SLPMessageFree(message); SLPBufferFree(recvbuf); } } else { SLPMessageFree(message); } } else { /* out of memory */ errorcode = SLP_ERROR_INTERNAL_ERROR; } return errorcode; }
/*=========================================================================*/ SLPError NetworkRqstRply(int sock, struct sockaddr_in* destaddr, const char* langtag, char* buf, char buftype, int bufsize, NetworkRqstRplyCallback callback, void * cookie) /* Transmits and receives SLP messages via multicast convergence algorithm */ /* */ /* Returns - SLP_OK on success */ /*=========================================================================*/ { struct timeval timeout; struct sockaddr_in peeraddr; SLPBuffer sendbuf = 0; SLPBuffer recvbuf = 0; SLPMessage msg = 0; SLPError result = 0; #ifdef WIN32 /* on WIN32 setsockopt takes a const char * argument */ char socktype = 0; #else int socktype = 0; #endif int langtaglen = 0; int prlistlen = 0; char* prlist = 0; int xid = 0; int mtu = 0; int size = 0; int xmitcount = 0; int rplycount = 0; int maxwait = 0; int totaltimeout = 0; int timeouts[MAX_RETRANSMITS]; /*----------------------------------------------------*/ /* Save off a few things we don't want to recalculate */ /*----------------------------------------------------*/ langtaglen = strlen(langtag); xid = SLPXidGenerate(); mtu = SLPPropertyAsInteger(SLPGetProperty("net.slp.MTU")); sendbuf = SLPBufferAlloc(mtu); if(sendbuf == 0) { result = SLP_MEMORY_ALLOC_FAILED; goto CLEANUP; } if(buftype == SLP_FUNCT_DASRVRQST) { /* do something special for SRVRQST that will be discovering DAs */ maxwait = SLPPropertyAsInteger(SLPGetProperty("net.slp.DADiscoveryMaximumWait")); SLPPropertyAsIntegerVector(SLPGetProperty("net.slp.DADiscovertTimeouts"), timeouts, MAX_RETRANSMITS ); /* SLP_FUNCT_DASRVRQST is a fake function. We really want to */ /* send a SRVRQST */ buftype = SLP_FUNCT_SRVRQST; } /* Figure unicast/multicast,TCP/UDP, wait and time out stuff */ if(ntohl(destaddr->sin_addr.s_addr) > 0xe0000000) { /* Multicast or broadcast */ maxwait = SLPPropertyAsInteger(SLPGetProperty("net.slp.multicastMaximumWait")); SLPPropertyAsIntegerVector(SLPGetProperty("net.slp.multicastTimeouts"), timeouts, MAX_RETRANSMITS ); socktype = SOCK_DGRAM; xmitcount = 0; } else { maxwait = SLPPropertyAsInteger(SLPGetProperty("net.slp.unicastMaximumWait")); SLPPropertyAsIntegerVector(SLPGetProperty("net.slp.unicastTimeouts"), timeouts, MAX_RETRANSMITS ); size = sizeof(socktype); getsockopt(sock,SOL_SOCKET,SO_TYPE,&socktype,&size); socktype = SOCK_STREAM; xmitcount = MAX_RETRANSMITS; } /*--------------------------------*/ /* Allocate memory for the prlist */ /*--------------------------------*/ prlist = (char*)malloc(mtu); if(prlist == 0) { result = SLP_MEMORY_ALLOC_FAILED; goto CLEANUP; } *prlist = 0; prlistlen = 0; /*--------------------------*/ /* Main retransmission loop */ /*--------------------------*/ while(xmitcount <= MAX_RETRANSMITS) { xmitcount++; /*--------------------*/ /* setup recv timeout */ /*--------------------*/ if(socktype == SOCK_DGRAM) { totaltimeout += timeouts[xmitcount]; if(totaltimeout >= maxwait || timeouts[xmitcount] == 0) { /* we are all done */ break; } timeout.tv_sec = timeouts[xmitcount] / 1000; timeout.tv_usec = (timeouts[xmitcount] % 1000) * 1000; } else { timeout.tv_sec = maxwait / 1000; timeout.tv_usec = (maxwait % 1000) * 1000; } size = 14 + langtaglen + 2 + prlistlen + bufsize; if(SLPBufferRealloc(sendbuf,size) == 0) { result = SLP_MEMORY_ALLOC_FAILED; goto CLEANUP; } /*-----------------------------------*/ /* Add the header to the send buffer */ /*-----------------------------------*/ /*version*/ *(sendbuf->start) = 2; /*function id*/ *(sendbuf->start + 1) = buftype; /*length*/ ToUINT24(sendbuf->start + 2, size); /*flags*/ ToUINT16(sendbuf->start + 5, socktype == SOCK_STREAM ? 0 : SLP_FLAG_MCAST); /*ext offset*/ ToUINT24(sendbuf->start + 7,0); /*xid*/ ToUINT16(sendbuf->start + 10,xid); /*lang tag len*/ ToUINT16(sendbuf->start + 12,langtaglen); /*lang tag*/ memcpy(sendbuf->start + 14, langtag, langtaglen); sendbuf->curpos = sendbuf->start + langtaglen + 14 ; /*-----------------------------------*/ /* Add the prlist to the send buffer */ /*-----------------------------------*/ if( buftype == SLP_FUNCT_SRVRQST || buftype == SLP_FUNCT_ATTRRQST || buftype == SLP_FUNCT_SRVTYPERQST) { ToUINT16(sendbuf->curpos,prlistlen); sendbuf->curpos = sendbuf->curpos + 2; memcpy(sendbuf->curpos, prlist, prlistlen); sendbuf->curpos = sendbuf->curpos + prlistlen; } /*-----------------------------*/ /* Add the rest of the message */ /*-----------------------------*/ memcpy(sendbuf->curpos, buf, bufsize); /*----------------------*/ /* send the send buffer */ /*----------------------*/ result = SLPNetworkSendMessage(sock, sendbuf, destaddr, &timeout); if(result != 0) { /* we could not send the message for some reason */ /* we're done */ result = SLP_NETWORK_ERROR; goto FINISHED; } /*----------------*/ /* Main recv loop */ /*----------------*/ while(1) { if(SLPNetworkRecvMessage(sock, &recvbuf, &peeraddr, &timeout) != 0) { /* An error occured while receiving the message */ /* probably a just time out error. Retry send. */ break; } /* Parse the message and call callback */ msg = SLPMessageRealloc(msg); if(msg == 0) { result = SLP_MEMORY_ALLOC_FAILED; goto FINISHED; } if(SLPMessageParseBuffer(recvbuf, msg) == 0) { if (msg->header.xid == xid) { rplycount = rplycount + 1; if(callback(result, msg, cookie) == 0) { goto CLEANUP; } } } if(socktype == SOCK_STREAM) { goto FINISHED; } /* add the peer to the previous responder list */ if(prlistlen != 0) { strcat(prlist,","); } strcat(prlist,inet_ntoa(peeraddr.sin_addr)); prlistlen = strlen(prlist); } } FINISHED: /*----------------*/ /* We're all done */ /*----------------*/ if(rplycount == 0) { result = SLP_NETWORK_TIMED_OUT; } /*-------------------------------------*/ /* Notify the callback that we're done */ /*-------------------------------------*/ callback(SLP_LAST_CALL,msg,cookie); /*----------------*/ /* Free resources */ /*----------------*/ CLEANUP: if(prlist) free(prlist); SLPBufferFree(sendbuf); SLPBufferFree(recvbuf); SLPMessageFree(msg); close(sock); return result; }