Ejemplo n.º 1
0
std::vector<double> AnalizeFunction::MinFunc(double begin, double end)
{
	if (end <= begin)
		throw std::invalid_argument("Error in MinFunc: end <= begin!\n");
	
	double step = 1;
	double min = func_name(begin);

	std::vector<double> result;
	result.push_back(begin);

	// 


	for (double x = begin; x <= end; x += step)
	{
		double next = func_name(x);
		if (min > next)
		{
			result.clear();
			min = next;
			result.push_back(x);
		}
		else if (min == next)
			result.push_back(x);
		
	}
	return result;
}
Ejemplo n.º 2
0
const SpObject *SpVM::eval(const SpExpr *expr, SpEnv *env) {
   // check whether this expression is an atom or a function call
   if (expr->head()->type() == TOKEN_FUNCTION_CALL) {
      // this is a function call expression
      std::string func_name(expr->head()->value());

      // we find the function associated with this name in the given environment
      const SpObject *obj = resolve(func_name, env);
      if (obj == NULL || obj->type() != T_FUNCTION) RUNTIME_ERROR_F("'%s' is not a function", func_name.c_str());

      // now call the function
      return call_function(func_name, 
         static_cast<const SpFunction *>(obj->self()), expr, env);
   } else {
      // evaluate this atom
      std::string val = expr->head()->value();
      switch (expr->head()->type()) {
         case TOKEN_NAME: {
            const SpObject *obj = resolve(val, env); 
            if (obj == NULL)
               RUNTIME_ERROR_F("Undeclared variable '%s'", val.c_str());
            return obj->shallow_copy();
         }
         case TOKEN_NUMERIC:
            return new SpIntValue(atoi(val.c_str()));
         case TOKEN_CLOSURE:
            // the closure expression is stored in the first argument of the
            // object expression
            return new SpRefObject(new SpClosure(ArgList(), NULL, *expr->cbegin()));
         default:
            RUNTIME_ERROR("Unsupported operation");
      }
   }
}
Ejemplo n.º 3
0
bool Portfolio::readyForRun() {
    string func_name(" [Portfolio::readyForRun]");
    if (!m_se) {
        HKU_WARN("m_se is null!" << func_name);
        return false;
    }

    if (!m_tm) {
        HKU_WARN("m_tm is null!" << func_name);
        return false;
    }

    if (!m_af) {
        HKU_WARN("m_am is null!" << func_name);
        return false;
    }

    reset();

    //将影子账户指定给资产分配器
    m_tm_shadow = m_tm->clone();
    m_af->setTM(m_tm_shadow);

    return true;
}
Ejemplo n.º 4
0
/**
 * Sends a pending aggregate message for a given group and message
 */
void send_pending(struct pr_group_list_t *group, int pendidx)
{
    switch (group->pending[pendidx].msg) {
    case REGISTER:
        send_register(group, pendidx);
        break;
    case FILEINFO_ACK:
        send_fileinfo_ack(group, pendidx);
        break;
    case STATUS:
        send_status(group, pendidx);
        break;
    case COMPLETE:
        send_complete(group, pendidx);
        break;
    default:
        glog1(group, "Tried to send pending on invalid type %s",
                     func_name(group->pending[pendidx].msg));
        return;
    }
    if ((group->pending[pendidx].count <= 0) ||
            (group->pending[pendidx].msg == STATUS)) {
        // Finish the cleanup we started in load_pending
        // Always do this for a STATUS, since we don't have a pending list
        free(group->pending[pendidx].naklist);
        memset(&group->pending[pendidx], 0, sizeof(struct pr_pending_info_t));
    }
}
Ejemplo n.º 5
0
/**
 * Sends a pending aggregate message for a given group and message
 */
void send_pending(int listidx, int pendidx)
{
    switch (group_list[listidx].pending[pendidx].msg) {
    case REGISTER:
        send_register(listidx, pendidx);
        break;
    case INFO_ACK:
        send_info_ack(listidx, pendidx, FILEINFO);
        break;
    case STATUS:
        send_status(listidx, pendidx);
        break;
    case COMPLETE:
        send_complete(listidx, pendidx);
        break;
    default:
        log(group_list[listidx].group_id, 0, "Tried to send pending on "
                "invalid type %s",
                func_name(group_list[listidx].pending[pendidx].msg));
        return;
    }
    if (group_list[listidx].pending[pendidx].count <= 0) {
        // Finish the cleanup we started in load_pending
        free(group_list[listidx].pending[pendidx].naklist);
        memset(&group_list[listidx].pending[pendidx], 0,
                sizeof(struct pr_pending_info_t));
    }
}
Ejemplo n.º 6
0
// Dump function name
void CallNode::dump(ostream& s) const
{
    s << func_name();

    if (VSEFlags::include_list_info)
	s << *_arg;
    else
	if (_arg->isArgNode())
	    s << "(" << *_arg << "...)";
	else
	    s << *_arg;
}
Ejemplo n.º 7
0
bool MySQLKDataDriver::_init() {
    string func_name(" [MySQLKDataDriver::MySQLKDataDriver]");

    string default_host("127.0.0.1");
    string default_usr("root");
    string default_pwd("");

    try {
        m_host = m_params.get<string>("host");
    } catch(...) {
        m_host = default_host;
        HKU_WARN("Can't get mysql host! " << func_name);
    }

    try {
        m_port = m_params.get<int>("port");
    } catch(...) {
        m_port = 3306;
    }

    try {
        m_usr = m_params.get<string>("usr");
    } catch(...) {
        m_usr = default_usr;
    }

    try {
        m_pwd = m_params.get<string>("pwd");
    } catch(...) {
        m_pwd = default_pwd;
    }

    shared_ptr<MYSQL> mysql(new MYSQL, MySQLCloser());
    if (!mysql_init(mysql.get())) {
        HKU_ERROR(" Initial MySQL handle error!" << func_name);
        return false;
    }

    if (!mysql_real_connect(mysql.get(), m_host.c_str(), m_usr.c_str(),
            m_pwd.c_str(), NULL, m_port, NULL, 0) ) {
        HKU_ERROR(" Failed to connect to database!" << func_name);
        return false;
    }

    if (mysql_set_character_set(mysql.get(), "utf8")) {
        HKU_ERROR(" mysql_set_character_set error!" << func_name);
        return false;
    }

    m_mysql = mysql;

    return true;
}
Ejemplo n.º 8
0
KRecord MySQLKDataDriver::
getKRecord(const string& market, const string& code,
          size_t pos, KQuery::KType kType) {
    string func_name(" [MySQLKDataDriver::getKRecord]");
    KRecord result;
    if (!m_mysql) {
        HKU_ERROR("Null m_mysql!" << func_name);
        return result;
    }

    /*if (kType >= KQuery::INVALID_KTYPE ) {
        HKU_WARN("ktype(" << kType << ") is invalid" << func_name);
        return result;
    }*/

    MYSQL_RES *mysql_result;
    MYSQL_ROW row;

    string table(_getTableName(market, code, kType));
    std::stringstream buf (std::stringstream::out);
    buf << "select date, open, high, low, close, amount, count from "
            << table << " order by date limit " << pos << ", 1";
    if (!_query(buf.str())) {
        HKU_ERROR("mysql_query error! " << func_name);
        return result;
    }

    mysql_result = mysql_store_result(m_mysql.get());
    if (!mysql_result) {
        HKU_ERROR("mysql_store_result error!" << func_name);
        return result;
    }

    while ((row = mysql_fetch_row(mysql_result))) {
        try {
            hku_uint64 d = boost::lexical_cast<hku_uint64>(row[0]);
            result.datetime = Datetime(d);
            result.openPrice = boost::lexical_cast<price_t>(row[1]);
            result.highPrice = boost::lexical_cast<price_t>(row[2]);
            result.lowPrice = boost::lexical_cast<price_t>(row[3]);
            result.closePrice = boost::lexical_cast<price_t>(row[4]);
            result.transAmount = boost::lexical_cast<price_t>(row[5]);
            result.transCount = boost::lexical_cast<price_t>(row[6]);
        } catch (...) {
            HKU_INFO("Error get record " << pos << " " << table << func_name);
            result = Null<KRecord>();
        }
    }

    mysql_free_result(mysql_result);
    return result;
}
Ejemplo n.º 9
0
size_t MySQLKDataDriver::
getCount(const string& market,
        const string& code,
        KQuery::KType kType) {
    string func_name(" [MySQLKDataDriver::getCount]");
    size_t result = 0;
    if (!m_mysql) {
        HKU_ERROR("Null m_mysql!" << func_name);
        return result;
    }

    /*if (kType >= KQuery::INVALID_KTYPE ) {
        HKU_WARN("ktype(" << kType << ") is invalid" << func_name);
        return result;
    }*/

    MYSQL_RES *mysql_result;
    MYSQL_ROW row;

    string table(_getTableName(market, code, kType));
    std::stringstream buf (std::stringstream::out);
    buf << "select count(1) from " << table;
    if (!_query(buf.str())) {
        HKU_ERROR("mysql_query error! " << func_name);
        return result;
    }

    mysql_result = mysql_store_result(m_mysql.get());
    if (!mysql_result) {
        HKU_ERROR("mysql_store_result error!" << func_name);
        return result;
    }

    while ((row = mysql_fetch_row(mysql_result))) {
        try {
            result = boost::lexical_cast<size_t>(row[0]);
        } catch (...) {
            HKU_INFO("Error get record count of" << table << func_name);
            result = 0;
        }
    }

    mysql_free_result(mysql_result);
    return result;
}
Ejemplo n.º 10
0
/*!
 * @brief Set size and thickness parameters if SIZE command is specified
 * @param cmd Command
 * @param loc Position of the first character to be checked
 * @return SET_SCALE_AND_THICKNESS if size and thickness parameter is set, 0 if not SIZE command
 */
int CommentGenerator::checkSIZE(std::string &cmd, std::string::size_type &loc){
	int res;
	std::vector<double> value_tmp;
	std::string func_name("SIZE(");

	res = getFunctionArgs(cmd, loc, func_name, 1, value_tmp);
	if(res>0){
		if(value_tmp[0]<=0){
			std::cerr << "Error in CommentGenerator::checkSIZE(): invalid command - SIZE values must be >0" << std::endl;
			return -4; //error
		}
		thick = (value_tmp[0]/scale)*thick;
		scale = value_tmp[0];

		return SET_SCALE_AND_THICKNESS; //found
	}
	return res;

}
//std::pair<std::string, std::string> matchFunctionDef(const std::string& input)
std::smatch matchFunctionDef(const std::string& input)
{
    std::smatch func_def_match;
	std::regex regex_def("(virtual|friend)?\\s*([[:alpha:]][[:alpha:][:digit:]_]*)\\s+([[:alpha:]][[:alpha:][:digit:]_]*)\\s*\\(\\s*(((.*)\\s*([[:alpha:]][[:alpha:]]*)\\s*[,]\\s*)*(.*)\\s*([[:alpha:]][[:alpha:]]*)*)\\s*\\);");
	if(std::regex_search(input,func_def_match,regex_def)) {
        std::string func_name(func_def_match.str(3)); //Extracting function name
        std::string func_param(func_def_match.str(4)); //Extracting function params
		//return std::pair<std::string, std::string>(func_name,func_param);
        //return func_def_match;
    }
    #if 0
	else
    {
        //return std::pair<std::string, std::string>("","");
        return std::string("");
    }
    #endif
    return func_def_match;
		
}
Ejemplo n.º 12
0
void testmain(void) {
    print("function");

    expect(77, t1());
    t2(79);
    t3(1, 2, 3, 4, 5, 6);
    t4();
    t5();
    expect(3, t6());
    expect(12, t7(3, 4));
    t8(23);
    t9();
    expect(7, t10(3, 4.0));
    func_ptr_call();
    func_name();
    empty();
    empty2();
    test_bool();
    test_struct();
}
Ejemplo n.º 13
0
/**
 * Sets the timeout time for a given group list member
 */
void set_timeout(struct pr_group_list_t *group, int pending_reset, int rescale)
{
    int pending, i;

    if (group->phase == PR_PHASE_READY) {
        if (!rescale) {
            gettimeofday(&group->start_phase_timeout_time, NULL);
        }
        group->phase_timeout_time = group->start_phase_timeout_time;
        add_timeval_d(&group->phase_timeout_time, 2 * group->grtt);
    }

    glog5(group, "set timeout: pending_reset=%d", pending_reset);
    for (pending = 0, i = 0; (i < MAX_PEND) && !pending; i++) {
        if (group->pending[i].msg != 0) {
            glog5(group, "set timeout: found pending %s",
                         func_name(group->pending[i].msg));
            pending = group->pending[i].msg;
        }
    }
    if (pending) {
        if (pending_reset) {
            if (!rescale) {
                gettimeofday(&group->start_timeout_time, NULL);
            }
            group->timeout_time = group->start_timeout_time;
            add_timeval_d(&group->timeout_time, 1 * group->grtt);
        }
    } else {
        if (!rescale) {
            gettimeofday(&group->start_timeout_time, NULL);
        }
        group->timeout_time = group->start_timeout_time;
        if (group->robust * group->grtt < 1.0) {
            add_timeval_d(&group->timeout_time, 1.0);
        } else {
            add_timeval_d(&group->timeout_time, group->robust * group->grtt);
        }
    }
}
Ejemplo n.º 14
0
	unique_ptr<builder_i> recursive_parser::create_builder(builder_factory_i& factory)
	{
		unique_ptr<builder_i> builder;
		if(name_.first == name_.second)
		{
			if(arguments_.size() == 1)
				builder = arguments_[0]->create_builder(factory);
			else
				throw parse_error("only one expression is expected!");
		}
		else
		{
			string func_name(name_.first, name_.second);
			builder = factory.create_function(func_name);
			
			for(auto& arg : arguments_)
			{
				builder->merge(arg->create_builder(factory));
			}			
		}
		return move(builder);
	}
Ejemplo n.º 15
0
bool MySQLKDataDriver::_query(const string& sql_str) {
    string func_name(" [MySQLKDataDriver::query]");
    int res = mysql_query(m_mysql.get(), sql_str.c_str());
    if (!res) {
        return true;
    }

    //重新连接数据库
    HKU_INFO("MySQL connect invalid, will retry connect!" << func_name);
    m_mysql = NULL;

    shared_ptr<MYSQL> mysql(new MYSQL, MySQLCloser());
    if (!mysql_init(mysql.get())) {
        HKU_ERROR(" Initial MySQL handle error!" << func_name);
        return false;
    }

    if (!mysql_real_connect(mysql.get(), m_host.c_str(), m_usr.c_str(),
        m_pwd.c_str(), NULL, m_port, NULL, 0) ) {
        HKU_ERROR(" Failed to connect to database!" << func_name);
        return false;
    }

    if (mysql_set_character_set(mysql.get(), "utf8")) {
        HKU_ERROR(" mysql_set_character_set error!" << func_name);
        return false;
    }

    m_mysql = mysql;

    res = mysql_query(m_mysql.get(), sql_str.c_str());
    if(!res) {
        return true;
    }

    HKU_ERROR("mysql_query error! error no: " << res
                << " " << sql_str << func_name);
    return false;
}
Ejemplo n.º 16
0
Archivo: function.c Proyecto: 4ker/8cc
void testmain() {
    print("function");

    expect(77, t1());
    t2(79);
    t3(1, 2, 3, 4, 5, 6);
    t4();
    t5();
    expect(3, t6());
    expect(12, t7(3, 4));
    expect(77, (1 ? t1 : t6)());
    expect(3, (0 ? t1 : t6)());
    t8(23);
    t9();
    expect(7, t10(3, 4.0));
    func_ptr_call();
    func_name();
    local_static();
    empty();
    empty2();
    test_bool();
    test_struct();
    test_funcdesg();
}
Ejemplo n.º 17
0
/*!
 * @brief Set color parameter if RGB command is specified
 * @param cmd Command
 * @param loc Position of the first character to be checked
 * @return SET_COLOR if color parameter is set, 0 if not RGB command
 */
int CommentGenerator::checkRGB(std::string &cmd, std::string::size_type &loc){
	int res;
	std::vector<double> color_tmp;
	std::string func_name("RGB(");

	res = getFunctionArgs(cmd, loc, func_name, 3, color_tmp);
	if(res>0){
		for(int i=0;i<3;i++){
			if(color_tmp[i]<0||color_tmp[i]>255){
				std::cerr << "Error in CommentGenerator::checkRGB(): invalid command - RGB values must be [0, 255]" << std::endl;
				return -4; //error
			}
			if(std::floor(color_tmp[i]) != std::ceil(color_tmp[i])){
				std::cerr << "Error in CommentGenerator::checkRGB(): invalid command - expected integer value" << std::endl;
				return -4; //error
			}
		}
		color.val[0] = color_tmp[2];
		color.val[1] = color_tmp[1];
		color.val[2] = color_tmp[0];
		return SET_COLOR; //found
	}
	return res;
}
//std::pair<std::string, std::string> matchFunctionCall(const std::string& input)
std::smatch matchFunctionCall(const std::string& input)
{
    const char *for_const ="for(";
    if(input.rfind(for_const,0)!=0)
    {
        std::smatch func_call_match;
        std::regex regex_call("([[:alpha:]][[:alpha:][:digit:]_]*)\\(\\s*(([[:alpha:]][[:alpha:][:digit:]_]*\\s*:[^:]*\\s*)\\s*(,\\s*[[:alpha:]][[:alpha:][:digit:]_]*\\s*:[^:]*\\s*)*)\\)\\s*");

        if(std::regex_search(input,func_call_match,regex_call)) {
            std::string func_name(func_call_match.str(1)); //Extracting function name
            std::string func_param(func_call_match.str(2)); //Extracting function params
            //return std::pair<std::string, std::string>(func_name,func_param);
            //return func_call_match.str(0);
        }
        #if 0
        else
        {
            return std::string("");
            //return std::pair<std::string, std::string>("","");
        }
        #endif
        return func_call_match;
    }
}
Ejemplo n.º 19
0
SgFunctionDeclaration * CudaOutliner::generateFunction ( SgBasicBlock* s,
                                                         const string& func_name_str,
                                                         ASTtools::VarSymSet_t& syms,
							 MintHostSymToDevInitMap_t hostToDevVars,
							 const ASTtools::VarSymSet_t& pdSyms,
                                                         const ASTtools::VarSymSet_t& psyms,
                                                         SgScopeStatement* scope)
{
  //Create a function named 'func_name_str', with a parameter list from 'syms'                                                             
  //pdSyms specifies symbols which must use pointer dereferencing if replaced during outlining,  
  //only used when -rose:outline:temp_variable is used                                                                                     
  //psyms are the symbols for OpenMP private variables, or dead variables (not live-in, not live-out)    

  ROSE_ASSERT ( s && scope);
  ROSE_ASSERT(isSgGlobal(scope));

  // step 1: perform necessary liveness and side effect analysis, if requested.     
  // ---------------------------------------------------------                                                                           
  std::set< SgInitializedName *> liveIns, liveOuts;
  // Collect read-only variables of the outlining target                                                                                
  std::set<SgInitializedName*> readOnlyVars;
  if (Outliner::temp_variable||Outliner::enable_classic)
    {
      SgStatement* firstStmt = (s->get_statements())[0];
      if (isSgForStatement(firstStmt)&& Outliner::enable_liveness)
        {
          LivenessAnalysis * liv = SageInterface::call_liveness_analysis (SageInterface::getProject());
	  SageInterface::getLiveVariables(liv, isSgForStatement(firstStmt), liveIns, liveOuts);
        }
      SageInterface::collectReadOnlyVariables(s,readOnlyVars);
      if (0)//Outliner::enable_debug)
        {
          cout<<"  INFO:Mint: CudaOutliner::generateFunction()---Found "<<readOnlyVars.size()<<" read only variables..:";
          for (std::set<SgInitializedName*>::const_iterator iter = readOnlyVars.begin();
               iter!=readOnlyVars.end(); iter++)
            cout<<" "<<(*iter)->get_name().getString()<<" ";
          cout<<endl;
          cout<<"CudaOutliner::generateFunction() -----Found "<<liveOuts.size()<<" live out variables..:";
          for (std::set<SgInitializedName*>::const_iterator iter = liveOuts.begin();
               iter!=liveOuts.end(); iter++)
            cout<<" "<<(*iter)->get_name().getString()<<" ";
          cout<<endl;
        }
    }
    //step 2. Create function skeleton, 'func'.             
    // -----------------------------------------                
  SgName func_name (func_name_str);
  SgFunctionParameterList *parameterList = buildFunctionParameterList();
  
  SgType* func_Type = SgTypeVoid::createType ();
  SgFunctionDeclaration* func = createFuncSkeleton (func_name, func_Type ,parameterList, scope);

  //adds __global__ keyword 
  func->get_functionModifier().setCudaKernel();
 
  ROSE_ASSERT (func);

  // Liao, 4/15/2009 , enforce C-bindings  for C++ outlined code 
  // enable C code to call this outlined function                                                                                
  // Only apply to C++ , pure C has trouble in recognizing extern "C"                                                    
  // Another way is to attach the function with preprocessing info:                                                     
  // #if __cplusplus                                                                                                           
  // extern "C"                                                                                                              
  // #endif                                                                                                                                
  // We don't choose it since the language linkage information is not explicit in AST                                                           
  if ( SageInterface::is_Cxx_language() || is_mixed_C_and_Cxx_language() \
       || is_mixed_Fortran_and_Cxx_language() || is_mixed_Fortran_and_C_and_Cxx_language() )
    {
      // Make function 'extern "C"'                                                                                                                                         
      func->get_declarationModifier().get_storageModifier().setExtern();
      func->set_linkage ("C");
    }

  //step 3. Create the function body                                                                                       
  // -----------------------------------------                                                                                              
  // Generate the function body by deep-copying 's'.                                                                                       
              
  SgBasicBlock* func_body = func->get_definition()->get_body();
  ROSE_ASSERT (func_body != NULL);

  // This does a copy of the statements in "s" to the function body of the outlined function.                                             
  ROSE_ASSERT(func_body->get_statements().empty() == true);

  // This calls AST copy on each statement in the SgBasicBlock, but not on the block, so the                                          
  // symbol table is setup by AST copy mechanism and it is  setup properly
  SageInterface::moveStatementsBetweenBlocks (s, func_body);

  if (Outliner::useNewFile)
    ASTtools::setSourcePositionAtRootAndAllChildrenAsTransformation(func_body);

  //step 4: variable handling, including:                                                                                                  
  // -----------------------------------------                                                                                             
  //   create parameters of the outlined functions                                                                                        
  //   add statements to unwrap the parameters if wrapping is requested
  //   add repacking statements if necessary                                                                                               
  //   replace variables to access to parameters, directly or indirectly                                                                  
  //   do not wrap parameters 
  Outliner::enable_classic = true;

  functionParameterHandling(syms, hostToDevVars, pdSyms, psyms, readOnlyVars, liveOuts, func);
  ROSE_ASSERT (func != NULL);
  
  // Retest this...  // Copied the similar fix from the rose outliner                        
  //     Liao 2/6/2013. It is essential to rebuild function type after the parameter list is finalized.
  //     The original function type was build using empty parameter list.
  SgType* stale_func_type = func->get_type();
  func->set_type(buildFunctionType(func->get_type()->get_return_type(), buildFunctionParameterTypeList(func->get_parameterList())));
  SgFunctionDeclaration* non_def_func = isSgFunctionDeclaration(func->get_firstNondefiningDeclaration ()) ;
  ROSE_ASSERT (non_def_func != NULL);
  ROSE_ASSERT (stale_func_type == non_def_func->get_type());
  non_def_func->set_type(func->get_type());

  ROSE_ASSERT(func->get_definition()->get_body()->get_parent() == func->get_definition());

  ROSE_ASSERT(scope->lookup_function_symbol(func->get_name()));

  return func;
}  
Ejemplo n.º 20
0
/**
 * Check an announce phase message and pass to appropriate message handler,
 * decrypting first if necessary
 * Returns 1 on success, 0 on error
 */
int handle_announce_phase(const unsigned char *packet, unsigned char *decrypted,
                          const struct sockaddr_in *receiver,
                          struct finfo_t *finfo,
                          int announce, int open, int regconf)
{
    struct uftp_h *header;
    const unsigned char *message;
    int hostidx;
    unsigned decryptlen, meslen;
    uint8_t *func;
    struct in_addr srcaddr;

    header = (struct uftp_h *)packet;
    hostidx = find_client(header->srcaddr);
    if (header->srcaddr == 0) {
        srcaddr = receiver->sin_addr;
    } else {
        srcaddr.s_addr = header->srcaddr;
    }
    if ((keytype != KEY_NONE) && (header->func == ENCRYPTED)) {
        if (hostidx == -1) {
            log(0, 0, "Got encrypted packet from unknown receiver %s",
                       inet_ntoa(srcaddr));
            return 0;
        }
        if (!validate_and_decrypt(packet, &decrypted, &decryptlen, mtu,
                keytype, groupkey, groupsalt, ivlen, hashtype, grouphmackey,
                hmaclen, sigtype, destlist[hostidx].encinfo->pubkey,
                destlist[hostidx].encinfo->pubkeylen)) {
            log1(0, 0, "Rejecting message from %s: decrypt/validate failed",
                        destlist[hostidx].name);
            return 0;
        }
        func = (uint8_t *)decrypted;
        message = decrypted;
        meslen = decryptlen;
    } else {
        if ((keytype != KEY_NONE) && (header->func == INFO_ACK)) {
            log1(0, 0, "Rejecting %s message from %s: not encrypted",
                       func_name(header->func), inet_ntoa(srcaddr));
            return 0;
        }
        func = (uint8_t *)&header->func;
        message = packet + sizeof(struct uftp_h);
        meslen = ntohs(header->blsize);
    }

    if (*func == ABORT) {
        handle_abort(message, meslen, hostidx, finfo, &srcaddr);
        return 1;
    }

    if (hostidx == -1) {
        if (open) {
            if (*func == REGISTER) {
                handle_open_register(message, meslen, finfo, receiver,
                                     &srcaddr, regconf);
            } else if (*func == CLIENT_KEY) {
                handle_open_clientkey(message, meslen, finfo, receiver,
                                      &srcaddr);
            } else {
                log1(0, 0, "Invalid function: expected "
                           "REGISTER or CLIENT_KEY, got %s", func_name(*func));
            }
        } else {
            log1(0, 0, "Host %s not in host list", inet_ntoa(srcaddr));
            send_abort(finfo, "Not in host list", receiver, &srcaddr, 0, 0);
        }
    } else {
        switch (destlist[hostidx].status) {
        case DEST_MUTE:
            if (*func == REGISTER) {
                handle_register(message, meslen, finfo, receiver,
                                &srcaddr, hostidx, regconf, open);
            } else if (*func == CLIENT_KEY) {
                handle_clientkey(message, meslen, finfo, receiver,
                                 &srcaddr, hostidx);
            } else {
                log1(0, 0, "Invalid function: expected "
                           "REGISTER or CLIENT_KEY, got %s", func_name(*func));
            }
            break;
        case DEST_REGISTERED:
            if (*func == INFO_ACK) {
                handle_info_ack(message, meslen, finfo, receiver,
                                &srcaddr, hostidx, announce);
            } else if (*func == REGISTER) {
                handle_register(message, meslen, finfo, receiver,
                                &srcaddr, hostidx, regconf, open);
            } else if (*func == CLIENT_KEY) {
                log(0, 0, "Received CLIENT_KEY+ from %s",
                           destlist[hostidx].name);
            } else if (!announce && (*func == COMPLETE)) {
                handle_complete(message, meslen, finfo, hostidx);
            } else {
                log1(0, 0, "Received invalid message %s from %s",
                            func_name(*func), destlist[hostidx].name);
            }
            break;
        case DEST_ACTIVE:
            if (*func == REGISTER) {
                handle_register(message, meslen, finfo, receiver,
                                &srcaddr, hostidx, regconf, open);
            } else if (*func == CLIENT_KEY) {
                log(0, 0, "Received CLIENT_KEY+ from %s",
                           destlist[hostidx].name);
            } else if (*func == INFO_ACK) {
                finfo->deststate[hostidx].conf_sent = 0;
                handle_info_ack(message, meslen, finfo, receiver,
                                &srcaddr, hostidx, announce);
            } else if (!announce && (*func == COMPLETE)) {
                handle_complete(message, meslen, finfo, hostidx);
            } else {
                log1(0, 0, "Received invalid message %s from %s",
                            func_name(*func), destlist[hostidx].name);
            }
            break;
        default:
            log1(0, 0, "Received invalid message %s from %s",
                      func_name(*func), destlist[hostidx].name);
            break;
        }
    }

    return 1;
}
Ejemplo n.º 21
0
/**
 * Puts the given message on the pending message list.  If it doesn't match
 * any pending message and there are no open slots, first send what's pending.
 * If the pending list is full after adding the given message, then send.
 */
void check_pending(int listidx, int hostidx, const unsigned char *message)
{
    struct infoack_h *infoack;
    struct status_h *status;
    struct complete_h *complete;
    const uint8_t *func;
    struct pr_pending_info_t *pending;
    int match, pendidx;

    func = message;
    infoack = (struct infoack_h *)message;
    status = (struct status_h *)message;
    complete = (struct complete_h *)message;

    for (pendidx = 0; pendidx < MAX_PEND; pendidx++) {
        pending = &group_list[listidx].pending[pendidx];
        if (group_list[listidx].pending[pendidx].msg == 0) {
            match = 1;
            break;
        }

        match = (*func == pending->msg);
        switch (*func) {
        case REGISTER:
            // REGISTER always matches itself
            break;
        case INFO_ACK:
            // Only in response to FILEINFO.
            // Responses to KEYINFO are not forwarded.
            match = match && (ntohs(infoack->file_id) == pending->file_id);
            break;
        case STATUS:
            match = match && ((ntohs(status->file_id) == pending->file_id) &&
                              (status->pass == pending->pass) &&
                              (ntohs(status->section) == pending->section));
            break;
        case COMPLETE:
            match = match && ((ntohs(complete->file_id) == pending->file_id) &&
                              (complete->status == pending->comp_status));
            break;
        default:
            log(group_list[listidx].group_id, 0, "Tried to check pending "
                    "on invalid type %s", func_name(*func));
            return;
        }
        if (match) {
            break;
        }
    }

    if (!match) {
        send_all_pending(listidx);
        pendidx = 0;
        pending = &group_list[listidx].pending[pendidx];
    }

    pending->msg = *func;
    if (group_list[listidx].destinfo[hostidx].pending != pendidx) {
        group_list[listidx].destinfo[hostidx].pending = pendidx;
        pending->count++;
    }

    switch (*func) {
    case INFO_ACK:
        if (pending->count == 1) {
            pending->partial = 1;
        }
        pending->file_id = ntohs(infoack->file_id);
        pending->partial = pending->partial &&
                            ((infoack->flags & FLAG_PARTIAL) != 0);
        break;
    case STATUS:
        pending->file_id = ntohs(status->file_id);
        pending->pass = status->pass;
        pending->section = ntohs(status->section);
        pending->seq = group_list[listidx].last_seq;
        if (!pending->naklist) {
            pending->naklist = calloc(group_list[listidx].blocksize, 1);
            if (pending->naklist == NULL) {
                syserror(0, 0, "calloc failed!");
                exit(1);
            }
        }
        if (ntohl(status->nak_count) != 0) {
            add_naks_to_pending(listidx, pendidx, message);
        }
        break;
    case COMPLETE:
        pending->file_id = ntohs(complete->file_id);
        pending->comp_status = complete->status;
        break;
    }

    if (pending->count == max_msg_dest(listidx, *func)) {
        send_pending(listidx, pendidx);
    } else {
        int total_pending, i;

        for (total_pending = 0, i = 0; i < MAX_PEND; i++) {
            total_pending += group_list[listidx].pending[i].count;
        }
        if (total_pending == 1) {
            set_timeout(listidx, 1);
        }
    }
}
Ejemplo n.º 22
0
/**
 * Puts the given message on the pending message list.  If it doesn't match
 * any pending message and there are no open slots, first send what's pending.
 * If the pending list is full after adding the given message, then send.
 */
void check_pending(struct pr_group_list_t *group, int hostidx,
                   const unsigned char *message)
{
    const struct fileinfoack_h *fileinfoack;
    const struct status_h *status;
    const struct complete_h *complete;
    const uint8_t *func;
    struct pr_pending_info_t *pending;
    int match, pendidx, hlen;

    func = message;
    fileinfoack = (const struct fileinfoack_h *)message;
    status = (const struct status_h *)message;
    complete = (const struct complete_h *)message;

    glog3(group, "check_timeout: looking for pending %s", func_name(*func));
    for (pendidx = 0; pendidx < MAX_PEND; pendidx++) {
        pending = &group->pending[pendidx];
        if (group->pending[pendidx].msg == 0) {
            glog3(group, "check_timeout: found empty slot %d", pendidx);
            match = 1;
            break;
        }

        match = (*func == pending->msg);
        switch (*func) {
        case REGISTER:
            // REGISTER always matches itself
            break;
        case FILEINFO_ACK:
            match = match && (ntohs(fileinfoack->file_id) == pending->file_id);
            break;
        case STATUS:
            match = match && ((ntohs(status->file_id) == pending->file_id) &&
                              (ntohs(status->section) == pending->section));
            break;
        case COMPLETE:
            match = match && ((ntohs(complete->file_id) == pending->file_id) &&
                              (complete->status == pending->comp_status));
            break;
        default:
            glog1(group, "Tried to check pending on invalid type %s",
                         func_name(*func));
            return;
        }
        if (match) {
            break;
        }
    }

    if (!match) {
        send_all_pending(group);
        pendidx = 0;
        pending = &group->pending[pendidx];
    }

    glog3(group, "check_timeout: found match at slot %d", pendidx);
    pending->msg = *func;
    if (group->destinfo[hostidx].pending != pendidx) {
        group->destinfo[hostidx].pending = pendidx;
        pending->count++;
    }

    switch (*func) {
    case REGISTER:
        hlen = sizeof(struct register_h);
        if (pending->count == 1) {
            gettimeofday(&pending->rx_tstamp, NULL);
            pending->tstamp = group->destinfo[hostidx].regtime;
            glog3(group, "send time = %d.%06d",
                         pending->tstamp.tv_sec, pending->tstamp.tv_usec);
            glog3(group, "rx time = %d.%06d",
                         pending->rx_tstamp.tv_sec, pending->rx_tstamp.tv_usec);
        }
        break;
    case FILEINFO_ACK:
        hlen = sizeof(struct fileinfoack_h);
        if (pending->count == 1) {
            pending->partial = 1;
            gettimeofday(&pending->rx_tstamp, NULL);
            pending->tstamp.tv_sec = ntohl(fileinfoack->tstamp_sec);
            pending->tstamp.tv_usec = ntohl(fileinfoack->tstamp_usec);
            glog3(group, "send time = %d.%06d",
                         pending->tstamp.tv_sec, pending->tstamp.tv_usec);
            glog3(group, "rx time = %d.%06d",
                         pending->rx_tstamp.tv_sec, pending->rx_tstamp.tv_usec);
        }
        pending->file_id = ntohs(fileinfoack->file_id);
        pending->partial = pending->partial &&
                            ((fileinfoack->flags & FLAG_PARTIAL) != 0);
        break;
    case STATUS:
        hlen = sizeof(struct status_h);
        pending->file_id = ntohs(status->file_id);
        pending->section = ntohs(status->section);
        if (!pending->naklist) {
            pending->naklist = safe_calloc(group->blocksize, 1);
        }
        add_naks_to_pending(group, pendidx, message);
        break;
    case COMPLETE:
        hlen = sizeof(struct complete_h);
        pending->file_id = ntohs(complete->file_id);
        pending->comp_status = complete->status;
        break;
    }

    if ((*func != STATUS) &&
            (pending->count == max_msg_dest(group, *func, hlen))) {
        send_pending(group, pendidx);
    } else {
        int total_pending, i;

        glog3(group, "check_timeout: getting pending count for %s",
                     func_name(*func));
        for (total_pending = 0, i = 0; i < MAX_PEND; i++) {
            glog3(group, "check_timeout: adding %d pending for %d",
                         group->pending[i].count, i);
            total_pending += group->pending[i].count;
        }
        if (total_pending == 1) {
            set_timeout(group, 1, 0);
        }
    }
}
Ejemplo n.º 23
0
// ...as tree
void CallNode::_dumpTree(ostream& s) const
{
    s << "\"" << func_name() << "\", ";
    _arg->dumpTree(s);
}
Ejemplo n.º 24
0
/**
 * This is the main message reading loop.  Messages are read, validated,
 * decrypted if necessary, then passed to the appropriate routine for handling.
 */
void mainloop()
{
    struct uftp_h *header;
    struct uftp2_h *v2_header;
    unsigned char *buf, *decrypted, *message;
    unsigned int decryptlen, meslen, expectedlen;
    int packetlen, listidx, i;
    uint8_t version, *func;
    uint32_t v2func;
    struct sockaddr_in src;
    struct timeval *tv;
    const int bsize = 9000;  // Roughly size of ethernet jumbo frame

    log0(0, 0, "%s", VERSIONSTR);
    for (i = 0; i < key_count; i++) {
        log1(0, 0, "Loaded key with fingerprint %s",
                  print_key_fingerprint(privkey[i]));
    }

    buf = calloc(bsize, 1);
    decrypted = calloc(bsize, 1);
    if ((buf == NULL) || (decrypted == NULL)){
        syserror(0, 0, "calloc failed!");
        exit(1);
    }
    header = (struct uftp_h *)buf;
    v2_header = (struct uftp2_h *)buf;

    while (1) {
        tv = getrecenttimeout();
        if (read_packet(listener, &src, buf, &packetlen,
                        bsize, tv) <= 0) {
            continue;
        }

        if ((header->uftp_id == UFTP_VER_NUM) ||
                (header->uftp_id == UFTP_3_0_VER)) {
            version = header->uftp_id;
            expectedlen = sizeof(struct uftp_h) + ntohs(header->blsize);
            listidx = find_file(ntohl(header->group_id));
        } else if (ntohl(v2_header->uftp_id) == V2_UFTP_ID) {
            version = UFTP_V2_VER;
            expectedlen = V2_PACKETSIZE;
            listidx = find_file(ntohl(v2_header->tx_id));
            v2func = ntohl(v2_header->func);
        } else {
            log(0, 0, "Invalid message from %s: not uftp packet "
                      "or invalid version", inet_ntoa(src.sin_addr));
            continue;
        }
        if (packetlen != expectedlen) {
            log(0, 0, "Invalid packet size from %s: got %d, expected %d",
                      inet_ntoa(src.sin_addr), packetlen, expectedlen);
            continue;
        }

        if (((version == UFTP_VER_NUM) || (version == UFTP_3_0_VER)) &&
                (header->func == ENCRYPTED) && (listidx != -1) &&
                (group_list[listidx].keytype != KEY_NONE)) {
            if (group_list[listidx].phase == PHASE_REGISTERED) {
                log(ntohl(header->group_id), 0, "Got encrypted packet from %s "
                        "but keys not established", inet_ntoa(src.sin_addr));
            }

            if (!validate_and_decrypt(buf, &decrypted, &decryptlen,
                    group_list[listidx].mtu, group_list[listidx].keytype,
                    group_list[listidx].groupkey, group_list[listidx].groupsalt,
                    group_list[listidx].ivlen, group_list[listidx].hashtype,
                    group_list[listidx].grouphmackey,
                    group_list[listidx].hmaclen, group_list[listidx].sigtype,
                    group_list[listidx].serverkey,
                    group_list[listidx].server_keylen)) {
                log(ntohl(header->group_id), 0, "Rejecting message from %s: "
                        "decrypt/validate failed", inet_ntoa(src.sin_addr));
                continue;
            }
            func = (uint8_t *)decrypted;
            message = decrypted;
            meslen = decryptlen;
        } else if ((version == UFTP_VER_NUM) || (version == UFTP_3_0_VER)) {
            if ((listidx != -1) && (group_list[listidx].keytype != KEY_NONE) &&
                    ((header->func == FILEINFO) || (header->func == FILESEG) ||
                     (header->func == DONE) || (header->func == DONE_CONF) ||
                     ((header->func == ABORT) &&
                         (group_list[listidx].phase != PHASE_REGISTERED)))) {
                log(0, 0, "Rejecting %s message from %s: not encrypted",
                        func_name(header->func), inet_ntoa(src.sin_addr));
                continue;
            }
            func = (uint8_t *)&header->func;
            message = buf + sizeof(struct uftp_h);
            meslen = ntohs(header->blsize);
        } else {
            // Version 2
            message = buf;
            meslen = V2_PACKETSIZE;
        }

        if (((version == UFTP_VER_NUM) || (version == UFTP_3_0_VER)) &&
                (header->func == PROXY_KEY)) {
            handle_proxy_key(&src, buf);
            continue;
        }
        if (((version == UFTP_VER_NUM) || (version == UFTP_3_0_VER)) &&
                (header->func == HB_RESP)) {
            handle_hb_response(listener, &src, buf, hb_hosts, hbhost_count,
                               noname, privkey[0]);
            continue;
        }
        if ((((version == UFTP_VER_NUM) || (version == UFTP_3_0_VER)) &&
                 (header->func == ANNOUNCE)) ||
                ((version == UFTP_V2_VER) && (v2func == V2_ANNOUNCE))) {
            // Ignore any ANNOUNCE for a group we're already handling
            if (listidx == -1) {
                handle_announce(src, version, buf);
            } else if (group_list[listidx].phase == PHASE_MIDGROUP) {
                // Make sure we don't time out while waiting for other
                // clients to register with the server.
                set_timeout(listidx);
            }
        } else {
            if (listidx == -1) {
                // group / file ID not in list
                continue;
            }
            if (group_list[listidx].version != version) {
                log(group_list[listidx].group_id, group_list[listidx].file_id,
                        "Version mismatch");
                continue;
            }
            if ((((version == UFTP_VER_NUM) || (version == UFTP_3_0_VER)) &&
                     (*func == ABORT)) ||
                    ((version == UFTP_V2_VER) && (v2func == V2_ABORT))) {
                handle_abort(listidx, message, meslen);
                continue;
            }
            switch (group_list[listidx].phase) {
            case PHASE_REGISTERED:
                if (version == UFTP_V2_VER) {
                    // This is repeated in one of the cases below, but it's
                    // separated out anyway to keep the V2 stuff separate.
                    handle_regconf(listidx, message, meslen);
                } else if (group_list[listidx].keytype != KEY_NONE) {
                    if (*func == KEYINFO) {
                        handle_keyinfo(listidx, buf);
                    } else {
                        log(group_list[listidx].group_id,
                                group_list[listidx].file_id,
                                "Expected KEYINFO, got %s", func_name(*func));
                    }
                } else if (group_list[listidx].keytype == KEY_NONE) {
                    if (*func == REG_CONF) {
                        handle_regconf(listidx, message, meslen);
                    } else if (*func == FILEINFO) {
                        handle_fileinfo(listidx, message, meslen);
                    } else {
                        log(group_list[listidx].group_id,
                                group_list[listidx].file_id,
                                "Expected REG_CONF, got %s", func_name(*func));
                    }
                }
                break;
            case PHASE_MIDGROUP:
                if (((version == UFTP_VER_NUM) || (version == UFTP_3_0_VER)) &&
                        (*func == FILEINFO)) {
                    handle_fileinfo(listidx, message, meslen);
                } else if (((version == UFTP_VER_NUM) ||
                            (version == UFTP_3_0_VER)) && (*func == KEYINFO)) {
                    handle_keyinfo(listidx, buf);
                } else if (((version == UFTP_V2_VER) && (v2func == V2_DONE)) ||
                        (((version == UFTP_VER_NUM) ||
                          (version == UFTP_3_0_VER)) && (*func == DONE))) {
                    handle_done(listidx, message, meslen);
                } else {
                    // Other clients may be still getting earlier files or
                    // setting up, so silently ignore anything unexpected
                    // and reset the timeout.
                    set_timeout(listidx);
                }
                break;
            case PHASE_RECEIVING:
                if (((version == UFTP_VER_NUM) || (version == UFTP_3_0_VER)) &&
                        (*func == FILEINFO)) {
                    handle_fileinfo(listidx, message, meslen);
                } else if (((version == UFTP_V2_VER) &&
                            (v2func == V2_FILESEG)) ||
                        (((version == UFTP_VER_NUM) ||
                          (version == UFTP_3_0_VER)) && (*func == FILESEG))) {
                    handle_fileseg(listidx, message, meslen);
                } else if (((version == UFTP_V2_VER) && (v2func == V2_DONE)) ||
                        (((version == UFTP_VER_NUM) ||
                          (version == UFTP_3_0_VER)) && (*func == DONE))) {
                    handle_done(listidx, message, meslen);
                }
                break;
            case PHASE_COMPLETE:
                if (((version == UFTP_V2_VER) && (v2func == V2_DONE_CONF)) ||
                        (((version == UFTP_VER_NUM) || 
                          (version == UFTP_3_0_VER)) && (*func == DONE_CONF))) {
                    handle_done_conf(listidx, message, meslen);
                }
                break;
            }
        }
    }
}
Ejemplo n.º 25
0
/**
 * This is the main message reading loop.  Messages are read, validated,
 * decrypted if necessary, then passed to the appropriate routine for handling.
 */
void mainloop(void)
{
    struct uftp_h *header;
    struct group_list_t *group;
    unsigned char *buf, *decrypted, *message;
    char rxname[INET6_ADDRSTRLEN];
    unsigned int decryptlen, meslen;
    int packetlen, rval, i, ecn;
    uint8_t version, *func, tos;
    uint16_t txseq;
    union sockaddr_u src;
    struct timeval *tv, rxtime;
    double new_grtt;

    log2(0, 0, 0, "%s", VERSIONSTR);
    for (i = 0; i < key_count; i++) {
        if (privkey_type[i] == KEYBLOB_RSA) {
            log2(0, 0, 0, "Loaded %d bit RSA key with fingerprint %s",
                  RSA_keylen(privkey[i].rsa) * 8,
                  print_key_fingerprint(privkey[i], KEYBLOB_RSA));
        } else {
            log2(0, 0, 0, "Loaded ECDSA key with curve %s and fingerprint %s",
                  curve_name(get_EC_curve(privkey[i].ec)),
                  print_key_fingerprint(privkey[i], KEYBLOB_EC));
        }
    }

    buf = safe_calloc(MAXMTU, 1);
    decrypted = safe_calloc(MAXMTU, 1);
    header = (struct uftp_h *)buf;

    while (1) {
        tv = getrecenttimeout();
        if (tv) {
            log5(0, 0, 0, "read timeout: %d.%06d", tv->tv_sec, tv->tv_usec);
        }
        if (read_packet(listener, &src, buf, &packetlen,
                        MAXMTU, tv, &tos) <= 0) {
            continue;
        }
        gettimeofday(&rxtime, NULL);

        if ((rval = getnameinfo((struct sockaddr *)&src, family_len(src),
                rxname, sizeof(rxname), NULL, 0, NI_NUMERICHOST)) != 0) {
            log1(0, 0, 0, "getnameinfo failed: %s", gai_strerror(rval));
        }

        if (header->version == UFTP_VER_NUM) {
            version = header->version;
            group = find_group(ntohl(header->group_id), header->group_inst);
        } else {
            log1(0, 0, 0, "Invalid message from %s: not uftp packet "
                          "or invalid version", rxname);
            continue;
        }
        if (packetlen < sizeof(struct uftp_h) + 4) {
            log1(0, 0, 0, "Invalid packet size from %s: %d", rxname, packetlen);
            continue;
        }

        txseq = htons(header->seq);
        // A KEY_INFO or ABORT could come from a proxy, so don't check the seq
        // TODO: need to account for these in the loss history
        if ((group != NULL) && (header->func != KEYINFO) &&
                (header->func != ABORT)) {
            if ((int16_t)(group->max_txseq - txseq) > MAXMISORDER) {
                glog3(group, "seq out of range, dropping");
                continue;
            }
            if (group->cc_type != CC_NONE) {
                ecn = ((tos & 0x3) == 3);
                update_loss_history(group, txseq, packetlen, ecn);
            } else if ((int16_t)(txseq - group->max_txseq) > 0) {
                group->max_txseq = txseq;
            }
        }

        if ((header->func == ENCRYPTED) && (group != NULL) &&
                (group->keytype != KEY_NONE)) {
            if (group->phase == PHASE_REGISTERED) {
                glog1(group, "Got encrypted packet from %s "
                             "but keys not established", rxname);
            }

            if (!validate_and_decrypt(buf, packetlen, &decrypted, &decryptlen,
                    group->keytype, group->groupkey, group->groupsalt,
                    group->ivlen, group->hashtype, group->grouphmackey,
                    group->hmaclen, group->sigtype, group->keyextype,
                    group->server_pubkey, group->server_pubkeylen)) {
                glog1(group, "Rejecting message from %s: "
                             "decrypt/validate failed", rxname);
                continue;
            }
            func = (uint8_t *)decrypted;
            message = decrypted;
            meslen = decryptlen;
        } else {
            if ((group != NULL) && (group->keytype != KEY_NONE) &&
                    ((header->func == FILEINFO) || (header->func == FILESEG) ||
                     (header->func == DONE) || (header->func == DONE_CONF) ||
                     ((header->func == ABORT) &&
                         (group->phase != PHASE_REGISTERED)))) {
                glog1(group, "Rejecting %s message from %s: not encrypted",
                             func_name(header->func), rxname);
                continue;
            }
            func = (uint8_t *)&header->func;
            message = buf + sizeof(struct uftp_h);
            meslen = packetlen - sizeof(struct uftp_h);
        }

        if (group != NULL) {
            new_grtt = unquantize_grtt(header->grtt);
            if (fabs(new_grtt - group->grtt) > 0.001) {
                group->grtt = new_grtt;
                set_timeout(group, 1);
            }
            group->gsize = unquantize_gsize(header->gsize);
            glog5(group, "grtt: %.3f", group->grtt);
        }

        if (header->func == PROXY_KEY) {
            handle_proxy_key(&src, message, meslen);
            continue;
        }
        if (header->func == HB_RESP) {
            handle_hb_response(listener, &src, message, meslen, hb_hosts,
                               hbhost_count, privkey[0], privkey_type[0], uid);
            continue;
        }
        if (header->func == ANNOUNCE) {
            // Ignore any ANNOUNCE for a group we're already handling
            if (group == NULL) {
                handle_announce(&src, buf, packetlen, rxtime);
            } else if (group->phase == PHASE_MIDGROUP) {
                // Make sure we don't time out while waiting for other
                // clients to register with the server.
                set_timeout(group, 0);
            }
        } else {
            if (group == NULL) {
                // group / file ID not in list
                continue;
            }
            if (group->version != version) {
                glog1(group, "Version mismatch");
                continue;
            }
            if (group->src_id != header->src_id) {
                glog1(group, "Source ID mismatch");
                continue;
            }
            if (*func == ABORT) {
                handle_abort(group, message, meslen);
                continue;
            }
            switch (group->phase) {
            case PHASE_REGISTERED:
                if (group->keytype != KEY_NONE) {
                    if (*func == KEYINFO) {
                        handle_keyinfo(group, message, meslen, header->src_id);
                    } else {
                        glog1(group, "Expected KEYINFO, got %s",
                                     func_name(*func));
                    }
                } else if (group->keytype == KEY_NONE) {
                    if (*func == REG_CONF) {
                        handle_regconf(group, message, meslen);
                    } else if (*func == FILEINFO) {
                        handle_fileinfo(group, message, meslen, rxtime);
                    } else {
                        glog1(group, "Expected REG_CONF, got %s",
                                     func_name(*func));
                    }
                }
                break;
            case PHASE_MIDGROUP:
                if (*func == FILEINFO) {
                    handle_fileinfo(group, message, meslen, rxtime);
                } else if (*func == KEYINFO) {
                    handle_keyinfo(group, message, meslen, header->src_id);
                } else if (*func == DONE) {
                    handle_done(group, message, meslen);
                } else {
                    // Other clients may be still getting earlier files or
                    // setting up, so silently ignore anything unexpected
                    // and reset the timeout.
                    set_timeout(group, 0);
                }
                break;
            case PHASE_RECEIVING:
                if (*func == FILEINFO) {
                    handle_fileinfo(group, message, meslen, rxtime);
                } else if (*func == FILESEG) {
                    handle_fileseg(group, message, meslen, txseq);
                } else if (*func == DONE) {
                    handle_done(group, message, meslen);
                } else if (*func == CONG_CTRL) {
                    handle_cong_ctrl(group, message, meslen, rxtime);
                }
                break;
            case PHASE_COMPLETE:
                if (*func == DONE_CONF) {
                    handle_done_conf(group, message, meslen);
                }
                break;
            }
        }
    }
}
Ejemplo n.º 26
0
bool Compiler::CompileLazy(Handle<SharedFunctionInfo> shared,
                           int loop_nesting) {
  CompilationZoneScope zone_scope(DELETE_ON_EXIT);

  // The VM is in the COMPILER state until exiting this function.
  VMState state(COMPILER);

  // Make sure we have an initial stack limit.
  StackGuard guard;
  PostponeInterruptsScope postpone;

  // Compute name, source code and script data.
  Handle<String> name(String::cast(shared->name()));
  Handle<Script> script(Script::cast(shared->script()));

  int start_position = shared->start_position();
  int end_position = shared->end_position();
  bool is_expression = shared->is_expression();
  Counters::total_compile_size.Increment(end_position - start_position);

  // Generate the AST for the lazily compiled function. The AST may be
  // NULL in case of parser stack overflow.
  FunctionLiteral* lit = MakeLazyAST(script, name,
                                     start_position,
                                     end_position,
                                     is_expression);

  // Check for parse errors.
  if (lit == NULL) {
    ASSERT(Top::has_pending_exception());
    return false;
  }

  // Update the loop nesting in the function literal.
  lit->set_loop_nesting(loop_nesting);

  // Measure how long it takes to do the lazy compilation; only take
  // the rest of the function into account to avoid overlap with the
  // lazy parsing statistics.
  HistogramTimerScope timer(&Counters::compile_lazy);

  // Compile the code.
  Handle<Code> code = MakeCode(lit, script, Handle<Context>::null(), false);

  // Check for stack-overflow exception.
  if (code.is_null()) {
    Top::StackOverflow();
    return false;
  }

#if defined ENABLE_LOGGING_AND_PROFILING || defined ENABLE_OPROFILE_AGENT
  // Log the code generation. If source information is available include script
  // name and line number. Check explicit whether logging is enabled as finding
  // the line number is not for free.
  if (Logger::is_logging() || OProfileAgent::is_enabled()) {
    Handle<String> func_name(name->length() > 0 ?
                             *name : shared->inferred_name());
    if (script->name()->IsString()) {
      int line_num = GetScriptLineNumber(script, start_position) + 1;
      LOG(CodeCreateEvent(Logger::LAZY_COMPILE_TAG, *code, *func_name,
                          String::cast(script->name()), line_num));
      OProfileAgent::CreateNativeCodeRegion(*func_name,
                                            String::cast(script->name()),
                                            line_num,
                                            code->instruction_start(),
                                            code->instruction_size());
    } else {
      LOG(CodeCreateEvent(Logger::LAZY_COMPILE_TAG, *code, *func_name));
      OProfileAgent::CreateNativeCodeRegion(*func_name,
                                            code->instruction_start(),
                                            code->instruction_size());
    }
  }
#endif

  // Update the shared function info with the compiled code.
  shared->set_code(*code);

  // Set the expected number of properties for instances.
  SetExpectedNofPropertiesFromEstimate(shared, lit->expected_property_count());

  // Set the optimication hints after performing lazy compilation, as these are
  // not set when the function is set up as a lazily compiled function.
  shared->SetThisPropertyAssignmentsInfo(
      lit->has_only_this_property_assignments(),
      lit->has_only_simple_this_property_assignments(),
      *lit->this_property_assignments());

  // Check the function has compiled code.
  ASSERT(shared->is_compiled());
  return true;
}
Ejemplo n.º 27
0
std::string generator_opencl::co(const node& n)
{
    switch (n.type) {
    case node::entry_point:
        return "p";
    case node::const_var:
        return std::to_string(n.aux_var);
    case node::const_bool:
        return std::to_string(n.aux_bool);
    case node::const_str:
        throw std::runtime_error("string encountered");

    case node::rotate:
        return "p_rotate" + pl(n);
    case node::rotate3:
        return "p_rotate3(" + co(n.input[0]) + ", (double3)(" + co(n.input[1]) + "," + co(n.input[2]) + "," + co(n.input[3]) + "), " + co(n.input[4]) + ")";
    case node::scale:
    case node::scale3:
        return "(" + co(n.input[0]) + "/" + co(n.input[1]) + ")";
    case node::shift:
        return "(" + co(n.input[0]) + "+(double2)(" + co(n.input[1]) + ","
               + co(n.input[2]) + "))";
    case node::shift3:
        return "(" + co(n.input[0]) + "+(double3)(" + co(n.input[1]) + ","
               + co(n.input[2]) + "," + co(n.input[3]) + "))";
    case node::swap:
        return "p_swap" + pl(n);

    case node::map: {
        std::string func_name{std::string("ip_map") + std::to_string(count_++)};

        std::stringstream func_body;
        func_body << "inline double2 " << func_name
                  << " (const double2 p) { return (double2)(" << co(n.input[1])
                  << ", " << co(n.input[2]) << "); }" << std::endl;

        functions_.emplace_back(func_body.str());

        return func_name + "(" + co(n.input[0]) + ")";
    }
    case node::map3: {
        std::string func_name{"ip_map3" + std::to_string(count_++)};

        std::stringstream func_body;
        func_body << "inline double3 " << func_name
                  << " (const double3 p) { return (double3)(" << co(n.input[1])
                  << ", " << co(n.input[2]) << ", " << co(n.input[3]) << "); }"
                  << std::endl;

        functions_.emplace_back(func_body.str());

        return func_name + "(" + co(n.input[0]) + ")";
    }

    case node::turbulence: {
        std::string func_name("ip_turb" + std::to_string(count_++));

        std::stringstream func_body;
        func_body << "inline double2 " << func_name
                  << " (const double2 p) { return (double2)("
                  << "p.x+(" << co(n.input[1]) << "), "
                  << "p.y+(" << co(n.input[2]) << ")); }" << std::endl;

        functions_.emplace_back(func_body.str());

        return func_name + "(" + co(n.input[0]) + ")";
    }

    case node::turbulence3: {
        std::string func_name("ip_turb3" + std::to_string(count_++));

        std::stringstream func_body;
        func_body << "inline double3 " << func_name
                  << " (const double3 p) { return (double3)("
                  << "p.x+(" << co(n.input[1]) << "), "
                  << "p.y+(" << co(n.input[2]) << "), "
                  << "p.z+(" << co(n.input[3]) << ")); }" << std::endl;

        functions_.emplace_back(func_body.str());

        return func_name + "(" + co(n.input[0]) + ")";
    }

    case node::worley: {
        std::string func_name("ip_worley" + std::to_string(count_++));

        std::stringstream func_body;
        func_body << "inline double " << func_name
                  << " (const double2 q, uint seed) { "
                  << "  double2 p = p_worley(q, seed);"
                  << "  return " << co(n.input[1]) << "; }" << std::endl;

        functions_.emplace_back(func_body.str());
        return func_name + "(" + co(n.input[0]) + "," + co(n.input[2]) + ")";
    }

    case node::worley3: {
        std::string func_name("ip_worley3" + std::to_string(count_++));

        std::stringstream func_body;
        func_body << "inline double " << func_name
                  << " (const double3 q, uint seed) { "
                  << "  double3 p = p_worley3(q, seed);"
                  << "  return " << co(n.input[1]) << "; }" << std::endl;

        functions_.emplace_back(func_body.str());
        return func_name + "(" + co(n.input[0]) + "," + co(n.input[2]) + ")";
    }

    case node::voronoi: {
        std::string func_name("ip_voronoi" + std::to_string(count_++));

        std::stringstream func_body;
        func_body << "inline double " << func_name
                  << " (const double2 q, uint seed) { "
                  << "  double2 p = p_voronoi(q, seed);"
                  << "  return " << co(n.input[1]) << "; }" << std::endl;

        functions_.emplace_back(func_body.str());
        return func_name + "(" + co(n.input[0]) + "," + co(n.input[2]) + ")";
    }

    case node::angle:
        return "p_angle" + pl(n);
    case node::chebyshev:
        return "p_chebyshev" + pl(n);
    case node::chebyshev3:
        return "p_chebyshev3" + pl(n);
    case node::checkerboard:
        return "p_checkerboard" + pl(n);
    case node::checkerboard3:
        return "p_checkerboard3" + pl(n);
    case node::distance:
    case node::distance3:
        return "length" + pl(n);
    case node::manhattan:
        return "p_manhattan" + pl(n);
    case node::manhattan3:
        return "p_manhattan3" + pl(n);
    case node::perlin:
        return "p_perlin" + pl(n);
    case node::perlin3:
        return "p_perlin3" + pl(n);
    case node::simplex:
        return "p_simplex" + pl(n);
    case node::simplex3:
        return "p_simplex3" + pl(n);
    case node::opensimplex:
        return "p_opensimplex" + pl(n);
    case node::opensimplex3:
        return "p_opensimplex3" + pl(n);
    case node::x:
        return co(n.input[0]) + ".x";
    case node::y:
        return co(n.input[0]) + ".y";
    case node::z:
        return co(n.input[0]) + ".z";
    case node::xy:
        return co(n.input[0]) + ".xy";
    case node::zplane:
        return "(double3)(" + co(n.input[0]) + "," + co(n.input[1]) + ")";

    case node::add:
        return "(" + co(n.input[0]) + "+" + co(n.input[1]) + ")";
    case node::sub:
        return "(" + co(n.input[0]) + "-" + co(n.input[1]) + ")";
    case node::mul:
        return "(" + co(n.input[0]) + "*" + co(n.input[1]) + ")";
    case node::div:
        return "(" + co(n.input[0]) + "/" + co(n.input[1]) + ")";

    case node::abs:
        return "fabs" + pl(n);
    case node::blend:
        return "p_blend" + pl(n);
    case node::cos:
        return "cospi" + pl(n);
    case node::min:
        return "fmin" + pl(n);
    case node::max:
        return "fmax" + pl(n);
    case node::neg:
        return "-" + co(n.input[0]);

    case node::pow: {
        if (n.input[1].is_const) {
            double exp(std::floor(n.input[1].aux_var));
            if (std::abs(exp - n.input[1].aux_var) < 1e-9)
                return "pown(" + co(n.input[0]) + ","
                       + std::to_string((int)exp) + ")";
        }
        return "pow" + pl(n);
    }

    case node::round:
        return "round" + pl(n);
    case node::saw:
        return "p_saw" + pl(n);
    case node::sin:
        return "sinpi" + pl(n);
    case node::sqrt:
        return "sqrt" + pl(n);
    case node::tan:
        return "tanpi" + pl(n);

    case node::band:
        return co(n.input[0]) + "&&" + co(n.input[1]);
    case node::bor:
        return co(n.input[0]) + "||" + co(n.input[1]);
    case node::bxor:
        return "((" + co(n.input[0]) + ")!=(" + co(n.input[1]) + "))";
    case node::bnot:
        return "!" + co(n.input[0]);

    case node::is_equal:
        return co(n.input[0]) + "==" + co(n.input[1]);
    case node::is_greaterthan:
        return co(n.input[0]) + ">" + co(n.input[1]);
    case node::is_gte:
        return co(n.input[0]) + ">=" + co(n.input[1]);
    case node::is_lessthan:
        return co(n.input[0]) + "<" + co(n.input[1]);
    case node::is_lte:
        return co(n.input[0]) + "<=" + co(n.input[1]);

    case node::is_in_circle:
        return "p_is_in_circle" + pl(n);
    case node::is_in_rectangle:
        return "p_is_in_rectangle" + pl(n);

    case node::then_else:
        return "(" + co(n.input[0]) + ")?(" + co(n.input[1]) + "):("
               + co(n.input[2]) + ")";

    case node::fractal: {
        assert(n.input.size() == 5);
        if (!n.input[2].is_const)
            throw std::runtime_error(
                "fractal octave count must be a constexpr");

        int octaves(std::min<int>(n.input[2].aux_var, OPENCL_OCTAVES_LIMIT));

        std::string func_name("ip_fractal_" + std::to_string(count_++));

        std::stringstream func_body;
        func_body
            << "double " << func_name
            << " (double2 p, const double lac, const double per) {"
            << "double result = 0.0; double div = 0.0; double step = 1.0;"
            << "for(int i = 0; i < " << octaves << "; ++i)"
            << "{"
            << "  result += " << co(n.input[1]) << " * step;"
            << "  div += step;"
            << "  step *= per;"
            << "  p *= lac;"
            << "  p.x += 12345.0;"
            << "}"
            << "return result / div;"
            << "}";

        functions_.emplace_back(func_body.str());

        return func_name + "(" + co(n.input[0]) + "," + co(n.input[3]) + ","
               + co(n.input[4]) + ")";
    }

    case node::fractal3: {
        assert(n.input.size() == 5);
        if (!n.input[2].is_const)
            throw std::runtime_error(
                "fractal octave count must be a constexpr");

        int octaves = std::min<int>(n.input[2].aux_var, OPENCL_OCTAVES_LIMIT);

        std::string func_name{"ip_fractal3_" + std::to_string(count_++)};

        std::stringstream func_body;
        func_body
            << "double " << func_name
            << " (double3 p, const double lac, const double per) {"
            << "double result = 0.0; double div = 0.0; double step = 1.0;"
            << "for(int i = 0; i < " << octaves << "; ++i)"
            << "{"
            << "  result += " << co(n.input[1]) << " * step;"
            << "  div += step;"
            << "  step *= per;"
            << "  p *= lac;"
            << "  p.x += 12345.0;"
            << "}"
            << "return result / div;"
            << "}";

        functions_.emplace_back(func_body.str());

        return func_name + "(" + co(n.input[0]) + "," + co(n.input[3]) + ","
               + co(n.input[4]) + ")";
    }

    case node::lambda_: {
        assert(n.input.size() == 2);
        std::string func_name{"ip_lambda_" + std::to_string(count_++)};
        std::string type{type_string(n.input[0])};

        std::stringstream func_body;
        func_body << "double " << func_name << " (" << type << " p) {"
                  << "return " << co(n.input[1]) << ";}" << std::endl;

        functions_.emplace_back(func_body.str());

        return func_name + "(" + co(n.input[0]) + ")";
    }

    case node::external_:
        throw std::runtime_error("OpenCL @external not implemented yet");

    case node::curve_linear:
        throw std::runtime_error("OpenCL curve_linear not implemented yet");

    case node::curve_spline:
        throw std::runtime_error("OpenCL curve_spline not implemented yet");

    case node::png_lookup:
        throw std::runtime_error("OpenCL png_lookup not implemented yet");

    default:
        throw std::runtime_error("function not implemented in OpenCL yet");
    }

    return std::string();
}
Ejemplo n.º 28
0
/**
 * For messages that send a list of clients in the body, append all clients
 * in the specified state to the packet, then send the message of the given
 * type when either the body is full or the end of the client list has been
 * reached.  All header fields besides uftp_h.blsize and message.destcount
 * must be populated before calling.
 * Returns 1 on success, 0 on fail.
 */
int send_multiple(const struct finfo_t *finfo, unsigned char *packet,
                  int message, int attempt, uint32_t *addrlist, int state,
                  uint16_t *mes_destcount, int encrypt,
                  const struct sockaddr_in *destaddr, int regconf)
{
    struct uftp_h *header;
    int hsize, payloadlen;
    int maxdest, packetcnt, dests, i;
    unsigned char *mheader, *encpacket, *outpacket;

    header = (struct uftp_h *)packet;
    mheader = packet + sizeof(struct uftp_h);
    hsize = (unsigned char *)addrlist - mheader;
    maxdest = ((encrypt ? encpayloadsize : payloadsize) - hsize) /
              sizeof(struct in_addr);
    packetcnt = 1;
    if (encrypt) {
        encpacket = calloc(mtu + keylen, 1); 
        if (encpacket == NULL) {
            syserror(0, 0, "calloc failed!");
            exit(1);
        }
    } else {
        encpacket = NULL;
    }
    for (i = 0, dests = 0; i < destcount; i++) {
        if (message == REG_CONF) {
            // Only send REG_CONF for a particular client if either it's
            // behind a proxy or we're sending them to everyone.
            // Also, don't send if we already sent one and we haven't
            // gotten another REGISTER
            if ((destlist[i].status == state) &&
                    (!finfo->deststate[i].conf_sent) &&
                    (regconf || (destlist[i].proxyidx != -1))) {
                addrlist[dests++] = destlist[i].addr.s_addr;
                finfo->deststate[i].conf_sent = 1;
            }
        } else if (message == DONE_CONF) {
            // As with REG_CONF, don't send a DONE_CONF for a client
            // if we already sent one and we haven't gotten another COMPLETE
            if ((destlist[i].status == state) &&
                    (!finfo->deststate[i].conf_sent)) {
                addrlist[dests++] = destlist[i].addr.s_addr;
                finfo->deststate[i].conf_sent = 1;
            }
        } else if (destlist[i].status == state) {
            addrlist[dests++] = destlist[i].addr.s_addr;
        }
        if ((dests >= maxdest) || ((i == destcount - 1) && (dests > 0))) {
            payloadlen = hsize + (dests * sizeof(uint32_t));
            *mes_destcount = htons(dests);
            if (encrypt) {
                if (!encrypt_and_sign(packet, &encpacket, payloadlen, mtu,
                        keytype, groupkey, groupsalt, ivlen, hashtype,
                        grouphmackey, hmaclen, sigtype, privkey, rsalen)) {
                    log0(0, 0, "Error encrypting %s", func_name(message));
                    free(encpacket);
                    return 0;
                }
                outpacket = encpacket;
                payloadlen = ntohs(((struct uftp_h *)outpacket)->blsize);
            } else {
                outpacket = packet;
                header->blsize = htons(payloadlen);
            }
            log2(0, 0, "Sending %s %d.%d", func_name(message), 
                       attempt, packetcnt);
            log4(0, 0, "Sending to %08X", ntohl(destaddr->sin_addr.s_addr));
            if (nb_sendto(sock, outpacket, payloadlen + sizeof(struct uftp_h),0,
                       (struct sockaddr *)destaddr,
                       sizeof(*destaddr)) == SOCKET_ERROR) {
                sockerror(0, 0, "Error sending %s", func_name(message));
                sleep(1);
                free(encpacket);
                return 0;
            }
            if (packet_wait) usleep(packet_wait);
            memset(addrlist, 0, maxdest * sizeof(uint32_t));
            dests = 0;
            packetcnt++;
        }
    }
    free(encpacket);
    return 1;
}
Ejemplo n.º 29
0
/**
 * Check a transfer phase message and pass to appropriate message handler,
 * decrypting first if necessary
 * Returns 1 on success, 0 on error
 */
int handle_transfer_phase(const unsigned char *packet, unsigned char *decrypted,
                          const struct sockaddr_in *receiver,
                          int blocks_this_sec, int section_offset,
                          int pass, int section, struct finfo_t *finfo)
{
    struct uftp_h *header;
    const unsigned char *message;
    int hostidx;
    unsigned int decryptlen, meslen;
    uint8_t *func;
    struct in_addr srcaddr;

    header = (struct uftp_h *)packet;
    hostidx = find_client(header->srcaddr);
    srcaddr.s_addr = header->srcaddr;
    if ((keytype != KEY_NONE) && (header->func == ENCRYPTED)) {
        if (hostidx == -1) {
            log1(0, 0, "Host %s not in host list", inet_ntoa(srcaddr));
            send_abort(finfo, "Not in host list", receiver, &srcaddr, 0, 0);
            return 0;
        }
        if (!validate_and_decrypt(packet, &decrypted, &decryptlen, mtu,
                keytype, groupkey, groupsalt, ivlen, hashtype, grouphmackey,
                hmaclen, sigtype, destlist[hostidx].encinfo->pubkey,
                destlist[hostidx].encinfo->pubkeylen)) {
            log1(0, 0, "Rejecting message from %s: decrypt/validate failed",
                        destlist[hostidx].name);
            return 0;
        }
        func = (uint8_t *)decrypted;
        message = decrypted;
        meslen = decryptlen;
    } else {
        if ((keytype != KEY_NONE) && ((header->func == PRSTATUS) ||
                (header->func == STATUS) || (header->func == COMPLETE) ||
                (header->func == ABORT))) {
            log1(0, 0, "Rejecting %s message from %s: not encrypted",
                       func_name(header->func), inet_ntoa(srcaddr));
            return 0;
        }
        func = (uint8_t *)&header->func;
        message = packet + sizeof(struct uftp_h);
        meslen = ntohs(header->blsize);
    }

    if (*func == ABORT) {
        handle_abort(message, meslen, hostidx, finfo, &srcaddr);
    } else if (hostidx == -1) {
        log1(0, 0, "Host %s not in host list", inet_ntoa(srcaddr));
        send_abort(finfo, "Not in host list", receiver, &srcaddr, 0, 0);
    } else {
        switch (destlist[hostidx].status) {
        case DEST_ACTIVE:
            if (*func == STATUS) {
                handle_status(message, meslen, finfo, hostidx,
                        blocks_this_sec, section_offset, pass, section);
            } else if (*func == COMPLETE) {
                handle_complete(message, meslen, finfo, hostidx);
            } else if ((destlist[hostidx].clientcnt != -1) &&
                       (*func == PRSTATUS)) {
                handle_prstatus(message, meslen, finfo, hostidx,
                        blocks_this_sec, section_offset, pass, section);
            } else {
                log1(0, 0, "Received invalid message %s from %s",
                           func_name(*func), destlist[hostidx].name);
            }
            break;
        case DEST_STATUS:
            if (*func == COMPLETE) {
                handle_complete(message, meslen, finfo, hostidx);
            } else if (*func == STATUS) {
                handle_status(message, meslen, finfo, hostidx,
                              blocks_this_sec, section_offset, pass, section);
            } else {
                log1(0, 0, "Received invalid message %s from %s",
                           func_name(*func), destlist[hostidx].name);
            }
            break;
        case DEST_DONE:
            if (*func == COMPLETE) {
                handle_complete(message, meslen, finfo, hostidx);
            } else {
                log1(0, 0, "Received invalid message %s from %s",
                           func_name(*func), destlist[hostidx].name);
            }
            break;
        }
    }
    return 1;
}
Ejemplo n.º 30
0
/**
 * This is the main message reading loop.  Messages are read, validated,
 * decrypted if necessary, then passed to the appropriate routine for handling.
 */
void mainloop()
{
    struct uftp_h *header;
    unsigned char *buf, *decrypted, *message;
    int packetlen, listidx, hostidx, i;
    unsigned int decryptlen, meslen;
    uint8_t *func;
    struct sockaddr_in src;
    struct in_addr srcaddr;
    struct timeval *tv;
    const int bsize = 9000;  // Roughly size of ethernet jumbo frame

    log0(0, 0, "%s", VERSIONSTR);
    for (i = 0; i < key_count; i++) {
        log(0, 0, "Loaded key with fingerprint %s",
                  print_key_fingerprint(privkey[i]));
    }

    buf = calloc(bsize, 1);
    decrypted = calloc(bsize, 1);
    if ((buf == NULL) || (decrypted == NULL)) {
        syserror(0, 0, "calloc failed!");
        exit(1);
    }
    header = (struct uftp_h *)buf;

    while (1) {
        tv = getrecenttimeout();
        if (read_packet(listener, &src, buf, &packetlen,
                        bsize, tv) <= 0) {
            continue;
        }

        if ((header->uftp_id != UFTP_VER_NUM) &&
                (header->uftp_id != UFTP_3_0_VER)) {
            log(0, 0, "Invalid message from %s: not uftp packet "
                      "or invalid version", inet_ntoa(src.sin_addr));
            continue;
        }
        if (packetlen != sizeof(struct uftp_h) + ntohs(header->blsize)) {
            log(0, 0, "Invalid packet size from %s: got %d, expected %d",
                      inet_ntoa(src.sin_addr), packetlen,
                      sizeof(struct uftp_h) + ntohs(header->blsize));
            continue;
        }

        if ((src.sin_addr.s_addr == out_addr.s_addr) &&
                (src.sin_port == htons(port))) {
            // Packet from self -- drop
            continue;
        }
        if (header->func == HB_REQ) {
            handle_hb_request(&src, buf);
            continue;
        }
        if (header->func == HB_RESP) {
            handle_hb_response(listener, &src, buf, hb_hosts, hbhost_count,
                               noname, privkey[0]);
            continue;
        }
        if (header->func == KEY_REQ) {
            handle_key_req(&src, buf);
            continue;
        }
        if (header->func == PROXY_KEY) {
            // Only clients handle these, so drop
            continue;
        }
        if ((proxy_type == SERVER_PROXY) &&
                (down_addr.sin_addr.s_addr == INADDR_ANY)) {
            log(0, 0, "Rejecting message from %s: downstream address "
                      "not established", inet_ntoa(src.sin_addr));
            continue;
        }

        listidx = find_group(ntohl(header->group_id));
        if (header->func == ANNOUNCE) {
            handle_announce(listidx, &src, buf);
        } else {
            if (listidx == -1) {
                continue;
            }
            if (proxy_type == SERVER_PROXY) {
                // Server proxies don't do anything outside of an ANNOUNCE.
                // Just send it on through.
                forward_message(listidx, &src, buf);
                continue;
            }
            if (header->func == ABORT) {
                handle_abort(listidx, &src, buf);
                continue;
            }
            if (!memcmp(&src, &group_list[listidx].up_addr, sizeof(src))) {
                // Downstream message
                if (header->func == KEYINFO) {
                    handle_keyinfo(listidx, buf);
                } else if ((header->func == REG_CONF) &&
                           (group_list[listidx].keytype != KEY_NONE)) {
                    handle_regconf(listidx, buf);
                } else {
                    // If we don't need to process the message, don't bother
                    // decrypting anything.  Just forward it on.
                    forward_message(listidx, &src, buf);
                }
            } else {
                // Upstream message
                // Decrypt first if necessary
                hostidx = find_client(listidx, header->srcaddr);
                if ((hostidx != -1) && (header->func == ENCRYPTED) &&
                        (group_list[listidx].keytype != KEY_NONE)) {
                    if (!validate_and_decrypt(buf, &decrypted, &decryptlen,
                            group_list[listidx].mtu,group_list[listidx].keytype,
                            group_list[listidx].groupkey,
                            group_list[listidx].groupsalt,
                            group_list[listidx].ivlen,
                            group_list[listidx].hashtype,
                            group_list[listidx].grouphmackey,
                            group_list[listidx].hmaclen,
                            group_list[listidx].sigtype,
                            group_list[listidx].destinfo[hostidx].pubkey,
                            group_list[listidx].destinfo[hostidx].pubkeylen)) {
                        log(ntohl(header->group_id), 0, "Rejecting message "
                                "from %s: decrypt/validate failed",
                                inet_ntoa(src.sin_addr));
                        continue;
                    }
                    func = (uint8_t *)decrypted;
                    message = decrypted;
                    meslen = decryptlen;
                } else {
                    if ((hostidx != -1) &&
                            (group_list[listidx].keytype != KEY_NONE) &&
                            ((header->func == INFO_ACK) ||
                             (header->func == STATUS) ||
                             (header->func == COMPLETE))) {
                        log(ntohl(header->group_id), 0, "Rejecting %s message "
                                "from %s: not encrypted", 
                                func_name(header->func),
                                inet_ntoa(src.sin_addr));
                        continue;
                    }
                    func = (uint8_t *)&header->func;
                    message = buf + sizeof(struct uftp_h);
                    meslen = ntohs(header->blsize);
                }

                if ((hostidx == -1) && (header->srcaddr == 0)) {
                    srcaddr = src.sin_addr;
                } else {
                    srcaddr.s_addr = header->srcaddr;
                }
                switch (*func) {
                case REGISTER:
                    handle_register(listidx, hostidx, message, meslen,
                                    srcaddr.s_addr);
                    break;
                case CLIENT_KEY:
                    handle_clientkey(listidx, hostidx, message, meslen,
                                     srcaddr.s_addr);
                    break;
                case INFO_ACK:
                    handle_info_ack(listidx, hostidx, message, meslen);
                    break;
                case STATUS:
                    handle_status(listidx, hostidx, message, meslen);
                    break;
                case COMPLETE:
                    handle_complete(listidx, hostidx, message, meslen);
                    break;
                default:
                    forward_message(listidx, &src, buf);
                    break;
                }
            }
        }
    }
}