/*=========================================================================*/ void SLPDOutgoingAge(time_t seconds) /*=========================================================================*/ { SLPDSocket* del = 0; SLPDSocket* sock = (SLPDSocket*)G_OutgoingSocketList.head; while ( sock ) { switch ( sock->state ) { case DATAGRAM_MULTICAST: case DATAGRAM_BROADCAST: case DATAGRAM_UNICAST: if ( sock->age > G_SlpdProperty.unicastMaximumWait / 1000 ) { del = sock; } sock->age = sock->age + seconds; break; case STREAM_READ_FIRST: case STREAM_WRITE_FIRST: sock->age = 0; break; case STREAM_CONNECT_BLOCK: case STREAM_READ: case STREAM_WRITE: if ( G_OutgoingSocketList.count > SLPD_COMFORT_SOCKETS ) { /* Accellerate ageing cause we are low on sockets */ if ( sock->age > SLPD_CONFIG_BUSY_CLOSE_CONN ) { SLPDKnownDARemove(&(sock->peeraddr.sin_addr)); del = sock; } } else { if ( sock->age > SLPD_CONFIG_CLOSE_CONN ) { SLPDKnownDARemove(&(sock->peeraddr.sin_addr)); del = sock; } } sock->age = sock->age + seconds; break; case STREAM_WRITE_WAIT: sock->age = 0; sock->state = STREAM_WRITE_FIRST; break; default: /* don't age the other sockets at all */ break; } sock = (SLPDSocket*)sock->listitem.next; if ( del ) { SLPDSocketFree((SLPDSocket*)SLPListUnlink(&G_OutgoingSocketList,(SLPListItem*)del)); del = 0; } } }
/** 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; } } }
/** 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; }
/*=========================================================================*/ void SLPDKnownDARegister(SLPDDatabaseEntry* dbhead, SLPDSocketList* sockets) /* */ /* Modify the specified socket list to register all entries of the */ /* specified database list with all known DAs */ /* */ /* Returns: Zero on success, non-zero on error */ /*=========================================================================*/ { SLPDDatabaseEntry* dbentry; SLPDSocket* sockentry; SLPDAEntry* daentry; if(dbhead) { daentry = G_KnownDAListHead; while(daentry) { /* check to see if a socket is already connected to this DA */ sockentry = sockets->head; while(sockentry) { if(sockentry->peerinfo.peertype == SLPD_PEER_CONNECTED) { if (memcmp(&sockentry->peerinfo.peeraddr.sin_addr, &daentry->daaddr, sizeof(daentry->daaddr)) == 0) { break; } } sockentry = (SLPDSocket*)sockentry->listitem.next; } if(sockentry == 0) { /* Could not find a connected socket */ /* Create a connected socket */ sockentry = SLPDSocketCreateConnected(&daentry->daaddr); if(sockentry == 0) { /* Could not create connected socket */ /* TODO: should we log here? */ /* Remove the known DA entry we could not connect to */ daentry = SLPDKnownDARemove(daentry); } else { SLPDSocketListAdd(sockets, sockentry); } } if(sockentry != 0) { /* Load the send buffer with reg stuff */ dbentry = dbhead; while(dbentry) { /* TODO: put a whole bunch of registration stuff here */ dbentry = (SLPDDatabaseEntry*)dbentry->listitem.next; } } daentry = (SLPDAEntry*)daentry->listitem.next; } } }