/*=========================================================================*/ int main(int argc, char* argv[]) /*=========================================================================*/ { fd_set readfds; fd_set writefds; int highfd; int fdcount = 0; #ifdef DEBUG xmalloc_init("/var/log/slpd_xmalloc.log",0); #endif /*------------------------*/ /* Parse the command line */ /*------------------------*/ if(SLPDParseCommandLine(argc,argv)) { SLPDFatal("Invalid command line\n"); } /*------------------------------*/ /* Make sure we are root */ /*------------------------------*/ if(getuid() != 0) { SLPDFatal("slpd must be started by root\n"); } /*--------------------------------------*/ /* Make sure we are not already running */ /*--------------------------------------*/ if(CheckPid(G_SlpdCommandLine.pidfile)) { SLPDFatal("slpd is already running. Check %s\n", G_SlpdCommandLine.pidfile); } /*------------------------------*/ /* Initialize the log file */ /*------------------------------*/ if(SLPDLogFileOpen(G_SlpdCommandLine.logfile, 1)) { SLPDFatal("Could not open logfile %s\n",G_SlpdCommandLine.logfile); } /*------------------------*/ /* Seed the XID generator */ /*------------------------*/ SLPXidSeed(); /*---------------------*/ /* Log startup message */ /*---------------------*/ SLPDLog("****************************************\n"); SLPDLogTime(); SLPDLog("SLPD daemon started\n"); SLPDLog("****************************************\n"); SLPDLog("Command line = %s\n",argv[0]); SLPDLog("Using configuration file = %s\n",G_SlpdCommandLine.cfgfile); SLPDLog("Using registration file = %s\n",G_SlpdCommandLine.regfile); #ifdef ENABLE_SECURITY SLPDLog("Using SPI file = %s\n",G_SlpdCommandLine.spifile); #endif /*--------------------------------------------------*/ /* Initialize for the first time */ /*--------------------------------------------------*/ if(SLPDPropertyInit(G_SlpdCommandLine.cfgfile) || #ifdef ENABLE_SECURITY SLPDSpiInit(G_SlpdCommandLine.spifile) || #endif SLPDDatabaseInit(G_SlpdCommandLine.regfile) || SLPDIncomingInit() || SLPDOutgoingInit() || SLPDKnownDAInit()) { SLPDFatal("slpd initialization failed\n"); } SLPDLog("Agent Interfaces = %s\n",G_SlpdProperty.interfaces); SLPDLog("Agent URL = %s\n",G_SlpdProperty.myUrl); /*---------------------------*/ /* make slpd run as a daemon */ /*---------------------------*/ if(Daemonize(G_SlpdCommandLine.pidfile)) { SLPDFatal("Could not daemonize\n"); } /*-----------------------*/ /* Setup signal handlers */ /*-----------------------*/ if(SetUpSignalHandlers()) { SLPDFatal("Error setting up signal handlers.\n"); } /*------------------------------*/ /* Set up alarm to age database */ /*------------------------------*/ alarm(SLPD_AGE_INTERVAL); /*-----------*/ /* Main loop */ /*-----------*/ SLPDLog("Startup complete entering main run loop ...\n\n"); G_SIGALRM = 0; G_SIGTERM = 0; G_SIGHUP = 0; #ifdef DEBUG G_SIGINT = 0; #endif while(G_SIGTERM == 0) { /*--------------------------------------------------------*/ /* Load the fdsets up with all valid sockets in the list */ /*--------------------------------------------------------*/ highfd = 0; FD_ZERO(&readfds); FD_ZERO(&writefds); LoadFdSets(&G_IncomingSocketList, &highfd, &readfds,&writefds); LoadFdSets(&G_OutgoingSocketList, &highfd, &readfds,&writefds); /*--------------------------------------------------*/ /* Before select(), check to see if we got a signal */ /*--------------------------------------------------*/ if(G_SIGALRM || G_SIGHUP) { goto HANDLE_SIGNAL; } /*-------------*/ /* Main select */ /*-------------*/ fdcount = select(highfd+1,&readfds,&writefds,0,0); if(fdcount > 0) /* fdcount will be < 0 when interrupted by a signal */ { SLPDIncomingHandler(&fdcount,&readfds,&writefds); SLPDOutgoingHandler(&fdcount,&readfds,&writefds); } /*----------------*/ /* Handle signals */ /*----------------*/ HANDLE_SIGNAL: if(G_SIGHUP) { HandleSigHup(); G_SIGHUP = 0; } if(G_SIGALRM) { HandleSigAlrm(); G_SIGALRM = 0; alarm(SLPD_AGE_INTERVAL); } #ifdef DEBUG if (G_SIGINT) { HandleSigInt(); G_SIGINT = 0; } #endif } /* End of main loop */ /* Got SIGTERM */ HandleSigTerm(); return 0; }
/** Read service registrations from a text file. * * A really big and nasty function that reads service registrations from * from a file. Don't look at this too hard or you'll be sick. This is by * far the most horrible code in OpenSLP. Please volunteer to rewrite it! * * "THANK GOODNESS this function is only called at startup" -- Matt * * @param[in] fd - The file to read from. * @param[out] msg - A message describing the SrvReg in buf. * @param[out] buf - The buffer used to hold @p message data. * * @return Zero on success. A value greater than zero on error. A value * less than zero on EOF. * * @note Eventually the caller needs to call SLPBufferFree and * SLPMessageFree to free memory. */ int SLPDRegFileReadSrvReg(FILE * fd, SLPMessage ** msg, SLPBuffer * buf) { char * slider1; char * slider2; char line[4096]; struct sockaddr_storage peer; int result = 0; size_t bufsize = 0; size_t langtaglen = 0; char * langtag = 0; size_t scopelistlen = 0; char * scopelist = 0; size_t urllen = 0; char * url = 0; int lifetime = 0; size_t srvtypelen = 0; char * srvtype = 0; size_t attrlistlen = 0; char * attrlist = 0; SLPBuffer tmp; #ifdef ENABLE_SLPv2_SECURITY unsigned char * urlauth = 0; int urlauthlen = 0; unsigned char * attrauth = 0; int attrauthlen = 0; #endif /* give the out params an initial NULL value */ *buf = 0; *msg = 0; /* read the next non-white non-comment line from the stream */ do { slider1 = RegFileReadLine(fd, line, 4096); if (slider1 == 0) return -1; } while (*slider1 == 0x0d || *slider1 == 0x0a); /* Parse the url-props */ slider2 = strchr(slider1, ','); if (slider2) { /* srvurl */ *slider2 = 0; /* squash comma to null terminate srvurl */ url = xstrdup(TrimWhitespace(slider1)); if (url == 0) { result = SLP_ERROR_INTERNAL_ERROR; goto CLEANUP; } urllen = strlen(url); /* derive srvtype from srvurl */ srvtype = strstr(slider1, "://"); if (srvtype == 0) { result = SLP_ERROR_INVALID_REGISTRATION; goto CLEANUP; } *srvtype = 0; srvtype=xstrdup(TrimWhitespace(slider1)); if (srvtype == 0) { result = SLP_ERROR_INTERNAL_ERROR; goto CLEANUP; } srvtypelen = strlen(srvtype); slider1 = slider2 + 1; /*lang*/ slider2 = strchr(slider1, ','); if (slider2) { *slider2 = 0; /* squash comma to null terminate lang */ langtag = xstrdup(TrimWhitespace(slider1)); if (langtag == 0) { result = SLP_ERROR_INVALID_REGISTRATION; goto CLEANUP; } langtaglen = strlen(langtag); slider1 = slider2 + 1; } else { result = SLP_ERROR_INVALID_REGISTRATION; goto CLEANUP; } /* ltime */ slider2 = strchr(slider1,','); if (slider2) { *slider2 = 0; /* squash comma to null terminate ltime */ lifetime = atoi(slider1); slider1 = slider2 + 1; } else { lifetime = atoi(slider1); slider1 = slider2; } if (lifetime < 1 || lifetime > SLP_LIFETIME_MAXIMUM) { result = SLP_ERROR_INVALID_REGISTRATION; goto CLEANUP; } /* get the srvtype if one was not derived by the srvurl */ if (srvtype == 0) { srvtype = xstrdup(TrimWhitespace(slider1)); if (srvtype == 0) { result = SLP_ERROR_INTERNAL_ERROR; goto CLEANUP; } srvtypelen = strlen(srvtype); if (srvtypelen == 0) { result = SLP_ERROR_INVALID_REGISTRATION; goto CLEANUP; } } } else { result = SLP_ERROR_INVALID_REGISTRATION; goto CLEANUP; } /* read all the attributes including the scopelist */ *line=0; while (1) { slider1 = RegFileReadLine(fd,line,4096); if (slider1 == 0) { result = -1; break; } if (*slider1 == 0x0d || *slider1 == 0x0a) break; /* Check to see if it is the scopes line */ /* FIXME We can collapse the scope stuff into the value getting and just make it a special case (do strcmp on the tag as opposed to the line) of attribute getting. */ if (strncasecmp(slider1,"scopes", 6) == 0) { /* found scopes line */ slider2 = strchr(slider1,'='); if (slider2) { slider2++; if (*slider2) { /* just in case some idiot puts multiple scopes lines */ if (scopelist) { result = SLP_ERROR_SCOPE_NOT_SUPPORTED; goto CLEANUP; } /* make sure there are no spaces in the scope list NOTE: There's nothing in the spec that indicates that scopes can't contain spaces. Commenting out for now. --jmc if (strchr(slider2, ' ')) { result = SLP_ERROR_SCOPE_NOT_SUPPORTED; goto CLEANUP; } */ scopelist = xstrdup(TrimWhitespace(slider2)); if (scopelist == 0) { result = SLP_ERROR_INTERNAL_ERROR; goto CLEANUP; } scopelistlen = strlen(scopelist); } } } else { /* line contains an attribute (slow but it works)*/ /* TODO Fix this so we do not have to realloc memory each time! */ TrimWhitespace(slider1); if (attrlist == 0) { attrlistlen += strlen(slider1) + 2; attrlist = xmalloc(attrlistlen + 1); if (attrlist == 0) { result = SLP_ERROR_INTERNAL_ERROR; goto CLEANUP; } *attrlist = 0; } else { char * tmp_attrlist; attrlistlen += strlen(slider1) + 3; if ((tmp_attrlist = xrealloc(attrlist, attrlistlen + 1)) == 0) { xfree(attrlist); result = SLP_ERROR_INTERNAL_ERROR; goto CLEANUP; } attrlist = tmp_attrlist; strcat(attrlist, ","); } if (attrlist == 0) { result = SLP_ERROR_INTERNAL_ERROR; goto CLEANUP; } /* we need special case for keywords (why do we need these) they seem like a waste of code. Why not just use booleans */ if (strchr(slider1, '=')) { /* normal attribute (with '=') */ strcat(attrlist, "("); strcat(attrlist, slider1); strcat(attrlist, ")"); } else { /* keyword (no '=') */ attrlistlen -= 2; /* subtract 2 bytes for no '(' or ')' */ strcat(attrlist, slider1); } } } /* Set the scope set in properties if not is set */ if (scopelist == 0) { scopelist = xstrdup(G_SlpdProperty.useScopes); if (scopelist == 0) { result = SLP_ERROR_INTERNAL_ERROR; goto CLEANUP; } scopelistlen = G_SlpdProperty.useScopesLen; } #ifdef ENABLE_SLPv2_SECURITY /* generate authentication blocks */ if (G_SlpdProperty.securityEnabled) { SLPAuthSignUrl(G_SlpdSpiHandle, 0, 0, urllen, url, &urlauthlen, &urlauth); SLPAuthSignString(G_SlpdSpiHandle, 0, 0, attrlistlen, attrlist, &attrauthlen, &attrauth); } #endif /* allocate buffer for the SrvReg Message */ bufsize = 14 + langtaglen; /* 14 bytes for header */ bufsize += urllen + 6; /* 1 byte for reserved */ /* 2 bytes for lifetime */ /* 2 bytes for urllen */ /* 1 byte for authcount */ bufsize += srvtypelen + 2; /* 2 bytes for len field */ bufsize += scopelistlen + 2; /* 2 bytes for len field */ bufsize += attrlistlen + 2; /* 2 bytes for len field */ bufsize += 1; /* 1 byte for authcount */ #ifdef ENABLE_SLPv2_SECURITY bufsize += urlauthlen; bufsize += attrauthlen; #endif tmp = *buf = SLPBufferAlloc(bufsize); if (tmp == 0) { result = SLP_ERROR_INTERNAL_ERROR; goto CLEANUP; } /* now build the SrvReg Message */ /* version */ *tmp->curpos++ = 2; /* function id */ *tmp->curpos++ = SLP_FUNCT_SRVREG; /* length */ PutUINT24(&tmp->curpos, bufsize); /* flags */ PutUINT16(&tmp->curpos, 0); /* ext offset */ PutUINT24(&tmp->curpos, 0); /* xid */ PutUINT16(&tmp->curpos, 0); /* lang tag len */ PutUINT16(&tmp->curpos, langtaglen); /* lang tag */ memcpy(tmp->curpos, langtag, langtaglen); tmp->curpos += langtaglen; /* url-entry reserved */ *tmp->curpos++ = 0; /* url-entry lifetime */ PutUINT16(&tmp->curpos, lifetime); /* url-entry urllen */ PutUINT16(&tmp->curpos, urllen); /* url-entry url */ memcpy(tmp->curpos, url, urllen); tmp->curpos += urllen; /* url-entry authblock */ #ifdef ENABLE_SLPv2_SECURITY if (urlauth) { /* authcount */ *tmp->curpos++ = 1; /* authblock */ memcpy(tmp->curpos, urlauth, urlauthlen); tmp->curpos += urlauthlen; } else #endif *tmp->curpos++ = 0; /* service type */ PutUINT16(&tmp->curpos, srvtypelen); memcpy(tmp->curpos, srvtype, srvtypelen); tmp->curpos += srvtypelen; /* scope list */ PutUINT16(&tmp->curpos, scopelistlen); memcpy(tmp->curpos, scopelist, scopelistlen); tmp->curpos += scopelistlen; /* attr list */ PutUINT16(&tmp->curpos, attrlistlen); memcpy(tmp->curpos, attrlist, attrlistlen); tmp->curpos += attrlistlen; /* attribute auth block */ #ifdef ENABLE_SLPv2_SECURITY if (attrauth) { /* authcount */ *tmp->curpos++ = 1; /* authblock */ memcpy(tmp->curpos, attrauth, attrauthlen); tmp->curpos += attrauthlen; } else #endif *tmp->curpos++ = 0; /* okay, now comes the really stupid (and lazy part) */ *msg = SLPMessageAlloc(); if (*msg == 0) { SLPBufferFree(*buf); *buf = 0; result = SLP_ERROR_INTERNAL_ERROR; goto CLEANUP; } /* this should be ok even if we are not supporting IPv4, * since it's a static service */ memset(&peer, 0, sizeof(struct sockaddr_in)); peer.ss_family = AF_UNSPEC; ((struct sockaddr_in *)&peer)->sin_addr.s_addr = htonl(INADDR_LOOPBACK); result = SLPMessageParseBuffer(&peer, &peer, *buf, *msg); (*msg)->body.srvreg.source = SLP_REG_SOURCE_STATIC; CLEANUP: /* check for errors and free memory */ switch(result) { case SLP_ERROR_INTERNAL_ERROR: SLPDLog("\nERROR: Out of memory one reg file line:\n %s\n", line); break; case SLP_ERROR_INVALID_REGISTRATION: SLPDLog("\nERROR: Invalid reg file format near:\n %s\n", line); break; case SLP_ERROR_SCOPE_NOT_SUPPORTED: SLPDLog("\nERROR: Duplicate scopes or scope list with " "embedded spaces near:\n %s\n", line); break; default: break; } xfree(langtag); xfree(scopelist); xfree(url); xfree(srvtype); xfree(attrlist); #ifdef ENABLE_SLPv2_SECURITY xfree(urlauth); xfree(attrauth); #endif return result; }
/** Delete entry from the index tree. * * Compares the value of the string with the value in the root node, then * either recursively deletes the value in the left or right sub-trees, or * deletes the value from the root node. * If the root_node needs to be deleted, then create a new tree from its * subtrees, re-balancing where necessary. * * @param[in] root_node - a pointer to the root of the (sub-)tree. * @param[in] value_str_len - length of the string to be removed. * @param[in] value_str - A pointer to string to be removed. * @param[in] p - The "location" value associated with the string. * * @return New root node of the tree, or null if the tree is now empty */ IndexTreeNode *index_tree_delete( IndexTreeNode *root_node, size_t value_str_len, const char *value_str, void *p) { int cmp; if (!root_node) /* Shouldn't really happen, but nothing to do */ return root_node; cmp = compare_with_tree_node(value_str_len, value_str, root_node); if (cmp < 0) { root_node->left_node = index_tree_delete(root_node->left_node, value_str_len, value_str, p); root_node->left_depth = tree_depth(root_node->left_node); if (root_node->left_node) root_node->left_node->parent_node = root_node; } else if (cmp > 0) { root_node->right_node = index_tree_delete(root_node->right_node, value_str_len, value_str, p); root_node->right_depth = tree_depth(root_node->right_node); if (root_node->right_node) root_node->right_node->parent_node = root_node; } else { IndexTreeNode *replacement_node; /* Find the given location in the value list */ IndexTreeValue *entry = find_in_value_set(root_node->value, p); if (!entry) /* Shouldn't really happen, but nothing to do */ return root_node; root_node->value = remove_from_value_set(root_node->value, entry); free_index_tree_value(entry); if (root_node->value) /* All we've done is remove one of the values in the set for this node, * so the tree structure does not need to be changed */ return root_node; /* The node needs to be deleted, so replace this node by the leftmost * node of the right sub-tree, or the rightmost mode of the left * sub-tree, depending on which has the greater depth */ if (root_node->left_depth > root_node->right_depth) { root_node->left_node = extract_rightmost(root_node->left_node, &replacement_node); root_node->left_depth = tree_depth(root_node->left_node); } else if (root_node->right_node) { root_node->right_node = extract_leftmost(root_node->right_node, &replacement_node); root_node->right_depth = tree_depth(root_node->right_node); } else { /* Both sub-trees are empty ie. this is a leaf node */ free_index_tree_node(root_node); return (IndexTreeNode *)0; } replacement_node->right_node = root_node->right_node; replacement_node->right_depth = root_node->right_depth; if (replacement_node->right_node) replacement_node->right_node->parent_node = replacement_node; replacement_node->left_node = root_node->left_node; replacement_node->left_depth = root_node->left_depth; if (replacement_node->left_node) replacement_node->left_node->parent_node = replacement_node; free_index_tree_node(root_node); root_node = replacement_node; } root_node = rebalance_tree(root_node); #if defined(DEBUG) && defined(CHECKING) if (!check_tree(root_node)) { SLPDLog("Index tree check fails deleting from tree %p\n", root_node); } #endif return root_node; }
/** Read an inbound datagram. * * @param[in] socklist - The list of monitored sockets. * @param[in] sock - The socket to be read. * * @internal */ static void IncomingDatagramRead(SLPList * socklist, SLPDSocket * sock) { int bytesread; int byteswritten; socklen_t peeraddrlen = sizeof(struct sockaddr_storage); char addr_str[INET6_ADDRSTRLEN]; sockfd_t sendsock = SLP_INVALID_SOCKET; (void)socklist; bytesread = recvfrom(sock->fd, (char*)sock->recvbuf->start, G_SlpdProperty.MTU, 0, (struct sockaddr *)&sock->peeraddr, &peeraddrlen); if (bytesread > 0) { sock->recvbuf->end = sock->recvbuf->start + bytesread; 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: break; default: #ifdef DARWIN /* If the socket is a multicast socket, find the designated UDP output socket for sending */ if (sock->state == DATAGRAM_MULTICAST) if ((sendsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) != SLP_INVALID_SOCKET) SLPNetworkSetSndRcvBuf(sendsock); #endif if (sendsock == SLP_INVALID_SOCKET) sendsock = sock->fd; /* check to see if we should send anything, breaking up individual packets in the buffer into different sendto calls (should only be an issue with the loopback DA response)*/ if (sock->sendbuf) { sock->sendbuf->curpos = sock->sendbuf->start; while (sock->sendbuf->curpos < sock->sendbuf->end) { int packetbytes = AS_UINT24(sock->sendbuf->curpos + 2); byteswritten = sendto(sendsock, (char*)sock->sendbuf->curpos, packetbytes, 0, (struct sockaddr *)&sock->peeraddr, SLPNetAddrLen(&sock->peeraddr)); if (byteswritten != packetbytes) { /* May be an overflow reply */ int flags = AS_UINT16(sock->sendbuf->curpos + 5); if ((byteswritten == -1) && #ifdef _WIN32 (WSAGetLastError() == WSAEMSGSIZE) && #else (errno == EMSGSIZE) && #endif (flags & SLP_FLAG_OVERFLOW)) { int byteswrittenmax = sendto(sendsock, (char*)sock->sendbuf->curpos, G_SlpdProperty.MTU, 0, (struct sockaddr *)&sock->peeraddr, SLPNetAddrLen(&sock->peeraddr)); if (byteswrittenmax == G_SlpdProperty.MTU) byteswritten = packetbytes; } } if (byteswritten != packetbytes) SLPDLog("NETWORK_ERROR - %d replying %s\n", errno, SLPNetSockAddrStorageToString(&(sock->peeraddr), addr_str, sizeof(addr_str))); sock->sendbuf->curpos += packetbytes; } /* Only close if we allocated a new socket */ if (sendsock != sock->fd) closesocket(sendsock); } break; } } }
/*-------------------------------------------------------------------------*/ void SLPDLogPeerAddr(struct sockaddr_in* peeraddr) /*-------------------------------------------------------------------------*/ { SLPDLog("Peer IP address: %s\n", inet_ntoa(peeraddr->sin_addr)); }
/*=========================================================================*/ void SLPDLogMessage(int msglogflags, struct sockaddr_in* peerinfo, SLPBuffer buf) /* Log record of receiving or sending an SLP Message. Logging will only */ /* occur if message logging is enabled G_SlpProperty.traceMsg != 0 */ /* */ /* msglogflags (IN) What type of message to log */ /* */ /* peerinfo (IN) the source or destination peer */ /* */ /* msg (IN) the message to log */ /* */ /* Returns: none */ /*=========================================================================*/ { SLPMessage msg; if (peerinfo == NULL || buf == NULL) { return; } if ((G_SlpdProperty.traceMsg && (msglogflags & SLPDLOG_TRACEMSG)) || (G_SlpdProperty.traceDrop && (msglogflags & SLPDLOG_TRACEDROP)) ) { /* Don't log localhost traffic since it is probably IPC */ /* and don't log empty messages */ if (!ISLOCAL(peerinfo->sin_addr) && buf->end != buf->start) { msg = SLPMessageAlloc(); if (msg) { SLPDLog("\n"); SLPDLogTime(); SLPDLog("MESSAGE - "); if (msglogflags == SLPDLOG_TRACEMSG_OUT) { SLPDLog("Trace message (OUT)\n"); } else if (msglogflags == SLPDLOG_TRACEMSG_IN) { SLPDLog("Trace message (IN)\n"); } else if (msglogflags == SLPDLOG_TRACEDROP) { SLPDLog("Dropped message (following message silently ignored)\n"); } else { SLPDLog("\n"); } if (SLPMessageParseBuffer(peerinfo,buf,msg) == 0) { SLPDLogMessageInternals(msg); } else { SLPDLog("Message parsing failed\n"); SLPDLog("Peer: \n"); SLPDLog(" IP address: %s\n", inet_ntoa(msg->peer.sin_addr)); } SLPMessageFree(msg); } } } }
/*=========================================================================*/ int SLPDIncomingInit() /* Initialize incoming socket list to have appropriate sockets for all */ /* network interfaces */ /* */ /* Returns Zero on success non-zero on error */ /*=========================================================================*/ { char* begin = NULL; char* beginSave = NULL; char* end = NULL; int finished; struct in_addr myaddr; struct in_addr mcastaddr; struct in_addr bcastaddr; struct in_addr loaddr; SLPDSocket* sock; /*------------------------------------------------------------*/ /* First, remove all of the sockets that might be in the list */ /*------------------------------------------------------------*/ while (G_IncomingSocketList.count) { SLPDSocketFree((SLPDSocket*)SLPListUnlink(&G_IncomingSocketList,G_IncomingSocketList.head)); } /*--------------------------------------------------*/ /* set up address to use for loopback and broadcast */ /*--------------------------------------------------*/ loaddr.s_addr = htonl(LOOPBACK_ADDRESS); bcastaddr.s_addr = htonl(SLP_BCAST_ADDRESS); mcastaddr.s_addr = htonl(SLP_MCAST_ADDRESS); /*--------------------------------------------------------------------*/ /* Create SOCKET_LISTEN socket for LOOPBACK for the library to talk to*/ /*--------------------------------------------------------------------*/ sock = SLPDSocketCreateListen(&loaddr); if (sock) { SLPListLinkTail(&G_IncomingSocketList,(SLPListItem*)sock); SLPDLog("Listening on loopback...\n"); } else { SLPDLog("NETWORK_ERROR - Could not listen on loopback\n"); SLPDLog("INTERNAL_ERROR - No SLPLIB support will be available\n"); } /*---------------------------------------------------------------------*/ /* Create sockets for all of the interfaces in the interfaces property */ /*---------------------------------------------------------------------*/ /*---------------------------------------------------------------------*/ /* Copy G_SlpdProperty.interfaces to a temporary buffer to parse the */ /* string in a safety way */ /*---------------------------------------------------------------------*/ if (G_SlpdProperty.interfaces != NULL) { begin = xstrdup((char *) G_SlpdProperty.interfaces); beginSave = begin; /* save pointer for free() operation later */ end = begin; finished = 0; } else { finished = 1; /* if no interface is defined, */ /* don't even enter the parsing loop */ } for (; (finished == 0); begin = ++end) { while (*end && *end != ',') end ++; if (*end == 0) finished = 1; *end = 0; /* Terminate string. */ if (end <= begin) continue; /* Skip empty entries */ /* begin now points to a null terminated ip address string */ myaddr.s_addr = inet_addr(begin); /*------------------------------------------------*/ /* Create TCP_LISTEN that will handle unicast TCP */ /*------------------------------------------------*/ sock = SLPDSocketCreateListen(&myaddr); if (sock) { SLPListLinkTail(&G_IncomingSocketList,(SLPListItem*)sock); SLPDLog("Listening on %s ...\n",inet_ntoa(myaddr)); } /*----------------------------------------------------------------*/ /* Create socket that will handle multicast UDP. */ /*----------------------------------------------------------------*/ sock = SLPDSocketCreateBoundDatagram(&myaddr, &mcastaddr, DATAGRAM_MULTICAST); if (sock) { SLPListLinkTail(&G_IncomingSocketList,(SLPListItem*)sock); SLPDLog("Multicast socket on %s ready\n",inet_ntoa(myaddr)); } else { SLPDLog("Couldn't bind to multicast for interface %s (%s)\n", inet_ntoa(myaddr), strerror(errno)); } #if defined(ENABLE_SLPv1) if (G_SlpdProperty.isDA) { /*------------------------------------------------------------*/ /* Create socket that will handle multicast UDP for SLPv1 DA */ /* Discovery. */ /*------------------------------------------------------------*/ mcastaddr.s_addr = htonl(SLPv1_DA_MCAST_ADDRESS); sock = SLPDSocketCreateBoundDatagram(&myaddr, &mcastaddr, DATAGRAM_MULTICAST); if (sock) { SLPListLinkTail(&G_IncomingSocketList,(SLPListItem*)sock); SLPDLog("SLPv1 DA Discovery Multicast socket on %s ready\n", inet_ntoa(myaddr)); } } #endif /*--------------------------------------------*/ /* Create socket that will handle unicast UDP */ /*--------------------------------------------*/ sock = SLPDSocketCreateBoundDatagram(&myaddr, &myaddr, DATAGRAM_UNICAST); if (sock) { SLPListLinkTail(&G_IncomingSocketList,(SLPListItem*)sock); SLPDLog("Unicast socket on %s ready\n",inet_ntoa(myaddr)); } } if (beginSave) xfree(beginSave); /*--------------------------------------------------------*/ /* Create socket that will handle broadcast UDP */ /*--------------------------------------------------------*/ sock = SLPDSocketCreateBoundDatagram(&myaddr, &bcastaddr, DATAGRAM_BROADCAST); if (sock) { SLPListLinkTail(&G_IncomingSocketList,(SLPListItem*)sock); SLPDLog("Broadcast socket for %s ready\n", inet_ntoa(bcastaddr)); } if (G_IncomingSocketList.count == 0) { SLPDLog("No usable interfaces\n"); return 1; } return 0; }
/*-------------------------------------------------------------------------*/ void SLPDLogAttrRplyMessage(SLPAttrRply* attrrply) /*-------------------------------------------------------------------------*/ { SLPDLog("Message ATTRRPLY:\n"); SLPDLog(" errorcode = %i\n",attrrply->errorcode); }
/** Process main entry point. * * @param[in] argc - The number of command line arguments passed in @p argv. * @param[in] argv - An array of pointers to command line arguments. * * @return Zero on success, or a non-zero shell error code. * * @remarks This routine contains the main server loop. */ int main(int argc, char * argv[]) { fd_set readfds; fd_set writefds; int highfd; int fdcount = 0; time_t curtime; struct timeval timeout; #ifdef DEBUG xmalloc_init("/var/log/slpd_xmalloc.log", 0); #endif /* Parse the command line */ if (SLPDParseCommandLine(argc,argv)) SLPDFatal("Invalid command line\n"); /* make sure we are root */ if (getuid() != 0) SLPDFatal("slpd must be started by root\n"); /* make sure we are not already running */ if (CheckPid(G_SlpdCommandLine.pidfile)) SLPDFatal("slpd is already running. Check %s\n", G_SlpdCommandLine.pidfile); /* Initialize the preferences so we know if the log file is to be overwritten or appended.*/ if (SLPDPropertyInit(G_SlpdCommandLine.cfgfile)) SLPDFatal("slpd initialization failed during property load\n"); /* make slpd run as a daemon */ if (Daemonize(G_SlpdCommandLine.pidfile)) SLPDFatal("Could not daemonize\n"); /* initialize the log file */ if (SLPDLogFileOpen(G_SlpdCommandLine.logfile, G_SlpdProperty.appendLog)) SLPDFatal("Could not open logfile %s\n",G_SlpdCommandLine.logfile); /* seed the XID generator */ SLPXidSeed(); /* log startup message */ SLPDLog("****************************************\n"); SLPDLogTime(); SLPDLog("SLPD daemon started\n"); SLPDLog("****************************************\n"); SLPDLog("Command line = %s\n", argv[0]); SLPDLog("Using configuration file = %s\n", G_SlpdCommandLine.cfgfile); SLPDLog("Using registration file = %s\n", G_SlpdCommandLine.regfile); #ifdef ENABLE_SLPv2_SECURITY SLPDLog("Using SPI file = %s\n", G_SlpdCommandLine.spifile); #endif /* initialize for the first time */ SLPDPropertyReinit(); /*So we get any property-related log messages*/ if ( #ifdef ENABLE_SLPv2_SECURITY SLPDSpiInit(G_SlpdCommandLine.spifile) || #endif SLPDDatabaseInit(G_SlpdCommandLine.regfile) || SLPDIncomingInit() || SLPDOutgoingInit() || SLPDKnownDAInit()) SLPDFatal("slpd initialization failed\n"); SLPDLog("Agent Interfaces = %s\n", G_SlpdProperty.interfaces); if (G_SlpdProperty.port != SLP_RESERVED_PORT) SLPDLog("Using port %d instead of default %d\n", G_SlpdProperty.port, SLP_RESERVED_PORT); /* drop privileges to reduce security risk */ if (DropPrivileges()) SLPDFatal("Could not drop privileges\n"); /* Setup signal handlers */ if (SetUpSignalHandlers()) SLPDFatal("Error setting up signal handlers.\n"); /* Set up alarm to age database -- a shorter start, so SAs register with us quickly on our startup */ alarm(2); /* Main loop */ SLPDLog("Startup complete entering main run loop ...\n\n"); G_SIGALRM = 0; G_SIGTERM = 0; G_SIGHUP = 0; #ifdef DEBUG G_SIGINT = 0; G_SIGUSR1 = 0; #endif while (G_SIGTERM == 0) { /* load the fdsets up with all valid sockets in the list */ highfd = 0; FD_ZERO(&readfds); FD_ZERO(&writefds); LoadFdSets(&G_IncomingSocketList, &highfd, &readfds, &writefds); LoadFdSets(&G_OutgoingSocketList, &highfd, &readfds, &writefds); /* before select(), check to see if we got a signal */ if (G_SIGALRM || G_SIGHUP) goto HANDLE_SIGNAL; /* main select -- we time out every second so the outgoing retries can occur*/ time(&curtime); timeout.tv_sec = 1; timeout.tv_usec = 0; fdcount = select(highfd + 1, &readfds, &writefds, 0, &timeout); if (fdcount > 0) /* fdcount will be < 0 when interrupted by a signal */ { SLPDIncomingHandler(&fdcount, &readfds, &writefds); SLPDOutgoingHandler(&fdcount, &readfds, &writefds); SLPDOutgoingRetry(time(0) - curtime); } else if (fdcount == 0) SLPDOutgoingRetry(time(0) - curtime); HANDLE_SIGNAL: if (G_SIGHUP) { HandleSigHup(); G_SIGHUP = 0; } if (G_SIGALRM) { HandleSigAlrm(); G_SIGALRM = 0; alarm(SLPD_AGE_INTERVAL); } #ifdef DEBUG if (G_SIGINT) { HandleSigInt(); G_SIGINT = 0; } if (G_SIGUSR1) { HandleSigUsr1(); G_SIGUSR1 = 0; } #endif } /* End of main loop */ /* Got SIGTERM */ HandleSigTerm(); return 0; }
/*-------------------------------------------------------------------------*/ void IncomingStreamRead(SLPList* socklist, SLPDSocket* sock) /*-------------------------------------------------------------------------*/ { int bytesread, recvlen = 0; 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) { if (*peek == 2) recvlen = AsUINT24(peek + 2); else if (*peek == 1) /* SLPv1 packet */ recvlen = AsUINT16(peek + 2); /* 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, 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: case SLP_ERROR_MESSAGE_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 ServiceStart (int argc, char **argv) /*--------------------------------------------------------------------------*/ { fd_set readfds; fd_set writefds; int highfd; int fdcount = 0; time_t curtime; time_t alarmtime; struct timeval timeout; WSADATA wsaData; WORD wVersionRequested = MAKEWORD(1,1); /*------------------------*/ /* Service initialization */ /*------------------------*/ if(!ReportStatusToSCMgr(SERVICE_START_PENDING, /* service state*/ NO_ERROR, /* exit code */ 3000)) /* wait hint */ { goto cleanup; } if(WSAStartup(wVersionRequested, &wsaData) != 0) { (void)ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 0); goto cleanup; } /*------------------------*/ /* Parse the command line */ /*------------------------*/ if(SLPDParseCommandLine(argc,argv)) { ReportStatusToSCMgr(SERVICE_STOP_PENDING, /* service state */ NO_ERROR, /* exit code */ 0); /* wait hint */ goto cleanup_winsock; } if(!ReportStatusToSCMgr(SERVICE_START_PENDING, /* service state */ NO_ERROR, /* exit code */ 3000)) /* wait hint */ { goto cleanup_winsock; } /*------------------------------*/ /* Initialize the log file */ /*------------------------------*/ if(SLPDLogFileOpen(G_SlpdCommandLine.logfile, 1)) { SLPDLog("Could not open logfile %s\n",G_SlpdCommandLine.logfile); goto cleanup_winsock; } /*------------------------*/ /* Seed the XID generator */ /*------------------------*/ SLPXidSeed(); /*---------------------*/ /* Log startup message */ /*---------------------*/ SLPDLog("****************************************\n"); SLPDLogTime(); SLPDLog("SLPD daemon started\n"); SLPDLog("****************************************\n"); SLPDLog("Command line = %s\n",argv[0]); SLPDLog("Using configuration file = %s\n",G_SlpdCommandLine.cfgfile); SLPDLog("Using registration file = %s\n",G_SlpdCommandLine.regfile); if(!ReportStatusToSCMgr(SERVICE_START_PENDING, /* service state */ NO_ERROR, /* exit code */ 3000)) /* wait hint */ { goto cleanup_winsock; } /*--------------------------------------------------*/ /* Initialize for the first time */ /*--------------------------------------------------*/ if(SLPDPropertyInit(G_SlpdCommandLine.cfgfile) || SLPDDatabaseInit(G_SlpdCommandLine.regfile) || SLPDIncomingInit() || SLPDOutgoingInit() || SLPDKnownDAInit()) { SLPDLog("slpd initialization failed\n"); goto cleanup_winsock; } SLPDLog("Agent Interfaces = %s\n",G_SlpdProperty.interfaces); /* Service is now running, perform work until shutdown */ if(!ReportStatusToSCMgr(SERVICE_RUNNING, /* service state */ NO_ERROR, /* exit code */ 0)) /* wait hint */ { goto cleanup_winsock; } /*-----------*/ /* Main loop */ /*-----------*/ SLPDLog("Startup complete entering main run loop ...\n\n"); G_SIGTERM = 0; curtime = time(&alarmtime); alarmtime = curtime + SLPD_AGE_INTERVAL; while(G_SIGTERM == 0) { /*--------------------------------------------------------*/ /* Load the fdsets up with all valid sockets in the list */ /*--------------------------------------------------------*/ highfd = 0; FD_ZERO(&readfds); FD_ZERO(&writefds); LoadFdSets(&G_IncomingSocketList, &highfd, &readfds,&writefds); LoadFdSets(&G_OutgoingSocketList, &highfd, &readfds,&writefds); /*--------------------------------------------------*/ /* Before select(), check to see if we got a signal */ /*--------------------------------------------------*/ if(G_SIGALRM) { goto HANDLE_SIGNAL; } /*-------------*/ /* Main select */ /*-------------*/ timeout.tv_sec = SLPD_AGE_INTERVAL; timeout.tv_usec = 0; fdcount = select(highfd+1,&readfds,&writefds,0,&timeout); if(fdcount > 0) /* fdcount will be < 0 when timed out */ { SLPDIncomingHandler(&fdcount,&readfds,&writefds); SLPDOutgoingHandler(&fdcount,&readfds,&writefds); } /*----------------*/ /* Handle signals */ /*----------------*/ HANDLE_SIGNAL: curtime = time(&curtime); if(curtime >= alarmtime) { HandleSigAlrm(); alarmtime = curtime + SLPD_AGE_INTERVAL; } } /* End of main loop */ /* Got SIGTERM */ HandleSigTerm(); cleanup_winsock: WSACleanup(); cleanup: ; }
/** Reconnect an outbound socket. * * @param[in] socklist - The list of sockets being monitored. * @param[in] sock - The socket to be reconnected. */ void OutgoingStreamReconnect(SLPList * socklist, SLPDSocket * sock) { char addr_str[INET6_ADDRSTRLEN]; (void)socklist; /*-----------------------------------------------------------------*/ /* If socket is already being reconnected but is reconnect blocked */ /* just return. Blocking connect sockets will eventually time out */ /*-----------------------------------------------------------------*/ if (sock->state == STREAM_CONNECT_BLOCK) return; #ifdef DEBUG /* Log that reconnect warning */ SLPDLog("WARNING: Reconnect to agent at %s. " "Agent may not be making efficient \n" " use of TCP.\n", SLPNetSockAddrStorageToString(&sock->peeraddr, addr_str, sizeof(addr_str))); #endif /*----------------------------------------------------------------*/ /* Make sure we have not reconnected too many times */ /* We only allow SLPD_CONFIG_MAX_RECONN reconnection retries */ /* before we stop */ /*----------------------------------------------------------------*/ sock->reconns += 1; if (sock->reconns > SLPD_CONFIG_MAX_RECONN) { SLPDLog("WARNING: Reconnect tries to agent at %s " "exceeded maximum. It\n is possible that " "the agent is malicious. Check it out!\n", SLPNetSockAddrStorageToString(&sock->peeraddr, addr_str, sizeof(addr_str))); /*Since we can't connect, remove it as a DA*/ SLPDKnownDARemove(&(sock->peeraddr)); sock->state = SOCKET_CLOSE; return; } /*----------------------------------------------------------------*/ /* Close the existing socket to clean the stream and open an new */ /* socket */ /*----------------------------------------------------------------*/ closesocket(sock->fd); if (sock->peeraddr.ss_family == AF_INET) sock->fd = socket(PF_INET, SOCK_STREAM, 0); else if (sock->peeraddr.ss_family == AF_INET6) sock->fd = socket(PF_INET6, SOCK_STREAM, 0); if (sock->fd == SLP_INVALID_SOCKET) { sock->state = SOCKET_CLOSE; return; } /*---------------------------------------------*/ /* Set the new socket to enable nonblocking IO */ /*---------------------------------------------*/ #ifdef _WIN32 { u_long fdflags = 1; ioctlsocket(sock->fd, FIONBIO, &fdflags); } #else { int fdflags = fcntl(sock->fd, F_GETFL, 0); fcntl(sock->fd, F_SETFL, fdflags | O_NONBLOCK); } #endif /*--------------------------*/ /* Connect a the new socket */ /*--------------------------*/ if (connect(sock->fd, (struct sockaddr *)&sock->peeraddr, sizeof(struct sockaddr_storage))) { #ifdef _WIN32 if (WSAEWOULDBLOCK == WSAGetLastError()) #else if (errno == EINPROGRESS) #endif { /* Connect blocked */ sock->state = STREAM_CONNECT_BLOCK; return; } } /* Connection occured immediately. Set to WRITE_FIRST so whole */ /* packet will be written */ sock->state = STREAM_WRITE_FIRST; }
/** Resend messages on sockets whose timeout has expired * * @param[in] seconds - The number of seconds old a socket must be to have * its messages resent. * * @remarks - Ideally, this would be at a resolution lower than one second, * but given the default timeout values, this isn't too far off the mark, and * should not add too much of a burden to the main loop. */ void SLPDOutgoingRetry(time_t seconds) { SLPDSocket * del = 0; SLPDSocket * sock = (SLPDSocket *) G_OutgoingSocketList.head; if(seconds <= 0) return; while (sock) { switch (sock->state) { case DATAGRAM_UNICAST: if(0 == sock->sendlist.count) /*Clean up as fast as we can, as all messages were sent*/ del = sock; else { sock->age += seconds; if(sock->age >= G_SlpdProperty.unicastTimeouts[sock->reconns] / 1000) { ++sock->reconns; if(sock->reconns >= MAX_RETRANSMITS) { char addr_str[INET6_ADDRSTRLEN]; SLPDLog("SLPD: Didn't receive response from DA at %s, removing it from list.\n", SLPNetSockAddrStorageToString(&sock->peeraddr, addr_str, sizeof(addr_str))); SLPDKnownDARemove(&(sock->peeraddr)); del = sock; } else { SLPBuffer pbuf; sock->age = 0; for(pbuf = (SLPBuffer) sock->sendlist.head; pbuf; pbuf = (SLPBuffer) pbuf->listitem.next) SLPDOutgoingDatagramWrite(sock, pbuf); } } } break; case DATAGRAM_MULTICAST: case DATAGRAM_BROADCAST: case STREAM_READ_FIRST: case STREAM_WRITE_FIRST: case STREAM_CONNECT_BLOCK: case STREAM_READ: case STREAM_WRITE: case STREAM_CONNECT_IDLE: case STREAM_WRITE_WAIT: default: break; } sock = (SLPDSocket *) sock->listitem.next; if (del) { SLPDSocketFree((SLPDSocket *) SLPListUnlink(&G_OutgoingSocketList, (SLPListItem *) del)); del = 0; } } }
/** Reinitialize the slpd property management subsystem. * * Clears and rereads configuration parameters from files into the system. * Resets slpd-specific overrides. */ void SLPDPropertyReinit(void) { int sts; char * myinterfaces = 0; int family = AF_UNSPEC; /* free previous settings (if any) */ xfree(G_SlpdProperty.useScopes); xfree(G_SlpdProperty.DAAddresses); xfree(G_SlpdProperty.interfaces); xfree(G_SlpdProperty.locale); /* reinitialize property sub-system */ (void)SLPPropertyReinit(); /* set the properties without hard defaults */ G_SlpdProperty.isDA = SLPPropertyAsBoolean("net.slp.isDA"); G_SlpdProperty.activeDADetection = SLPPropertyAsBoolean("net.slp.activeDADetection"); if (G_SlpdProperty.activeDADetection) { G_SlpdProperty.DAActiveDiscoveryInterval = SLPPropertyAsInteger("net.slp.DAActiveDiscoveryInterval"); if (G_SlpdProperty.DAActiveDiscoveryInterval > 1 && G_SlpdProperty.DAActiveDiscoveryInterval < SLPD_CONFIG_DA_FIND) G_SlpdProperty.DAActiveDiscoveryInterval = SLPD_CONFIG_DA_FIND; } else G_SlpdProperty.DAActiveDiscoveryInterval = 0; G_SlpdProperty.passiveDADetection = SLPPropertyAsBoolean("net.slp.passiveDADetection"); G_SlpdProperty.staleDACheckPeriod = SLPPropertyAsInteger("net.slp.staleDACheckPeriod"); if (G_SlpdProperty.staleDACheckPeriod > 0) { if (G_SlpdProperty.staleDACheckPeriod < (SLPD_HEARTBEATS_PER_CHECK_PERIOD + 1) * SLPD_AGE_INTERVAL) G_SlpdProperty.staleDACheckPeriod = (SLPD_HEARTBEATS_PER_CHECK_PERIOD + 1) * SLPD_AGE_INTERVAL; SLPDLog("staleDACheckPeriod = %ds\n", G_SlpdProperty.staleDACheckPeriod); } G_SlpdProperty.isBroadcastOnly = SLPPropertyAsBoolean("net.slp.isBroadcastOnly"); G_SlpdProperty.multicastTTL = SLPPropertyAsInteger("net.slp.multicastTTL"); G_SlpdProperty.multicastMaximumWait = SLPPropertyAsInteger("net.slp.multicastMaximumWait"); G_SlpdProperty.unicastMaximumWait = SLPPropertyAsInteger("net.slp.unicastMaximumWait"); SLPPropertyAsIntegerVector("net.slp.unicastTimeouts", G_SlpdProperty.unicastTimeouts, MAX_RETRANSMITS); G_SlpdProperty.randomWaitBound = SLPPropertyAsInteger("net.slp.randomWaitBound"); G_SlpdProperty.maxResults = SLPPropertyAsInteger("net.slp.maxResults"); G_SlpdProperty.traceMsg = SLPPropertyAsBoolean("net.slp.traceMsg"); G_SlpdProperty.traceReg = SLPPropertyAsBoolean("net.slp.traceReg"); G_SlpdProperty.traceDrop = SLPPropertyAsBoolean("net.slp.traceDrop"); G_SlpdProperty.traceDATraffic = SLPPropertyAsBoolean("net.slp.traceDATraffic"); G_SlpdProperty.appendLog = SLPPropertyAsBoolean("net.slp.appendLog"); if ((G_SlpdProperty.DAAddresses = SLPPropertyXDup("net.slp.DAAddresses")) != 0) G_SlpdProperty.DAAddressesLen = strlen(G_SlpdProperty.DAAddresses); /** @todo Make sure that we are using scopes correctly. What about DHCP, etc? */ if ((G_SlpdProperty.useScopes = SLPPropertyXDup("net.slp.useScopes")) != 0) G_SlpdProperty.useScopesLen = strlen(G_SlpdProperty.useScopes); if ((G_SlpdProperty.locale = SLPPropertyXDup("net.slp.locale")) != 0) G_SlpdProperty.localeLen = strlen(G_SlpdProperty.locale); G_SlpdProperty.securityEnabled = SLPPropertyAsBoolean("net.slp.securityEnabled"); G_SlpdProperty.checkSourceAddr = SLPPropertyAsBoolean("net.slp.checkSourceAddr"); G_SlpdProperty.DAHeartBeat = SLPPropertyAsInteger("net.slp.DAHeartBeat"); if (G_SlpdProperty.staleDACheckPeriod > 0) { /* Adjust the heartbeat interval if we need to send it faster for * stale DA detection */ int maxHeartbeat = G_SlpdProperty.staleDACheckPeriod / SLPD_HEARTBEATS_PER_CHECK_PERIOD; if ((G_SlpdProperty.DAHeartBeat == 0) || (G_SlpdProperty.DAHeartBeat > maxHeartbeat)) { SLPDLog("Overriding heartbeat to %ds for stale DA check\n", maxHeartbeat); G_SlpdProperty.DAHeartBeat = maxHeartbeat; } } /* Can't send it out more frequently than every interval */ if (G_SlpdProperty.DAHeartBeat < SLPD_AGE_INTERVAL) G_SlpdProperty.DAHeartBeat = SLPD_AGE_INTERVAL; G_SlpdProperty.port = (uint16_t)SLPPropertyAsInteger("net.slp.port"); /* set the net.slp.interfaces property */ if (SLPNetIsIPV4() && SLPNetIsIPV6()) family = AF_UNSPEC; else if (SLPNetIsIPV4()) family = AF_INET; else if (SLPNetIsIPV6()) family = AF_INET6; myinterfaces = SLPPropertyXDup("net.slp.interfaces"); sts = SLPIfaceGetInfo(myinterfaces, &G_SlpdProperty.ifaceInfo, family); xfree(myinterfaces); if (!G_SlpdProperty.indexingPropertiesSet) { #ifdef ENABLE_PREDICATES G_SlpdProperty.indexedAttributesLen = 0; if ((G_SlpdProperty.indexedAttributes = SLPPropertyXDup("net.slp.indexedAttributes")) != 0) G_SlpdProperty.indexedAttributesLen = strlen(G_SlpdProperty.indexedAttributes); #endif G_SlpdProperty.srvtypeIsIndexed = SLPPropertyAsBoolean("net.slp.indexSrvtype"); G_SlpdProperty.indexingPropertiesSet = 1; } else { #ifdef ENABLE_PREDICATES int attrchg = 0; char *indexedAttributes = SLPPropertyXDup("net.slp.indexedAttributes"); if (!indexedAttributes && G_SlpdProperty.indexedAttributes) attrchg = 1; else if (indexedAttributes && !G_SlpdProperty.indexedAttributes) attrchg = 1; else if (indexedAttributes) { if (strcmp(indexedAttributes, G_SlpdProperty.indexedAttributes) != 0) attrchg = 1; } if (attrchg) SLPDLog("Cannot change value of net.slp.indexedAttributes without restarting the daemon\n"); xfree(indexedAttributes); #endif if (G_SlpdProperty.srvtypeIsIndexed != SLPPropertyAsBoolean("net.slp.indexSrvtype")) SLPDLog("Cannot change value of net.slp.indexSrvtype without restarting the daemon\n"); } if (sts == 0) { myinterfaces = 0; if (SLPIfaceSockaddrsToString(G_SlpdProperty.ifaceInfo.iface_addr, G_SlpdProperty.ifaceInfo.iface_count, &myinterfaces) == 0) { SLPPropertySet("net.slp.interfaces", myinterfaces, SLP_PA_USERSET); G_SlpdProperty.interfaces = myinterfaces; G_SlpdProperty.interfacesLen = strlen(G_SlpdProperty.interfaces); } } /* set the value used internally as the url for this agent */ strcpy(G_SlpdProperty.urlPrefix, G_SlpdProperty.isDA? SLP_DA_SERVICE_TYPE: SLP_SA_SERVICE_TYPE); strcat(G_SlpdProperty.urlPrefix, "://"); G_SlpdProperty.urlPrefixLen = strlen(G_SlpdProperty.urlPrefix); /* set other values used internally */ G_SlpdProperty.DATimestamp = (uint32_t)time(0); /* DATimestamp must be the boot time of the process */ G_SlpdProperty.activeDiscoveryXmits = 3; /* ensures xmit on first 3 calls to SLPDKnownDAActiveDiscovery() */ G_SlpdProperty.nextActiveDiscovery = 0; /* ensures xmit on first call to SLPDKnownDAActiveDiscovery() */ G_SlpdProperty.nextPassiveDAAdvert = 0; /* ensures xmit on first call to SLPDKnownDAPassiveDiscovery()*/ }
/** 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; }
/*-------------------------------------------------------------------------*/ void SLPDLogSrvAckMessage(SLPSrvAck* srvack) /*-------------------------------------------------------------------------*/ { SLPDLog("Message SRVACK:\n"); SLPDLog(" errorcode = %i\n",srvack->errorcode); }
/** Process a DA service request message. * * @param[in] message - The message to process. * @param[out] sendbuf - The response buffer to fill. * @param[in] errorcode - The error code from the client request. * * @return Zero on success, or a non-zero SLP error on failure. * * @internal */ static int ProcessDASrvRqst(SLPMessage * message, SLPBuffer * sendbuf, int errorcode) { SLPBuffer tmp = 0; SLPMessage * msg = 0; void * eh = 0; /* TODO should really be a configurable property, maybe G_SlpdProperty.MTU? Left at 4096 to retain same behaviour */ size_t initial_buffer_size = 4096; size_t grow_size = initial_buffer_size; /* Special case for when libslp asks slpd (through the loopback) about a known DAs. Fill sendbuf with DAAdverts from all known DAs. */ if (SLPNetIsLoopback(&message->peer)) { *sendbuf = SLPBufferRealloc(*sendbuf, initial_buffer_size); if (*sendbuf == 0) return SLP_ERROR_INTERNAL_ERROR; if (errorcode == 0) { /* Note: The weird *sendbuf code is making a single SLPBuffer that contains multiple DAAdverts. This is a special process that only happens for the DA SrvRqst through loopback to the SLPAPI */ /*If we are a DA, always have ourself at the start of the list, so the lib requests can be handled locally for speed */ if(G_SlpdProperty.isDA) { struct sockaddr_storage loaddr; if(SLPNetIsIPV4()) { int addr = INADDR_LOOPBACK; SLPNetSetAddr(&loaddr, AF_INET, G_SlpdProperty.port, &addr); } else { SLPNetSetAddr(&loaddr, AF_INET6, G_SlpdProperty.port, &slp_in6addr_loopback); } if(0 == SLPDKnownDAGenerateMyDAAdvert(&loaddr, 0, 0, 0, message->header.xid, &tmp)) { memcpy((*sendbuf)->curpos, tmp->start, tmp->end - tmp->start); (*sendbuf)->curpos = ((*sendbuf)->curpos) + (tmp->end - tmp->start); SLPBufferFree(tmp); tmp = 0; } else { SLPDLog("Unable to add initial DAAdvert due to error\n"); } } eh = SLPDKnownDAEnumStart(); if (eh) { while (1) { /* iterate over all database entries */ if (SLPDKnownDAEnum(eh, &msg, &tmp) == 0) { break; } /* if we resize succesfully.. */ if( CheckAndResizeBuffer(sendbuf, tmp, grow_size) == 0 ) { /* buffer should now be resized to an appropriate size to handle all current database entries */ /* TRICKY: Fix up the XID and clear the flags. */ tmp->curpos = tmp->start + 10; TO_UINT16(tmp->curpos, message->header.xid); if (*(tmp->start) == 1) *(tmp->start + 4) = 0; else TO_UINT16(tmp->start + 5, 0); /* copy all data out of tmp into the sendbuf */ memcpy((*sendbuf)->curpos, tmp->start, tmp->end - tmp->start); /* increment the current position in sendbuf */ (*sendbuf)->curpos = ((*sendbuf)->curpos) + (tmp->end - tmp->start); } else { errorcode = SLP_ERROR_INTERNAL_ERROR; } } SLPDKnownDAEnumEnd(eh); } /* tmp can store database entries which should not be freed by anyone else so reset the pointer to prevent double deletion */ tmp = 0; /* Tack on a "terminator" DAAdvert Note that this function *always* returns the error code passed as its second parameter (or SLP_ERROR_INTERNAL_ERROR if the buffer fails to resize) The errorcode is also inserted into the srvrply header by this function */ SLPDKnownDAGenerateMyDAAdvert(&message->localaddr, SLP_ERROR_INTERNAL_ERROR, 0, 0, message->header.xid, &tmp); /* if we resize succesfully.. */ if ( CheckAndResizeBuffer(sendbuf, tmp, grow_size) == 0 ) { memcpy((*sendbuf)->curpos, tmp->start, tmp->end - tmp->start); (*sendbuf)->curpos = ((*sendbuf)->curpos) + (tmp->end - tmp->start); /* mark the end of the sendbuf */ (*sendbuf)->end = (*sendbuf)->curpos; } else { errorcode = SLP_ERROR_INTERNAL_ERROR; } SLPBufferFree(tmp); tmp = 0; } return errorcode; } /* Normal case where a remote Agent asks for a DA */ *sendbuf = SLPBufferRealloc(*sendbuf, G_SlpdProperty.MTU); if (*sendbuf == 0) return SLP_ERROR_INTERNAL_ERROR; if (G_SlpdProperty.isDA) { if (message->body.srvrqst.scopelistlen == 0 || SLPIntersectStringList(message->body.srvrqst.scopelistlen, message->body.srvrqst.scopelist, G_SlpdProperty.useScopesLen, G_SlpdProperty.useScopes)) { errorcode = SLPDKnownDAGenerateMyDAAdvert(&message->localaddr, errorcode, 0, 0, message->header.xid, sendbuf); } else errorcode = SLP_ERROR_SCOPE_NOT_SUPPORTED; } else errorcode = SLP_ERROR_MESSAGE_NOT_SUPPORTED; /* don't return errorcodes to multicast messages */ if (errorcode != 0) { if (message->header.flags & SLP_FLAG_MCAST || SLPNetIsMCast(&(message->peer))) (*sendbuf)->end = (*sendbuf)->start; } return errorcode; }
/*-------------------------------------------------------------------------*/ void SLPDLogSrvTypeRplyMessage(SLPSrvTypeRply* srvtyperply) /*-------------------------------------------------------------------------*/ { SLPDLog("Message SRVTYPERPLY:\n"); SLPDLog(" errorcode = %i\n",srvtyperply->errorcode); }
/*-------------------------------------------------------------------------*/ 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 SLPDLogMessageInternals(SLPMessage message) /*=========================================================================*/ { SLPDLog("Peer: \n"); SLPDLog(" IP address: %s\n", inet_ntoa(message->peer.sin_addr)); SLPDLog("Header:\n"); SLPDLog(" version = %i\n",message->header.version); SLPDLog(" functionid = %i\n",message->header.functionid); SLPDLog(" length = %i\n",message->header.length); SLPDLog(" flags = %i\n",message->header.flags); SLPDLog(" extoffset = %i\n",message->header.extoffset); SLPDLog(" xid = %i\n",message->header.xid); SLPDLogBuffer(" langtag = ", message->header.langtaglen, message->header.langtag); switch (message->header.functionid) { case SLP_FUNCT_SRVRQST: SLPDLogSrvRqstMessage(&(message->body.srvrqst)); break; case SLP_FUNCT_SRVRPLY: SLPDLogSrvRplyMessage(&(message->body.srvrply)); break; case SLP_FUNCT_SRVREG: SLPDLogSrvRegMessage(&(message->body.srvreg)); break; case SLP_FUNCT_SRVDEREG: SLPDLogSrvDeRegMessage(&(message->body.srvdereg)); break; case SLP_FUNCT_SRVACK: SLPDLogSrvAckMessage(&(message->body.srvack)); break; case SLP_FUNCT_ATTRRQST: SLPDLogAttrRqstMessage(&(message->body.attrrqst)); break; case SLP_FUNCT_ATTRRPLY: SLPDLogAttrRplyMessage(&(message->body.attrrply)); break; case SLP_FUNCT_DAADVERT: SLPDLogDAAdvertMessage(&(message->body.daadvert)); break; case SLP_FUNCT_SRVTYPERQST: SLPDLogSrvTypeRqstMessage(&(message->body.srvtyperqst)); break; case SLP_FUNCT_SRVTYPERPLY: SLPDLogSrvTypeRplyMessage(&(message->body.srvtyperply)); break; case SLP_FUNCT_SAADVERT: SLPDLogSAAdvertMessage(&(message->body.saadvert)); break; default: SLPDLog("Message %i UNKNOWN:\n",message->header.functionid); SLPDLog(" This is really bad\n"); break; } }
/*-------------------------------------------------------------------------*/ void OutgoingStreamWrite(SLPList* socklist, SLPDSocket* sock) /*-------------------------------------------------------------------------*/ { int byteswritten; int flags = 0; #if defined(MSG_DONTWAIT) flags = MSG_DONTWAIT; #endif if ( sock->state == STREAM_WRITE_FIRST ) { /* make sure that there is something to do list */ sock->sendbuf = (SLPBuffer)sock->sendlist.head; if ( sock->sendbuf == 0 ) { /* there is nothing in the to do list */ sock->state = STREAM_CONNECT_IDLE; /* reset the reconnect count because the socket */ /* appears to be healthy again */ sock->reconns = 0; return; } /* make sure that the start and curpos pointers are the same */ sock->sendbuf->curpos = sock->sendbuf->start; sock->state = STREAM_WRITE; } if ( sock->sendbuf->end - sock->sendbuf->start > 0 ) { byteswritten = send(sock->fd, sock->sendbuf->curpos, sock->sendbuf->end - sock->sendbuf->start, flags); if ( byteswritten > 0 ) { /* reset age because of activity */ sock->age = 0; /* move buffer pointers */ sock->sendbuf->curpos += byteswritten; /* check to see if everything was written */ if ( sock->sendbuf->curpos == sock->sendbuf->end ) { /* Message is completely sent. Set state to read the reply */ sock->state = STREAM_READ_FIRST; } } 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); } } } else { /* nothing to write */ #ifdef DEBUG SLPDLog("yikes, an empty socket is being written!\n"); #endif sock->state = SOCKET_CLOSE; } }
/** Re-balance the (sub-)tree, if necessary. * * Checks whether the tree is balanced, and performs rotations as required to * re-balance if necessary. * * @param[in] root_node - a pointer to the root of the (sub-)tree. * * @return New root node of the tree */ static IndexTreeNode *rebalance_tree( IndexTreeNode *root_node) { /* Check whether we need to re-balance the (sub-)tree */ if (root_node->left_depth - root_node->right_depth == 2) { /* Need to perform a right-rotation */ IndexTreeNode *parent_node; IndexTreeNode *pivot = root_node->left_node; if (tree_depth(pivot->right_node) > tree_depth(pivot->left_node)) { /* Rotate the pivot tree left first, as the right subtree will be * going beneath the current root node which will be going beneath * the pivot node, so will increase the depth. By rotating the * subtrees, we ensure that the shallower sub-tree has its depth * increased, to minimise the difference in depth */ IndexTreeNode *new_pivot = pivot->right_node; parent_node = pivot->parent_node; pivot->right_node = new_pivot->left_node; if (pivot->right_node) pivot->right_node->parent_node = pivot; pivot->right_depth = new_pivot->left_depth; pivot->parent_node = new_pivot; new_pivot->left_node = pivot; new_pivot->left_depth = tree_depth(pivot); new_pivot->parent_node = parent_node; pivot = new_pivot; } /* Now perform the right rotation */ parent_node = root_node->parent_node; root_node->left_node = pivot->right_node; if (root_node->left_node) root_node->left_node->parent_node = root_node; root_node->left_depth = pivot->right_depth; root_node->parent_node = pivot; pivot->right_node = root_node; pivot->right_depth = tree_depth(root_node); pivot->parent_node = parent_node; root_node = pivot; } else if (root_node->right_depth - root_node->left_depth == 2) { /* Need to perform a left-rotation */ IndexTreeNode *parent_node; IndexTreeNode *pivot = root_node->right_node; if (tree_depth(pivot->left_node) > tree_depth(pivot->right_node)) { /* Rotate the pivot tree right first, as the left subtree will be * going beneath the current root node which will be going beneath * the pivot node, so will increase the depth. By rotating the * subtrees, we ensure that the shallower sub-tree has its depth * increased, to minimise the difference in depth */ IndexTreeNode *new_pivot = pivot->left_node; parent_node = pivot->parent_node; pivot->left_node = new_pivot->right_node; if (pivot->left_node) pivot->left_node->parent_node = pivot; pivot->left_depth = new_pivot->right_depth; pivot->parent_node = new_pivot; new_pivot->right_node = pivot; new_pivot->right_depth = tree_depth(pivot); new_pivot->parent_node = parent_node; pivot = new_pivot; } /* Now perform the left rotation */ parent_node = root_node->parent_node; root_node->right_node = pivot->left_node; if (root_node->right_node) root_node->right_node->parent_node = root_node; root_node->right_depth = pivot->left_depth; root_node->parent_node = pivot; pivot->left_node = root_node; pivot->left_depth = tree_depth(root_node); pivot->parent_node = parent_node; root_node = pivot; } #if defined(DEBUG) && defined(CHECKING) if (!check_tree(root_node)) { SLPDLog("Index tree check fails after rebalancing tree %p\n", root_node); } #endif return root_node; }
/*-------------------------------------------------------------------------*/ void OutgoingStreamReconnect(SLPList* socklist, SLPDSocket* sock) /*-------------------------------------------------------------------------*/ { #ifdef WIN32 u_long fdflags; #else int fdflags; #endif /*-----------------------------------------------------------------*/ /* If socket is already being reconnected but is reconnect blocked */ /* just return. Blocking connect sockets will eventually time out */ /*-----------------------------------------------------------------*/ if(sock->state == STREAM_CONNECT_BLOCK) { return; } #ifdef DEBUG /* Log that reconnect warning */ SLPDLog("WARNING: Reconnect to agent at %s. Agent may not be making efficient \n" " use of TCP.\n", inet_ntoa(sock->peeraddr.sin_addr)); #endif /*----------------------------------------------------------------*/ /* Make sure we have not reconnected too many times */ /* We only allow SLPD_CONFIG_MAX_RECONN reconnection retries */ /* before we stop */ /*----------------------------------------------------------------*/ sock->reconns += 1; if ( sock->reconns > SLPD_CONFIG_MAX_RECONN ) { sock->state = SOCKET_CLOSE; SLPDLog("WARNING: Reconnect tries to agent at %s exceeded maximum. It\n" " is possible that the agent is malicious. Check it out!\n", inet_ntoa(sock->peeraddr.sin_addr)); return; } /*----------------------------------------------------------------*/ /* Close the existing socket to clean the stream and open an new */ /* socket */ /*----------------------------------------------------------------*/ CloseSocket(sock->fd); sock->fd = socket(PF_INET,SOCK_STREAM,0); if ( sock->fd < 0 ) { sock->state = SOCKET_CLOSE; return; } /*---------------------------------------------*/ /* Set the new socket to enable nonblocking IO */ /*---------------------------------------------*/ #ifdef WIN32 fdflags = 1; ioctlsocket(sock->fd, FIONBIO, &fdflags); #else fdflags = fcntl(sock->fd, F_GETFL, 0); fcntl(sock->fd,F_SETFL, fdflags | O_NONBLOCK); #endif /*--------------------------*/ /* Connect a the new socket */ /*--------------------------*/ if ( connect(sock->fd, (struct sockaddr *)&(sock->peeraddr), sizeof(struct sockaddr_in)) ) { #ifdef WIN32 if ( WSAEWOULDBLOCK == WSAGetLastError() ) #else if ( errno == EINPROGRESS ) #endif { /* Connect blocked */ sock->state = STREAM_CONNECT_BLOCK; return; } } /* Connection occured immediately. Set to WRITE_FIRST so whole */ /* packet will be written */ sock->state = STREAM_WRITE_FIRST; }
/*-------------------------------------------------------------------------*/ void SLPDLogSrvRplyMessage(SLPSrvRply* srvrply) /*-------------------------------------------------------------------------*/ { SLPDLog("Message SRVRPLY:\n"); SLPDLog(" errorcode = %i\n",srvrply->errorcode); }
/** 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); } } }