/** Thread start procedure for asynchronous service registration. * * @param[in] handle - Contains the request parameters. * * @return An SLPError code. * * @internal */ static SLPError AsyncProcessSrvReg(SLPHandleInfo * handle) { SLPError serr = ProcessSrvReg(handle); xfree((void *)handle->params.reg.url); xfree((void *)handle->params.reg.srvtype); xfree((void *)handle->params.reg.scopelist); xfree((void *)handle->params.reg.attrlist); SLPSpinLockRelease(&handle->inUse); return serr; }
/*-------------------------------------------------------------------------*/ SLPError AsyncProcessSrvReg(PSLPHandleInfo handle) /*-------------------------------------------------------------------------*/ { SLPError result = ProcessSrvReg(handle); xfree((void*)handle->params.reg.url); xfree((void*)handle->params.reg.srvtype); xfree((void*)handle->params.reg.scopelist); xfree((void*)handle->params.reg.attrlist); handle->inUse = SLP_FALSE; return result; }
/*=========================================================================*/ 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; }
/*=========================================================================*/ SLPError SLPReg(SLPHandle hSLP, const char *srvUrl, const unsigned short lifetime, const char *srvType, const char *attrList, SLPBoolean fresh, SLPRegReport callback, void *cookie) /* */ /* See slplib.h for detailed documentation */ /*=========================================================================*/ { PSLPHandleInfo handle = 0; SLPError result = SLP_OK; SLPSrvURL* parsedurl = 0; /*------------------------------*/ /* check for invalid parameters */ /*------------------------------*/ if(hSLP == 0 || *(unsigned int*)hSLP != SLP_HANDLE_SIG || srvUrl == 0 || *srvUrl == 0 || /* srvUrl can't be empty string */ lifetime == 0 || /* lifetime can not be zero */ attrList == 0 || callback == 0) { return SLP_PARAMETER_BAD; } /*-----------------------------------------*/ /* We don't handle fresh registrations */ /*-----------------------------------------*/ if(fresh == SLP_FALSE) { return SLP_NOT_IMPLEMENTED; } /*-----------------------------------------*/ /* cast the SLPHandle into a SLPHandleInfo */ /*-----------------------------------------*/ handle = (PSLPHandleInfo)hSLP; /*-----------------------------------------*/ /* Check to see if the handle is in use */ /*-----------------------------------------*/ if(handle->inUse == SLP_TRUE) { return SLP_HANDLE_IN_USE; } handle->inUse = SLP_TRUE; /*------------------*/ /* Parse the srvurl */ /*------------------*/ result = SLPParseSrvURL(srvUrl,&parsedurl); if(result) { if(result == SLP_PARSE_ERROR) { result = SLP_INVALID_REGISTRATION; } if(parsedurl) SLPFree(parsedurl); handle->inUse = SLP_FALSE; return result; } /*-------------------------------------------*/ /* Set the handle up to reference parameters */ /*-------------------------------------------*/ handle->params.reg.fresh = fresh; handle->params.reg.lifetime = lifetime; handle->params.reg.urllen = strlen(srvUrl); handle->params.reg.url = srvUrl; handle->params.reg.srvtype = parsedurl->s_pcSrvType; handle->params.reg.srvtypelen = strlen(handle->params.reg.srvtype); handle->params.reg.scopelist = SLPGetProperty("net.slp.useScopes"); if(handle->params.reg.scopelist) { handle->params.reg.scopelistlen = strlen(handle->params.reg.scopelist); } handle->params.reg.attrlistlen = strlen(attrList); handle->params.reg.attrlist = attrList; handle->params.reg.callback = callback; handle->params.reg.cookie = cookie; #ifdef ENABLE_ASYNC_API /*----------------------------------------------*/ /* Check to see if we should be async or sync */ /*----------------------------------------------*/ if(handle->isAsync) { /* Copy all of the referenced parameters before making thread */ handle->params.reg.url = xstrdup(handle->params.reg.url); handle->params.reg.srvtype = xstrdup(handle->params.reg.url); handle->params.reg.scopelist = xstrdup(handle->params.reg.scopelist); handle->params.reg.attrlist = xstrdup(handle->params.reg.attrlist); /* make sure that the strdups did not fail */ if(handle->params.reg.url && handle->params.reg.srvtype && handle->params.reg.scopelist && handle->params.reg.attrlist) { result = ThreadCreate((ThreadStartProc)AsyncProcessSrvReg,handle); } else { result = SLP_MEMORY_ALLOC_FAILED; } if(result) { if(handle->params.reg.url) xfree((void*)handle->params.reg.url); if(handle->params.reg.srvtype) xfree((void*)handle->params.reg.srvtype); if(handle->params.reg.scopelist) xfree((void*)handle->params.reg.scopelist); if(handle->params.reg.attrlist) xfree((void*)handle->params.reg.attrlist); handle->inUse = SLP_FALSE; } } else #endif //ffdef ENABLE_ASYNC_API { result = ProcessSrvReg(handle); handle->inUse = SLP_FALSE; } if(parsedurl) SLPFree(parsedurl); return result; }
/** Register a service URL through OpenSLP. * * Registers the URL in @p pcSrvURL having the lifetime usLifetime with * the attribute list in pcAttrs. The @p pcAttrs list is a comma separated * list of attribute assignments in the wire format (including escaping * of reserved characters). The @p usLifetime parameter must be nonzero * and less than or equal to SLP_LIFETIME_MAXIMUM. If the @p fresh flag * is SLP_TRUE, then the registration is new (the SLP protocol FRESH flag * is set) and the registration replaces any existing registrations. * The @p pcSrvType parameter is a service type name and can be included * for service URLs that are not in the service: scheme. If the URL is * in the service: scheme, the @p pcSrvType parameter is ignored. If the * @p fresh flag is SLP_FALSE, then an existing registration is updated. * Rules for new and updated registrations, and the format for @p pcAttrs * and @p pcScopeList can be found in [RFC 2608]. Registrations and * updates take place in the language locale of the @p hSLP handle. * * @par * The API library is required to perform the operation in all scopes * obtained through configuration. * * @param[in] hSLP - The language-specific SLPHandle on which to register * the advertisement. * @param[in] srvUrl - The URL to register. May not be the empty string. * May not be NULL. Must conform to SLP Service URL syntax. * SLP_INVALID_REGISTRATION will be returned if not. * @param[in] lifetime - An unsigned short giving the life time of the * service advertisement, in seconds. The value must be an unsigned * integer less than or equal to SLP_LIFETIME_MAXIMUM, and greater * than zero. If SLP_LIFETIME_MAXIMUM is used, the registration * will remain for the life of the calling process. Also, OpenSLP, * will not allow registrations to be made with SLP_LIFETIME_MAXIMUM * unless SLP_REG_FLAG_WATCH_PID is also used. Note that RFC 2614 * defines this parameter as const unsigned short. The 'const' is * superfluous. * @param[in] srvType - The service type. If @p pURL is a "service:" * URL, then this parameter is ignored. (ALWAYS ignored since the SLP * Service URL syntax required for the @p pcSrvURL encapsulates the * service type.) * @param[in] attrList - A comma separated list of attribute assignment * expressions for the attributes of the advertisement. Use empty * string ("") for no attributes. * @param[in] fresh - An SLPBoolean that is SLP_TRUE if the registration * is new or SLP_FALSE if a RE-registration. Use of non-fresh * registrations is deprecated (post RFC 2614). SLP_TRUE must be * passed in for this parameter or SLP_BAD_PARAMETER will be returned. * It also appears that this flag has been overloaded to accept certain * specific values of "true" for internal purposes... (jmc) * @param[in] callback - A callback to report the operation completion * status. * @param[in] cookie - Memory passed to the callback code from the * client. May be NULL. * * @return If an error occurs in starting the operation, one of the * SLPError codes is returned. */ SLPEXP SLPError SLPAPI SLPReg( SLPHandle hSLP, const char * srvUrl, unsigned short lifetime, const char * srvType, const char * attrList, SLPBoolean fresh, SLPRegReport callback, void * cookie) { bool inuse; SLPError serr; SLPSrvURL * parsedurl = 0; SLPHandleInfo * handle = hSLP; /** @todo Add code to accept non- "service:" scheme * URL's - normalize with srvType parameter info. */ (void)srvType; /* not used yet */ /* Check for invalid parameters. */ SLP_ASSERT(handle != 0); SLP_ASSERT(handle->sig == SLP_HANDLE_SIG); SLP_ASSERT(srvUrl != 0); SLP_ASSERT(*srvUrl != 0); SLP_ASSERT(lifetime != 0); SLP_ASSERT(attrList != 0); SLP_ASSERT(callback != 0); if (handle == 0 || handle->sig != SLP_HANDLE_SIG || srvUrl == 0 || *srvUrl == 0 || lifetime == 0 || attrList == 0 || callback == 0) return SLP_PARAMETER_BAD; /** @todo Handle non-fresh registrations in SLPReg. */ if (fresh == SLP_FALSE) return SLP_NOT_IMPLEMENTED; /* Check to see if the handle is in use. */ inuse = SLPSpinLockTryAcquire(&handle->inUse); SLP_ASSERT(!inuse); if (inuse) return SLP_HANDLE_IN_USE; /* Parse the srvurl - mainly for service type info. */ serr = SLPParseSrvURL(srvUrl, &parsedurl); if (serr) { SLPSpinLockRelease(&handle->inUse); return serr == SLP_PARSE_ERROR? SLP_INVALID_REGISTRATION: serr; } /* Set the handle up to reference parameters. */ handle->params.reg.fresh = fresh; handle->params.reg.lifetime = lifetime; handle->params.reg.urllen = strlen(srvUrl); handle->params.reg.url = srvUrl; handle->params.reg.srvtype = parsedurl->s_pcSrvType; handle->params.reg.srvtypelen = strlen(handle->params.reg.srvtype); handle->params.reg.scopelist = SLPPropertyGet("net.slp.useScopes", 0, 0); handle->params.reg.scopelistlen = strlen(handle->params.reg.scopelist); handle->params.reg.attrlistlen = strlen(attrList); handle->params.reg.attrlist = attrList; handle->params.reg.callback = callback; handle->params.reg.cookie = cookie; #ifdef ENABLE_ASYNC_API if (handle->isAsync) { /* Copy all of the referenced parameters before creating thread. */ handle->params.reg.url = xstrdup(handle->params.reg.url); handle->params.reg.srvtype = xstrdup(handle->params.reg.url); handle->params.reg.scopelist = xstrdup(handle->params.reg.scopelist); handle->params.reg.attrlist = xstrdup(handle->params.reg.attrlist); /* Ensure strdups and thread create succeed. */ if (handle->params.reg.url == 0 || handle->params.reg.srvtype == 0 || handle->params.reg.scopelist == 0 || handle->params.reg.attrlist == 0 || (handle->th = SLPThreadCreate((SLPThreadStartProc) AsyncProcessSrvReg, handle)) == 0) { serr = SLP_MEMORY_ALLOC_FAILED; xfree((void *)handle->params.reg.url); xfree((void *)handle->params.reg.srvtype); xfree((void *)handle->params.reg.scopelist); xfree((void *)handle->params.reg.attrlist); SLPSpinLockRelease(&handle->inUse); } } else #endif { /* Reference all the parameters. */ serr = ProcessSrvReg(handle); SLPSpinLockRelease(&handle->inUse); } SLPFree(parsedurl); return serr; }
/** 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; }
/*=========================================================================*/ 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; }