package com.nvarghese.beowulf.sfc.services; import java.io.IOException; import java.net.ServerSocket; import java.net.URI; import java.net.URISyntaxException; import java.net.UnknownHostException; import java.util.Date; import javax.jms.JMSException; import org.apache.commons.configuration.ConfigurationException; import org.bson.types.ObjectId; import org.msgpack.rpc.Server; import org.msgpack.rpc.loop.EventLoop; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.code.morphia.Datastore; import com.nvarghese.beowulf.common.BeowulfCommonConfigManager; import com.nvarghese.beowulf.common.ds.DataStoreUtil; import com.nvarghese.beowulf.common.http.txn.AbstractHttpTransaction; import com.nvarghese.beowulf.common.http.txn.HttpMethodType; import com.nvarghese.beowulf.common.http.txn.HttpTransactionFactory; import com.nvarghese.beowulf.common.http.txn.HttpTxnDAO; import com.nvarghese.beowulf.common.http.txn.TransactionSource; import com.nvarghese.beowulf.common.jobs.NewScanJob; import com.nvarghese.beowulf.common.scan.dao.WebScanDAO; import com.nvarghese.beowulf.common.scan.model.WebScanDocument; import com.nvarghese.beowulf.common.utils.ByteUtils; import com.nvarghese.beowulf.common.webtest.CategorizerType; import com.nvarghese.beowulf.common.webtest.JobStatus; import com.nvarghese.beowulf.common.webtest.ScanPhase; import com.nvarghese.beowulf.common.webtest.scs.jobs.CategorizationJobDAO; import com.nvarghese.beowulf.common.webtest.scs.jobs.CategorizationJobDocument; import com.nvarghese.beowulf.common.webtest.scs.jobs.CategorizerJob; import com.nvarghese.beowulf.sfc.SFControllerManager; public class NewScanService { static Logger logger = LoggerFactory.getLogger(NewScanService.class); public void startScan(NewScanJob newScanJob) { logger.info("New scan job received to kick start the service with WebScanDocument#obj_id: {}", newScanJob.getWebScanObjectId()); ObjectId id = new ObjectId(newScanJob.getWebScanObjectId()); WebScanDAO webScanDAO = new WebScanDAO(SFControllerManager.getInstance().getDataStore()); WebScanDocument webScanDocument = webScanDAO.getWebScanDocument(id); Datastore ds = null; if (webScanDocument != null) { // create data store ds = createScanDataStore(); // start rpc server int rpcPort = startRpcServerInstance(id); // update web scan document webScanDocument.setBwControllerIPAddress(SFControllerManager.getInstance().getSettings().getIpAddress()); webScanDocument.setBwControllerPort(rpcPort); webScanDocument.setScanRunning(true); webScanDocument.setScanStartTime(new Date()); webScanDocument.setScanJobsInProgress(true); webScanDocument.setScanPhase(ScanPhase.PRIMARY_SCAN.getName()); webScanDocument.setTxnDbName(ds.getDB().getName()); webScanDAO.updateWebScanDocument(webScanDocument); // crawl base URI URI baseURI; ObjectId txnId = null; try { baseURI = getBaseURI(webScanDocument); txnId = requestBaseURI(ds, baseURI); } catch (URISyntaxException e) { logger.error("Failed to crawl base URI. Reason: {}", e.getMessage(), e); webScanDocument.getComments().add(e.getMessage()); } finally { webScanDAO.updateWebScanDocument(webScanDocument); } // persist job and post message ObjectId categJobObjId = createMetaCategorizationJobDocument(ds, txnId, webScanDocument.getId()); CategorizerJob categJob = new CategorizerJob(); categJob.setCategorizerJobObjId(categJobObjId.toString()); categJob.setWebScanObjId(webScanDocument.getId().toString()); categJob.setDatabaseName(ds.getDB().getName()); BwCategorizerService categService = new BwCategorizerService(); try { categService.submitJob(categJob); } catch (JMSException e) { logger.error("Failed to send JMS message to categorizer system. Reason: {}", e.getMessage(), e); webScanDocument.getComments().add(e.getMessage()); } finally { webScanDAO.updateWebScanDocument(webScanDocument); } } else { logger.warn("Web scan document with id: {} cannot be found. Failed to start scan"); } } private ObjectId createMetaCategorizationJobDocument(Datastore ds, ObjectId txnObjId, ObjectId webscanObjId) { CategorizationJobDocument jobDoc = new CategorizationJobDocument(); jobDoc.setJobStatus(JobStatus.INIT); jobDoc.setTxnObjId(txnObjId); jobDoc.setWebScanObjId(webscanObjId); jobDoc.setCategorizerType(CategorizerType.META); CategorizationJobDAO categorizationJobDAO = new CategorizationJobDAO(ds); ObjectId id = categorizationJobDAO.createCategorizationJobDocument(jobDoc); return id; } private URI getBaseURI(WebScanDocument webScanDocument) throws URISyntaxException { if (webScanDocument.getBaseUris().size() > 0) { URI uri = new URI(webScanDocument.getBaseUris().get(0)); return uri; } else { throw new URISyntaxException(null, "BaseURI is null"); } } private int startRpcServerInstance(final ObjectId webScanObjId) { final int port = findFreePort(); new Thread() { public void run() { EventLoop loop = EventLoop.defaultEventLoop(); Server svr = new Server(loop); ScanInstanceServer scanInstanceServer = new ScanInstanceServer(svr, webScanObjId); // start rpc interface svr.serve(scanInstanceServer); // start scan monitoring scanInstanceServer.startScanMonitoring(); ScanInstanceRegister.getInstance().registerScanInstanceServer(webScanObjId.toString(), scanInstanceServer); try { svr.listen(port); logger.info("Server listening on port TCP/" + port + " for connections"); loop.join(); } catch (IOException e) { logger.error("Failed to start rpc server. Reason: {}", e.getMessage(), e); svr.close(); } catch (InterruptedException e) { logger.error("Interrupted rpc server running at port: {}. ", port, e); svr.close(); } } }.start(); return port; } private ObjectId requestBaseURI(Datastore ds, URI baseUri) { AbstractHttpTransaction transaction = HttpTransactionFactory.createTransaction(HttpMethodType.GET, baseUri, null, null, TransactionSource.BASE); transaction.execute(); HttpTxnDAO txnDAO = new HttpTxnDAO(ds); ObjectId id = txnDAO.createHttpTxnDocument(transaction.toHttpTxnDocument()); return id; } private Datastore createScanDataStore() { String databaseName = "scan_inst_" + ByteUtils.toHex(ByteUtils.getRandomBytes(6)); Datastore ds = null; try { ds = DataStoreUtil.createOrGetDataStore(BeowulfCommonConfigManager.getDbUri(), databaseName); } catch (ConfigurationException e) { logger.error("Failed to create scan data store. Reason: {}", e.getMessage(), e); } catch (UnknownHostException e) { logger.error("Failed to create scan data store. Reason: {}", e.getMessage(), e); } return ds; } private int findFreePort() { int port = 0; try { ServerSocket server = new ServerSocket(0); port = server.getLocalPort(); server.close(); return port; } catch (IOException e) { logger.error("Failed to retrieve free port. Reason: {}", e.getMessage(), e); } return port; } }