/*-------------------------------------------------------------------------*/ int v1ProcessSrvRqst(struct sockaddr_in* peeraddr, SLPMessage message, SLPBuffer* sendbuf, int errorcode) /*-------------------------------------------------------------------------*/ { int i; int urllen; int size = 0; SLPDDatabaseSrvRqstResult* db = 0; SLPBuffer result = *sendbuf; /*--------------------------------------------------------------*/ /* If errorcode is set, we can not be sure that message is good */ /* Go directly to send response code */ /*--------------------------------------------------------------*/ if (errorcode) { goto RESPOND; } /*-------------------------------------------------*/ /* Check for one of our IP addresses in the prlist */ /*-------------------------------------------------*/ if (SLPIntersectStringList(message->body.srvrqst.prlistlen, message->body.srvrqst.prlist, G_SlpdProperty.interfacesLen, G_SlpdProperty.interfaces)) { result->end = result->start; goto FINISHED; } /*------------------------------------------------*/ /* Check to to see if a this is a special SrvRqst */ /*------------------------------------------------*/ if (SLPCompareString(message->body.srvrqst.srvtypelen, message->body.srvrqst.srvtype, 15, "directory-agent") == 0) { errorcode = v1ProcessDASrvRqst(peeraddr, message, sendbuf, errorcode); return errorcode; } /*------------------------------------*/ /* Make sure that we handle the scope */ /*------ -----------------------------*/ if (SLPIntersectStringList(message->body.srvrqst.scopelistlen, message->body.srvrqst.scopelist, G_SlpdProperty.useScopesLen, G_SlpdProperty.useScopes) != 0) { /*-------------------------------*/ /* Find services in the database */ /*-------------------------------*/ errorcode = SLPDDatabaseSrvRqstStart(message, &db); } else { errorcode = SLP_ERROR_SCOPE_NOT_SUPPORTED; } RESPOND: /*----------------------------------------------------------------*/ /* Do not send error codes or empty replies to multicast requests */ /*----------------------------------------------------------------*/ if (message->header.flags & SLP_FLAG_MCAST) { if (errorcode != 0 || db->urlcount == 0) { result->end = result->start; goto FINISHED; } } /*-------------------------------------------------------------*/ /* ensure the buffer is big enough to handle the whole srvrply */ /*-------------------------------------------------------------*/ size = 16; /* 12 bytes for header, 2 bytes for error code, 2 bytes for url count */ if (errorcode == 0) { for (i = 0; i < db->urlcount; i++) { urllen = INT_MAX; errorcode = SLPv1ToEncoding(0, &urllen, message->header.encoding, db->urlarray[i]->url, db->urlarray[i]->urllen); if (errorcode) break; size += urllen + 4; /* 2 bytes for lifetime, 2 bytes for urllen */ } result = SLPBufferRealloc(result,size); if (result == 0) { errorcode = SLP_ERROR_INTERNAL_ERROR; } } /*----------------*/ /* Add the header */ /*----------------*/ /*version*/ *(result->start) = 1; /*function id*/ *(result->start + 1) = SLP_FUNCT_SRVRPLY; /*length*/ ToUINT16(result->start + 2, size); /*flags - TODO set the flags correctly */ *(result->start + 4) = message->header.flags | (size > SLP_MAX_DATAGRAM_SIZE ? SLPv1_FLAG_OVERFLOW : 0); /*dialect*/ *(result->start + 5) = 0; /*language code*/ memcpy(result->start + 6, message->header.langtag, 2); ToUINT16(result->start + 8, message->header.encoding); /*xid*/ ToUINT16(result->start + 10, message->header.xid); /*-------------------------*/ /* Add rest of the SrvRply */ /*-------------------------*/ result->curpos = result->start + 12; /* error code*/ ToUINT16(result->curpos, errorcode); result->curpos = result->curpos + 2; if (errorcode == 0) { /* urlentry count */ ToUINT16(result->curpos, db->urlcount); result->curpos = result->curpos + 2; for (i = 0; i < db->urlcount; i++) { /* url-entry lifetime */ ToUINT16(result->curpos, db->urlarray[i]->lifetime); result->curpos = result->curpos + 2; /* url-entry url and urllen */ urllen = size; errorcode = SLPv1ToEncoding(result->curpos + 2, &urllen, message->header.encoding, db->urlarray[i]->url, db->urlarray[i]->urllen); ToUINT16(result->curpos, urllen); result->curpos = result->curpos + 2 + urllen; } } else { /* urlentry count */ ToUINT16(result->curpos, 0); result->curpos = result->curpos + 2; } FINISHED: SLPDDatabaseSrvRqstEnd(db); *sendbuf = result; return errorcode; }
/** Read data from an outbound stream-oriented connection. * * @param[in] socklist - The list of sockets being monitored. * @param[in] sock - The socket to be read from. */ void OutgoingStreamRead(SLPList * socklist, SLPDSocket * sock) { int bytesread; char peek[16]; socklen_t peeraddrlen = sizeof(struct sockaddr_storage); unsigned int msglen; 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 */ msglen = PEEK_LENGTH(peek); sock->recvbuf = SLPBufferRealloc(sock->recvbuf, msglen); if (sock->recvbuf) sock->state = STREAM_READ; else { SLPDLog("INTERNAL_ERROR - out of memory!\n"); sock->state = SOCKET_CLOSE; } } else if (bytesread == -1) { #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); } } else { sock->state = SOCKET_CLOSE; } } if (sock->state == STREAM_READ) { /*------------------------------*/ /* recv the rest of the message */ /*------------------------------*/ bytesread = recv(sock->fd, (char *)sock->recvbuf->curpos, (int)(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->localaddr), sock->recvbuf, &(sock->sendbuf), 0)) { 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(sock->sendbuf); sock->sendbuf = NULL; 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 HandleStreamRead(SLPDSocketList* list, SLPDSocket* sock) /*-------------------------------------------------------------------------*/ { int fdflags; int bytesread; char peek[16]; if(sock->state == STREAM_FIRST_READ) { fdflags = fcntl(sock->fd, F_GETFL, 0); fcntl(sock->fd,F_SETFL, fdflags | O_NONBLOCK); /*---------------------------------------------------------------*/ /* take a peek at the packet to get version and size information */ /*---------------------------------------------------------------*/ bytesread = recvfrom(sock->fd, peek, 16, MSG_PEEK, &(sock->peerinfo.peeraddr), &(sock->peerinfo.peeraddrlen)); if(bytesread > 0) { /* check the version */ if(*peek == 2) { /* 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 { SLPLog("Slpd is out of memory!\n"); sock->state = SOCKET_CLOSE; } } else { SLPLog("Unsupported version %i received from %s\n", *peek, inet_ntoa(sock->peerinfo.peeraddr.sin_addr)); sock->state = SOCKET_CLOSE; } } else { if(errno != EWOULDBLOCK) { sock->state = SOCKET_CLOSE; return; } } /*------------------------------*/ /* recv the rest of the message */ /*------------------------------*/ bytesread = recv(sock->fd, sock->recvbuf->curpos, sock->recvbuf->end - sock->recvbuf->curpos, 0); if(bytesread > 0) { /*------------------------------*/ /* Reset the timestamp */ /*------------------------------*/ time(&(sock->timestamp)); sock->recvbuf->curpos += bytesread; if(sock->recvbuf->curpos == sock->recvbuf->end) { if(SLPDProcessMessage(&sock->peerinfo, sock->recvbuf, sock->sendbuf) == 0) { sock->state = STREAM_FIRST_WRITE; } else { /* An error has occured in SLPDProcessMessage() */ SLPLog("An error while processing message from %s\n", inet_ntoa(sock->peerinfo.peeraddr.sin_addr)); sock->state = SOCKET_CLOSE; } } } else { if(errno != EWOULDBLOCK) { /* error in recv() */ sock->state = SOCKET_CLOSE; } } } }
/*-------------------------------------------------------------------------*/ int ProcessSrvReg(struct sockaddr_in* peeraddr, SLPMessage message, SLPBuffer* sendbuf, int errorcode) /* */ /* Returns: non-zero if message should be silently dropped */ /*-------------------------------------------------------------------------*/ { unsigned int regtype; SLPBuffer result = *sendbuf; /*--------------------------------------------------------------*/ /* If errorcode is set, we can not be sure that message is good */ /* Go directly to send response code also do not process mcast */ /* srvreg or srvdereg messages */ /*--------------------------------------------------------------*/ if(errorcode || message->header.flags & SLP_FLAG_MCAST) { goto RESPOND; } /*------------------------------------*/ /* Make sure that we handle the scope */ /*------ -----------------------------*/ if(SLPIntersectStringList(message->body.srvreg.scopelistlen, message->body.srvreg.scopelist, G_SlpdProperty.useScopesLen, G_SlpdProperty.useScopes)) { /*-------------------------------*/ /* TODO: Validate the authblocks */ /*-------------------------------*/ /*---------------------------------*/ /* put the service in the database */ /*---------------------------------*/ regtype = 0; if(message->header.flags & SLP_FLAG_FRESH) { regtype |= SLPDDATABASE_REG_FRESH; } if(ISLOCAL(peeraddr->sin_addr)) { regtype |= SLPDDATABASE_REG_LOCAL; } errorcode = SLPDDatabaseReg(&(message->body.srvreg),regtype); if(errorcode > 0) { errorcode = SLP_ERROR_INVALID_REGISTRATION; } else if(errorcode < 0) { errorcode = SLP_ERROR_INTERNAL_ERROR; } } else { errorcode = SLP_ERROR_SCOPE_NOT_SUPPORTED; } RESPOND: /*--------------------------------------------------------------------*/ /* don't send back reply anything multicast SrvReg (set result empty) */ /*--------------------------------------------------------------------*/ if(message->header.flags & SLP_FLAG_MCAST || ISMCAST(peeraddr->sin_addr)) { result->end = result->start; goto FINISHED; } /*------------------------------------------------------------*/ /* ensure the buffer is big enough to handle the whole srvack */ /*------------------------------------------------------------*/ result = SLPBufferRealloc(result,message->header.langtaglen + 16); if(result == 0) { errorcode = SLP_ERROR_INTERNAL_ERROR; goto FINISHED; } /*----------------*/ /* Add the header */ /*----------------*/ /*version*/ *(result->start) = 2; /*function id*/ *(result->start + 1) = SLP_FUNCT_SRVACK; /*length*/ ToUINT24(result->start + 2,message->header.langtaglen + 16); /*flags*/ ToUINT16(result->start + 5,0); /*ext offset*/ ToUINT24(result->start + 7,0); /*xid*/ ToUINT16(result->start + 10,message->header.xid); /*lang tag len*/ ToUINT16(result->start + 12,message->header.langtaglen); /*lang tag*/ memcpy(result->start + 14, message->header.langtag, message->header.langtaglen); /*-------------------*/ /* Add the errorcode */ /*-------------------*/ ToUINT16(result->start + 14 + message->header.langtaglen, errorcode); FINISHED: *sendbuf = result; return errorcode; }
/*-------------------------------------------------------------------------*/ void ProcessSrvReg(SLPDPeerInfo* peerinfo, SLPMessage message, SLPBuffer result) /*-------------------------------------------------------------------------*/ { int errorcode; if(message->header.flags & SLP_FLAG_MCAST) { /* don't do anything multicast SrvReg (set result empty) */ result->end = result->start; return; } /*------------------------------------*/ /* Make sure that we handle the scope */ /*------ -----------------------------*/ if(SLPIntersectStringList(message->body.srvreg.scopelistlen, message->body.srvreg.scopelist, G_SlpdProperty.useScopesLen, G_SlpdProperty.useScopes)) { /*-------------------------------*/ /* TODO: Validate the authblocks */ /*-------------------------------*/ /*---------------------------------*/ /* put the service in the database */ /*---------------------------------*/ #ifdef WIN32 if(SLPDDatabaseReg(&(message->body.srvreg), message->header.flags | SLP_FLAG_FRESH, GetCurrentProcessId(), 0) == 0) /* TODO: Find an equivalent to user id on Win32*/ #else if(SLPDDatabaseReg(&(message->body.srvreg), message->header.flags | SLP_FLAG_FRESH, getpid(), getuid()) == 0) #endif { errorcode = 0; } else { errorcode = SLP_ERROR_INTERNAL_ERROR; } } else { errorcode = SLP_ERROR_SCOPE_NOT_SUPPORTED; } /*------------------------------------------------------------*/ /* ensure the buffer is big enough to handle the whole srvack */ /*------------------------------------------------------------*/ result = SLPBufferRealloc(result,message->header.langtaglen + 16); /*----------------*/ /* Add the header */ /*----------------*/ /*version*/ *(result->start) = 2; /*function id*/ *(result->start + 1) = SLP_FUNCT_SRVACK; /*length*/ ToUINT24(result->start + 2,message->header.langtaglen + 16); /*flags*/ ToUINT16(result->start + 5,0); /*ext offset*/ ToUINT24(result->start + 7,0); /*xid*/ ToUINT16(result->start + 10,message->header.xid); /*lang tag len*/ ToUINT16(result->start + 12,message->header.langtaglen); /*lang tag*/ memcpy(result->start + 14, message->header.langtag, message->header.langtaglen); /*-------------------*/ /* Add the errorcode */ /*-------------------*/ ToUINT16(result->start + 14 + message->header.langtaglen, errorcode); }
/*-------------------------------------------------------------------------*/ int v1ProcessSrvTypeRqst(struct sockaddr_in* peeraddr, SLPMessage message, SLPBuffer* sendbuf, int errorcode) /*-------------------------------------------------------------------------*/ { char* type; char* end; char* slider; int i; int typelen; int numsrvtypes = 0; int size = 0; SLPDDatabaseSrvTypeRqstResult* db = 0; SLPBuffer result = *sendbuf; /*-------------------------------------------------*/ /* Check for one of our IP addresses in the prlist */ /*-------------------------------------------------*/ if (SLPIntersectStringList(message->body.srvtyperqst.prlistlen, message->body.srvtyperqst.prlist, G_SlpdProperty.interfacesLen, G_SlpdProperty.interfaces)) { result->end = result->start; goto FINISHED; } /*------------------------------------*/ /* Make sure that we handle the scope */ /*------------------------------------*/ if (SLPIntersectStringList(message->body.srvtyperqst.scopelistlen, message->body.srvtyperqst.scopelist, G_SlpdProperty.useScopesLen, G_SlpdProperty.useScopes) != 0) { /*------------------------------------*/ /* Find service types in the database */ /*------------------------------------*/ errorcode = SLPDDatabaseSrvTypeRqstStart(message, &db); } else { errorcode = SLP_ERROR_SCOPE_NOT_SUPPORTED; } /*----------------------------------------------------------------*/ /* Do not send error codes or empty replies to multicast requests */ /*----------------------------------------------------------------*/ if (message->header.flags & SLP_FLAG_MCAST) { if (errorcode != 0 || db->srvtypelistlen == 0) { result->end = result->start; goto FINISHED; } } /*-----------------------------------------------------------------*/ /* ensure the buffer is big enough to handle the whole srvtyperply */ /*-----------------------------------------------------------------*/ size = 16; /* 12 bytes for header, 2 bytes for error code, 2 bytes for num of service types */ if (errorcode == 0) { if (db->srvtypelistlen) { /* there has to be at least one service type*/ numsrvtypes = 1; /* count the rest of the service types */ type = db->srvtypelist; for (i=0; i< db->srvtypelistlen; i++) { if (type[i] == ',') { numsrvtypes += 1; } } /* figure out how much memory is required for srvtype strings */ typelen = INT_MAX; errorcode = SLPv1ToEncoding(0, &typelen, message->header.encoding, db->srvtypelist, db->srvtypelistlen); /* TRICKY: we add in the numofsrvtypes + 1 to make room for the */ /* type length. We can do this because the ',' of the comma */ /* delimited list is one byte. */ size = size + typelen + numsrvtypes + 1; } else { numsrvtypes = 0; } } /*-----------------*/ /* Allocate memory */ /*-----------------*/ result = SLPBufferRealloc(result,size); if (result == 0) { errorcode = SLP_ERROR_INTERNAL_ERROR; goto FINISHED; } /*----------------*/ /* Add the header */ /*----------------*/ /*version*/ *(result->start) = 1; /*function id*/ *(result->start + 1) = SLP_FUNCT_SRVTYPERPLY; /*length*/ ToUINT16(result->start + 2, size); /*flags - TODO set the flags correctly */ *(result->start + 4) = message->header.flags | (size > SLP_MAX_DATAGRAM_SIZE ? SLPv1_FLAG_OVERFLOW : 0); /*dialect*/ *(result->start + 5) = 0; /*language code*/ memcpy(result->start + 6, message->header.langtag, 2); ToUINT16(result->start + 8, message->header.encoding); /*xid*/ ToUINT16(result->start + 10, message->header.xid); /*-----------------------------*/ /* Add rest of the SrvTypeRply */ /*-----------------------------*/ result->curpos = result->start + 12; /* error code*/ ToUINT16(result->curpos, errorcode); result->curpos += 2; if (errorcode == 0) { /* num of service types */ ToUINT16(result->curpos, numsrvtypes); result->curpos += 2; /* service type strings */ type = db->srvtypelist; slider = db->srvtypelist; end = &(type[db->srvtypelistlen]); for (i=0;i<numsrvtypes; i++) { while (slider < end && *slider != ',') slider++; typelen = size; /* put in the encoded service type */ SLPv1ToEncoding(result->curpos + 2, &typelen, message->header.encoding, type, slider - type); /* slip in the typelen */ ToUINT16(result->curpos, typelen); result->curpos += 2; result->curpos += typelen; slider ++; /* skip comma */ type = slider; } /* TODO - make sure we don't return generic types */ } FINISHED: if (db) SLPDDatabaseSrvTypeRqstEnd(db); *sendbuf = result; return errorcode; }
/*-------------------------------------------------------------------------*/ int ProcessDASrvRqst(struct sockaddr_in* peeraddr, SLPMessage message, SLPBuffer* sendbuf, int errorcode) /*-------------------------------------------------------------------------*/ { SLPDAEntry daentry; SLPBuffer tmp = 0; SLPDAEntry* entry = 0; void* i = 0; /* set up local data */ memset(&daentry,0,sizeof(daentry)); /*---------------------------------------------------------------------*/ /* Special case for when libslp asks slpd (through the loopback) about */ /* a known DAs. Fill sendbuf with DAAdverts from all known DAs. */ /*---------------------------------------------------------------------*/ if(ISLOCAL(peeraddr->sin_addr)) { /* TODO: be smarter about how much memory is allocated here! */ /* 4096 may not be big enough to handle all DAAdverts */ *sendbuf = SLPBufferRealloc(*sendbuf, 4096); if(*sendbuf == 0) { return SLP_ERROR_INTERNAL_ERROR; } if(errorcode == 0) { /* Note: The weird *sendbuf code is making a single SLPBuffer */ /* that contains multiple DAAdverts. This is a special */ /* process that only happens for the DA SrvRqst through */ /* loopback to the SLPAPI */ while(SLPDKnownDAEnum(&i,&entry) == 0) { if(SLPDKnownDAEntryToDAAdvert(errorcode, message->header.xid, entry, &tmp) == 0) { if(((*sendbuf)->curpos) + (tmp->end - tmp->start) > (*sendbuf)->end) { break; } memcpy((*sendbuf)->curpos, tmp->start, tmp->end - tmp->start); (*sendbuf)->curpos = ((*sendbuf)->curpos) + (tmp->end - tmp->start); } } /* Tack on a "terminator" DAAdvert */ SLPDKnownDAEntryToDAAdvert(SLP_ERROR_INTERNAL_ERROR, message->header.xid, &daentry, &tmp); if(((*sendbuf)->curpos) + (tmp->end - tmp->start) <= (*sendbuf)->end) { memcpy((*sendbuf)->curpos, tmp->start, tmp->end - tmp->start); (*sendbuf)->curpos = ((*sendbuf)->curpos) + (tmp->end - tmp->start); } /* mark the end of the sendbuf */ (*sendbuf)->end = (*sendbuf)->curpos; if(tmp) { SLPBufferFree(tmp); } } return errorcode; } /*---------------------------------------------------------------------*/ /* Normal case where a remote Agent asks for a DA */ /*---------------------------------------------------------------------*/ if(G_SlpdProperty.isDA) { if(message->body.srvrqst.scopelistlen == 0 || SLPIntersectStringList(message->body.srvrqst.scopelistlen, message->body.srvrqst.scopelist, G_SlpdProperty.useScopesLen, G_SlpdProperty.useScopes)) { /* fill out real structure */ G_SlpdProperty.DATimestamp += 1; daentry.bootstamp = G_SlpdProperty.DATimestamp; daentry.langtaglen = G_SlpdProperty.localeLen; daentry.langtag = (char*)G_SlpdProperty.locale; daentry.urllen = G_SlpdProperty.myUrlLen; daentry.url = (char*)G_SlpdProperty.myUrl; daentry.scopelistlen = G_SlpdProperty.useScopesLen; daentry.scopelist = (char*)G_SlpdProperty.useScopes; daentry.attrlistlen = 0; daentry.attrlist = 0; daentry.spilistlen = 0; daentry.spilist = 0; } else { errorcode = SLP_ERROR_SCOPE_NOT_SUPPORTED; } } else { errorcode = SLP_ERROR_MESSAGE_NOT_SUPPORTED; } /* don't return errorcodes to multicast messages */ if(errorcode != 0) { if(message->header.flags & SLP_FLAG_MCAST || ISMCAST(peeraddr->sin_addr)) { (*sendbuf)->end = (*sendbuf)->start; return errorcode; } } errorcode = SLPDKnownDAEntryToDAAdvert(errorcode, message->header.xid, &daentry, sendbuf); return errorcode; }
/*-------------------------------------------------------------------------*/ void ProcessSASrvRqst(SLPDPeerInfo* peerinfo, SLPMessage message, SLPBuffer result) /*-------------------------------------------------------------------------*/ { int size = 0; if(message->body.srvrqst.scopelistlen == 0 || SLPStringListIntersect(message->body.srvrqst.scopelistlen, message->body.srvrqst.scopelist, G_SlpdProperty.useScopesLen, G_SlpdProperty.useScopes) != 0 ) { /*----------------------*/ /* Send back a SAAdvert */ /*----------------------*/ /*-------------------------------------------------------------*/ /* ensure the buffer is big enough to handle the whole srvrply */ /*-------------------------------------------------------------*/ size = message->header.langtaglen + 21; /* 14 bytes for header */ /* 2 bytes for url count */ /* 2 bytes for scope list len */ /* 2 bytes for attr list len */ /* 1 byte for authblock count */ size += G_SlpdProperty.myUrlLen; size += G_SlpdProperty.useScopesLen; /* TODO: size += G_SlpdProperty.SAAttributes */ result = SLPBufferRealloc(result,size); if(result == 0) { /* TODO: out of memory, what should we do here! */ return; } /*----------------*/ /* Add the header */ /*----------------*/ /*version*/ *(result->start) = 2; /*function id*/ *(result->start + 1) = SLP_FUNCT_SAADVERT; /*length*/ ToUINT24(result->start + 2, size); /*flags*/ ToUINT16(result->start + 5, size > SLP_MAX_DATAGRAM_SIZE ? SLP_FLAG_OVERFLOW : 0); /*ext offset*/ ToUINT24(result->start + 7,0); /*xid*/ ToUINT16(result->start + 10,message->header.xid); /*lang tag len*/ ToUINT16(result->start + 12,message->header.langtaglen); /*lang tag*/ memcpy(result->start + 14, message->header.langtag, message->header.langtaglen); /*--------------------------*/ /* Add rest of the SAAdvert */ /*--------------------------*/ result->curpos = result->start + 14 + message->header.langtaglen; /* url len */ ToUINT16(result->curpos, G_SlpdProperty.myUrlLen); result->curpos = result->curpos + 2; /* url */ memcpy(result->start,G_SlpdProperty.myUrl,G_SlpdProperty.myUrlLen); result->curpos = result->curpos + G_SlpdProperty.myUrlLen; /* scope list len */ ToUINT16(result->curpos, G_SlpdProperty.useScopesLen); result->curpos = result->curpos + 2; /* scope list */ memcpy(result->start,G_SlpdProperty.useScopes,G_SlpdProperty.useScopesLen); result->curpos = result->curpos + G_SlpdProperty.useScopesLen; /* attr list len */ /* ToUINT16(result->curpos,G_SlpdProperty.SAAttributesLen) */ ToUINT16(result->curpos, 0); result->curpos = result->curpos + 2; /* attr list */ /* memcpy(result->start,G_SlpdProperty.SAAttributes,G_SlpdProperty.SAAttributesLen) */ /* authblock count */ *(result->curpos) = 0; } else { /*--------------------------------*/ /* Send back a SrvRply with error */ /*--------------------------------*/ if(message->header.flags & SLP_FLAG_MCAST) { /* drop multicast SrvRqsts we can not answer */ result->end = result->start; } else { /*-------------------------------------------------------------*/ /* ensure the buffer is big enough to handle the whole srvrply */ /*-------------------------------------------------------------*/ size = message->header.langtaglen + 18; /* 14 bytes for header */ /* 2 bytes for error code */ /* 2 bytes for url count */ result = SLPBufferRealloc(result,size); if(result == 0) { /* TODO: out of memory, what should we do here! */ return; } /*----------------*/ /* Add the header */ /*----------------*/ /*version*/ *(result->start) = 2; /*function id*/ *(result->start + 1) = SLP_FUNCT_SRVRPLY; /*length*/ ToUINT24(result->start + 2, size); /*flags*/ ToUINT16(result->start + 5, size > SLP_MAX_DATAGRAM_SIZE ? SLP_FLAG_OVERFLOW : 0); /*ext offset*/ ToUINT24(result->start + 7,0); /*xid*/ ToUINT16(result->start + 10,message->header.xid); /*lang tag len*/ ToUINT16(result->start + 12,message->header.langtaglen); /*lang tag*/ memcpy(result->start + 14, message->header.langtag, message->header.langtaglen); /*-------------------------*/ /* Add rest of the SrvRply */ /*-------------------------*/ result->curpos = result->start + 14 + message->header.langtaglen; /* error code*/ ToUINT16(result->curpos, SLP_ERROR_SCOPE_NOT_SUPPORTED); result->curpos = result->curpos + 2; /* urlentry count */ ToUINT16(result->curpos, 0); result->curpos = result->curpos + 2; } } }
/*-------------------------------------------------------------------------*/ void ProcessSrvDeReg(SLPDPeerInfo* peerinfo, SLPMessage message, SLPBuffer result) /*-------------------------------------------------------------------------*/ { int errorcode; if(message->header.flags & SLP_FLAG_MCAST) { /* don't do anything multicast SrvDeReg (set result empty) */ result->end = result->start; return; } /*------------------------------------------*/ /* TODO: make sure that we handle the scope */ /*------------------------------------------*/ if(SLPStringListIntersect(message->body.srvdereg.scopelistlen, message->body.srvdereg.scopelist, G_SlpdProperty.useScopesLen, G_SlpdProperty.useScopes)) { /*-------------------------------*/ /* TODO: Validate the authblocks */ /*-------------------------------*/ /*--------------------------------------*/ /* remove the service from the database */ /*--------------------------------------*/ if(SLPDDatabaseDeReg(&(message->body.srvdereg)) == 0) { errorcode = 0; } else { errorcode = SLP_ERROR_INTERNAL_ERROR; } } else { errorcode = SLP_ERROR_SCOPE_NOT_SUPPORTED; } /*------------------------------------------------------------*/ /* ensure the buffer is big enough to handle the whole srvack */ /*------------------------------------------------------------*/ result = SLPBufferRealloc(result,message->header.langtaglen + 16); /*----------------*/ /* Add the header */ /*----------------*/ /*version*/ *(result->start) = 2; /*function id*/ *(result->start + 1) = SLP_FUNCT_SRVACK; /*length*/ ToUINT24(result->start + 2,message->header.langtaglen + 16); /*flags*/ ToUINT16(result->start + 5,0); /*ext offset*/ ToUINT24(result->start + 7,0); /*xid*/ ToUINT16(result->start + 10,message->header.xid); /*lang tag len*/ ToUINT16(result->start + 12,message->header.langtaglen); /*lang tag*/ memcpy(result->start + 14, message->header.langtag, message->header.langtaglen); /*-------------------*/ /* Add the errorcode */ /*-------------------*/ ToUINT16(result->start + 14 + message->header.langtaglen, errorcode); }
/*-------------------------------------------------------------------------*/ void IncomingStreamRead(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 { sock->state = SOCKET_CLOSE; return; } } 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 to max because of activity */ sock->age = 0; sock->recvbuf->curpos += bytesread; if(sock->recvbuf->curpos == sock->recvbuf->end) { switch(SLPDProcessMessage(&sock->peeraddr, sock->recvbuf, &(sock->sendbuf))) { case SLP_ERROR_PARSE_ERROR: case SLP_ERROR_VER_NOT_SUPPORTED: sock->state = SOCKET_CLOSE; break; default: sock->state = STREAM_WRITE_FIRST; IncomingStreamWrite(socklist, sock); } } } else { /* error in recv() */ sock->state = SOCKET_CLOSE; } } }
/*-------------------------------------------------------------------------*/ void ProcessSrvRqst(SLPDPeerInfo* peerinfo, SLPMessage message, SLPBuffer result) /*-------------------------------------------------------------------------*/ { int i; int size = 0; int count = 0; int found = 0; SLPDDatabaseSrvUrl* srvarray = 0; int errorcode = 0; /*-------------------------------------------------*/ /* Check for one of our IP addresses in the prlist */ /*-------------------------------------------------*/ if(SLPStringListIntersect(message->body.srvrqst.prlistlen, message->body.srvrqst.prlist, G_SlpdProperty.interfacesLen, G_SlpdProperty.interfaces)) { result->end = result->start; goto FINISHED; } /*------------------------------------------------*/ /* Check to to see if a this is a special SrvRqst */ /*------------------------------------------------*/ if(SLPStringCompare(message->body.srvrqst.srvtypelen, message->body.srvrqst.srvtype, 23, "service:directory-agent") == 0) { ProcessDASrvRqst(peerinfo, message, result); goto FINISHED; } if(SLPStringCompare(message->body.srvrqst.srvtypelen, message->body.srvrqst.srvtype, 21, "service:service-agent") == 0) { ProcessSASrvRqst(peerinfo, message, result); goto FINISHED; } /*------------------------------------*/ /* Make sure that we handle the scope */ /*------ -----------------------------*/ if(SLPStringListIntersect(message->body.srvrqst.scopelistlen, message->body.srvrqst.scopelist, G_SlpdProperty.useScopesLen, G_SlpdProperty.useScopes) != 0) { /*-------------------------------*/ /* Find services in the database */ /*-------------------------------*/ while(found == count) { count += SLPDPROCESS_RESULT_COUNT; if(srvarray) free(srvarray); srvarray = (SLPDDatabaseSrvUrl*)malloc(sizeof(SLPDDatabaseSrvUrl) * count); if(srvarray == 0) { found = 0; errorcode = SLP_ERROR_INTERNAL_ERROR; break; } found = SLPDDatabaseFindSrv(&(message->body.srvrqst), srvarray, count); if(found < 0) { found = 0; errorcode = SLP_ERROR_INTERNAL_ERROR; break; } } } else { errorcode = SLP_ERROR_SCOPE_NOT_SUPPORTED; } /*----------------------------------------------------------------*/ /* Do not send error codes or empty replies to multicast requests */ /*----------------------------------------------------------------*/ if(found <= 0 && (message->header.flags & SLP_FLAG_MCAST)) { result->end = result->start; goto FINISHED; } /*-------------------------------------------------------------*/ /* ensure the buffer is big enough to handle the whole srvrply */ /*-------------------------------------------------------------*/ size = message->header.langtaglen + 18; /* 14 bytes for header */ /* 2 bytes for error code */ /* 2 bytes for url count */ for(i=0;i<found;i++) { size += srvarray[i].urllen + 6; /* 1 byte for reserved */ /* 2 bytes for lifetime */ /* 2 bytes for urllen */ /* 1 byte for authcount */ /* TODO: Fix this for authentication */ } result = SLPBufferRealloc(result,size); if(result == 0) { found = 0; errorcode = SLP_ERROR_INTERNAL_ERROR; } /*----------------*/ /* Add the header */ /*----------------*/ /*version*/ *(result->start) = 2; /*function id*/ *(result->start + 1) = SLP_FUNCT_SRVRPLY; /*length*/ ToUINT24(result->start + 2, size); /*flags*/ ToUINT16(result->start + 5, size > SLP_MAX_DATAGRAM_SIZE ? SLP_FLAG_OVERFLOW : 0); /*ext offset*/ ToUINT24(result->start + 7,0); /*xid*/ ToUINT16(result->start + 10,message->header.xid); /*lang tag len*/ ToUINT16(result->start + 12,message->header.langtaglen); /*lang tag*/ memcpy(result->start + 14, message->header.langtag, message->header.langtaglen); /*-------------------------*/ /* Add rest of the SrvRply */ /*-------------------------*/ result->curpos = result->start + 14 + message->header.langtaglen; /* error code*/ ToUINT16(result->curpos, errorcode); result->curpos = result->curpos + 2; /* urlentry count */ ToUINT16(result->curpos, found); result->curpos = result->curpos + 2; for(i=0;i<found;i++) { /* url-entry reserved */ *result->curpos = 0; result->curpos = result->curpos + 1; /* url-entry lifetime */ ToUINT16(result->curpos,srvarray[i].lifetime); result->curpos = result->curpos + 2; /* url-entry urllen */ ToUINT16(result->curpos,srvarray[i].urllen); result->curpos = result->curpos + 2; /* url-entry url */ memcpy(result->curpos,srvarray[i].url,srvarray[i].urllen); result->curpos = result->curpos + srvarray[i].urllen; /* url-entry authcount */ *result->curpos = 0; result->curpos = result->curpos + 1; /* TODO: put in authentication stuff too */ } FINISHED: if(srvarray) free(srvarray); }
/*-------------------------------------------------------------------------*/ void ProcessSrvRqstError(SLPMessage message, SLPBuffer result, int errorcode) /*-------------------------------------------------------------------------*/ { int size; /*--------------------------------*/ /* Send back a SrvRply with error */ /*--------------------------------*/ if(message->header.flags & SLP_FLAG_MCAST) { /* drop multicast SrvRqsts we can not answer */ result->end = result->start; } else { /*-------------------------------------------------------------*/ /* ensure the buffer is big enough to handle the whole srvrply */ /*-------------------------------------------------------------*/ size = message->header.langtaglen + 18; /* 14 bytes for header */ /* 2 bytes for error code */ /* 2 bytes for url count */ result = SLPBufferRealloc(result,size); if(result == 0) { /* TODO: out of memory, should we do anything else here! */ result->end = result->start; return; } /*----------------*/ /* Add the header */ /*----------------*/ /*version*/ *(result->start) = 2; /*function id*/ *(result->start + 1) = SLP_FUNCT_SRVRPLY; /*length*/ ToUINT24(result->start + 2, size); /*flags*/ ToUINT16(result->start + 5, size > SLP_MAX_DATAGRAM_SIZE ? SLP_FLAG_OVERFLOW : 0); /*ext offset*/ ToUINT24(result->start + 7,0); /*xid*/ ToUINT16(result->start + 10,message->header.xid); /*lang tag len*/ ToUINT16(result->start + 12,message->header.langtaglen); /*lang tag*/ memcpy(result->start + 14, message->header.langtag, message->header.langtaglen); /*------------------------------------------*/ /* Add rest of the SrvRply (with errorcode) */ /*------------------------------------------*/ result->curpos = result->start + 14 + message->header.langtaglen; /* error code*/ ToUINT16(result->curpos, errorcode); result->curpos = result->curpos + 2; /* urlentry count */ ToUINT16(result->curpos, 0); result->curpos = result->curpos + 2; } }
/*-------------------------------------------------------------------------*/ void ProcessDASrvRqst(SLPDPeerInfo* peerinfo, SLPMessage message, SLPBuffer result) /*-------------------------------------------------------------------------*/ { int size = 0; if(G_SlpdProperty.isDA == 0) { /*----------------------------------------------------------------*/ /* Do not send error codes or empty replies to multicast requests */ /*----------------------------------------------------------------*/ if(message->header.flags & SLP_FLAG_MCAST) { result->end = result->start; return; } ProcessSrvRqstError(message, result, SLP_ERROR_MESSAGE_NOT_SUPPORTED); return; } if(message->body.srvrqst.scopelistlen == 0 || SLPIntersectStringList(message->body.srvrqst.scopelistlen, message->body.srvrqst.scopelist, G_SlpdProperty.useScopesLen, G_SlpdProperty.useScopes) != 0 ) { /*----------------------*/ /* Send back a DAAdvert */ /*----------------------*/ /* increment the value for DATimestamp */ G_SlpdProperty.DATimestamp += 1; if(G_SlpdProperty.DATimestamp == 0) { G_SlpdProperty.DATimestamp = 1; } /*-------------------------------------------------------------*/ /* ensure the buffer is big enough to handle the whole srvrply */ /*-------------------------------------------------------------*/ size = message->header.langtaglen + 29; /* 14 bytes for header */ /* 2 errorcode */ /* 4 bytes for timestamp */ /* 2 bytes for url len */ /* 2 bytes for scope list len */ /* 2 bytes for attr list len */ /* 2 bytes for spi str len */ /* 1 byte for authblock count */ size += G_SlpdProperty.myUrlLen; size += G_SlpdProperty.useScopesLen; /* TODO: - we don't use attributes yet */ /* size += G_SlpdProperty.SAAttributes; */ result = SLPBufferRealloc(result,size); if(result == 0) { /* TODO: out of memory, what should we do here! */ return; } /*----------------*/ /* Add the header */ /*----------------*/ /*version*/ *(result->start) = 2; /*function id*/ *(result->start + 1) = SLP_FUNCT_DAADVERT; /*length*/ ToUINT24(result->start + 2, size); /*flags*/ ToUINT16(result->start + 5, size > SLP_MAX_DATAGRAM_SIZE ? SLP_FLAG_OVERFLOW : 0); /*ext offset*/ ToUINT24(result->start + 7,0); /*xid*/ ToUINT16(result->start + 10,message->header.xid); /*lang tag len*/ ToUINT16(result->start + 12,message->header.langtaglen); /*lang tag*/ memcpy(result->start + 14, message->header.langtag, message->header.langtaglen); /*--------------------------*/ /* Add rest of the DAAdvert */ /*--------------------------*/ result->curpos = result->start + 14 + message->header.langtaglen; /* error code */ ToUINT16(result->curpos,0); result->curpos = result->curpos + 2; /* timestamp */ ToUINT32(result->curpos,G_SlpdProperty.DATimestamp); result->curpos = result->curpos + 4; /* url len */ ToUINT16(result->curpos, G_SlpdProperty.myUrlLen); result->curpos = result->curpos + 2; /* url */ memcpy(result->curpos,G_SlpdProperty.myUrl,G_SlpdProperty.myUrlLen); result->curpos = result->curpos + G_SlpdProperty.myUrlLen; /* scope list len */ ToUINT16(result->curpos, G_SlpdProperty.useScopesLen); result->curpos = result->curpos + 2; /* scope list */ memcpy(result->curpos,G_SlpdProperty.useScopes,G_SlpdProperty.useScopesLen); result->curpos = result->curpos + G_SlpdProperty.useScopesLen; /* attr list len */ ToUINT16(result->curpos, 0); result->curpos = result->curpos + 2; /* attr list */ /* memcpy(result->start,G_SlpdProperty.DAAttributes,G_SlpdProperty.DAAttributesLen) */ /* result->curpos = result->curpos + G_SlpdProperty.DAAttributesLen */ /* SPI List */ ToUINT16(result->curpos,0); result->curpos = result->curpos + 2; /* authblock count */ *(result->curpos) = 0; result->curpos = result->curpos + 1; } else { ProcessSrvRqstError(message, result, SLP_ERROR_SCOPE_NOT_SUPPORTED); } }
/** Receives datagram messages. * * Receives messages from one of the sockets in the specified * SLPXcastsSockets structure, @p sockets. * * @param[in] sockets - A pointer to the SOPXcastSockets structure that * describes the sockets from which to read messages. * @param[out] buf - A pointer to an SLPBuffer that will contain the * received message upon successful return. * @param[out] peeraddr - A pointer to a sockaddr structure that will * contain the address of the peer from which the message was received. * @param[in,out] timeout - A pointer to the timeval structure that * indicates how much time to wait for a message to arrive. * * @return Zero on success, or a non-zero with errno set on failure. */ int SLPXcastRecvMessage(const SLPXcastSockets * sockets, SLPBuffer * buf, void * peeraddr, struct timeval * timeout) { fd_set readfds; sockfd_t highfd; int i; int readable; int bytesread; int recvloop; char peek[16]; int result = 0; /* recv loop */ recvloop = 1; while (recvloop) { /* Set the readfds */ FD_ZERO(&readfds); highfd = 0; for (i = 0; i < sockets->sock_count; i++) { FD_SET(sockets->sock[i],&readfds); if (sockets->sock[i] > highfd) highfd = sockets->sock[i]; } /* Select */ readable = select((int)(highfd + 1), &readfds, 0, 0, timeout); if (readable > 0) { /* Read the datagram */ for (i = 0; i < sockets->sock_count; i++) { if (FD_ISSET(sockets->sock[i], &readfds)) { /* Peek at the first 16 bytes of the header */ socklen_t peeraddrlen = sizeof(struct sockaddr_storage); bytesread = recvfrom(sockets->sock[i], peek, 16, MSG_PEEK, peeraddr, &peeraddrlen); if (bytesread == 16 #ifdef _WIN32 /* Win32 returns WSAEMSGSIZE if the message is larger * than the requested size, even with MSG_PEEK. But if * this is the error code we can be sure that the * message is at least 16 bytes */ || (bytesread == -1 && WSAGetLastError() == WSAEMSGSIZE) #endif ) { if (AS_UINT24(peek + 2) <= SLP_MAX_DATAGRAM_SIZE) { *buf = SLPBufferRealloc(*buf, AS_UINT24(peek + 2)); bytesread = recv(sockets->sock[i], (char *)(*buf)->curpos, (int)((*buf)->end - (*buf)->curpos), 0); /* This should never happen but we'll be paranoid*/ if (bytesread != (int)AS_UINT24(peek + 2)) (*buf)->end = (*buf)->curpos + bytesread; /* Message read. We're done! */ result = 0; recvloop = 0; break; } else { /* we got a bad message, or one that is too big! */ #ifndef UNICAST_NOT_SUPPORTED /* Reading SLP_MAX_DATAGRAM_SIZE bytes on the socket */ *buf = SLPBufferRealloc(*buf, SLP_MAX_DATAGRAM_SIZE); bytesread = recv(sockets->sock[i], (char *)(*buf)->curpos, (int)((*buf)->end - (*buf)->curpos), 0); /* This should never happen but we'll be paranoid*/ if (bytesread != SLP_MAX_DATAGRAM_SIZE) (*buf)->end = (*buf)->curpos + bytesread; result = SLP_ERROR_RETRY_UNICAST; recvloop = 0; return result; #endif } } else { /* Not even 16 bytes available */ } } } } else if (readable == 0) { result = -1; errno = ETIMEDOUT; recvloop = 0; } else { result = -1; recvloop = 0; } } return result; }
/*-------------------------------------------------------------------------*/ int v1ProcessSrvDeReg(struct sockaddr_in* peeraddr, SLPMessage message, SLPBuffer* sendbuf, int errorcode) /* */ /* Returns: non-zero if message should be silently dropped */ /*-------------------------------------------------------------------------*/ { SLPBuffer result = *sendbuf; /*--------------------------------------------------------------*/ /* If errorcode is set, we can not be sure that message is good */ /* Go directly to send response code also do not process mcast */ /* srvreg or srvdereg messages */ /*--------------------------------------------------------------*/ if (errorcode || message->header.flags & SLP_FLAG_MCAST) { goto RESPOND; } /*------------------------------------*/ /* Make sure that we handle the scope */ /*------------------------------------*/ if (SLPIntersectStringList(message->body.srvdereg.scopelistlen, message->body.srvdereg.scopelist, G_SlpdProperty.useScopesLen, G_SlpdProperty.useScopes)) { /*--------------------------------------*/ /* remove the service from the database */ /*--------------------------------------*/ errorcode = SLPDDatabaseDeReg(message); } else { errorcode = SLP_ERROR_SCOPE_NOT_SUPPORTED; } RESPOND: /*---------------------------------------------------------*/ /* don't do anything multicast SrvDeReg (set result empty) */ /*---------------------------------------------------------*/ if (message->header.flags & SLP_FLAG_MCAST) { result->end = result->start; goto FINISHED; } /*------------------------------------------------------------*/ /* ensure the buffer is big enough to handle the whole srvack */ /*------------------------------------------------------------*/ result = SLPBufferRealloc(result, 14); if (result == 0) { errorcode = SLP_ERROR_INTERNAL_ERROR; goto FINISHED; } /*----------------*/ /* Add the header */ /*----------------*/ /*version*/ *(result->start) = 1; /*function id*/ *(result->start + 1) = SLP_FUNCT_SRVACK; /*length*/ ToUINT16(result->start + 2, 14); /*flags - TODO set the flags correctly */ *(result->start + 4) = 0; /*dialect*/ *(result->start + 5) = 0; /*language code*/ memcpy(result->start + 6, message->header.langtag, 2); ToUINT16(result->start + 8, message->header.encoding); /*xid*/ ToUINT16(result->start + 10, message->header.xid); /*-------------------*/ /* Add the errorcode */ /*-------------------*/ ToUINT16(result->start + 12, errorcode); FINISHED: *sendbuf = result; return errorcode; }
/*-------------------------------------------------------------------------*/ void ProcessAttrRqst(SLPDPeerInfo* peerinfo, SLPMessage message, SLPBuffer result) /*-------------------------------------------------------------------------*/ { int i; int attrlistlen = 0; int size = 0; int count = 0; int found = 0; SLPDDatabaseAttr* attrarray = 0; int errorcode = 0; /*-------------------------------------------------*/ /* Check for one of our IP addresses in the prlist */ /*-------------------------------------------------*/ if(SLPStringListIntersect(message->body.attrrqst.prlistlen, message->body.attrrqst.prlist, G_SlpdProperty.interfacesLen, G_SlpdProperty.interfaces)) { result->end = result->start; return; } /*------------------------------------*/ /* Make sure that we handle the scope */ /*------ -----------------------------*/ if(SLPStringListIntersect(message->body.attrrqst.scopelistlen, message->body.attrrqst.scopelist, G_SlpdProperty.useScopesLen, G_SlpdProperty.useScopes) == 0) { result->end = result->start; return; } /*-------------------------------*/ /* Find attributes in the database */ /*-------------------------------*/ while(found == count) { count += SLPDPROCESS_RESULT_COUNT; if(attrarray) free(attrarray); attrarray = (SLPDDatabaseAttr*)malloc(sizeof(SLPDDatabaseAttr) * count); if(attrarray == 0) { found = 0; errorcode = SLP_ERROR_INTERNAL_ERROR; break; } found = SLPDDatabaseFindAttr(&(message->body.attrrqst), attrarray, count); if(found < 0) { found = 0; errorcode = SLP_ERROR_INTERNAL_ERROR; break; } } /*----------------------------------------------------------------*/ /* Do not send error codes or empty replies to multicast requests */ /*----------------------------------------------------------------*/ if(found <= 0 && (message->header.flags & SLP_FLAG_MCAST)) { if(attrarray) free(attrarray); result->end = result->start; return; } /*--------------------------------------------------------------*/ /* ensure the buffer is big enough to handle the whole attrrply */ /*--------------------------------------------------------------*/ size = message->header.langtaglen + 20; /* 14 bytes for header */ /* 2 bytes for error code */ /* 2 bytes for attr-list len */ /* 2 bytes for the authblockcount */ for (i=0;i<found;i++) { attrlistlen += attrarray[i].attrlen; } size += attrlistlen; /*-------------------*/ /* Alloc the buffer */ /*-------------------*/ result = SLPBufferRealloc(result,size); if(result == 0) { found = 0; errorcode = SLP_ERROR_INTERNAL_ERROR; } /*----------------*/ /* Add the header */ /*----------------*/ /*version*/ *(result->start) = 2; /*function id*/ *(result->start + 1) = SLP_FUNCT_ATTRRPLY; /*length*/ ToUINT24(result->start + 2,size); /*flags*/ ToUINT16(result->start + 5, size > SLP_MAX_DATAGRAM_SIZE ? SLP_FLAG_OVERFLOW : 0); /*ext offset*/ ToUINT24(result->start + 7,0); /*xid*/ ToUINT16(result->start + 10,message->header.xid); /*lang tag len*/ ToUINT16(result->start + 12,message->header.langtaglen); /*lang tag*/ memcpy(result->start + 14, message->header.langtag, message->header.langtaglen); /*--------------------------*/ /* Add rest of the AttrRqst */ /*--------------------------*/ result->curpos = result->start + 14 + message->header.langtaglen; /* error code*/ ToUINT16(result->curpos, errorcode); result->curpos = result->curpos + 2; /* attr-list len */ ToUINT16(result->curpos, attrlistlen); result->curpos = result->curpos + 2; for(i=0;i<found;i++) { memcpy(result->curpos,attrarray[i].attr,attrarray[i].attrlen); result->curpos = result->curpos + attrarray[i].attrlen; } /* TODO: no auth block */ ToUINT16(result->curpos, 0); if(attrarray) free(attrarray); }
/*-------------------------------------------------------------------------*/ int v1ProcessAttrRqst(struct sockaddr_in* peeraddr, SLPMessage message, SLPBuffer* sendbuf, int errorcode) /*-------------------------------------------------------------------------*/ { SLPDDatabaseAttrRqstResult* db = 0; int attrlen = 0; int size = 0; SLPBuffer result = *sendbuf; /*--------------------------------------------------------------*/ /* If errorcode is set, we can not be sure that message is good */ /* Go directly to send response code */ /*--------------------------------------------------------------*/ if (errorcode) { goto RESPOND; } /*-------------------------------------------------*/ /* Check for one of our IP addresses in the prlist */ /*-------------------------------------------------*/ if (SLPIntersectStringList(message->body.attrrqst.prlistlen, message->body.attrrqst.prlist, G_SlpdProperty.interfacesLen, G_SlpdProperty.interfaces)) { result->end = result->start; goto FINISHED; } /*------------------------------------*/ /* Make sure that we handle the scope */ /*------ -----------------------------*/ if (SLPIntersectStringList(message->body.attrrqst.scopelistlen, message->body.attrrqst.scopelist, G_SlpdProperty.useScopesLen, G_SlpdProperty.useScopes)) { /*---------------------------------*/ /* Find attributes in the database */ /*---------------------------------*/ errorcode = SLPDDatabaseAttrRqstStart(message,&db); } else { errorcode = SLP_ERROR_SCOPE_NOT_SUPPORTED; } RESPOND: /*----------------------------------------------------------------*/ /* Do not send error codes or empty replies to multicast requests */ /*----------------------------------------------------------------*/ if (message->header.flags & SLP_FLAG_MCAST) { if (errorcode != 0 || db->attrlistlen == 0) { result->end = result->start; goto FINISHED; } } /*--------------------------------------------------------------*/ /* ensure the buffer is big enough to handle the whole attrrply */ /*--------------------------------------------------------------*/ size = 16; /* 12 bytes for header, 2 bytes for error code, 2 bytes for attr-list len */ if (errorcode == 0) { attrlen = INT_MAX; errorcode = SLPv1ToEncoding(0, &attrlen, message->header.encoding, db->attrlist, db->attrlistlen); size += attrlen; } /*-------------------*/ /* Alloc the buffer */ /*-------------------*/ result = SLPBufferRealloc(result,size); if (result == 0) { errorcode = SLP_ERROR_INTERNAL_ERROR; goto FINISHED; } /*----------------*/ /* Add the header */ /*----------------*/ /*version*/ *(result->start) = 1; /*function id*/ *(result->start + 1) = SLP_FUNCT_ATTRRPLY; /*length*/ ToUINT16(result->start + 2, size); /*flags - TODO set the flags correctly */ *(result->start + 4) = message->header.flags | (size > SLP_MAX_DATAGRAM_SIZE ? SLPv1_FLAG_OVERFLOW : 0); /*dialect*/ *(result->start + 5) = 0; /*language code*/ memcpy(result->start + 6, message->header.langtag, 2); ToUINT16(result->start + 8, message->header.encoding); /*xid*/ ToUINT16(result->start + 10, message->header.xid); /*--------------------------*/ /* Add rest of the AttrRply */ /*--------------------------*/ result->curpos = result->start + 12; /* error code*/ ToUINT16(result->curpos, errorcode); result->curpos = result->curpos + 2; if (errorcode == 0) { /* attr-list len */ ToUINT16(result->curpos, attrlen); result->curpos = result->curpos + 2; attrlen = size; SLPv1ToEncoding(result->curpos, &attrlen, message->header.encoding, db->attrlist, db->attrlistlen); result->curpos = result->curpos + attrlen; } FINISHED: *sendbuf = result; if (db) SLPDDatabaseAttrRqstEnd(db); return errorcode; }
/*=========================================================================*/ SLPError NetworkRqstRply(int sock, struct sockaddr_in* destaddr, const char* langtag, char* buf, char buftype, int bufsize, NetworkRqstRplyCallback callback, void * cookie) /* Transmits and receives SLP messages via multicast convergence algorithm */ /* */ /* Returns - SLP_OK on success */ /*=========================================================================*/ { struct timeval timeout; struct sockaddr_in peeraddr; SLPBuffer sendbuf = 0; SLPBuffer recvbuf = 0; SLPMessage msg = 0; SLPError result = 0; #ifdef WIN32 /* on WIN32 setsockopt takes a const char * argument */ char socktype = 0; #else int socktype = 0; #endif int langtaglen = 0; int prlistlen = 0; char* prlist = 0; int xid = 0; int mtu = 0; int size = 0; int xmitcount = 0; int rplycount = 0; int maxwait = 0; int totaltimeout = 0; int timeouts[MAX_RETRANSMITS]; /*----------------------------------------------------*/ /* Save off a few things we don't want to recalculate */ /*----------------------------------------------------*/ langtaglen = strlen(langtag); xid = SLPXidGenerate(); mtu = SLPPropertyAsInteger(SLPGetProperty("net.slp.MTU")); sendbuf = SLPBufferAlloc(mtu); if(sendbuf == 0) { result = SLP_MEMORY_ALLOC_FAILED; goto CLEANUP; } if(buftype == SLP_FUNCT_DASRVRQST) { /* do something special for SRVRQST that will be discovering DAs */ maxwait = SLPPropertyAsInteger(SLPGetProperty("net.slp.DADiscoveryMaximumWait")); SLPPropertyAsIntegerVector(SLPGetProperty("net.slp.DADiscovertTimeouts"), timeouts, MAX_RETRANSMITS ); /* SLP_FUNCT_DASRVRQST is a fake function. We really want to */ /* send a SRVRQST */ buftype = SLP_FUNCT_SRVRQST; } /* Figure unicast/multicast,TCP/UDP, wait and time out stuff */ if(ntohl(destaddr->sin_addr.s_addr) > 0xe0000000) { /* Multicast or broadcast */ maxwait = SLPPropertyAsInteger(SLPGetProperty("net.slp.multicastMaximumWait")); SLPPropertyAsIntegerVector(SLPGetProperty("net.slp.multicastTimeouts"), timeouts, MAX_RETRANSMITS ); socktype = SOCK_DGRAM; xmitcount = 0; } else { maxwait = SLPPropertyAsInteger(SLPGetProperty("net.slp.unicastMaximumWait")); SLPPropertyAsIntegerVector(SLPGetProperty("net.slp.unicastTimeouts"), timeouts, MAX_RETRANSMITS ); size = sizeof(socktype); getsockopt(sock,SOL_SOCKET,SO_TYPE,&socktype,&size); socktype = SOCK_STREAM; xmitcount = MAX_RETRANSMITS; } /*--------------------------------*/ /* Allocate memory for the prlist */ /*--------------------------------*/ prlist = (char*)malloc(mtu); if(prlist == 0) { result = SLP_MEMORY_ALLOC_FAILED; goto CLEANUP; } *prlist = 0; prlistlen = 0; /*--------------------------*/ /* Main retransmission loop */ /*--------------------------*/ while(xmitcount <= MAX_RETRANSMITS) { xmitcount++; /*--------------------*/ /* setup recv timeout */ /*--------------------*/ if(socktype == SOCK_DGRAM) { totaltimeout += timeouts[xmitcount]; if(totaltimeout >= maxwait || timeouts[xmitcount] == 0) { /* we are all done */ break; } timeout.tv_sec = timeouts[xmitcount] / 1000; timeout.tv_usec = (timeouts[xmitcount] % 1000) * 1000; } else { timeout.tv_sec = maxwait / 1000; timeout.tv_usec = (maxwait % 1000) * 1000; } size = 14 + langtaglen + 2 + prlistlen + bufsize; if(SLPBufferRealloc(sendbuf,size) == 0) { result = SLP_MEMORY_ALLOC_FAILED; goto CLEANUP; } /*-----------------------------------*/ /* Add the header to the send buffer */ /*-----------------------------------*/ /*version*/ *(sendbuf->start) = 2; /*function id*/ *(sendbuf->start + 1) = buftype; /*length*/ ToUINT24(sendbuf->start + 2, size); /*flags*/ ToUINT16(sendbuf->start + 5, socktype == SOCK_STREAM ? 0 : SLP_FLAG_MCAST); /*ext offset*/ ToUINT24(sendbuf->start + 7,0); /*xid*/ ToUINT16(sendbuf->start + 10,xid); /*lang tag len*/ ToUINT16(sendbuf->start + 12,langtaglen); /*lang tag*/ memcpy(sendbuf->start + 14, langtag, langtaglen); sendbuf->curpos = sendbuf->start + langtaglen + 14 ; /*-----------------------------------*/ /* Add the prlist to the send buffer */ /*-----------------------------------*/ if( buftype == SLP_FUNCT_SRVRQST || buftype == SLP_FUNCT_ATTRRQST || buftype == SLP_FUNCT_SRVTYPERQST) { ToUINT16(sendbuf->curpos,prlistlen); sendbuf->curpos = sendbuf->curpos + 2; memcpy(sendbuf->curpos, prlist, prlistlen); sendbuf->curpos = sendbuf->curpos + prlistlen; } /*-----------------------------*/ /* Add the rest of the message */ /*-----------------------------*/ memcpy(sendbuf->curpos, buf, bufsize); /*----------------------*/ /* send the send buffer */ /*----------------------*/ result = SLPNetworkSendMessage(sock, sendbuf, destaddr, &timeout); if(result != 0) { /* we could not send the message for some reason */ /* we're done */ result = SLP_NETWORK_ERROR; goto FINISHED; } /*----------------*/ /* Main recv loop */ /*----------------*/ while(1) { if(SLPNetworkRecvMessage(sock, &recvbuf, &peeraddr, &timeout) != 0) { /* An error occured while receiving the message */ /* probably a just time out error. Retry send. */ break; } /* Parse the message and call callback */ msg = SLPMessageRealloc(msg); if(msg == 0) { result = SLP_MEMORY_ALLOC_FAILED; goto FINISHED; } if(SLPMessageParseBuffer(recvbuf, msg) == 0) { if (msg->header.xid == xid) { rplycount = rplycount + 1; if(callback(result, msg, cookie) == 0) { goto CLEANUP; } } } if(socktype == SOCK_STREAM) { goto FINISHED; } /* add the peer to the previous responder list */ if(prlistlen != 0) { strcat(prlist,","); } strcat(prlist,inet_ntoa(peeraddr.sin_addr)); prlistlen = strlen(prlist); } } FINISHED: /*----------------*/ /* We're all done */ /*----------------*/ if(rplycount == 0) { result = SLP_NETWORK_TIMED_OUT; } /*-------------------------------------*/ /* Notify the callback that we're done */ /*-------------------------------------*/ callback(SLP_LAST_CALL,msg,cookie); /*----------------*/ /* Free resources */ /*----------------*/ CLEANUP: if(prlist) free(prlist); SLPBufferFree(sendbuf); SLPBufferFree(recvbuf); SLPMessageFree(msg); close(sock); return result; }
/*=========================================================================*/ int SLPNetworkRecvMessage(int sockfd, int socktype, SLPBuffer* buf, struct sockaddr_in* peeraddr, struct timeval* timeout) /* Receives a message */ /* */ /* Returns - zero on success, non-zero on failure */ /* */ /* errno ENOTCONN error during read */ /* ETIME read timed out */ /* ENOMEM out of memory */ /* EINVAL parse error */ /*=========================================================================*/ { int xferbytes; fd_set readfds; char peek[16]; int peeraddrlen = sizeof(struct sockaddr_in); /*---------------------------------------------------------------*/ /* take a peek at the packet to get version and size information */ /*---------------------------------------------------------------*/ FD_ZERO(&readfds); FD_SET(sockfd, &readfds); xferbytes = select(sockfd + 1, &readfds, 0 , 0, timeout); if(xferbytes > 0) { if(socktype == SOCK_DGRAM) { xferbytes = recvfrom(sockfd, peek, 16, MSG_PEEK, (struct sockaddr *)peeraddr, &peeraddrlen); } else { xferbytes = recv(sockfd, peek, 16, MSG_PEEK); } if(xferbytes <= 0) { #ifdef WIN32 if(WSAGetLastError() != WSAEMSGSIZE) { errno = ENOTCONN; return -1; } #else errno = ENOTCONN; return -1; #endif } } else if(xferbytes == 0) { errno = ETIMEDOUT; return -1; } else { errno = ENOTCONN; return -1; } /*------------------------------*/ /* Read the rest of the message */ /*------------------------------*/ /* check the version */ if(*peek == 2) { /* allocate the recvmsg big enough for the whole message */ *buf = SLPBufferRealloc(*buf, AsUINT24(peek + 2)); if(*buf) { while((*buf)->curpos < (*buf)->end) { FD_ZERO(&readfds); FD_SET(sockfd, &readfds); xferbytes = select(sockfd + 1, &readfds, 0 , 0, timeout); if(xferbytes > 0) { xferbytes = recv(sockfd, (*buf)->curpos, (*buf)->end - (*buf)->curpos, 0); if(xferbytes > 0) { (*buf)->curpos = (*buf)->curpos + xferbytes; } else { errno = ENOTCONN; return -1; } } else if(xferbytes == 0) { errno = ETIMEDOUT; return -1; } else { errno = ENOTCONN; return -1; } } /* end of main read while. */ } else { errno = ENOMEM; return -1; } } else { errno = EINVAL; return -1; } return 0; }
/** Read inbound stream data. * * @param[in] socklist - The list of monitored sockets. * @param[in] sock - The socket to be read. * * @internal */ static void IncomingStreamRead(SLPList * socklist, SLPDSocket * sock) { int bytesread; size_t recvlen = 0; char peek[16]; socklen_t peeraddrlen = sizeof(struct sockaddr_storage); if (sock->state == STREAM_READ_FIRST) { /*---------------------------------------------------*/ /* take a peek at the packet to get size information */ /*---------------------------------------------------*/ bytesread = recvfrom(sock->fd, (char *)peek, 16, MSG_PEEK, (struct sockaddr *)&sock->peeraddr, &peeraddrlen); if (bytesread > 0 && bytesread >= (*peek == 2? 5: 4)) { recvlen = PEEK_LENGTH(peek); /* allocate the recvbuf big enough for the whole message */ sock->recvbuf = SLPBufferRealloc(sock->recvbuf, recvlen); if (sock->recvbuf) sock->state = STREAM_READ; else { SLPDLog("INTERNAL_ERROR - out of memory!\n"); sock->state = SOCKET_CLOSE; } } else { sock->state = SOCKET_CLOSE; return; } } if (sock->state == STREAM_READ) { /*------------------------------*/ /* recv the rest of the message */ /*------------------------------*/ bytesread = recv(sock->fd, (char *)sock->recvbuf->curpos, (int)(sock->recvbuf->end - sock->recvbuf->curpos), 0); if (bytesread > 0) { /* reset age to max because of activity */ sock->age = 0; sock->recvbuf->curpos += bytesread; if (sock->recvbuf->curpos == sock->recvbuf->end) { if (!sock->sendbuf) /* Some of the error handling code expects a sendbuf to be available * to be emptied, so make sure there is at least a minimal buffer */ sock->sendbuf = SLPBufferAlloc(1); switch (SLPDProcessMessage(&sock->peeraddr, &sock->localaddr, sock->recvbuf, &sock->sendbuf, 0)) { case SLP_ERROR_PARSE_ERROR: case SLP_ERROR_VER_NOT_SUPPORTED: case SLP_ERROR_MESSAGE_NOT_SUPPORTED: sock->state = SOCKET_CLOSE; break; default: if (!sock->sendbuf || sock->sendbuf->end == sock->sendbuf->start) { /* no answer available, just close socket */ sock->state = SOCKET_CLOSE; break; } /* some clients cannot cope with the OVERFLOW * bit set on a TCP stream, so always clear it */ if (sock->sendbuf->end - sock->sendbuf->start > 5) { if (sock->sendbuf->start[0] == 1) sock->sendbuf->start[4] &= ~SLPv1_FLAG_OVERFLOW; else sock->sendbuf->start[5] &= ~(SLP_FLAG_OVERFLOW >> 8); } sock->state = STREAM_WRITE_FIRST; IncomingStreamWrite(socklist, sock); } } }
/*-------------------------------------------------------------------------*/ int ProcessSrvRqst(struct sockaddr_in* peeraddr, SLPMessage message, SLPBuffer* sendbuf, int errorcode) /*-------------------------------------------------------------------------*/ { int i; int size = 0; int count = 0; int found = 0; SLPDDatabaseSrvUrl* srvarray = 0; SLPBuffer result = *sendbuf; /*--------------------------------------------------------------*/ /* If errorcode is set, we can not be sure that message is good */ /* Go directly to send response code */ /*--------------------------------------------------------------*/ if(errorcode) { goto RESPOND; } /*-------------------------------------------------*/ /* Check for one of our IP addresses in the prlist */ /*-------------------------------------------------*/ if(SLPIntersectStringList(message->body.srvrqst.prlistlen, message->body.srvrqst.prlist, G_SlpdProperty.interfacesLen, G_SlpdProperty.interfaces)) { result->end = result->start; goto FINISHED; } /*------------------------------------------------*/ /* Check to to see if a this is a special SrvRqst */ /*------------------------------------------------*/ if(SLPCompareString(message->body.srvrqst.srvtypelen, message->body.srvrqst.srvtype, 23, "service:directory-agent") == 0) { errorcode = ProcessDASrvRqst(peeraddr, message, sendbuf, errorcode); return errorcode; } if(SLPCompareString(message->body.srvrqst.srvtypelen, message->body.srvrqst.srvtype, 21, "service:service-agent") == 0) { errorcode = ProcessSASrvRqst(peeraddr, message, sendbuf, errorcode); return errorcode; } /* TODO: check the spi list of the message and return */ /* AUTHENTICATION_UNKNOWN since we do not do authentication yet */ /*------------------------------------*/ /* Make sure that we handle the scope */ /*------ -----------------------------*/ if(SLPIntersectStringList(message->body.srvrqst.scopelistlen, message->body.srvrqst.scopelist, G_SlpdProperty.useScopesLen, G_SlpdProperty.useScopes) != 0) { /*-------------------------------*/ /* Find services in the database */ /*-------------------------------*/ while(found == count) { count += G_SlpdProperty.maxResults; if(srvarray) free(srvarray); srvarray = (SLPDDatabaseSrvUrl*)malloc(sizeof(SLPDDatabaseSrvUrl) * count); if(srvarray == 0) { found = 0; errorcode = SLP_ERROR_INTERNAL_ERROR; break; } found = SLPDDatabaseFindSrv(&(message->body.srvrqst), srvarray, count); if(found < 0) { found = 0; errorcode = SLP_ERROR_INTERNAL_ERROR; break; } } /* remember the amount found if is really big for next time */ if(found > G_SlpdProperty.maxResults) { G_SlpdProperty.maxResults = found; } } else { errorcode = SLP_ERROR_SCOPE_NOT_SUPPORTED; } RESPOND: /*----------------------------------------------------------------*/ /* Do not send error codes or empty replies to multicast requests */ /*----------------------------------------------------------------*/ if(found == 0 || errorcode != 0) { if(message->header.flags & SLP_FLAG_MCAST || ISMCAST(peeraddr->sin_addr)) { result->end = result->start; goto FINISHED; } } /*-------------------------------------------------------------*/ /* ensure the buffer is big enough to handle the whole srvrply */ /*-------------------------------------------------------------*/ size = message->header.langtaglen + 18; /* 14 bytes for header */ /* 2 bytes for error code */ /* 2 bytes for url count */ if(errorcode == 0) { for(i=0;i<found;i++) { size += srvarray[i].urllen + 6; /* 1 byte for reserved */ /* 2 bytes for lifetime */ /* 2 bytes for urllen */ /* 1 byte for authcount */ /* TODO: Fix this for authentication */ } result = SLPBufferRealloc(result,size); if(result == 0) { found = 0; errorcode = SLP_ERROR_INTERNAL_ERROR; goto FINISHED; } } /*----------------*/ /* Add the header */ /*----------------*/ /*version*/ *(result->start) = 2; /*function id*/ *(result->start + 1) = SLP_FUNCT_SRVRPLY; /*length*/ ToUINT24(result->start + 2, size); /*flags*/ ToUINT16(result->start + 5, size > SLP_MAX_DATAGRAM_SIZE ? SLP_FLAG_OVERFLOW : 0); /*ext offset*/ ToUINT24(result->start + 7,0); /*xid*/ ToUINT16(result->start + 10,message->header.xid); /*lang tag len*/ ToUINT16(result->start + 12,message->header.langtaglen); /*lang tag*/ memcpy(result->start + 14, message->header.langtag, message->header.langtaglen); /*-------------------------*/ /* Add rest of the SrvRply */ /*-------------------------*/ result->curpos = result->start + 14 + message->header.langtaglen; /* error code*/ ToUINT16(result->curpos, errorcode); result->curpos = result->curpos + 2; /* urlentry count */ ToUINT16(result->curpos, found); result->curpos = result->curpos + 2; for(i=0;i<found;i++) { /* url-entry reserved */ *result->curpos = 0; result->curpos = result->curpos + 1; /* url-entry lifetime */ ToUINT16(result->curpos,srvarray[i].lifetime); result->curpos = result->curpos + 2; /* url-entry urllen */ ToUINT16(result->curpos,srvarray[i].urllen); result->curpos = result->curpos + 2; /* url-entry url */ memcpy(result->curpos,srvarray[i].url,srvarray[i].urllen); result->curpos = result->curpos + srvarray[i].urllen; /* url-entry authcount */ *result->curpos = 0; result->curpos = result->curpos + 1; /* TODO: put in authentication stuff too */ } FINISHED: if(srvarray) free(srvarray); *sendbuf = result; return errorcode; }
/*-------------------------------------------------------------------------*/ int v1ProcessSrvTypeRqst(struct sockaddr_in* peeraddr, SLPMessage message, SLPBuffer* sendbuf, int errorcode) /*-------------------------------------------------------------------------*/ { int i, typelen; int size = 0; int count = 0; int found = 0; SLPDDatabaseSrvType* srvtypearray = 0; SLPBuffer result = *sendbuf; /*-------------------------------------------------*/ /* Check for one of our IP addresses in the prlist */ /*-------------------------------------------------*/ if(SLPIntersectStringList(message->body.srvtyperqst.prlistlen, message->body.srvtyperqst.prlist, G_SlpdProperty.interfacesLen, G_SlpdProperty.interfaces)) { result->end = result->start; goto FINISHED; } /*------------------------------------*/ /* Make sure that we handle the scope */ /*------------------------------------*/ if(SLPIntersectStringList(message->body.srvtyperqst.scopelistlen, message->body.srvtyperqst.scopelist, G_SlpdProperty.useScopesLen, G_SlpdProperty.useScopes) != 0) { /*------------------------------------*/ /* Find service types in the database */ /*------------------------------------*/ while(found == count) { count += G_SlpdProperty.maxResults; if(srvtypearray) free(srvtypearray); srvtypearray = (SLPDDatabaseSrvType*)malloc(sizeof(SLPDDatabaseSrvType) * count); if(srvtypearray == 0) { found = 0; errorcode = SLP_ERROR_INTERNAL_ERROR; break; } found = SLPDDatabaseFindType(&(message->body.srvtyperqst), srvtypearray, count); if(found < 0) { found = 0; errorcode = SLP_ERROR_INTERNAL_ERROR; break; } } /* remember the amount found if is really big for next time */ if(found > G_SlpdProperty.maxResults) { G_SlpdProperty.maxResults = found; } } else { errorcode = SLP_ERROR_SCOPE_NOT_SUPPORTED; } /*----------------------------------------------------------------*/ /* Do not send error codes or empty replies to multicast requests */ /*----------------------------------------------------------------*/ if(message->header.flags & SLP_FLAG_MCAST) { if(found == 0 || errorcode != 0) { result->end = result->start; goto FINISHED; } } /*-----------------------------------------------------------------*/ /* ensure the buffer is big enough to handle the whole srvtyperply */ /*-----------------------------------------------------------------*/ size = 16; /* 12 bytes for header, 2 bytes for error code, 2 bytes for srvtype count */ if(errorcode == 0) { for(i=0;i<found;i++) { typelen = INT_MAX; errorcode = SLPv1ToEncoding(0, &typelen, message->header.encoding, srvtypearray[i].type, srvtypearray[i].typelen); if(errorcode) break; size += typelen + 2; /* 2 byte for length */ } } result = SLPBufferRealloc(result,size); if(result == 0) { found = 0; errorcode = SLP_ERROR_INTERNAL_ERROR; } /*----------------*/ /* Add the header */ /*----------------*/ /*version*/ *(result->start) = 1; /*function id*/ *(result->start + 1) = SLP_FUNCT_SRVTYPERPLY; /*length*/ ToUINT16(result->start + 2, size); /*flags - TODO set the flags correctly */ *(result->start + 4) = message->header.flags | (size > SLP_MAX_DATAGRAM_SIZE ? SLPv1_FLAG_OVERFLOW : 0); /*dialect*/ *(result->start + 5) = 0; /*language code*/ memcpy(result->start + 6, message->header.langtag, 2); ToUINT16(result->start + 8, message->header.encoding); /*xid*/ ToUINT16(result->start + 10, message->header.xid); /*-----------------------------*/ /* Add rest of the SrvTypeRply */ /*-----------------------------*/ result->curpos = result->start + 12; /* error code*/ ToUINT16(result->curpos, errorcode); result->curpos += 2; /* service type count */ ToUINT16(result->curpos, found); result->curpos += 2; /* TODO - make sure we don't return generic types */ for(i=0;i<found;i++) { typelen = size; SLPv1ToEncoding(result->curpos + 2, &typelen, message->header.encoding, srvtypearray[i].type, srvtypearray[i].typelen); ToUINT16(result->curpos, srvtypearray[i].typelen); result->curpos += 2 + typelen; } FINISHED: if(srvtypearray) free(srvtypearray); *sendbuf = result; return errorcode; }
/*-------------------------------------------------------------------------*/ int ProcessSASrvRqst(struct sockaddr_in* peeraddr, SLPMessage message, SLPBuffer* sendbuf, int errorcode) /*-------------------------------------------------------------------------*/ { int size = 0; SLPBuffer result = *sendbuf; if(message->body.srvrqst.scopelistlen == 0 || SLPIntersectStringList(message->body.srvrqst.scopelistlen, message->body.srvrqst.scopelist, G_SlpdProperty.useScopesLen, G_SlpdProperty.useScopes) != 0) { /*----------------------*/ /* Send back a SAAdvert */ /*----------------------*/ /*--------------------------------------------------------------*/ /* ensure the buffer is big enough to handle the whole SAAdvert */ /*--------------------------------------------------------------*/ size = message->header.langtaglen + 21; /* 14 bytes for header */ /* 2 bytes for url count */ /* 2 bytes for scope list len */ /* 2 bytes for attr list len */ /* 1 byte for authblock count */ size += G_SlpdProperty.myUrlLen; size += G_SlpdProperty.useScopesLen; /* TODO: size += G_SlpdProperty.SAAttributes */ result = SLPBufferRealloc(result,size); if(result == 0) { /* TODO: out of memory, what should we do here! */ errorcode = SLP_ERROR_INTERNAL_ERROR; goto FINISHED; } /*----------------*/ /* Add the header */ /*----------------*/ /*version*/ *(result->start) = 2; /*function id*/ *(result->start + 1) = SLP_FUNCT_SAADVERT; /*length*/ ToUINT24(result->start + 2, size); /*flags*/ ToUINT16(result->start + 5, size > SLP_MAX_DATAGRAM_SIZE ? SLP_FLAG_OVERFLOW : 0); /*ext offset*/ ToUINT24(result->start + 7,0); /*xid*/ ToUINT16(result->start + 10,message->header.xid); /*lang tag len*/ ToUINT16(result->start + 12,message->header.langtaglen); /*lang tag*/ memcpy(result->start + 14, message->header.langtag, message->header.langtaglen); /*--------------------------*/ /* Add rest of the SAAdvert */ /*--------------------------*/ result->curpos = result->start + 14 + message->header.langtaglen; /* url len */ ToUINT16(result->curpos, G_SlpdProperty.myUrlLen); result->curpos = result->curpos + 2; /* url */ memcpy(result->curpos,G_SlpdProperty.myUrl,G_SlpdProperty.myUrlLen); result->curpos = result->curpos + G_SlpdProperty.myUrlLen; /* scope list len */ ToUINT16(result->curpos, G_SlpdProperty.useScopesLen); result->curpos = result->curpos + 2; /* scope list */ memcpy(result->curpos,G_SlpdProperty.useScopes,G_SlpdProperty.useScopesLen); result->curpos = result->curpos + G_SlpdProperty.useScopesLen; /* attr list len */ /* ToUINT16(result->curpos,G_SlpdProperty.SAAttributesLen) */ ToUINT16(result->curpos, 0); result->curpos = result->curpos + 2; /* attr list */ /* memcpy(result->start,G_SlpdProperty.SAAttributes,G_SlpdProperty.SAAttributesLen) */ /* authblock count */ *(result->curpos) = 0; } FINISHED: *sendbuf = result; return errorcode; }
/*=========================================================================*/ SLPError NetworkRecvMessage(int sockfd, SLPBuffer buf, struct timeval* timeout, struct sockaddr* peeraddr, int* peeraddrlen) /* Receives a message */ /* */ /* Returns - SLP_OK, SLP_NETWORK_TIMEOUT, SLP_NETWORK_ERROR, or */ /* SLP_PARSE_ERROR. */ /*=========================================================================*/ { SLPError result = SLP_OK; int xferbytes; fd_set readfds; char peek[16]; /*---------------------------------------------------------------*/ /* take a peek at the packet to get version and size information */ /*---------------------------------------------------------------*/ FD_ZERO(&readfds); FD_SET(sockfd, &readfds); xferbytes = select(sockfd + 1, &readfds, 0 , 0, timeout); if(xferbytes > 0) { xferbytes = recvfrom(sockfd, peek, 16, MSG_PEEK, peeraddr, peeraddrlen); if(xferbytes <= 0) { result = SLP_NETWORK_ERROR; } } else if(xferbytes == 0) { result = SLP_NETWORK_TIMED_OUT; } else { result = SLP_NETWORK_ERROR; } /*---------------------------------------*/ /* return now if peek was not successful */ /*---------------------------------------*/ if(result) return result; /*------------------------------*/ /* Read the rest of the message */ /*------------------------------*/ /* check the version */ if(*peek == 2) { /* allocate the recvmsg big enough for the whole message */ if(SLPBufferRealloc(buf, AsUINT24(peek + 2))) { while(buf->curpos < buf->end) { FD_ZERO(&readfds); FD_SET(sockfd, &readfds); xferbytes = select(sockfd + 1, &readfds, 0 , 0, timeout); if(xferbytes > 0) { xferbytes = recv(sockfd, buf->curpos, buf->end - buf->curpos, 0); if(xferbytes > 0) { buf->curpos = buf->curpos + xferbytes; } else { result = SLP_NETWORK_ERROR; break; } } else if(xferbytes == 0) { result = SLP_NETWORK_TIMED_OUT; break; } else { result = SLP_NETWORK_ERROR; break; } } /* end of main read while. */ } else { result = SLP_MEMORY_ALLOC_FAILED; } } else { result = SLP_PARSE_ERROR; } return result; }