/** SLPReg callback routine for NetworkRqstRply. * * @param[in] errorcode - The network operation SLPError result. * @param[in] peeraddr - The network address of the responder. * @param[in] replybuf - The response buffer from the network request. * @param[in] cookie - Callback context data from ProcessSrvReg. * * @return SLP_FALSE (to stop any iterative callbacks). * * @note The SLPv2 wire protocol error codes are negated values of SLP * API error codes (SLPError values). Thus, the algorithm for converting * from an SLPv2 wire protocol error to a client SLPReg error is to simply * negate the wire protocol error value and cast the result to an SLPError. * * @todo Verify that no non-SLPError wire values make it back to this * routine, to be mis-converted into a non-existent SLPError value. * * @internal */ static SLPBoolean CallbackSrvReg(SLPError errorcode, void * peeraddr, SLPBuffer replybuf, void * cookie) { SLPHandleInfo * handle = (SLPHandleInfo *)cookie; /* Check the errorcode and bail if it is set. */ if (errorcode == 0) { /* Parse the replybuf into a message. */ SLPMessage * replymsg = SLPMessageAlloc(); if (replymsg) { errorcode = (SLPError)(-SLPMessageParseBuffer( peeraddr, 0, replybuf, replymsg)); if (errorcode == 0 && replymsg->header.functionid == SLP_FUNCT_SRVACK) errorcode = (SLPError)(-replymsg->body.srvack.errorcode); else errorcode = SLP_NETWORK_ERROR; SLPMessageFree(replymsg); } else errorcode = SLP_MEMORY_ALLOC_FAILED; } /* Call the user's callback function. */ handle->params.reg.callback(handle, errorcode, handle->params.reg.cookie); return SLP_FALSE; }
/** SLPFindSrvTypes callback routine for NetworkRqstRply. * * @param[in] errorcode - The network operation error code. * @param[in] peerinfo - The network address of the responder. * @param[in] replybuf - The response buffer from the network request. * @param[in] cookie - Callback context data from ProcessSrvReg. * * @return SLP_FALSE (to stop any iterative callbacks). * * @internal */ static SLPBoolean ProcessSrvTypeRplyCallback(SLPError errorcode, void * peerinfo, SLPBuffer replybuf, void * cookie) { SLPMessage * replymsg; SLPBoolean result = SLP_TRUE; SLPHandleInfo * handle = (SLPHandleInfo *)cookie; /* Check the errorcode and bail if it is set. */ if (errorcode) return CollateToSLPSrvTypeCallback(handle, 0, errorcode); /* Parse the replybuf. */ replymsg = SLPMessageAlloc(); if (replymsg) { if (!SLPMessageParseBuffer(peerinfo, 0, replybuf, replymsg) && replymsg->header.functionid == SLP_FUNCT_SRVTYPERPLY && !replymsg->body.srvtyperply.errorcode) { SLPSrvTypeRply * srvtyperply = &replymsg->body.srvtyperply; if (srvtyperply->srvtypelistlen) result = CollateToSLPSrvTypeCallback((SLPHandle)handle, srvtyperply->srvtypelist, srvtyperply->errorcode * -1); } SLPMessageFree(replymsg); } return result; }
/*=========================================================================*/ void SLPDLogTraceMsg(const char* prefix, struct sockaddr_in* peeraddr, SLPBuffer buf) /*=========================================================================*/ { SLPMessage msg; if(G_SlpdProperty.traceMsg) { msg = SLPMessageAlloc(); if(msg) { if(SLPMessageParseBuffer(buf,msg) == 0) { SLPLog("----------------------------------------\n"); SLPLog("traceMsg %s:\n",prefix); SLPLog("----------------------------------------\n"); SLPDLogPeerAddr(peeraddr); SLPDLogMessage(msg); SLPLog("\n"); } } SLPMessageFree(msg); } }
/*----------------------------------------------------------------------------*/ SLPBoolean ProcessSrvTypeRplyCallback(SLPError errorcode, struct sockaddr_in* peerinfo, SLPBuffer replybuf, void* cookie) /*----------------------------------------------------------------------------*/ { SLPMessage replymsg; SLPSrvTypeRply* srvtyperply; PSLPHandleInfo handle = (PSLPHandleInfo) cookie; SLPBoolean result = SLP_TRUE; /*-------------------------------------------*/ /* Check the errorcode and bail if it is set */ /*-------------------------------------------*/ if(errorcode) { return ColateSrvTypeCallback((SLPHandle)handle, 0, errorcode, handle->params.findsrvtypes.cookie); } /*--------------------*/ /* Parse the replybuf */ /*--------------------*/ replymsg = SLPMessageAlloc(); if(replymsg) { if(SLPMessageParseBuffer(peerinfo,replybuf,replymsg) == 0 && replymsg->header.functionid == SLP_FUNCT_SRVTYPERPLY && replymsg->body.srvtyperply.errorcode == 0) { srvtyperply = &(replymsg->body.srvtyperply); if(srvtyperply->srvtypelistlen) { /*------------------------------------------*/ /* Send the service type list to the caller */ /*------------------------------------------*/ /* TRICKY: null terminate the srvtypelist by setting the last byte 0 */ ((char*)(srvtyperply->srvtypelist))[srvtyperply->srvtypelistlen] = 0; /* Call the callback function */ result = ColateSrvTypeCallback((SLPHandle)handle, srvtyperply->srvtypelist, srvtyperply->errorcode * - 1, handle->params.findsrvtypes.cookie); } } SLPMessageFree(replymsg); } return result; }
/*-------------------------------------------------------------------------*/ SLPBoolean CallbackSrvReg(SLPError errorcode, struct sockaddr_in* peerinfo, SLPBuffer replybuf, void* cookie) /*-------------------------------------------------------------------------*/ { SLPMessage replymsg; PSLPHandleInfo handle = (PSLPHandleInfo) cookie; /*-------------------------------------------*/ /* Check the errorcode and bail if it is set */ /*-------------------------------------------*/ if(errorcode == 0) { /*--------------------*/ /* Parse the replybuf */ /*--------------------*/ replymsg = SLPMessageAlloc(); if(replymsg) { errorcode = SLPMessageParseBuffer(peerinfo,replybuf,replymsg); if(errorcode == 0) { if(replymsg->header.functionid == SLP_FUNCT_SRVACK) { errorcode = replymsg->body.srvack.errorcode * - 1; } } SLPMessageFree(replymsg); } else { errorcode = SLP_MEMORY_ALLOC_FAILED; } } /*----------------------------*/ /* Call the callback function */ /*----------------------------*/ handle->params.reg.callback((SLPHandle)handle, errorcode, handle->params.reg.cookie); return SLP_FALSE; }
/*-------------------------------------------------------------------------*/ 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; }
/*=========================================================================*/ void SLPDLogMessage(int msglogflags, struct sockaddr_storage* peerinfo, struct sockaddr_storage* localaddr, SLPBuffer buf) /* Log record of receiving or sending an SLP Message. Logging will only */ /* occur if message logging is enabled G_SlpProperty.traceMsg != 0 */ /* */ /* msglogflags (IN) What type of message to log */ /* */ /* peerinfo (IN) the source or destination peer */ /* */ /* peerinfo (IN) the local address */ /* */ /* msg (IN) the message to log */ /* */ /* Returns: none */ /*=========================================================================*/ { SLPMessage msg; char addr_str[INET6_ADDRSTRLEN]; if (peerinfo == NULL || buf == NULL) { return; } if ((G_SlpdProperty.traceMsg && (msglogflags & SLPDLOG_TRACEMSG)) || (G_SlpdProperty.traceDrop && (msglogflags & SLPDLOG_TRACEDROP)) ) { /* Don't log localhost traffic since it is probably IPC */ /* and don't log empty messages */ if (!SLPNetIsLocal(peerinfo) && buf->end != buf->start) { msg = SLPMessageAlloc(); if (msg) { SLPDLog("\n"); SLPDLogTime(); SLPDLog("MESSAGE - "); if (msglogflags == SLPDLOG_TRACEMSG_OUT) { SLPDLog("Trace message (OUT)\n"); } else if (msglogflags == SLPDLOG_TRACEMSG_IN) { SLPDLog("Trace message (IN)\n"); } else if (msglogflags == SLPDLOG_TRACEDROP) { SLPDLog("Dropped message (following message silently ignored)\n"); } else { SLPDLog("\n"); } if (SLPMessageParseBuffer(peerinfo,localaddr,buf,msg) == 0) { SLPDLogMessageInternals(msg); } else { SLPDLog("Message parsing failed\n"); SLPDLog("Peer: \n"); SLPDLog(" IP address: %s\n", SLPNetSockAddrStorageToString(&(msg->peer), addr_str, sizeof(addr_str))); } SLPMessageFree(msg); } } } }
/*=========================================================================*/ int SLPDProcessMessage(SLPDPeerInfo* peerinfo, SLPBuffer recvbuf, SLPBuffer sendbuf) /* Processes the recvbuf and places the results in sendbuf */ /* */ /* recvfd - 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. */ /*=========================================================================*/ { SLPMessage message = 0; int result = 0; message = SLPMessageAlloc(); if(message == 0) { return SLP_ERROR_INTERNAL_ERROR; } result = SLPMessageParseBuffer(recvbuf, message); if(result == 0) { switch(message->header.functionid) { case SLP_FUNCT_SRVRQST: ProcessSrvRqst(peerinfo,message,sendbuf); break; case SLP_FUNCT_SRVREG: ProcessSrvReg(peerinfo,message,sendbuf); break; case SLP_FUNCT_SRVDEREG: ProcessSrvDeReg(peerinfo,message,sendbuf); break; case SLP_FUNCT_SRVACK: ProcessSrvAck(peerinfo,message,sendbuf); break; case SLP_FUNCT_ATTRRQST: ProcessAttrRqst(peerinfo,message,sendbuf); break; case SLP_FUNCT_DAADVERT: ProcessDAAdvert(peerinfo,message,sendbuf); break; case SLP_FUNCT_SRVTYPERQST: ProcessSrvTypeRqst(peerinfo,message,sendbuf); break; case SLP_FUNCT_SAADVERT: ProcessSAAdvert(peerinfo,message,sendbuf); break; default: /* this will NEVER happen */ break; } /* Log traceMsg of message was received and the one that will be sent */ if(G_SlpdProperty.traceMsg) { SLPDLogTraceMsg(peerinfo,recvbuf,sendbuf); } } else { /* TODO: Log here? */ } SLPMessageFree(message); return result; }
/*-------------------------------------------------------------------------*/ SLPBoolean ProcessSrvRplyCallback(SLPError errorcode, struct sockaddr_in* peerinfo, SLPBuffer replybuf, void* cookie) /*-------------------------------------------------------------------------*/ { int i; SLPUrlEntry* urlentry; SLPMessage replymsg; PSLPHandleInfo handle = (PSLPHandleInfo) cookie; SLPBoolean result = SLP_TRUE; #ifdef ENABLE_SLPv2_SECURITY int securityenabled; securityenabled = SLPPropertyAsBoolean(SLPGetProperty("net.slp.securityEnabled")); #endif /*-------------------------------------------*/ /* Check the errorcode and bail if it is set */ /*-------------------------------------------*/ if(errorcode != SLP_OK) { return ColateSLPSrvURLCallback((SLPHandle)handle, 0, 0, errorcode, handle->params.findsrvs.cookie); } /*--------------------*/ /* Parse the replybuf */ /*--------------------*/ replymsg = SLPMessageAlloc(); if(replymsg) { if(SLPMessageParseBuffer(peerinfo,replybuf,replymsg) == 0) { if(replymsg->header.functionid == SLP_FUNCT_SRVRPLY && replymsg->body.srvrply.errorcode == 0) { urlentry = replymsg->body.srvrply.urlarray; for(i=0;i<replymsg->body.srvrply.urlcount;i++) { #ifdef ENABLE_SLPv2_SECURITY /*-------------------------------*/ /* Validate the authblocks */ /*-------------------------------*/ if(securityenabled && SLPAuthVerifyUrl(handle->hspi, 1, &(urlentry[i]))) { /* authentication failed skip this URLEntry */ continue; } #endif /*--------------------------------*/ /* Send the URL to the API caller */ /*--------------------------------*/ /* TRICKY: null terminate the url by setting the authcount to 0 */ ((char*)(urlentry[i].url))[urlentry[i].urllen] = 0; result = ColateSLPSrvURLCallback((SLPHandle)handle, urlentry[i].url, (unsigned short)urlentry[i].lifetime, SLP_OK, handle->params.findsrvs.cookie); if(result == SLP_FALSE) { break; } } } else if(replymsg->header.functionid == SLP_FUNCT_DAADVERT && replymsg->body.daadvert.errorcode == 0) { #ifdef ENABLE_SLPv2_SECURITY if(securityenabled && SLPAuthVerifyDAAdvert(handle->hspi, 1, &(replymsg->body.daadvert))) { /* Verification failed. Ignore message */ SLPMessageFree(replymsg); return SLP_TRUE; } #endif ((char*)(replymsg->body.daadvert.url))[replymsg->body.daadvert.urllen] = 0; result = ColateSLPSrvURLCallback((SLPHandle)handle, replymsg->body.daadvert.url, SLP_LIFETIME_MAXIMUM, SLP_OK, handle->params.findsrvs.cookie); } else if(replymsg->header.functionid == SLP_FUNCT_SAADVERT) { #ifdef ENABLE_SLPv2_SECURITY if(securityenabled && SLPAuthVerifySAAdvert(handle->hspi, 1, &(replymsg->body.saadvert))) { /* Verification failed. Ignore message */ SLPMessageFree(replymsg); return SLP_TRUE; } #endif ((char*)(replymsg->body.saadvert.url))[replymsg->body.saadvert.urllen] = 0; result = ColateSLPSrvURLCallback((SLPHandle)handle, replymsg->body.saadvert.url, SLP_LIFETIME_MAXIMUM, SLP_OK, handle->params.findsrvs.cookie); } } SLPMessageFree(replymsg); } return result; }
/** SLPFindSrvs callback routine for NetworkRqstRply. * * @param[in] errorcode - The network operation error code. * @param[in] peeraddr - The network address of the responder. * @param[in] replybuf - The response buffer from the network request. * @param[in] cookie - Callback context data from ProcessSrvReg. * * @return SLP_FALSE (to stop any iterative callbacks). * * @internal */ static SLPBoolean ProcessSrvRplyCallback(SLPError errorcode, void * peeraddr, SLPBuffer replybuf, void * cookie) { SLPMessage * replymsg; SLPBoolean result = SLP_TRUE; SLPHandleInfo * handle = (SLPHandleInfo *)cookie; #ifdef ENABLE_SLPv2_SECURITY SLPBoolean securityEnabled = SLPPropertyAsBoolean("net.slp.securityEnabled"); #endif /* Check the errorcode and bail if it is set. */ if (errorcode != SLP_OK) return CollateToSLPSrvURLCallback(handle, 0, 0, errorcode); /* parse the replybuf */ replymsg = SLPMessageAlloc(); if (replymsg) { if (!SLPMessageParseBuffer(peeraddr, 0, replybuf, replymsg)) { if (replymsg->header.functionid == SLP_FUNCT_SRVRPLY && replymsg->body.srvrply.errorcode == 0) { int i; SLPUrlEntry * urlentry = replymsg->body.srvrply.urlarray; for (i = 0; i < replymsg->body.srvrply.urlcount; i++) { #ifdef ENABLE_SLPv2_SECURITY /* Validate the service authblocks. */ if (securityEnabled && SLPAuthVerifyUrl(handle->hspi, 1, &urlentry[i])) continue; /* Authentication failed, skip this URLEntry. */ #endif result = CollateToSLPSrvURLCallback(handle, urlentry[i].url, (unsigned short)urlentry[i].lifetime, SLP_OK); if (result == SLP_FALSE) break; } } else if (replymsg->header.functionid == SLP_FUNCT_DAADVERT && replymsg->body.daadvert.errorcode == 0) { #ifdef ENABLE_SLPv2_SECURITY if (securityEnabled && SLPAuthVerifyDAAdvert(handle->hspi, 1, &replymsg->body.daadvert)) { /* Verification failed. Ignore message. */ SLPMessageFree(replymsg); return SLP_TRUE; } #endif result = CollateToSLPSrvURLCallback(handle, replymsg->body.daadvert.url, SLP_LIFETIME_MAXIMUM, SLP_OK); } else if (replymsg->header.functionid == SLP_FUNCT_SAADVERT) { #ifdef ENABLE_SLPv2_SECURITY if (securityEnabled && SLPAuthVerifySAAdvert(handle->hspi, 1, &replymsg->body.saadvert)) { /* Verification failed. Ignore message. */ SLPMessageFree(replymsg); return SLP_TRUE; } #endif result = CollateToSLPSrvURLCallback(handle, replymsg->body.saadvert.url, SLP_LIFETIME_MAXIMUM, SLP_OK); } } SLPMessageFree(replymsg); } return result; }
/** 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; }
/** 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 SLPDProcessMessage(struct sockaddr_in* peerinfo, SLPBuffer recvbuf, SLPBuffer* sendbuf) /* Processes the recvbuf and places the results in sendbuf */ /* */ /* recvfd - 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. */ /*=========================================================================*/ { SLPMessage message = 0; int errorcode = 0; message = SLPMessageAlloc(); if(message == 0) { return SLP_ERROR_INTERNAL_ERROR; } errorcode = SLPMessageParseBuffer(recvbuf, message); #if defined(ENABLE_SLPv1) if(message->header.version == 1) return SLPDv1ProcessMessage(peerinfo, recvbuf, sendbuf, message, errorcode); #endif /* Log trace message */ SLPDLogTraceMsg("IN",peerinfo,recvbuf); switch(message->header.functionid) { case SLP_FUNCT_SRVRQST: errorcode = ProcessSrvRqst(peerinfo, message, sendbuf, errorcode); break; case SLP_FUNCT_SRVREG: errorcode = ProcessSrvReg(peerinfo, message,sendbuf, errorcode); if(errorcode == 0) { SLPDKnownDAEcho(peerinfo, message, recvbuf); } break; case SLP_FUNCT_SRVDEREG: errorcode = ProcessSrvDeReg(peerinfo, message,sendbuf, errorcode); if(errorcode == 0) { SLPDKnownDAEcho(peerinfo, message, recvbuf); } break; case SLP_FUNCT_SRVACK: errorcode = ProcessSrvAck(peerinfo, message,sendbuf, errorcode); break; case SLP_FUNCT_ATTRRQST: errorcode = ProcessAttrRqst(peerinfo, message,sendbuf, errorcode); break; case SLP_FUNCT_DAADVERT: errorcode = ProcessDAAdvert(peerinfo, message, sendbuf, errorcode); /* If necessary log that we received a DAAdvert */ SLPDLogDATrafficMsg("IN", peerinfo, message); break; case SLP_FUNCT_SRVTYPERQST: errorcode = ProcessSrvTypeRqst(peerinfo, message, sendbuf, errorcode); break; case SLP_FUNCT_SAADVERT: errorcode = ProcessSAAdvert(peerinfo, message, sendbuf, errorcode); break; default: /* This may happen on a really early parse error or version not */ /* supported error */ /* TODO log errorcode here */ break; } /* Log traceMsg of message was received and the one that will be sent */ SLPDLogTraceMsg("OUT",peerinfo,*sendbuf); SLPMessageFree(message); /* Log reception of important errors */ switch(errorcode) { case SLP_ERROR_DA_BUSY_NOW: SLPLog("DA_BUSY from %s\n", inet_ntoa(peerinfo->sin_addr)); break; case SLP_ERROR_INTERNAL_ERROR: SLPLog("INTERNAL_ERROR from %s\n", inet_ntoa(peerinfo->sin_addr)); break; case SLP_ERROR_PARSE_ERROR: SLPLog("PARSE_ERROR from %s\n", inet_ntoa(peerinfo->sin_addr)); break; case SLP_ERROR_VER_NOT_SUPPORTED: SLPLog("VER_NOT_SUPPORTED from %s\n", inet_ntoa(peerinfo->sin_addr)); break; } return errorcode; }
/*-------------------------------------------------------------------------*/ SLPBoolean ProcessAttrRplyCallback(SLPError errorcode, struct sockaddr_in* peerinfo, SLPBuffer replybuf, void* cookie) /*-------------------------------------------------------------------------*/ { SLPMessage replymsg; SLPAttrRply* attrrply; PSLPHandleInfo handle = (PSLPHandleInfo) cookie; SLPBoolean result = SLP_TRUE; #ifdef ENABLE_SLPv2_SECURITY int securityenabled; securityenabled = SLPPropertyAsBoolean(SLPGetProperty("net.slp.securityEnabled")); #endif /*-------------------------------------------*/ /* Check the errorcode and bail if it is set */ /*-------------------------------------------*/ if(errorcode) { handle->params.findattrs.callback((SLPHandle)handle, 0, errorcode, handle->params.findattrs.cookie); return SLP_FALSE; } /*--------------------*/ /* Parse the replybuf */ /*--------------------*/ replymsg = SLPMessageAlloc(); if(replymsg) { if(SLPMessageParseBuffer(peerinfo,replybuf,replymsg) == 0 && replymsg->header.functionid == SLP_FUNCT_ATTRRPLY && replymsg->body.attrrply.errorcode == 0) { attrrply = &(replymsg->body.attrrply); if(attrrply->attrlistlen) { #ifdef ENABLE_SLPv2_SECURITY /*-------------------------------*/ /* Validate the authblocks */ /*-------------------------------*/ if(SLPPropertyAsBoolean(SLPGetProperty("net.slp.securityEnabled")) && SLPAuthVerifyString(handle->hspi, 1, attrrply->attrlistlen, attrrply->attrlist, attrrply->authcount, attrrply->autharray)) { /* Could not verify the attr auth block */ SLPMessageFree(replymsg); return result; } #endif /*---------------------------------------*/ /* Send the attribute list to the caller */ /*---------------------------------------*/ /* TRICKY: null terminate the attrlist by setting the authcount to 0 */ ((char*)(attrrply->attrlist))[attrrply->attrlistlen] = 0; /* Call the callback function */ result = handle->params.findattrs.callback((SLPHandle)handle, attrrply->attrlist, attrrply->errorcode * -1, handle->params.findattrs.cookie); } } SLPMessageFree(replymsg); } return result; }
/*=========================================================================*/ 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; }