2012-12-24 23:29:02 +01:00
// yacyCore.java
// -------------------------------------
// (C) by Michael Peter Christen; mc@yacy.net
// first published on http://www.anomic.de
// Frankfurt, Germany, 2004
//
// $LastChangedDate$
// $LastChangedRevision$
// $LastChangedBy$
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/ *
the yacy process of getting in touch of other peers starts as follows :
- init seed cache . It is needed to determine the right peer for the Hello - Process
- create a own seed . This can be a new one or one loaded from a file
- The httpd must start up then first
- the own seed is completed by performing the ' yacyHello ' process . This
process will result in a request back to the own peer to check if it runs
in server mode . This is the reason that the httpd must be started in advance .
* /
// contributions:
// principal peer status via file generation by Alexander Schier [AS]
package net.yacy.peers ;
import java.net.MalformedURLException ;
import java.util.Collections ;
import java.util.Date ;
import java.util.HashMap ;
import java.util.Iterator ;
import java.util.LinkedList ;
import java.util.List ;
import java.util.Map ;
2014-09-30 14:53:52 +02:00
import java.util.Set ;
2012-12-24 23:29:02 +01:00
import java.util.concurrent.ConcurrentHashMap ;
import java.util.concurrent.Semaphore ;
import net.yacy.cora.date.GenericFormatter ;
2013-09-15 00:30:23 +02:00
import net.yacy.cora.document.encoding.ASCII ;
import net.yacy.cora.document.feed.RSSFeed ;
import net.yacy.cora.document.feed.RSSMessage ;
import net.yacy.cora.document.id.DigestURL ;
2012-12-24 23:29:02 +01:00
import net.yacy.cora.protocol.Domains ;
2013-07-09 14:28:25 +02:00
import net.yacy.cora.util.ConcurrentLog ;
2012-12-24 23:29:02 +01:00
import net.yacy.peers.operation.yacySeedUploadFile ;
import net.yacy.peers.operation.yacySeedUploadFtp ;
import net.yacy.peers.operation.yacySeedUploadScp ;
import net.yacy.peers.operation.yacySeedUploader ;
import net.yacy.search.Switchboard ;
import net.yacy.search.SwitchboardConstants ;
import net.yacy.server.serverCore ;
public class Network
{
// statics
public static final ThreadGroup publishThreadGroup = new ThreadGroup ( " publishThreadGroup " ) ;
public static final HashMap < String , String > seedUploadMethods = new HashMap < String , String > ( ) ;
2013-07-09 14:28:25 +02:00
public static final ConcurrentLog log = new ConcurrentLog ( " YACY " ) ;
2012-12-24 23:29:02 +01:00
/** pseudo-random key derived from a time-interval while YaCy startup */
public static long speedKey = 0 ;
public static long magic = System . currentTimeMillis ( ) ;
public static final Map < String , Accessible > amIAccessibleDB = new ConcurrentHashMap < String , Accessible > ( ) ; // Holds PeerHash / yacyAccessible Relations
// constants for PeerPing behavior
private static final int PING_INITIAL = 20 ;
private static final int PING_MAX_RUNNING = 3 ;
private static final int PING_MIN_RUNNING = 1 ;
private static final int PING_MIN_DBSIZE = 5 ;
private static final int PING_MIN_PEERSEEN = 1 ; // min. accessible to force senior
private static final long PING_MAX_DBAGE = 15 * 60 * 1000 ; // in milliseconds
// public static yacyShare shareManager = null;
// public static boolean terminate = false;
// class variables
Switchboard sb ;
public Network ( final Switchboard sb ) {
final long time = System . currentTimeMillis ( ) ;
this . sb = sb ;
sb . setConfig ( " yacyStatus " , " " ) ;
// create a peer news channel
final RSSFeed peernews = EventChannel . channels ( EventChannel . PEERNEWS ) ;
peernews . addMessage ( new RSSMessage ( " YaCy started " , " " , " " ) ) ;
// ensure that correct IP is used
final String staticIP = sb . getConfig ( " staticIP " , " " ) ;
2014-09-30 14:53:52 +02:00
if ( staticIP . length ( ) ! = 0 & & Seed . isProperIP ( staticIP ) ) {
2012-12-24 23:29:02 +01:00
serverCore . useStaticIP = true ;
sb . peers . mySeed ( ) . setIP ( staticIP ) ;
2013-07-09 14:28:25 +02:00
log . info ( " staticIP set to " + staticIP ) ;
2012-12-24 23:29:02 +01:00
} else {
serverCore . useStaticIP = false ;
}
loadSeedUploadMethods ( ) ;
2013-07-09 14:28:25 +02:00
log . config ( " CORE INITIALIZED " ) ;
2012-12-24 23:29:02 +01:00
// ATTENTION, VERY IMPORTANT: before starting the thread, the httpd yacy server must be running!
speedKey = System . currentTimeMillis ( ) - time ;
}
public final void publishSeedList ( ) {
2014-09-30 14:53:52 +02:00
if ( log . isFine ( ) ) log . fine ( " yacyCore.publishSeedList: Triggered Seed Publish " ) ;
2012-12-24 23:29:02 +01:00
/ *
if ( oldIPStamp . equals ( ( String ) seedDB . mySeed . get ( yacySeed . IP , " 127.0.0.1 " ) ) )
yacyCore . log . logDebug ( " ***DEBUG publishSeedList: oldIP is equal " ) ;
if ( seedCacheSizeStamp = = seedDB . sizeConnected ( ) )
yacyCore . log . logDebug ( " ***DEBUG publishSeedList: sizeConnected is equal " ) ;
if ( canReachMyself ( ) )
yacyCore . log . logDebug ( " ***DEBUG publishSeedList: I can reach myself " ) ;
* /
2014-09-30 14:53:52 +02:00
if ( ( this . sb . peers . mySeed ( ) . getIPs ( ) . contains ( this . sb . peers . lastSeedUpload_myIP ) )
2012-12-24 23:29:02 +01:00
& & ( this . sb . peers . lastSeedUpload_seedDBSize = = this . sb . peers . sizeConnected ( ) )
& & ( System . currentTimeMillis ( ) - this . sb . peers . lastSeedUpload_timeStamp < 1000 * 60 * 60 * 24 )
& & ( this . sb . peers . mySeed ( ) . isPrincipal ( ) ) ) {
2014-09-30 14:53:52 +02:00
if ( log . isFine ( ) ) log . fine ( " yacyCore.publishSeedList: not necessary to publish: oldIP is equal, sizeConnected is equal and I can reach myself under the old IP. " ) ;
2012-12-24 23:29:02 +01:00
return ;
}
// getting the seed upload method that should be used ...
final String seedUploadMethod = this . sb . getConfig ( " seedUploadMethod " , " " ) ;
if ( ( ! seedUploadMethod . equalsIgnoreCase ( " none " ) )
| | ( ( seedUploadMethod . equals ( " " ) ) & & ( this . sb . getConfig ( " seedFTPPassword " , " " ) . length ( ) > 0 ) )
| | ( ( seedUploadMethod . equals ( " " ) ) & & ( this . sb . getConfig ( " seedFilePath " , " " ) . length ( ) > 0 ) ) ) {
if ( seedUploadMethod . equals ( " " ) ) {
if ( this . sb . getConfig ( " seedFTPPassword " , " " ) . length ( ) > 0 ) {
this . sb . setConfig ( " seedUploadMethod " , " Ftp " ) ;
}
if ( this . sb . getConfig ( " seedFilePath " , " " ) . length ( ) > 0 ) {
this . sb . setConfig ( " seedUploadMethod " , " File " ) ;
}
}
// we want to be a principal...
saveSeedList ( this . sb ) ;
} else {
if ( seedUploadMethod . equals ( " " ) ) {
this . sb . setConfig ( " seedUploadMethod " , " none " ) ;
}
2014-09-30 14:53:52 +02:00
if ( log . isFine ( ) ) log . fine ( " yacyCore.publishSeedList: No uploading method configured " ) ;
2012-12-24 23:29:02 +01:00
return ;
}
}
public final void peerPing ( ) {
if ( ( this . sb . isRobinsonMode ( ) )
& & ( this . sb . getConfig ( SwitchboardConstants . CLUSTER_MODE , " " ) . equals ( SwitchboardConstants . CLUSTER_MODE_PRIVATE_PEER ) ) ) {
// in case this peer is a privat peer we omit the peer ping
// all other robinson peer types do a peer ping:
// the privatecluster does the ping to the other cluster members
// the publiccluster does the ping to all peers, but prefers the own peer
// the publicpeer does the ping to all peers
return ;
}
// before publishing, update some seed data
this . sb . updateMySeed ( ) ;
// publish own seed to other peer, this can every peer, but makes only sense for senior peers
if ( this . sb . peers . sizeConnected ( ) = = 0 ) {
// reload the seed lists
this . sb . loadSeedLists ( ) ;
2013-07-09 14:28:25 +02:00
log . info ( " re-initialized seed list. received "
2012-12-24 23:29:02 +01:00
+ this . sb . peers . sizeConnected ( )
+ " new peer(s) " ) ;
}
2014-10-01 03:10:39 +02:00
publishMySeed ( false ) ;
2012-12-24 23:29:02 +01:00
}
// use our own formatter to prevent concurrency locks with other processes
private final static GenericFormatter my_SHORT_SECOND_FORMATTER = new GenericFormatter (
GenericFormatter . FORMAT_SHORT_SECOND ,
GenericFormatter . time_second ) ;
protected class publishThread extends Thread
{
2014-10-01 03:10:39 +02:00
private Map < String , String > result ;
2012-12-24 23:29:02 +01:00
private final Seed seed ;
private final Semaphore sync ;
private final List < Thread > syncList ;
public publishThread (
final ThreadGroup tg ,
final Seed seed ,
final Semaphore sync ,
final List < Thread > syncList ) throws InterruptedException {
super ( tg , " PublishSeed_ " + seed . getName ( ) ) ;
this . sync = sync ;
this . sync . acquire ( ) ;
this . syncList = syncList ;
this . seed = seed ;
2014-10-01 03:10:39 +02:00
this . result = null ;
2012-12-24 23:29:02 +01:00
}
@Override
public final void run ( ) {
try {
2014-10-01 03:47:57 +02:00
for ( String ip : this . seed . getIPs ( ) ) {
this . result = Protocol . hello ( Network . this . sb . peers . mySeed ( ) , Network . this . sb . peers . peerActions , this . seed . getPublicAddress ( ip ) , this . seed . hash ) ;
if ( this . result ! = null ) break ;
}
2014-10-01 03:10:39 +02:00
if ( this . result = = null ) {
2012-12-24 23:29:02 +01:00
// no or wrong response, delete that address
final String cause = " peer ping to peer resulted in error response (added < 0) " ;
2013-07-09 14:28:25 +02:00
log . info ( " publish: disconnected "
2012-12-24 23:29:02 +01:00
+ this . seed . get ( Seed . PEERTYPE , Seed . PEERTYPE_SENIOR )
+ " peer ' "
+ this . seed . getName ( )
+ " ' from "
2014-09-30 14:53:52 +02:00
+ this . seed . getIPs ( )
2012-12-24 23:29:02 +01:00
+ " : "
+ cause ) ;
Network . this . sb . peers . peerActions . peerDeparture ( this . seed , cause ) ;
} else {
// success! we have published our peer to a senior peer
// update latest news from the other peer
2013-07-09 14:28:25 +02:00
log . info ( " publish: handshaked "
2012-12-24 23:29:02 +01:00
+ this . seed . get ( Seed . PEERTYPE , Seed . PEERTYPE_SENIOR )
+ " peer ' "
+ this . seed . getName ( )
+ " ' at "
2014-09-30 14:53:52 +02:00
+ this . seed . getIPs ( ) ) ;
2012-12-24 23:29:02 +01:00
// check if seed's lastSeen has been updated
final Seed newSeed = Network . this . sb . peers . getConnected ( this . seed . hash ) ;
if ( newSeed ! = null ) {
if ( ! newSeed . isOnline ( ) ) {
if ( log . isFine ( ) ) {
2013-07-09 14:28:25 +02:00
log . fine ( " publish: recently handshaked "
2012-12-24 23:29:02 +01:00
+ this . seed . get ( Seed . PEERTYPE , Seed . PEERTYPE_SENIOR )
+ " peer ' "
+ this . seed . getName ( )
+ " ' at "
2014-09-30 14:53:52 +02:00
+ this . seed . getIPs ( )
2012-12-24 23:29:02 +01:00
+ " is not online. "
+ " Removing Peer from connected " ) ;
}
Network . this . sb . peers . peerActions . peerDeparture ( newSeed , " peer not online " ) ;
} else if ( newSeed . getLastSeenUTC ( ) < ( System . currentTimeMillis ( ) - 10000 ) ) {
// update last seed date
if ( newSeed . getLastSeenUTC ( ) > = this . seed . getLastSeenUTC ( ) ) {
if ( log . isFine ( ) ) {
log
2013-07-09 14:28:25 +02:00
. fine ( " publish: recently handshaked "
2012-12-24 23:29:02 +01:00
+ this . seed . get ( Seed . PEERTYPE , Seed . PEERTYPE_SENIOR )
+ " peer ' "
+ this . seed . getName ( )
+ " ' at "
2014-09-30 14:53:52 +02:00
+ this . seed . getIPs ( )
2012-12-24 23:29:02 +01:00
+ " with old LastSeen: ' "
+ my_SHORT_SECOND_FORMATTER . format ( new Date ( newSeed
. getLastSeenUTC ( ) ) ) + " ' " ) ;
}
newSeed . setLastSeenUTC ( ) ;
Network . this . sb . peers . peerActions . peerArrival ( newSeed , true ) ;
} else {
if ( log . isFine ( ) ) {
log
2013-07-09 14:28:25 +02:00
. fine ( " publish: recently handshaked "
2012-12-24 23:29:02 +01:00
+ this . seed . get ( Seed . PEERTYPE , Seed . PEERTYPE_SENIOR )
+ " peer ' "
+ this . seed . getName ( )
+ " ' at "
2014-09-30 14:53:52 +02:00
+ this . seed . getIPs ( )
2012-12-24 23:29:02 +01:00
+ " with old LastSeen: ' "
+ my_SHORT_SECOND_FORMATTER . format ( new Date ( newSeed
. getLastSeenUTC ( ) ) )
+ " ', this is more recent: ' "
+ my_SHORT_SECOND_FORMATTER . format ( new Date ( this . seed
. getLastSeenUTC ( ) ) )
+ " ' " ) ;
}
this . seed . setLastSeenUTC ( ) ;
Network . this . sb . peers . peerActions . peerArrival ( this . seed , true ) ;
}
}
} else {
if ( log . isFine ( ) ) {
2013-07-09 14:28:25 +02:00
log . fine ( " publish: recently handshaked "
2012-12-24 23:29:02 +01:00
+ this . seed . get ( Seed . PEERTYPE , Seed . PEERTYPE_SENIOR )
+ " peer ' "
+ this . seed . getName ( )
+ " ' at "
2014-09-30 14:53:52 +02:00
+ this . seed . getIPs ( )
2012-12-24 23:29:02 +01:00
+ " not in connectedDB " ) ;
}
}
}
2013-07-17 18:31:30 +02:00
} catch ( final Exception e ) {
2013-07-09 14:28:25 +02:00
ConcurrentLog . logException ( e ) ;
log . severe (
2012-12-24 23:29:02 +01:00
" publishThread: error with target seed " + this . seed . toString ( ) + " : " + e . getMessage ( ) ,
e ) ;
} finally {
this . syncList . add ( this ) ;
this . sync . release ( ) ;
}
}
}
2014-10-01 03:10:39 +02:00
private boolean publishMySeed ( final boolean force ) {
2012-12-24 23:29:02 +01:00
try {
// call this after the httpd was started up
// we need to find out our own ip
// This is not always easy, since the application may
// live behind a firewall or nat.
// the normal way to do this is either measure the value that java gives us,
// but this is not correct if the peer lives behind a NAT/Router or has several
// addresses and not the right one can be found out.
// We have several alternatives:
// 1. ask another peer. This should be normal and the default method.
// but if no other peer lives, or we don't know them, we cannot do that
// 2. ask own NAT. This is only an option if the NAT is a DI604, because this is the
// only supported for address retrieval
// 3. ask ip respond services in the internet. There are several, and they are all
// probed until we get a valid response.
// init yacyHello-process
Map < String , Seed > seeds ; // hash/yacySeed relation
int attempts = this . sb . peers . sizeConnected ( ) ;
// getting a list of peers to contact
if ( this . sb . peers . mySeed ( ) . get ( Seed . PEERTYPE , Seed . PEERTYPE_VIRGIN ) . equals ( Seed . PEERTYPE_VIRGIN ) ) {
2014-10-01 03:10:39 +02:00
if ( attempts > PING_INITIAL ) attempts = PING_INITIAL ;
2014-09-30 14:53:52 +02:00
final Set < byte [ ] > ch = Switchboard . getSwitchboard ( ) . clusterhashes ;
2012-12-24 23:29:02 +01:00
seeds = DHTSelection . seedsByAge ( this . sb . peers , true , attempts - ( ( ch = = null ) ? 0 : ch . size ( ) ) ) ; // best for fast connection
// add also all peers from cluster if this is a public robinson cluster
if ( ch ! = null ) {
String hash ;
Seed seed ;
2014-09-30 14:53:52 +02:00
for ( byte [ ] hashb : ch ) {
hash = ASCII . String ( hashb ) ;
2012-12-24 23:29:02 +01:00
seed = seeds . get ( hash ) ;
2014-09-30 14:53:52 +02:00
if ( seed = = null ) {
2012-12-24 23:29:02 +01:00
seed = this . sb . peers . get ( hash ) ;
2014-10-01 03:10:39 +02:00
if ( seed = = null ) continue ;
2012-12-24 23:29:02 +01:00
}
seeds . put ( hash , seed ) ;
}
}
} else {
int diff = PING_MIN_DBSIZE - amIAccessibleDB . size ( ) ;
if ( diff > PING_MIN_RUNNING ) {
diff = Math . min ( diff , PING_MAX_RUNNING ) ;
if ( attempts > diff ) {
attempts = diff ;
}
} else {
if ( attempts > PING_MAX_RUNNING ) {
attempts = PING_MAX_RUNNING ;
}
}
seeds = DHTSelection . seedsByAge ( this . sb . peers , false , attempts ) ; // best for seed list maintenance/cleaning
}
2014-10-01 03:10:39 +02:00
if ( seeds = = null | | seeds . isEmpty ( ) ) return false ;
if ( seeds . size ( ) < attempts ) attempts = seeds . size ( ) ;
2012-12-24 23:29:02 +01:00
// This will try to get Peers that are not currently in amIAccessibleDB
final Iterator < Seed > si = seeds . values ( ) . iterator ( ) ;
Seed seed ;
// include a YaCyNews record to my seed
try {
final NewsDB . Record record = this . sb . peers . newsPool . myPublication ( ) ;
if ( record = = null ) {
2013-11-22 14:15:31 +01:00
this . sb . peers . mySeed ( ) . put ( Seed . NEWS , " " ) ;
2012-12-24 23:29:02 +01:00
} else {
2013-11-22 14:15:31 +01:00
this . sb . peers . mySeed ( ) . put ( Seed . NEWS , net . yacy . utils . crypt . simpleEncode ( record . toString ( ) ) ) ;
2012-12-24 23:29:02 +01:00
}
2013-07-17 18:31:30 +02:00
} catch ( final Exception e ) {
2013-07-09 14:28:25 +02:00
log . severe ( " publishMySeed: problem with news encoding " , e ) ;
2012-12-24 23:29:02 +01:00
}
this . sb . peers . mySeed ( ) . setUnusedFlags ( ) ;
//if (seeds.length > 1) {
// holding a reference to all started threads
int contactedSeedCount = 0 ;
final List < Thread > syncList = Collections . synchronizedList ( new LinkedList < Thread > ( ) ) ; // memory for threads
final Semaphore sync = new Semaphore ( attempts ) ;
2014-10-01 03:10:39 +02:00
// go through the peer list and starting a new publisher thread for each peer
2012-12-24 23:29:02 +01:00
int i = 0 ;
while ( si . hasNext ( ) ) {
seed = si . next ( ) ;
if ( seed = = null | | seed . hash . equals ( this . sb . peers . mySeed ( ) . hash ) ) {
sync . acquire ( ) ;
continue ;
}
i + + ;
2014-09-30 14:53:52 +02:00
final String address = seed . getPublicAddress ( seed . getIP ( ) ) ;
2014-10-01 03:10:39 +02:00
if ( log . isFine ( ) ) log . fine ( " HELLO # " + i + " to peer ' " + seed . get ( Seed . NAME , " " ) + " ' at " + address ) ; // debug
2012-12-24 23:29:02 +01:00
final String seederror = seed . isProper ( false ) ;
if ( ( address = = null ) | | ( seederror ! = null ) ) {
// we don't like that address, delete it
2014-09-30 14:53:52 +02:00
this . sb . peers . peerActions . peerDeparture ( seed , " peer ping to peer resulted in address = " + address + " ; seederror = " + seederror ) ;
2012-12-24 23:29:02 +01:00
sync . acquire ( ) ;
} else {
// starting a new publisher thread
contactedSeedCount + + ;
( new publishThread ( Network . publishThreadGroup , seed , sync , syncList ) ) . start ( ) ;
}
}
// receiving the result of all started publisher threads
for ( int j = 0 ; j < contactedSeedCount ; j + + ) {
// waiting for the next thread to finish
sync . acquire ( ) ;
// if this is true something is wrong ...
if ( syncList . isEmpty ( ) ) {
2013-07-09 14:28:25 +02:00
log . warn ( " PeerPing: syncList.isEmpty()==true " ) ;
2012-12-24 23:29:02 +01:00
continue ;
//return 0;
}
// getting a reference to the finished thread
final publishThread t = ( publishThread ) syncList . remove ( 0 ) ;
}
int accessible = 0 ;
int notaccessible = 0 ;
final long cutofftime = System . currentTimeMillis ( ) - PING_MAX_DBAGE ;
final int dbSize ;
synchronized ( amIAccessibleDB ) {
dbSize = amIAccessibleDB . size ( ) ;
final Iterator < String > ai = amIAccessibleDB . keySet ( ) . iterator ( ) ;
while ( ai . hasNext ( ) ) {
final Accessible ya = amIAccessibleDB . get ( ai . next ( ) ) ;
if ( ya . lastUpdated < cutofftime ) {
ai . remove ( ) ;
} else {
if ( ya . IWasAccessed ) {
accessible + + ;
} else {
notaccessible + + ;
}
}
}
2014-10-01 03:10:39 +02:00
if ( log . isFine ( ) ) log . fine ( " DBSize before -> after Cleanup: " + dbSize + " -> " + amIAccessibleDB . size ( ) ) ;
2012-12-24 23:29:02 +01:00
}
2014-10-01 03:10:39 +02:00
log . info ( " PeerPing: I am accessible for " + accessible + " peer(s), not accessible for " + notaccessible + " peer(s). " ) ;
2012-12-24 23:29:02 +01:00
if ( ( accessible + notaccessible ) > 0 ) {
final String newPeerType ;
// At least one other Peer told us our type
if ( ( accessible > = PING_MIN_PEERSEEN ) | | ( accessible > = notaccessible ) ) {
// We can be reached from a majority of other Peers
if ( this . sb . peers . mySeed ( ) . isPrincipal ( ) ) {
newPeerType = Seed . PEERTYPE_PRINCIPAL ;
} else {
newPeerType = Seed . PEERTYPE_SENIOR ;
}
} else {
// We cannot be reached from the outside
newPeerType = Seed . PEERTYPE_JUNIOR ;
}
if ( this . sb . peers . mySeed ( ) . orVirgin ( ) . equals ( newPeerType ) ) {
2013-07-09 14:28:25 +02:00
log . info ( " PeerPing: myType is " + this . sb . peers . mySeed ( ) . orVirgin ( ) ) ;
2012-12-24 23:29:02 +01:00
} else {
2014-10-01 03:10:39 +02:00
log . info ( " PeerPing: changing myType from ' " + this . sb . peers . mySeed ( ) . orVirgin ( ) + " ' to ' " + newPeerType + " ' " ) ;
2012-12-24 23:29:02 +01:00
this . sb . peers . mySeed ( ) . put ( Seed . PEERTYPE , newPeerType ) ;
}
} else {
2013-07-09 14:28:25 +02:00
log . info ( " PeerPing: No data, staying at myType: " + this . sb . peers . mySeed ( ) . orVirgin ( ) ) ;
2012-12-24 23:29:02 +01:00
}
// success! we have published our peer to a senior peer
// update latest news from the other peer
// log.logInfo("publish: handshaked " + t.seed.get(yacySeed.PEERTYPE, yacySeed.PEERTYPE_SENIOR) + " peer '" + t.seed.getName() + "' at " + t.seed.getAddress());
this . sb . peers . saveMySeed ( ) ;
// if we have an address, we do nothing
2014-10-01 03:10:39 +02:00
if ( this . sb . peers . mySeed ( ) . isProper ( true ) = = null ) return true ;
2012-12-24 23:29:02 +01:00
2014-10-01 03:10:39 +02:00
// still no success
2012-12-24 23:29:02 +01:00
final String ip = this . sb . getConfig ( " staticIP " , " " ) ;
2014-09-30 14:53:52 +02:00
if ( Seed . isProperIP ( ip ) ) {
2012-12-24 23:29:02 +01:00
this . sb . peers . mySeed ( ) . setIP ( ip ) ;
}
if ( this . sb . peers . mySeed ( ) . get ( Seed . PEERTYPE , Seed . PEERTYPE_JUNIOR ) . equals ( Seed . PEERTYPE_JUNIOR ) ) {
this . sb . peers . mySeed ( ) . put ( Seed . PEERTYPE , Seed . PEERTYPE_SENIOR ) ; // to start bootstraping, we need to be recognised as PEERTYPE_SENIOR peer
}
2014-09-30 14:53:52 +02:00
log . info ( " publish: no recipient found, our address is " + this . sb . peers . mySeed ( ) . getIPs ( ) ) ;
2012-12-24 23:29:02 +01:00
this . sb . peers . saveMySeed ( ) ;
2014-10-01 03:10:39 +02:00
return false ;
2013-07-17 18:31:30 +02:00
} catch ( final InterruptedException e ) {
2012-12-24 23:29:02 +01:00
try {
2013-07-09 14:28:25 +02:00
log . info ( " publish: Interruption detected while publishing my seed. " ) ;
2012-12-24 23:29:02 +01:00
// consuming the theads interrupted signal
Thread . interrupted ( ) ;
// interrupt all already started publishThreads
2013-07-09 14:28:25 +02:00
log . info ( " publish: Signaling shutdown to "
2012-12-24 23:29:02 +01:00
+ Network . publishThreadGroup . activeCount ( )
+ " remaining publishing threads ... " ) ;
Network . publishThreadGroup . interrupt ( ) ;
// waiting some time for the publishThreads to finish execution
try {
Thread . sleep ( 500 ) ;
2013-07-17 18:31:30 +02:00
} catch ( final InterruptedException ex ) {
2012-12-24 23:29:02 +01:00
}
// getting the amount of remaining publishing threads
int threadCount = Network . publishThreadGroup . activeCount ( ) ;
final Thread [ ] threadList = new Thread [ threadCount ] ;
threadCount = Network . publishThreadGroup . enumerate ( threadList ) ;
// we need to use a timeout here because of missing interruptable session threads ...
if ( log . isFine ( ) ) {
2013-07-09 14:28:25 +02:00
log . fine ( " publish: Waiting for "
2012-12-24 23:29:02 +01:00
+ Network . publishThreadGroup . activeCount ( )
+ " remaining publishing threads to finish shutdown ... " ) ;
}
for ( int currentThreadIdx = 0 ; currentThreadIdx < threadCount ; currentThreadIdx + + ) {
final Thread currentThread = threadList [ currentThreadIdx ] ;
if ( currentThread . isAlive ( ) ) {
if ( log . isFine ( ) ) {
2013-07-09 14:28:25 +02:00
log . fine ( " publish: Waiting for remaining publishing thread ' "
2012-12-24 23:29:02 +01:00
+ currentThread . getName ( )
+ " ' to finish shutdown " ) ;
}
try {
currentThread . join ( 500 ) ;
2013-07-17 18:31:30 +02:00
} catch ( final InterruptedException ex ) {
2012-12-24 23:29:02 +01:00
}
}
}
2013-07-09 14:28:25 +02:00
log . info ( " publish: Shutdown off all remaining publishing thread finished. " ) ;
2012-12-24 23:29:02 +01:00
2013-07-17 18:31:30 +02:00
} catch ( final Exception ee ) {
2014-10-01 03:10:39 +02:00
log . warn ( " publish: Unexpected error while trying to shutdown all remaining publishing threads. " , e ) ;
2012-12-24 23:29:02 +01:00
}
2014-10-01 03:10:39 +02:00
return false ;
2012-12-24 23:29:02 +01:00
}
}
@SuppressWarnings ( " unchecked " )
public static HashMap < String , String > getSeedUploadMethods ( ) {
synchronized ( Network . seedUploadMethods ) {
return ( HashMap < String , String > ) Network . seedUploadMethods . clone ( ) ;
}
}
public static yacySeedUploader getSeedUploader ( final String methodname ) {
String className = null ;
synchronized ( Network . seedUploadMethods ) {
if ( Network . seedUploadMethods . containsKey ( methodname ) ) {
className = Network . seedUploadMethods . get ( methodname ) ;
}
}
if ( className = = null ) {
return null ;
}
try {
final Class < ? > uploaderClass = Class . forName ( className ) ;
final Object uploader = uploaderClass . newInstance ( ) ;
return ( yacySeedUploader ) uploader ;
2013-07-17 18:31:30 +02:00
} catch ( final Exception e ) {
2012-12-24 23:29:02 +01:00
return null ;
}
}
public static void loadSeedUploadMethods ( ) {
yacySeedUploader uploader ;
uploader = new yacySeedUploadFile ( ) ;
Network . seedUploadMethods . put ( uploader
. getClass ( )
. getSimpleName ( )
. substring ( " yacySeedUpload " . length ( ) ) , uploader . getClass ( ) . getCanonicalName ( ) ) ;
uploader = new yacySeedUploadFtp ( ) ;
Network . seedUploadMethods . put ( uploader
. getClass ( )
. getSimpleName ( )
. substring ( " yacySeedUpload " . length ( ) ) , uploader . getClass ( ) . getCanonicalName ( ) ) ;
uploader = new yacySeedUploadScp ( ) ;
Network . seedUploadMethods . put ( uploader
. getClass ( )
. getSimpleName ( )
. substring ( " yacySeedUpload " . length ( ) ) , uploader . getClass ( ) . getCanonicalName ( ) ) ;
}
public static boolean changeSeedUploadMethod ( final String method ) {
if ( method = = null | | method . isEmpty ( ) ) {
return false ;
}
if ( method . equalsIgnoreCase ( " none " ) ) {
return true ;
}
synchronized ( Network . seedUploadMethods ) {
return Network . seedUploadMethods . containsKey ( method ) ;
}
}
public static final String saveSeedList ( final Switchboard sb ) {
try {
// return an error if this is not successful, and NULL if everything is fine
String logt ;
// be shure that we have something to say
if ( sb . peers . mySeed ( ) . getPublicAddress ( ) = = null ) {
final String errorMsg = " We have no valid IP address until now " ;
2013-07-09 14:28:25 +02:00
log . warn ( " SaveSeedList: " + errorMsg ) ;
2012-12-24 23:29:02 +01:00
return errorMsg ;
}
// getting the configured seed uploader
String seedUploadMethod = sb . getConfig ( " seedUploadMethod " , " " ) ;
// for backward compatiblity ....
if ( seedUploadMethod . equalsIgnoreCase ( " Ftp " )
| | ( seedUploadMethod . equals ( " " ) & & sb . getConfig ( " seedFTPPassword " , " " ) . length ( ) > 0 ) ) {
seedUploadMethod = " Ftp " ;
sb . setConfig ( " seedUploadMethod " , seedUploadMethod ) ;
} else if ( seedUploadMethod . equalsIgnoreCase ( " File " )
| | ( seedUploadMethod . equals ( " " ) & & sb . getConfig ( " seedFilePath " , " " ) . length ( ) > 0 ) ) {
seedUploadMethod = " File " ;
sb . setConfig ( " seedUploadMethod " , seedUploadMethod ) ;
}
// determine the seed uploader that should be used ...
if ( seedUploadMethod . equalsIgnoreCase ( " none " ) ) {
return " no uploader specified " ;
}
final yacySeedUploader uploader = getSeedUploader ( seedUploadMethod ) ;
if ( uploader = = null ) {
final String errorMsg =
" Unable to get the proper uploader-class for seed uploading method ' "
+ seedUploadMethod
+ " '. " ;
2013-07-09 14:28:25 +02:00
log . warn ( " SaveSeedList: " + errorMsg ) ;
2012-12-24 23:29:02 +01:00
return errorMsg ;
}
// ensure that the seed file url is configured properly
2013-09-15 00:30:23 +02:00
DigestURL seedURL ;
2012-12-24 23:29:02 +01:00
try {
final String seedURLStr = sb . peers . mySeed ( ) . get ( Seed . SEEDLISTURL , " " ) ;
if ( seedURLStr . isEmpty ( ) ) {
throw new MalformedURLException ( " The seed-file url must not be empty. " ) ;
}
if ( ! ( seedURLStr . toLowerCase ( ) . startsWith ( " http:// " ) | | seedURLStr . toLowerCase ( ) . startsWith (
" https:// " ) ) ) {
throw new MalformedURLException ( " Unsupported protocol. " ) ;
}
2013-09-15 00:30:23 +02:00
seedURL = new DigestURL ( seedURLStr ) ;
2012-12-24 23:29:02 +01:00
final String host = seedURL . getHost ( ) ;
2014-08-25 01:25:22 +02:00
if ( Domains . isLocalhost ( host ) | | ( Domains . isIntranet ( host ) & & ! sb . isIntranetMode ( ) ) ) { // check seedlist reacheable
// TODO: this does not prevent setting a local hostname e.g. "http://testhost_8090/seedlist.txt" (fyi: never did)
// but the or part allows to setup a principal peer in intranet environment
2014-01-05 04:55:30 +01:00
final String errorMsg = " seedURL in local network rejected (local hosts can't be reached from outside) " ;
2013-07-09 14:28:25 +02:00
log . warn ( " SaveSeedList: " + errorMsg ) ;
2012-12-24 23:29:02 +01:00
return errorMsg ;
}
2013-07-17 18:31:30 +02:00
} catch ( final MalformedURLException e ) {
2012-12-24 23:29:02 +01:00
final String errorMsg =
" Malformed seed file URL ' "
+ sb . peers . mySeed ( ) . get ( Seed . SEEDLISTURL , " " )
+ " '. "
+ e . getMessage ( ) ;
2013-07-09 14:28:25 +02:00
log . warn ( " SaveSeedList: " + errorMsg ) ;
2012-12-24 23:29:02 +01:00
return errorMsg ;
}
// upload the seed-list using the configured uploader class
String prevStatus = sb . peers . mySeed ( ) . get ( Seed . PEERTYPE , Seed . PEERTYPE_JUNIOR ) ;
if ( prevStatus . equals ( Seed . PEERTYPE_PRINCIPAL ) ) {
prevStatus = Seed . PEERTYPE_SENIOR ;
}
try {
sb . peers . mySeed ( ) . put ( Seed . PEERTYPE , Seed . PEERTYPE_PRINCIPAL ) ; // this information shall also be uploaded
if ( log . isFine ( ) ) {
2013-07-09 14:28:25 +02:00
log . fine ( " SaveSeedList: Using seed uploading method ' "
2012-12-24 23:29:02 +01:00
+ seedUploadMethod
+ " ' for seed-list uploading. "
+ " \ n \ tPrevious peerType is ' "
+ sb . peers . mySeed ( ) . get ( Seed . PEERTYPE , Seed . PEERTYPE_JUNIOR )
+ " '. " ) ;
}
logt = sb . peers . uploadSeedList ( uploader , sb , sb . peers , seedURL ) ;
if ( logt ! = null ) {
if ( logt . indexOf ( " Error " , 0 ) > = 0 ) {
sb . peers . mySeed ( ) . put ( Seed . PEERTYPE , prevStatus ) ;
final String errorMsg =
" SaveSeedList: seed upload failed using "
+ uploader . getClass ( ) . getName ( )
+ " (error): "
+ logt . substring ( logt . indexOf ( " Error " , 0 ) + 6 ) ;
2013-07-09 14:28:25 +02:00
log . severe ( errorMsg ) ;
2012-12-24 23:29:02 +01:00
return errorMsg ;
}
2013-07-09 14:28:25 +02:00
log . info ( logt ) ;
2012-12-24 23:29:02 +01:00
}
// finally, set the principal status
sb . setConfig ( " yacyStatus " , Seed . PEERTYPE_PRINCIPAL ) ;
return null ;
2013-07-17 18:31:30 +02:00
} catch ( final Exception e ) {
2012-12-24 23:29:02 +01:00
sb . peers . mySeed ( ) . put ( Seed . PEERTYPE , prevStatus ) ;
sb . setConfig ( " yacyStatus " , prevStatus ) ;
final String errorMsg = " SaveSeedList: Seed upload failed (IO error): " + e . getMessage ( ) ;
2013-07-09 14:28:25 +02:00
log . info ( errorMsg , e ) ;
2012-12-24 23:29:02 +01:00
return errorMsg ;
}
} finally {
sb . peers . lastSeedUpload_seedDBSize = sb . peers . sizeConnected ( ) ;
sb . peers . lastSeedUpload_timeStamp = System . currentTimeMillis ( ) ;
sb . peers . lastSeedUpload_myIP = sb . peers . mySeed ( ) . getIP ( ) ;
}
}
}