/** Release all unused socket on inbound socket list. * * Deinitialize incoming socket list to have appropriate sockets for all * network interfaces. * * @param[in] graceful - Flag indicates do NOT close sockets with pending * writes outstanding. * * @return Zero on success, or a non-zero value when pending writes * remain. */ int SLPDOutgoingDeinit(int graceful) { SLPDSocket * del = 0; SLPDSocket * sock = (SLPDSocket *) G_OutgoingSocketList.head; while (sock) { /* graceful only closes sockets without pending I/O */ if (graceful == 0) del = sock; else if (sock->state < SOCKET_PENDING_IO) del = sock; sock = (SLPDSocket *) sock->listitem.next; if (del) { SLPDSocketFree((SLPDSocket *) SLPListUnlink(&G_OutgoingSocketList, (SLPListItem *) del)); del = 0; } } return G_OutgoingSocketList.count; }
/*=========================================================================*/ int KnownDABadDA(struct sockaddr_in* peeraddr) /* Mark a KnownDA as a Bad DA. */ /* */ /* peeraddr (IN) address of the bad DA */ /* */ /* Returns: zero on success. */ /*=========================================================================*/ { SLPDAEntry* entry; entry = (SLPDAEntry*)G_KnownDACache.head; while(entry) { if(memcmp(&(peeraddr->sin_addr), &(entry->daaddr), sizeof(struct in_addr)) == 0) { /* Remove entry from list and free it */ SLPDAEntryFree( (SLPDAEntry*)SLPListUnlink(&G_KnownDACache, (SLPListItem*)entry) ); break; } entry = (SLPDAEntry*) entry->listitem.next; } return 0; }
/*=========================================================================*/ int SLPDOutgoingDeinit(int graceful) /* Deinitialize incoming socket list to have appropriate sockets for all */ /* network interfaces */ /* */ /* graceful (IN) Do not close sockets with pending writes */ /* */ /* Returns Zero on success non-zero when pending writes remain */ /*=========================================================================*/ { SLPDSocket* del = 0; SLPDSocket* sock = (SLPDSocket*)G_OutgoingSocketList.head; while ( sock ) { /* graceful only closes sockets without pending I/O */ if ( graceful == 0 ) { del = sock; } else if ( sock->state < SOCKET_PENDING_IO ) { del = sock; } sock = (SLPDSocket*)sock->listitem.next; if ( del ) { SLPDSocketFree((SLPDSocket*)SLPListUnlink(&G_OutgoingSocketList,(SLPListItem*)del)); del = 0; } } return G_OutgoingSocketList.count; }
/*=========================================================================*/ void SLPDDatabaseAge(int seconds) /* Agea the database entries and clears new and deleted entry lists */ /* */ /* seconds (IN) the number of seconds to age each entry by */ /* */ /* Returns - None */ /*=========================================================================*/ { SLPDDatabaseEntry* entry; SLPDDatabaseEntry* del = 0; /* Age the database */ entry = (SLPDDatabaseEntry*)G_DatabaseList.head; while(entry) { /* don't age services with lifetime > SLP_LIFETIME_MAXIMUM */ if(entry->lifetime < SLP_LIFETIME_MAXIMUM) { entry->lifetime = entry->lifetime - seconds; if(entry->lifetime <= 0) { del = entry; } } entry = (SLPDDatabaseEntry*)entry->listitem.next; if(del) { FreeEntry((SLPDDatabaseEntry*)SLPListUnlink(&G_DatabaseList,(SLPListItem*)del)); del = 0; } } }
/*=========================================================================*/ int SLPDDatabaseReInit(const char* regfile) /* Re-initialize the database with changed registrations from a regfile. */ /* */ /* regfile (IN) the regfile to register. */ /* */ /* Returns - zero on success or non-zero on error. */ /*=========================================================================*/ { /* Delete all static registrations */ SLPDDatabaseEntry* del; SLPDDatabaseEntry* entry = (SLPDDatabaseEntry*)G_DatabaseList.head; /* delete all the static entries */ while(entry) { if(entry->regtype & SLPDDATABASE_REG_STATIC) { del = entry; entry = (SLPDDatabaseEntry*) entry->listitem.next; SLPDDatabaseEntryFree((SLPDDatabaseEntry*)SLPListUnlink(&G_DatabaseList, (SLPListItem*)del)); } else { entry = (SLPDDatabaseEntry*) entry->listitem.next; } } /* reload all the static entries by calling the init function */ return SLPDDatabaseInit(regfile); }
/*=========================================================================*/ 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 _xfree(const char* file, int line, void* buf) /*=========================================================================*/ { xallocation_t* x; x =_xmalloc_find(buf); if(x == NULL) { if(G_xmalloc_fh) { fprintf(G_xmalloc_fh, "*** xfree called on non xmalloced memory ***\n"); } return; } if(G_xmalloc_fh) { fprintf(G_xmalloc_fh,"Called xfree() %s:%i ",file,line); _xmalloc_log(x); } G_xmalloc_allocmem -= x->size; free(x->buf); free(SLPListUnlink(&G_xmalloc_list, (SLPListItem*)x)); }
/*-------------------------------------------------------------------------*/ void LoadFdSets(SLPList* socklist, int* highfd, fd_set* readfds, fd_set* writefds) /*-------------------------------------------------------------------------*/ { SLPDSocket* sock = 0; SLPDSocket* del = 0; sock = (SLPDSocket*)socklist->head; while(sock) { if(sock->fd > *highfd) { *highfd = sock->fd; } switch(sock->state) { case DATAGRAM_UNICAST: case DATAGRAM_MULTICAST: case DATAGRAM_BROADCAST: FD_SET(sock->fd,readfds); break; case SOCKET_LISTEN: if(socklist->count < SLPD_MAX_SOCKETS) { FD_SET(sock->fd,readfds); } break; case STREAM_READ: case STREAM_READ_FIRST: FD_SET(sock->fd,readfds); break; case STREAM_WRITE: case STREAM_WRITE_FIRST: case STREAM_CONNECT_BLOCK: FD_SET(sock->fd,writefds); break; case SOCKET_CLOSE: del = sock; break; default: break; } sock = (SLPDSocket*)sock->listitem.next; if(del) { SLPDSocketFree((SLPDSocket*)SLPListUnlink(socklist,(SLPListItem*)del)); del = 0; } } }
/*-------------------------------------------------------------------------*/ void FreeAllEntries(SLPList* list) /*-------------------------------------------------------------------------*/ { while(list->count) { FreeEntry((SLPDDatabaseEntry*)SLPListUnlink(list,list->head)); } }
/*=========================================================================*/ void SLPDDatabaseDeinit() /* De-initialize the database. Free all resources taken by registrations */ /*=========================================================================*/ { while(G_DatabaseList.count) { SLPDDatabaseEntryFree((SLPDDatabaseEntry*)SLPListUnlink(&G_DatabaseList, G_DatabaseList.head)); } }
/** Set a new value for a property by name. * * If the value is NULL or empty, then simply erase the existing value and * return. * * @param[in] name - The name of the desired property. * @param[in] value - The new value to which @p name should be set or * NULL if the existing value should be removed. * @param[in] attrs - The attributes of this property - zero means no * attributes are assigned, other values include SLP_PA_USERSET and * SLP_PA_READONLY. * * @return Zero on success; -1 on error, with errno set. * * @remarks The @p attrs parameter contains a set of bit flags indicating * various attributes of the property. These attributes control write * permissions mostly. SLP_PA_USERSET means that an attribute may not * be changed by reading a configuration file, except in a complete * re-initialization scenario. SLP_PA_READONLY sounds like the same thing, * but it's not. The difference is that once set, properties with the * SLP_PA_READONLY attribute may NEVER be reset (again, except in a complete * re-initialization scenario), while properties with the SLP_PA_USERSET * attribute may only be reset by passing this same flag in @p attrs, * indicating that the caller is actually a user, and so has the right * to reset the property value. */ int SLPPropertySet(char const * name, char const * value, unsigned attrs) { size_t namesz, valuesz; SLPProperty * oldprop; SLPProperty * newprop = 0; /* we may be just removing the old */ bool update = true; /* reset if old property exists */ /* property names must not be null or empty */ SLP_ASSERT(name && *name); if (!name || !*name) return -1; if (value) { /* allocate property entry for this new value */ namesz = strlen(name) + 1; valuesz = strlen(value) + 1; if ((newprop = (SLPProperty*)xmalloc( sizeof(SLPProperty) - 1 + namesz + valuesz)) == 0) { errno = ENOMEM; return -1; } /* set internal pointers to trailing buffer space, copy values */ newprop->attrs = attrs; memcpy(newprop->name, name, namesz); newprop->value = newprop->name + namesz; memcpy(newprop->value, value, valuesz); } SLPMutexAcquire(s_PropDbLock); /* locate and possibly remove old property */ if ((oldprop = Find(name))!= 0) { /* update ONLY if old is clean, or new and old are user-settable . */ update = !oldprop->attrs || (oldprop->attrs == SLP_PA_USERSET && attrs == SLP_PA_USERSET); if (update) SLPListUnlink(&s_PropertyList, (SLPListItem *)oldprop); } /* link in new property, if specified and old property was removed */ if (newprop && update) SLPListLinkHead(&s_PropertyList, (SLPListItem *)newprop); SLPMutexRelease(s_PropDbLock); /* if old property was not removed, delete the new one instead */ xfree(update? oldprop: newprop); return update? 0: ((errno = EACCES), -1); }
/** Initialize outgoing socket list for all network interfaces. * * @return Zero - always. */ int SLPDOutgoingInit(void) { /*------------------------------------------------------------*/ /* First, remove all of the sockets that might be in the list */ /*------------------------------------------------------------*/ while (G_OutgoingSocketList.count) SLPDSocketFree((SLPDSocket *) SLPListUnlink(&G_OutgoingSocketList, (SLPListItem *) G_OutgoingSocketList.head)); return 0; }
/** Deinitialize the debug memory allocator. */ void xmalloc_deinit(void) { xmalloc_report(); if (G_xmalloc_fh) { fclose(G_xmalloc_fh); G_xmalloc_fh = NULL; } while (G_xmalloc_list.count) free(SLPListUnlink(&G_xmalloc_list, G_xmalloc_list.head)); memset(&G_xmalloc_list, 0, sizeof(G_xmalloc_list)); }
/*=========================================================================*/ int SLPDDatabaseDeReg(SLPSrvDeReg* srvdereg) /* Remove a service registration from the database */ /* */ /* regfile - (IN) filename of the registration file to read into the */ /* database. Pass in NULL for no file. */ /* */ /* Returns - Zero on success. Non-zero if syntax error in registration */ /* file. */ /*=========================================================================*/ { SLPDDatabaseEntry* del = 0; SLPDDatabaseEntry* entry = (SLPDDatabaseEntry*)G_DatabaseList.head; while(entry) { if(SLPCompareString(entry->urllen, entry->url, srvdereg->urlentry.urllen, srvdereg->urlentry.url) == 0) { if(SLPIntersectStringList(entry->scopelistlen, entry->scopelist, srvdereg->scopelistlen, srvdereg->scopelist) > 0) { if(G_SlpdProperty.traceReg) { SLPDLogTraceReg("SrvDeReg",entry); } del = entry; break; } } entry = (SLPDDatabaseEntry*) entry->listitem.next; if(del) { FreeEntry((SLPDDatabaseEntry*)SLPListUnlink(&G_DatabaseList,(SLPListItem*)del)); del = 0; } } return 0; }
/*=========================================================================*/ void xmalloc_deinit() /*=========================================================================*/ { xmalloc_report(); if(G_xmalloc_fh) { fclose(G_xmalloc_fh); } while(G_xmalloc_list.count) { free((xallocation_t*)SLPListUnlink(&G_xmalloc_list,G_xmalloc_list.head)); } memset(&G_xmalloc_list,0,sizeof(G_xmalloc_list)); }
/*=========================================================================*/ int KnownDAConnect(const char* scopelist, int scopelistlen, struct sockaddr_in* peeraddr, struct timeval* timeout) /*=========================================================================*/ { int sock; SLPDAEntry* entry; SLPDAEntry* del = 0; /* TODO THIS FUNCTION MUST BE SYNCRONIZED !! */ memset(peeraddr,0,sizeof(struct sockaddr_in)); peeraddr->sin_family = AF_INET; peeraddr->sin_port = htons(SLP_RESERVED_PORT); entry = (SLPDAEntry*)G_KnownDAList.head; while(entry) { if(SLPIntersectStringList(entry->scopelistlen, entry->scopelist, scopelistlen, scopelist)) { peeraddr->sin_addr = entry->daaddr; sock = SLPNetworkConnectStream(peeraddr,timeout); if(sock >= 0) { return sock; } del = entry; } entry = (SLPDAEntry*) entry->listitem.next; if (del) { SLPDAEntryFree((SLPDAEntry*)SLPListUnlink(&G_KnownDAList,(SLPListItem*)del)); KnownDASaveHints(); } } return -1; }
/*-------------------------------------------------------------------------*/ int SlpPerfTest1_slpdereg (SLPHandle hslp, SLPList* service_list, double* ave_slpdereg, int* count_slpdereg) /*-------------------------------------------------------------------------*/ { struct timezone tz; struct timeval start; struct timeval end; TestService_T* srv; SLPError errorcode; srv = FindRandomTestService(service_list); /* mark start time */ gettimeofday(&start,&tz); /* call SLP API */ errorcode = SLPDereg(hslp, srv->serviceurl, SlpPerfTest1_deregreport, srv); if(errorcode != SLP_OK) { printf("SLPDereg(hslp,%s,callback,0) returned %i\n", srv->serviceurl, errorcode); printf("This should not happen!\n"); return -1; } /* mark end time */ gettimeofday(&end,&tz); /* unlink the registered service from the list and free it*/ free(SLPListUnlink(service_list,(SLPListItem*)srv)); /* recalculate average time */ *ave_slpdereg = (*ave_slpdereg) * (*count_slpdereg) + ElapsedTime(&start,&end); *count_slpdereg = *count_slpdereg + 1; *ave_slpdereg = *ave_slpdereg / *count_slpdereg; return 0; }
/*=========================================================================*/ void SLPDDatabaseAge(int seconds, int ageall) /* Agea the database entries and clears new and deleted entry lists */ /* */ /* seconds (IN) the number of seconds to age each entry by */ /* */ /* ageall (IN) age even entries with SLP_LIFETIME_MAX */ /* */ /* Returns - None */ /*=========================================================================*/ { SLPDDatabaseEntry* entry; SLPDDatabaseEntry* del = 0; /* Age the database */ entry = (SLPDDatabaseEntry*)G_DatabaseList.head; while(entry) { /*-----------------------------------------------------------*/ /* OK, if an entry is local and has a lifetime of */ /* SLP_LIFETIME_MAXIMUM then it must never ever ever be aged */ /*-----------------------------------------------------------*/ if(!(entry->regtype & SLPDDATABASE_REG_LOCAL && entry->lifetime == SLP_LIFETIME_MAXIMUM)) { /*---------------------------------------------------------*/ /* don't age services with lifetime > SLP_LIFETIME_MAXIMUM */ /* unless explicitly told to */ /*---------------------------------------------------------*/ if(ageall || entry->lifetime < SLP_LIFETIME_MAXIMUM) { entry->lifetime = entry->lifetime - seconds; if(entry->lifetime <= 0) { del = entry; } } } entry = (SLPDDatabaseEntry*)entry->listitem.next; if(del) { SLPDDatabaseEntryFree((SLPDDatabaseEntry*)SLPListUnlink(&G_DatabaseList,(SLPListItem*)del)); del = 0; } } }
/*=========================================================================*/ void SLPDIncomingAge(time_t seconds) /*=========================================================================*/ { SLPDSocket* del = 0; SLPDSocket* sock = (SLPDSocket*)G_IncomingSocketList.head; while (sock) { switch (sock->state) { case STREAM_READ_FIRST: case STREAM_READ: case STREAM_WRITE_FIRST: case STREAM_WRITE: if (G_IncomingSocketList.count > SLPD_COMFORT_SOCKETS) { /* Accellerate ageing cause we are low on sockets */ if (sock->age > SLPD_CONFIG_BUSY_CLOSE_CONN) { del = sock; } } else { if (sock->age > SLPD_CONFIG_CLOSE_CONN) { del = sock; } } sock->age = sock->age + seconds; break; default: /* don't age the other sockets at all */ break; } sock = (SLPDSocket*)sock->listitem.next; if (del) { SLPDSocketFree((SLPDSocket*)SLPListUnlink(&G_IncomingSocketList,(SLPListItem*)del)); del = 0; } } }
/*=========================================================================*/ void SLPDIncomingAge(time_t seconds) /*=========================================================================*/ { SLPDSocket* del = 0; SLPDSocket* sock = (SLPDSocket*)G_IncomingSocketList.head; while(sock) { switch (sock->state) { case STREAM_READ_FIRST: case STREAM_READ: case STREAM_WRITE_FIRST: case STREAM_WRITE: sock->age = sock->age + seconds; if(G_IncomingSocketList.count > SLPD_COMFORT_SOCKETS) { if (sock->age > G_SlpdProperty.unicastMaximumWait) { del = sock; } } else { if (sock->age > SLPD_MAX_SOCKET_LIFETIME) { del = sock; } } break; default: /* don't age the other sockets at all */ break; } sock = (SLPDSocket*)sock->listitem.next; if(del) { SLPDSocketFree((SLPDSocket*)SLPListUnlink(&G_IncomingSocketList,(SLPListItem*)del)); del = 0; } } }
/*=========================================================================*/ int SLPDOutgoingInit() /* Initialize outgoing socket list to have appropriate sockets for all */ /* network interfaces */ /* */ /* list (IN/OUT) pointer to a socket list to be filled with sockets */ /* */ /* Returns Zero on success non-zero on error */ /*=========================================================================*/ { /*------------------------------------------------------------*/ /* First, remove all of the sockets that might be in the list */ /*------------------------------------------------------------*/ while ( G_OutgoingSocketList.count ) { SLPDSocketFree((SLPDSocket*)SLPListUnlink(&G_OutgoingSocketList,(SLPListItem*)G_OutgoingSocketList.head)); } return 0; }
/*=========================================================================*/ int SLPDIncomingDeinit() /* Deinitialize incoming socket list to have appropriate sockets for all */ /* network interfaces */ /* */ /* Returns Zero on success non-zero on error */ /*=========================================================================*/ { SLPDSocket* del = 0; SLPDSocket* sock = (SLPDSocket*)G_IncomingSocketList.head; while (sock) { del = sock; sock = (SLPDSocket*)sock->listitem.next; if (del) { SLPDSocketFree((SLPDSocket*)SLPListUnlink(&G_IncomingSocketList,(SLPListItem*)del)); del = 0; } } return 0; }
/** Free's a block of memory (DEBUG). * * @param[in] file - The file where @e xfree was called. * @param[in] line - The line number where @e xfree was called. * @param[in] ptr - The address of the block to be free'd. */ void _xfree(const char * file, int line, void * ptr) { xallocation_t * x; x =_xmalloc_find(ptr); if (x == 0) { if (G_xmalloc_fh) fprintf(G_xmalloc_fh, "*** xfree called on " "non-xmalloc'd memory ***\n"); return; } if (G_xmalloc_fh) { fprintf(G_xmalloc_fh, "Called xfree at %s:%i ", file, line); _xmalloc_log(x); } G_xmalloc_allocmem -= x->size; free(x->buf); free(SLPListUnlink(&G_xmalloc_list, (SLPListItem *)x)); }
/*-------------------------------------------------------------------------*/ int KnownDAListRemove(SLPList* dalist, SLPDAEntry* remove) /* Remove an entry to the KnownDA cach */ /*-------------------------------------------------------------------------*/ { SLPDAEntry* entry; entry = (SLPDAEntry*)dalist->head; while(entry) { if(SLPCompareString(remove->urllen, remove->url, entry->urllen, entry->url) == 0) { /* Remove entry from list and free it */ SLPDAEntryFree( (SLPDAEntry*)SLPListUnlink(dalist, (SLPListItem*)entry) ); break; } entry = (SLPDAEntry*) entry->listitem.next; } return 0; }
/** 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 SLPPropertySet(const char *pcName, const char *pcValue) /*=========================================================================*/ { int pcNameSize; int pcValueSize; SLPProperty* newProperty; if(pcValue == 0) { /* Bail for right now */ return 0; } newProperty = Find(pcName); pcNameSize = strlen(pcName) + 1; pcValueSize = strlen(pcValue) + 1; if(newProperty == 0) { /* property does not exist in the list */ newProperty = (SLPProperty*)xmalloc(sizeof(SLPProperty) + pcNameSize + pcValueSize); if(newProperty == 0) { /* out of memory */ errno = ENOMEM; return -1; } /* set the pointers in the SLPProperty structure to point to areas of */ /* the previously allocated block of memory */ newProperty->propertyName = ((char*)newProperty) + sizeof(SLPProperty); newProperty->propertyValue = newProperty->propertyName + pcNameSize; /* copy the passed in name and value */ memcpy(newProperty->propertyName,pcName,pcNameSize); memcpy(newProperty->propertyValue,pcValue,pcValueSize); /* Link the new property into the list */ SLPListLinkHead(&G_SLPPropertyList,(SLPListItem*)newProperty); } else { SLPListUnlink(&G_SLPPropertyList,(SLPListItem*)newProperty); /* property already exists in the list */ newProperty = (SLPProperty*)xrealloc(newProperty,sizeof(SLPProperty) + pcNameSize + pcValueSize); if(newProperty == 0) { /* out of memory */ errno = ENOMEM; return -1; } /* set the pointers in the SLPProperty structure to point to areas of */ /* the previously allocated block of memory */ newProperty->propertyName = ((char*)newProperty) + sizeof(SLPProperty); newProperty->propertyValue = newProperty->propertyName + pcNameSize; /* copy the passed in name and value */ memcpy(newProperty->propertyName,pcName,pcNameSize); memcpy(newProperty->propertyValue,pcValue,pcValueSize); SLPListLinkHead(&G_SLPPropertyList,(SLPListItem*)newProperty); } return 0; }
/*-------------------------------------------------------------------------*/ SLPBoolean ColateSLPSrvURLCallback(SLPHandle hSLP, const char* pcSrvURL, unsigned short sLifetime, SLPError errCode, void *pvCookie) /*-------------------------------------------------------------------------*/ { SLPSrvUrlColatedItem* collateditem; PSLPHandleInfo handle; handle = (PSLPHandleInfo) hSLP; handle->callbackcount ++; #ifdef ENABLE_ASYNC_API /* Do not colate for async calls */ if(handle->isAsync) { return handle->params.findsrvs.callback(hSLP, pcSrvURL, sLifetime, errCode, pvCookie); } #endif if(errCode == SLP_LAST_CALL || handle->callbackcount > SLPPropertyAsInteger(SLPGetProperty("net.slp.maxResults"))) { /* We are done so call the caller's callback for each */ /* service URL colated item and clean up the colation list */ handle->params.findsrvs.callback((SLPHandle)handle, NULL, 0, SLP_LAST_CALL, handle->params.findsrvs.cookie); goto CLEANUP; } else if(errCode != SLP_OK) { return SLP_TRUE; } /* Add the service URL to the colation list */ collateditem = (SLPSrvUrlColatedItem*) handle->collatedsrvurls.head; while(collateditem) { if(strcmp(collateditem->srvurl,pcSrvURL) == 0) { break; } collateditem = (SLPSrvUrlColatedItem*)collateditem->listitem.next; } /* create a new item if none was found */ if(collateditem == NULL) { collateditem = (SLPSrvUrlColatedItem*) xmalloc(sizeof(SLPSrvUrlColatedItem) + \ strlen(pcSrvURL) + 1); if(collateditem) { memset(collateditem,0,sizeof(SLPSrvUrlColatedItem)); collateditem->srvurl = (char*)(collateditem + 1); strcpy(collateditem->srvurl,pcSrvURL); collateditem->lifetime = sLifetime; /* Add the new item to the collated list */ SLPListLinkTail(&(handle->collatedsrvurls), (SLPListItem*)collateditem); /* Call the caller's callback */ if(handle->params.findsrvs.callback((SLPHandle)handle, pcSrvURL, sLifetime, SLP_OK, handle->params.findsrvs.cookie) == SLP_FALSE) { goto CLEANUP; } } } return SLP_TRUE; CLEANUP: /* free the collation list */ while(handle->collatedsrvurls.count) { collateditem = (SLPSrvUrlColatedItem*)SLPListUnlink(&(handle->collatedsrvurls), handle->collatedsrvurls.head); xfree(collateditem); } handle->callbackcount = 0; return SLP_FALSE; }
/** Collates response data to user callback for SLPFindSrv requests. * * @param[in] hSLP - The SLP handle object associated with the request. * @param[in] pcSrvURL - The service URL for this pass. * @param[in] sLifetime - The lifetime value for @p pcSrvURL. * @param[in] errorcode - The error code received on this pass. * * @return An SLP boolean value; SLP_TRUE indicates we are finished; * SLP_FALSE indicates we should continue. * * @todo Trace the logic of CollateToSLPSrvURLCallback to ensure * that it works. * * @internal */ static SLPBoolean CollateToSLPSrvURLCallback(SLPHandle hSLP, const char * pcSrvURL, unsigned short sLifetime, SLPError errorcode) { int maxResults; SLPHandleInfo * handle = hSLP; SLPSrvUrlCollatedItem * collateditem; #ifdef ENABLE_ASYNC_API /* Do not collate for async calls. */ if (handle->isAsync) return handle->params.findsrvs.callback(hSLP, pcSrvURL, sLifetime, errorcode, handle->params.findsrvs.cookie); #endif /* Configure behaviour for desired max results */ maxResults = SLPPropertyAsInteger("net.slp.maxResults"); if (maxResults == -1) maxResults = INT_MAX; if (errorcode == SLP_LAST_CALL || handle->callbackcount > maxResults) { /* We are done so call the caller's callback for each * service URL collated item and clean up the collation list. */ handle->params.findsrvs.callback(handle, 0, 0, SLP_LAST_CALL, handle->params.findsrvs.cookie); goto CLEANUP; } else if (errorcode != SLP_OK) return SLP_TRUE; /* We're adding another result - increment result count. */ handle->callbackcount++; /* Add the service URL to the colation list. */ collateditem = (SLPSrvUrlCollatedItem *)handle->collatedsrvurls.head; while (collateditem) { if (strcmp(collateditem->srvurl, pcSrvURL) == 0) break; collateditem = (SLPSrvUrlCollatedItem *)collateditem->listitem.next; } /* Create a new item if none was found. */ if (collateditem == 0) { collateditem = xmalloc(sizeof(SLPSrvUrlCollatedItem) + strlen(pcSrvURL) + 1); if (collateditem) { memset(collateditem, 0, sizeof(SLPSrvUrlCollatedItem)); collateditem->srvurl = (char *)(collateditem + 1); strcpy(collateditem->srvurl, pcSrvURL); collateditem->lifetime = sLifetime; /* Add the new item to the collated list. */ SLPListLinkTail(&handle->collatedsrvurls, (SLPListItem *)collateditem); /* Call the caller's callback. */ if (handle->params.findsrvs.callback(handle, pcSrvURL, sLifetime, SLP_OK, handle->params.findsrvs.cookie) == SLP_FALSE) goto CLEANUP; } } return SLP_TRUE; CLEANUP: /* Free the collation list. */ while (handle->collatedsrvurls.count) { collateditem = (SLPSrvUrlCollatedItem *)SLPListUnlink( &handle->collatedsrvurls, handle->collatedsrvurls.head); xfree(collateditem); } handle->callbackcount = 0; return SLP_FALSE; }
/*-------------------------------------------------------------------------*/ void OutgoingStreamRead(SLPList* socklist, SLPDSocket* sock) /*-------------------------------------------------------------------------*/ { int bytesread; char peek[16]; int peeraddrlen = sizeof(struct sockaddr_in); if ( sock->state == STREAM_READ_FIRST ) { /*---------------------------------------------------*/ /* take a peek at the packet to get size information */ /*---------------------------------------------------*/ bytesread = recvfrom(sock->fd, peek, 16, MSG_PEEK, (struct sockaddr *)&(sock->peeraddr), &peeraddrlen); if ( bytesread > 0 ) { /* allocate the recvbuf big enough for the whole message */ sock->recvbuf = SLPBufferRealloc(sock->recvbuf,AsUINT24(peek+2)); if ( sock->recvbuf ) { sock->state = STREAM_READ; } else { SLPDLog("INTERNAL_ERROR - out of memory!\n"); sock->state = SOCKET_CLOSE; } } else { #ifdef WIN32 if ( WSAEWOULDBLOCK != WSAGetLastError() ) #else if ( errno != EWOULDBLOCK ) #endif { /* Error occured or connection was closed. Try to reconnect */ /* Socket will be closed if connect times out */ OutgoingStreamReconnect(socklist,sock); } } } if ( sock->state == STREAM_READ ) { /*------------------------------*/ /* recv the rest of the message */ /*------------------------------*/ bytesread = recv(sock->fd, sock->recvbuf->curpos, sock->recvbuf->end - sock->recvbuf->curpos, 0); if ( bytesread > 0 ) { /* reset age because of activity */ sock->age = 0; /* move buffer pointers */ sock->recvbuf->curpos += bytesread; /* check to see if everything was read */ if ( sock->recvbuf->curpos == sock->recvbuf->end ) { switch ( SLPDProcessMessage(&(sock->peeraddr), sock->recvbuf, &(sock->sendbuf)) ) { case SLP_ERROR_DA_BUSY_NOW: sock->state = STREAM_WRITE_WAIT; break; case SLP_ERROR_PARSE_ERROR: case SLP_ERROR_VER_NOT_SUPPORTED: sock->state = SOCKET_CLOSE; break; default: /* End of outgoing message exchange. Unlink */ /* send buf from to do list and free it */ SLPBufferFree((SLPBuffer)SLPListUnlink(&(sock->sendlist),(SLPListItem*)(sock->sendbuf))); sock->state = STREAM_WRITE_FIRST; /* clear the reconnection count since we actually * transmitted a successful message exchange */ sock->reconns = 0; break; } } } else { #ifdef WIN32 if ( WSAEWOULDBLOCK != WSAGetLastError() ) #else if ( errno != EWOULDBLOCK ) #endif { /* Error occured or connection was closed. Try to reconnect */ /* Socket will be closed if connect times out */ OutgoingStreamReconnect(socklist,sock); } } } }
/*=========================================================================*/ void SLPDOutgoingAge(time_t seconds) /*=========================================================================*/ { SLPDSocket* del = 0; SLPDSocket* sock = (SLPDSocket*)G_OutgoingSocketList.head; while ( sock ) { switch ( sock->state ) { case DATAGRAM_MULTICAST: case DATAGRAM_BROADCAST: case DATAGRAM_UNICAST: if ( sock->age > G_SlpdProperty.unicastMaximumWait / 1000 ) { del = sock; } sock->age = sock->age + seconds; break; case STREAM_READ_FIRST: case STREAM_WRITE_FIRST: sock->age = 0; break; case STREAM_CONNECT_BLOCK: case STREAM_READ: case STREAM_WRITE: if ( G_OutgoingSocketList.count > SLPD_COMFORT_SOCKETS ) { /* Accellerate ageing cause we are low on sockets */ if ( sock->age > SLPD_CONFIG_BUSY_CLOSE_CONN ) { SLPDKnownDARemove(&(sock->peeraddr.sin_addr)); del = sock; } } else { if ( sock->age > SLPD_CONFIG_CLOSE_CONN ) { SLPDKnownDARemove(&(sock->peeraddr.sin_addr)); del = sock; } } sock->age = sock->age + seconds; break; case STREAM_WRITE_WAIT: sock->age = 0; sock->state = STREAM_WRITE_FIRST; break; default: /* don't age the other sockets at all */ break; } sock = (SLPDSocket*)sock->listitem.next; if ( del ) { SLPDSocketFree((SLPDSocket*)SLPListUnlink(&G_OutgoingSocketList,(SLPListItem*)del)); del = 0; } } }