/****************************************************************************** * Copyright (c) 2000-2019 Ericsson Telecom AB * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html * * Contributors: * Antal Wuh.Hen.Chang - initial implementation and initial documentation * Adam Delic * Andrea Darabos * Endre Kulcsar * Gabor Szalai * Tibor Szabo ******************************************************************************/ // // File: PCAPasp_PT.cc // Description: PCAP test port source file // Rev: R8A // Prodnr: CNL 113 443 // #include "PCAPasp_PT.hh" #include #include #include #include #include #include #include //#include //#include //#include //#include //#include #include #include #include #include #include "memory.h" using namespace PCAPasp__Types; namespace PCAPasp__PortType{ static const u_int16_t c_infinite = 0xFFFF; static bool logging = false; static bool noFilter = false; static Protocol_data p_data; static PCAPasp__PT *act_pt; INTEGER default_getMsgLen(const OCTETSTRING &stream, const BOOLEAN& /*conn__closed*/, const Transport &/*stream__transport*/){ return stream.lengthof(); } INTEGER default_getMsgStartPos(const OCTETSTRING &/*stream*/, const BOOLEAN& /*conn__closed*/, const Transport &/*stream__transport*/){ return 0; } static tf__getMsgLen def_getMsgLen_ref=default_getMsgLen; static tf__getMsgStartPos def_getMsgStartPos_ref=default_getMsgStartPos; void genlog(const char *fmt, ...) { TTCN_Logger::begin_event(TTCN_DEBUG); va_list ap; va_start(ap, fmt); TTCN_Logger::log_event_va_list(fmt, ap); va_end(ap); TTCN_Logger::end_event(); } INTEGER f_null_ICV(const OCTETSTRING& /*ipheader*/, const OCTETSTRING& /*ipdata*/, OCTETSTRING& /*user__data*/) { return 0; } BOOLEAN f_null_encryption(const OCTETSTRING& /*ipheader*/, const OCTETSTRING& ipdata, OCTETSTRING& decrypted__data, OCTETSTRING&/* user__data*/) { int ret_len=ipdata.lengthof(); int start_pos=0; if(ret_len>9){ int pad_len=((const unsigned char*)ipdata)[ret_len-1]; ret_len-=9+pad_len; // spi_length+seq_no_length+pad_length_length = 4+4+1 if(ret_len<0){ ret_len=ipdata.lengthof(); } else { start_pos=8;// skip spi+seq_no } } decrypted__data = OCTETSTRING(ret_len,(const unsigned char*)ipdata+start_pos); return TRUE; } ESP_obj::ESP_obj(PCAPasp__Types::ASP__PCAP__ESP__Setup data){ spi=data.spi().get_long_long_val(); if(data.icv__function().ispresent()){ icv_fv=data.icv__function(); } else { icv_fv=f_null_ICV; } if(data.icv__function__user__data().ispresent()){ icv_data=data.icv__function__user__data(); } else { icv_data=OCTETSTRING(0,NULL); } if(data.esp__decrypt__function().ispresent()){ decrypt_fv=data.esp__decrypt__function(); } else { decrypt_fv=f_null_encryption; } if(data.esp__decrypt__function__user__data().ispresent()){ decrypt_data=data.esp__decrypt__function__user__data(); } else { decrypt_data=OCTETSTRING(0,NULL); } struct in_addr tmp; if(data.sourceIP().ispresent() && inet_aton((const char *)data.sourceIP()(),&tmp)){ ip_port=std::string((const char *)&tmp,sizeof(tmp)); } else { ip_port=std::string(0,sizeof(tmp)); } if(data.destinationIP().ispresent() && inet_aton((const char *)data.destinationIP()(),&tmp)){ ip_port+=std::string((const char *)&tmp,sizeof(tmp)); } else { ip_port+=std::string(0,sizeof(tmp)); } u_int16_t tmp2; if(data.sourcePort().ispresent()){ tmp2=htons(data.sourcePort()()); } else { tmp2=0; } ip_port+=std::string((const char *)&tmp2,sizeof(tmp2)); if(data.destinationPort().ispresent()){ tmp2=htons(data.destinationPort()()); } else { tmp2=0; } ip_port+=std::string((const char *)&tmp2,sizeof(tmp2)); mode=data.mode(); } ESP_obj::~ESP_obj(){} ESP_handler::ESP_handler(){} ESP_handler::~ESP_handler(){ clean_up(); } bool ESP_handler::setup_esp(PCAPasp__Types::ASP__PCAP__ESP__Setup data){ std::map::iterator it=spi_ESP_obj_map.find(data.spi().get_long_long_val()); if(data.mode() == PCAPasp__Types::ESP__mode::ESP__DELETE){ if(it==spi_ESP_obj_map.end()){ return false; } address_ESP_obj_map.erase((it->second)->ip_port); for (std::list::iterator it2=ESP_OBJ_list.begin(); it2 != ESP_OBJ_list.end(); ++it2){ if(*it2 == it->second) { ESP_OBJ_list.erase(it2); break; } } delete it->second; spi_ESP_obj_map.erase(it); return true; } else { if(it!=spi_ESP_obj_map.end()){ return false; } ESP_obj* new_esp=new ESP_obj(data); if(address_ESP_obj_map.find(new_esp->ip_port)!=address_ESP_obj_map.end()){ delete new_esp; return false; } address_ESP_obj_map[new_esp->ip_port]=new_esp; spi_ESP_obj_map[new_esp->spi]=new_esp; ESP_OBJ_list.push_back(new_esp); return true; } return false; } bool ESP_handler::find_esp(unsigned int spi, ESP_obj *& esp){ std::map::iterator it=spi_ESP_obj_map.find(spi); if(it==spi_ESP_obj_map.end()){ return false; } esp=it->second; return true; } bool ESP_handler::esp_exists(struct in_addr *ip_src, unsigned int port_src,struct in_addr *ip_dst,unsigned int port_dst,unsigned int /*proto*/){ u_int16_t p_src=port_src; u_int16_t p_dst=port_dst; if(address_ESP_obj_map.find(std::string((const char *)ip_src,sizeof(ip_src))+ std::string((const char *)ip_dst,sizeof(ip_dst))+ std::string((const char *)&p_src,sizeof(p_src))+ std::string((const char *)&p_dst,sizeof(p_dst)) )!=address_ESP_obj_map.end()){ return true; } if(address_ESP_obj_map.find(std::string((const char *)ip_src,sizeof(ip_src))+ std::string((const char *)ip_dst,sizeof(ip_dst))+ std::string(2,'\0')+ std::string((const char *)&p_dst,sizeof(p_dst)) )!=address_ESP_obj_map.end()){ return true; } if(address_ESP_obj_map.find(std::string((const char *)ip_src,sizeof(ip_src))+ std::string((const char *)ip_dst,sizeof(ip_dst))+ std::string((const char *)&p_src,sizeof(p_src))+ std::string(2,'\0') )!=address_ESP_obj_map.end()){ return true; } if(address_ESP_obj_map.find(std::string(4,'\0')+ std::string((const char *)ip_dst,sizeof(ip_dst))+ std::string(2,'\0')+ std::string((const char *)&p_dst,sizeof(p_dst)) )!=address_ESP_obj_map.end()){ return true; } if(address_ESP_obj_map.find(std::string(4,'\0')+ std::string((const char *)ip_dst,sizeof(ip_dst))+ std::string(2,'\0')+ std::string((const char *)&p_dst,sizeof(p_dst)) )!=address_ESP_obj_map.end()){ return true; } return false; } void ESP_handler::clean_up(){ spi_ESP_obj_map.clear(); address_ESP_obj_map.clear(); for (std::list::iterator it=ESP_OBJ_list.begin(); it != ESP_OBJ_list.end(); ++it){ delete *it; } ESP_OBJ_list.clear(); } bool ESP_handler::match_esp(struct in_addr *ip_src, unsigned int port_src,struct in_addr *ip_dst,unsigned int port_dst,const ESP_obj *esp){ u_int16_t p_src=port_src; u_int16_t p_dst=port_dst; return (esp->ip_port.substr(0,4)==std::string(4,'\0') || esp->ip_port.substr(0,4)==std::string((const char *)ip_src,sizeof(ip_src))) && (esp->ip_port.substr(4,4)==std::string(4,'\0') || esp->ip_port.substr(4,4)==std::string((const char *)ip_dst,sizeof(ip_dst))) && (esp->ip_port.substr(8,2)==std::string(2,'\0') || esp->ip_port.substr(8,2)==std::string((const char *)&p_src,sizeof(p_src))) && (esp->ip_port.substr(8,2)==std::string(2,'\0') || esp->ip_port.substr(8,2)==std::string((const char *)&p_dst,sizeof(p_dst))); } //////////////////////////////////////////////////////////// // Constructor //////////////////////////////////////////////////////////// PCAPasp__PT::PCAPasp__PT(const char *par_port_name) : PCAPasp__PT_BASE(par_port_name) { capture_file = NULL; packet_filter = new char[1]; packet_filter[0] = '\0'; logging = false; handle = NULL; dumpfile = NULL; //for debugging: peer_list_tcp.setType(true); peer_list_udp.setType(false); peer_list_sctp.setType(false); } //////////////////////////////////////////////////////////// // Destructor //////////////////////////////////////////////////////////// PCAPasp__PT::~PCAPasp__PT() { if (capture_file) delete [] capture_file; if (packet_filter) delete [] packet_filter; } //////////////////////////////////////////////////////////// // set_parameter //////////////////////////////////////////////////////////// void PCAPasp__PT::set_parameter(const char *parameter_name, const char *parameter_value) { //Capturing related parameters if (strcmp("capture_file", parameter_name) == 0) { if (capture_file) delete [] capture_file; capture_file = new char[strlen(parameter_value) + 1]; strcpy(capture_file, parameter_value); } else if (strcmp("packet_filter", parameter_name) == 0) { if (packet_filter) delete [] packet_filter; packet_filter = new char[strlen(parameter_value) + 1]; strcpy(packet_filter, parameter_value); } else if (strcmp("logging", parameter_name) == 0) { if (strcasecmp(parameter_value, "TRUE") == 0) { logging = true; } else logging = false; } else if (strcmp("noFilter", parameter_name) == 0) { if (strcasecmp(parameter_value, "TRUE") == 0) { noFilter = true; } else noFilter = false; } else TTCN_warning("PCAP Test Port(%s): Invalid parameter: %s.",port_name ,parameter_name); } //////////////////////////////////////////////////////////// // Event_Handler //////////////////////////////////////////////////////////// void PCAPasp__PT::Event_Handler(const fd_set */*read_fds*/, const fd_set */*write_fds*/, const fd_set */*error_fds*/, double /*time_since_last_call*/) { const u_char* packet; packet = pcap_next( handle, &header); if (packet == NULL) TTCN_error("PCAP can't capture"); if (capture) pcap_dump((u_char*)dumpfile, &header, packet); } //////////////////////////////////////////////////////////// // user_map //////////////////////////////////////////////////////////// void PCAPasp__PT::user_map(const char */*system_port*/) { if( geteuid() != 0 ) TTCN_warning ( "You must be root to be able to use the test port in capturing mode!"); capture = 0; settings = 0; if (capture_file!=NULL){ if (dump_reader.open(capture_file)==false) { TTCN_error("Failed to open capture file \"%s\"", capture_file); return; } else { log("Capture file \"%s\" was opened", capture_file); } } if (packet_filter!=NULL){ if (dump_reader.setFilter(packet_filter)==false) { TTCN_error("Failed to set the packet filter %s", packet_filter); return; } else { log("Filter \"%s\" was applied", packet_filter); } } } //////////////////////////////////////////////////////////// // user_unmap //////////////////////////////////////////////////////////// void PCAPasp__PT::user_unmap(const char */*system_port*/) { peer_list_tcp.log_stat(); Uninstall_Handler(); filter_table.clear(); if (handle) pcap_close( handle); if (dumpfile) pcap_dump_close( dumpfile); } void PCAPasp__PT::user_start() { } void PCAPasp__PT::user_stop() { } //////////////////////////////////////////////////////////// // outgoing_send //////////////////////////////////////////////////////////// void PCAPasp__PT::outgoing_send(const PCAPasp__Types::ASP__PCAP__ESP__Setup& send_par){ PCAPasp__Types::ASP__PCAP__ESP__Setup__Resp ret_val; if(esp.setup_esp(send_par)){ ret_val.status__code()=PCAPasp__Types::ESP__Status::ESP__OK; ret_val.status__message()=OMIT_VALUE; } else { ret_val.status__code()=PCAPasp__Types::ESP__Status::ESP__SETUP__ERROR; ret_val.status__message()="Failed to register the ESP"; } incoming_message(ret_val); } void PCAPasp__PT::outgoing_send(const PCAPasp__Types::ASP__PCAP__Capture& send_par) { PCAPasp__Types::ASP__PCAP__ConfigResp myStatus; fd_set readfds; myStatus.status() = CommandStatus::INVALID; myStatus.errorMessage() = OMIT_VALUE; if( send_par.command() == CaptureControl::START ) { myStatus.command() = CommandId::STARTCMD; if (settings) { if (capture) { myStatus.errorMessage() = CommandError::CAPTURING__HAS__ALREADY__STARTED; } else { myStatus.status() = CommandStatus::VALID; capture = 1; FD_ZERO( &readfds); FD_SET( pcap_fileno( handle), &readfds ); Install_Handler( &readfds, NULL, NULL, 0.0 ); } } else { myStatus.errorMessage() = CommandError::THERE__IS__NO__FILTER__SET; } } else if( send_par.command() == CaptureControl::STOP ) { myStatus.command() = CommandId::STOPCMD; if (capture) { myStatus.status() = CommandStatus::CommandStatus::VALID; capture = 0; } else { myStatus.errorMessage() = CommandError::CAPTURING__HAS__NOT__STARTED; } } incoming_message( myStatus ); } //////////////////////////////////////////////////////////// // outgoing_send //////////////////////////////////////////////////////////// void PCAPasp__PT::outgoing_send(const PCAPasp__Types::ASP__PCAP__ConfigReq& send_par) { struct bpf_program filter; char errbuf[PCAP_ERRBUF_SIZE]; bpf_u_int32 mask; bpf_u_int32 net; CHARSTRING myInterface; CHARSTRING myFilter; INTEGER myMask; PCAPasp__Types::ASP__PCAP__ConfigResp myStatus; myStatus.command() = CommandId::FILTERCMD; myStatus.status() = CommandStatus::INVALID; myStatus.errorMessage() = OMIT_VALUE; if (capture) { myStatus.errorMessage() = CommandError::PORT__IS__ALREADY__CAPTURING; } else { settings = 0; Uninstall_Handler(); if( dumpfile != NULL){ pcap_dump_close( dumpfile); dumpfile = NULL; } if (send_par.interface().ispresent()) myInterface = send_par.interface(); else myInterface = "eth0"; if (send_par.filter().ispresent()) myFilter = send_par.filter(); else myFilter = ""; if (send_par.mask().ispresent()) myMask = send_par.mask(); else myMask = 0xffffff; char* myFilterString = new char[strlen(myFilter) + 1]; strcpy(myFilterString, (const char*)myFilter); if( pcap_lookupnet( myInterface, &net, &mask, errbuf) == -1){ myStatus.errorMessage() = CommandError::ERROR__LOOKING__NET__UP; } else { handle = pcap_open_live( myInterface, 1514, 1, 0, errbuf); if( handle == NULL ){ myStatus.errorMessage() = CommandError::ERROR__LIVE__OPENING; } else if( pcap_compile( handle, &filter, myFilterString, 0, myMask) == -1){ myStatus.errorMessage() = CommandError::ERROR__COMPILING__FILTER; } else if( pcap_setfilter( handle, &filter) == -1 ){ myStatus.errorMessage() = CommandError::ERROR__SETTING__FILTER; } else if( pcap_setnonblock( handle, 1, errbuf) == -1 ){ myStatus.errorMessage() = CommandError::ERROR__SETTING__NONBLOCK__MODE; } else { dumpfile = pcap_dump_open( handle, (const char*)send_par.filename()); if( dumpfile == NULL) { myStatus.errorMessage() = CommandError::ERROR__OPENING__OUTPUT__FILE; } else { settings = 1; myStatus.status() = CommandStatus::CommandStatus::VALID; } } } if (myFilterString) delete [] myFilterString; } incoming_message( myStatus ); } //////////////////////////////////////////////////////////// // outgoing_send //////////////////////////////////////////////////////////// void PCAPasp__PT::outgoing_send(const PCAPasp__Types::ASP__PCAP__DumpReaderFilter& send_par) { PCAPasp__Types::ASP__PCAP__DumpFilterResp respStatus; bool srcIpAll = strcmp(send_par.localIp(), "*") == 0; if (!srcIpAll && !isValidIp(send_par.localIp())) { respStatus.status() = CommandStatus::INVALID; respStatus.errorMessage() = DumpFilterError::WRONG__SOURCE__IP; incoming_message( respStatus ); return; } if (!isValidIp(send_par.remoteIp())) { respStatus.status() = CommandStatus::INVALID; respStatus.errorMessage() = DumpFilterError::WRONG__DESTINATION__IP; incoming_message( respStatus ); return; } respStatus.status() = CommandStatus::CommandStatus::VALID; respStatus.errorMessage() = OMIT_VALUE; incoming_message( respStatus ); for (int portIdx=0; portIdx < send_par.remotePorts().size_of(); portIdx++) { std::string sourceIp(send_par.localIp()); std::string destinationIp(send_par.remoteIp()); filter_table.addEntry( (int) send_par.messageType(), sourceIp, srcIpAll, destinationIp, (unsigned int) send_par.remotePorts()[portIdx]); } } bool PCAPasp__PT::isValidIp(CHARSTRING addressToValidate) { return isValidIp4(addressToValidate) || isValidIp6(addressToValidate); } bool PCAPasp__PT::isValidIp4(CHARSTRING addressToValidate) { in_addr ip; return inet_pton(AF_INET, addressToValidate, &ip) == 1; } bool PCAPasp__PT::isValidIp6(CHARSTRING addressToValidate) { in6_addr ip; return inet_pton(AF_INET6, addressToValidate, &ip) == 1; } //////////////////////////////////////////////////////////// // outgoing_send //////////////////////////////////////////////////////////// void PCAPasp__PT::outgoing_send(const PCAPasp__Types::ASP__PCAP__MessageReq& send_par) { PCAPasp__Types::ASP__PCAP__MessageResp incoming_msg; TCPSegment* seg = NULL; bool ready_message = false; bool no_more_message = false; do { Peer* act_peer; for (int i=0; itcp_buf.length > 0) { // is there anything in the buffer? log("peer_list_tcp, peer %d", i); embedded_length=act_peer->get_msg_len(); log("peer_list_tcp, embedded_length %d", embedded_length); if(embedded_length>0){ if (send_par.nextMessage() == act_peer->protocol_type || send_par.nextMessage() == -1) { ready_message=true; incoming_msg.status() = Status::VALID__MESSAGE; incoming_msg.timeStamp() = act_peer->tcp_buf.timestamp; incoming_msg.contentLength() = embedded_length; incoming_msg.sourcePort() = act_peer->port_src; incoming_msg.destinationPort() = act_peer->port_dst; incoming_msg.sourceIP() = act_peer->ip_src.c_str(); incoming_msg.destinationIP() = act_peer->ip_dst.c_str(); incoming_msg.msgtype()=act_peer->protocol_type; incoming_msg.nextMessage()=OCTETSTRING(embedded_length,act_peer->tcp_buf.get_read_data()); incoming_message(incoming_msg); } act_peer->tcp_buf.set_pos(act_peer->tcp_buf.get_pos()+embedded_length); act_peer->tcp_buf.cut(); } } // if peer's buffer > 0 if(embedded_length<=0 && act_peer->tcp_buf.closed && !act_peer->tcp_buf.close_sent){ act_peer->tcp_buf.close_sent=true; ASP__PCAP__ConnectionClosed apcc_msg; apcc_msg.protocol() = act_peer->protocol_type; apcc_msg.destinationPort() = act_peer->port_dst; apcc_msg.destinationIP() = act_peer->ip_dst.c_str(); apcc_msg.sourcePort() = act_peer->port_src; apcc_msg.sourceIP() = act_peer->ip_src.c_str(); incoming_message(apcc_msg); } if(ready_message) break; } // for each tcp peer if (!ready_message) //if no requested message was found we iterate through the UDP streams as well. for (int i=0; itcp_buf.length > 0) { // is there anything in the buffer? int embedded_length=act_peer->get_msg_len(); if(embedded_length>0){ if (send_par.nextMessage() == act_peer->protocol_type || send_par.nextMessage() == -1) { ready_message=true; incoming_msg.status() = Status::VALID__MESSAGE; incoming_msg.timeStamp() = act_peer->tcp_buf.timestamp; incoming_msg.contentLength() = embedded_length; incoming_msg.sourcePort() = act_peer->port_src; incoming_msg.destinationPort() = act_peer->port_dst; incoming_msg.sourceIP() = act_peer->ip_src.c_str(); incoming_msg.destinationIP() = act_peer->ip_dst.c_str(); incoming_msg.msgtype()=act_peer->protocol_type; incoming_msg.nextMessage()=OCTETSTRING(embedded_length,act_peer->tcp_buf.get_data()); incoming_message(incoming_msg); } act_peer->tcp_buf.set_pos(embedded_length); act_peer->tcp_buf.cut(); } } // if peer's buffer > 0 if(ready_message) break; } // for each udp peer if (!ready_message) //if no requested message was found we iterate through the SCTP streams as well. for (int i=0; ihas_message()) { // is there anything in the buffer? int embedded_length=act_peer->get_first_sctp_data_len(); if(embedded_length>0){ if (send_par.nextMessage() == act_peer->protocol_type || send_par.nextMessage() == -1) { ready_message=true; incoming_msg.status() = Status::VALID__MESSAGE; incoming_msg.timeStamp() = act_peer->get_first_sctp_timestamp(); incoming_msg.contentLength() = embedded_length; incoming_msg.sourcePort() = act_peer->port_src; incoming_msg.destinationPort() = act_peer->port_dst; incoming_msg.sourceIP() = act_peer->ip_src.c_str(); incoming_msg.destinationIP() = act_peer->ip_dst.c_str(); incoming_msg.msgtype()=act_peer->protocol_type; incoming_msg.nextMessage()=OCTETSTRING(embedded_length,act_peer->get_first_sctp_data()); incoming_message(incoming_msg); } act_peer->delete_first_sctp_message(); } } // if peer's buffer > 0 if(ready_message) break; } // for each sctp peer if (!ready_message) { act_pt=this; seg = getNextFilteredSegment(); if (seg) { seg->log(); if (seg->seg_type == SCTP_SEG && seg->fin) { //PCAP_ASP_ConnectionClosed must be sent to TTCN in case a TCP connection is terminated ASP__PCAP__ConnectionClosed apcc_msg; apcc_msg.protocol() = seg->protocol_type; apcc_msg.destinationPort() = seg->port_dst; apcc_msg.destinationIP() = seg->ip_dst.c_str(); apcc_msg.sourcePort() = seg->port_src; apcc_msg.sourceIP() = seg->ip_src.c_str(); incoming_message(apcc_msg); } if (seg->seg_type == TCP_SEG) { INTEGER port_dst = seg->port_dst; INTEGER port_src = seg->port_src; CHARSTRING ip_src = seg->ip_src.c_str(); CHARSTRING ip_dst = seg->ip_dst.c_str(); if (!peer_list_tcp.sendSegmentToPeer(seg)) { //We detected a lost segment. //Note that, the source and destination directions are exchanged //because the lost segment was in other direction than the acknowledgment //via we detected it. ASP__PCAP__Error ape; ape.errorType() = PCAPError::LOST__SEGMENT; ape.sourcePort() = port_dst; ape.destinationPort() = port_src; ape.sourceIP() = ip_dst; ape.destinationIP() = ip_src; incoming_message(ape); } } else if (seg->seg_type == UDP_SEG) { peer_list_udp.sendSegmentToPeer(seg); } else if (seg->seg_type == SCTP_SEG) { INTEGER port_dst = seg->port_dst; INTEGER port_src = seg->port_src; CHARSTRING ip_src = seg->ip_src.c_str(); CHARSTRING ip_dst = seg->ip_dst.c_str(); if (!peer_list_sctp.sendSegmentToPeer(seg)) { //We detected a lost segment. //Note that, the source and destination directions are exchanged //because the lost segment was in other direction than the acknowledgment //via we detected it. ASP__PCAP__Error ape; ape.errorType() = PCAPError::LOST__SEGMENT; ape.sourcePort() = port_dst; ape.destinationPort() = port_src; ape.sourceIP() = ip_dst; ape.destinationIP() = ip_src; incoming_message(ape); } } } else no_more_message = true; } } while (!no_more_message && !ready_message); //No more messages in the dump file if (no_more_message) { incoming_msg.status() = Status::NO__MESSAGE; incoming_msg.timeStamp() = OMIT_VALUE; incoming_msg.contentLength() = OMIT_VALUE; incoming_msg.sourcePort() = OMIT_VALUE; incoming_msg.destinationPort() = OMIT_VALUE; incoming_msg.sourceIP() = OMIT_VALUE; incoming_msg.destinationIP() = OMIT_VALUE; incoming_msg.msgtype()= OMIT_VALUE; incoming_msg.nextMessage() = OMIT_VALUE; incoming_message(incoming_msg); if (logging){ log("stream buffers:"); peer_list_tcp.dump(); peer_list_udp.dump(); } } } void PCAPasp__PT::outgoing_send(const PCAPasp__Types::ASP__PACP__SetupProtocol& send_par){ p_data.add_protocol(send_par.protocol__id(), send_par.getMsgLen__function().ispresent()?send_par.getMsgLen__function()():default_getMsgLen, send_par.getMsgStartPos__function().ispresent()?send_par.getMsgStartPos__function()():default_getMsgStartPos ); } //////////////////////////////////////////////////////////// // getNextFilteredSegment //////////////////////////////////////////////////////////// TCPSegment* PCAPasp__PT::getNextFilteredSegment() { TCPSegment* seg = NULL; int protocol_type; bool found = false; do { seg = dump_reader.getNextSegment(); if (!seg) { break; } protocol_type = filter_table.filter(seg); log("Check protocol"); if (protocol_type != NO_PROTOCOL) { log("found protocol"); seg->protocol_type = protocol_type; found = true; } else { log("no protocol"); delete seg; seg = NULL; } } while (!found); return seg; } void PCAPasp__PT::log(const char *fmt, ...) { TTCN_Logger::begin_event(TTCN_DEBUG); TTCN_Logger::log_event("PCAPasp_PT: "); va_list ap; va_start(ap, fmt); TTCN_Logger::log_event_va_list(fmt, ap); va_end(ap); TTCN_Logger::end_event(); } //////////////////////////////////////////////////////////// // TCPSegment implementation //////////////////////////////////////////////////////////// TCPSegment::TCPSegment(in_addr src, in_addr dst) { this->init(); char buff[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &src, buff, INET_ADDRSTRLEN); this->ip_src = buff; inet_ntop(AF_INET, &dst, buff, INET_ADDRSTRLEN); this->ip_dst = buff; } TCPSegment::TCPSegment(in6_addr src, in6_addr dst) { this->init(); char buff[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, &src, buff, INET6_ADDRSTRLEN); this->ip_src = buff; inet_ntop(AF_INET6, &dst, buff, INET6_ADDRSTRLEN); this->ip_dst = buff; } void TCPSegment::init() { payload = NULL; length = 0; syn = false; fin = false; seq_num = 0; ack_num = 0; seg_type = TCP_SEG; protocol_type = NO_PROTOCOL; timestamp = 0.0; } TCPSegment::~TCPSegment() { if (payload) delete [] payload; } void TCPSegment::put(char* buf, size_t size) { if (size>0) { if (payload) delete [] payload; payload = new unsigned char[size]; memcpy(payload, buf, size); length = size; } else { if (payload) delete [] payload; payload = NULL; length = 0; } } void TCPSegment::log(const char *fmt, ...) { TTCN_Logger::begin_event(TTCN_DEBUG); TTCN_Logger::log_event("TCPSegment: "); va_list ap; va_start(ap, fmt); TTCN_Logger::log_event_va_list(fmt, ap); va_end(ap); TTCN_Logger::end_event(); } void TCPSegment::log() { TTCN_Logger::begin_event(TTCN_DEBUG); TTCN_Logger::log_event("-=> TCPSegment object: \n"); TTCN_Logger::log_event("address %p ¦n", this); TTCN_Logger::log_event("IP src: %s ", ip_src.c_str()); TTCN_Logger::log_event("dst: %s\n", ip_dst.c_str()); TTCN_Logger::log_event("Port src: %d dst: %d\n", port_src, port_dst); switch (seg_type) { case UDP_SEG: TTCN_Logger::log_event("UDP segment len:%zu\n", length); break; case TCP_SEG: TTCN_Logger::log_event("TCP segment len:%zu seq:%lu ack:%lu", length, seq_num, ack_num); if (syn) TTCN_Logger::log_event(" SYN\n"); else TTCN_Logger::log_event("\n"); break; } u_char* dataptr = (u_char*) payload; for (u_int i=1; i= 0) return true; else { if(res == -1) { TTCN_warning("Error reading the packets: %s", pcap_geterr(fp)); } return false; } } else { TTCN_warning("No capture file is set"); return false; } } bool DumpReader::setFilter(char* filter_script, bpf_u_int32 netmask) { if (strlen(filter_script) != 0) { if(pcap_compile(fp, &BPFcode, filter_script, 1, netmask)<0) { TTCN_warning("Unable to compile the filter. check the syntax: %s", filter_script); return false; } if(pcap_setfilter(fp, &BPFcode)<0) { TTCN_warning("Error setting the filter: %s", filter_script); return false; } } return true; } bool DumpReader::getNextEthernet() { while (getNext()) { struct ::ether_header* ether_ptr = (struct ::ether_header *) actData; u_short protocol_type = ntohs (ether_ptr->ether_type); if ( protocol_type == ETHERTYPE_IP || protocol_type == ETHERTYPE_IPV6 ) { actEthernetHeader = ether_ptr; actEthernetData = const_cast(actData); actEthernetData += sizeof(struct ::ether_header); return true; } else if ( protocol_type == PCAP_ETHERTYPE_VLAN8021Q ) { struct vlan_header* vlan_ptr = (struct vlan_header*) (const_cast(actData) + sizeof(struct ::ether_header)); if (ntohs(vlan_ptr->vlan_type) != ETHERTYPE_IP) { TTCN_warning("Not an IP datagram in VLAN 802.1Q packet"); continue; } actEthernetHeader = ether_ptr; actEthernetData = const_cast(actData); actEthernetData += sizeof(struct ::ether_header) + sizeof(vlan_header); return true; } else { TTCN_warning("Not an IP datagram or unknown Ethernet header"); } } return false; } unsigned int DumpReader::ipVersion() { /* * First 4 bits of both IPv4 and v6 header is version of IP. * * example values: * actEthernetData[0] contains first 8 bits: 0010 1010 * ...so, we need to clear last 4: 0010 0000 * ...and shift everything: 0000 0010 */ return (actEthernetData[0] & 0xf0) >> 4; } bool DumpReader::getNextIP() { free_ptr = false; while (this->getNextEthernet()) { this->version = ipVersion(); if (this->version == 4) { struct ip_header* ip_ptr = (struct ip_header *) actEthernetData; unsigned int len = ntohs(ip_ptr->ip_len); u_int hlen = IP_HL(ip_ptr); /* make sure that the packet is at least as long as the min IP header */ if (actHeader->caplen > sizeof(struct ip_header)) { /* check and see if we got everything. NOTE: we must use * ip_total_len after this, because we may have captured bytes * beyond the end of the packet (e.g. ethernet padding). */ if (actHeader->caplen >= len) { /* IP_sec decoding */ if(ip_ptr->ip_p == IPPROTO_ESP){ if((len-hlen*4)>10) { // minimum size of the ESP unsigned int spi=(((unsigned int)actEthernetData[hlen*4])<<24)+(((unsigned int)actEthernetData[hlen*4+1])<<16)+(((unsigned int)actEthernetData[hlen*4+2])<<8)+actEthernetData[hlen*4+3]; ESP_obj *espobj; if(act_pt->esp.find_esp(spi,espobj)){ int icv_len=espobj->icv_fv.invoke(OCTETSTRING(hlen*4,(const unsigned char*)actEthernetData), OCTETSTRING(len-hlen*4,(const unsigned char*)actEthernetData+hlen*4), espobj->icv_data); if(icv_len>=0){ // valid ICV int proto=*((const unsigned char*)actEthernetData+len-icv_len); OCTETSTRING decrypted_data; if(espobj->decrypt_fv.invoke(OCTETSTRING(hlen*4,(const unsigned char*)actEthernetData), OCTETSTRING(len-hlen*4-icv_len-1,(const unsigned char*)actEthernetData+hlen*4), decrypted_data, espobj->decrypt_data)){ ip_ptr->ip_p=proto; ip_ptr->ip_len=htons(hlen*4+decrypted_data.lengthof()); unsigned char* dataptr=(unsigned char*)actEthernetData+hlen*4; memcpy(actEthernetData+hlen*4,(const unsigned char*)decrypted_data,decrypted_data.lengthof()); if(!act_pt->esp.match_esp(&(ip_ptr->ip_src),(dataptr[0]<<8)+dataptr[1],&(ip_ptr->ip_dst),(dataptr[2]<<8)+dataptr[3],espobj)){ // The ESP registered for different address PCAPasp__Types::ASP__PCAP__ESP__Report ret_val; ret_val.status__code()=PCAPasp__Types::ESP__Status::ESP__WRONG__SPI; ret_val.spi().set_long_long_val(spi); ret_val.destinationIP()=inet_ntoa(ip_ptr->ip_dst); ret_val.destinationPort()=OMIT_VALUE; ret_val.sourceIP()=inet_ntoa(ip_ptr->ip_src); ret_val.sourcePort()=OMIT_VALUE; ret_val.payload__transport()=-1; act_pt->inc_msg(ret_val); } } else { // decrypt failed PCAPasp__Types::ASP__PCAP__ESP__Report ret_val; ret_val.status__code()=PCAPasp__Types::ESP__Status::ESP__DECRYPT__ERROR; ret_val.spi().set_long_long_val(spi); ret_val.destinationIP()=inet_ntoa(ip_ptr->ip_dst); ret_val.destinationPort()=OMIT_VALUE; ret_val.sourceIP()=inet_ntoa(ip_ptr->ip_src); ret_val.sourcePort()=OMIT_VALUE; ret_val.payload__transport()=-1; act_pt->inc_msg(ret_val); } } else { PCAPasp__Types::ASP__PCAP__ESP__Report ret_val; ret_val.status__code()=PCAPasp__Types::ESP__Status::ESP__ICV__ERROR; ret_val.spi().set_long_long_val(spi); ret_val.destinationIP()=inet_ntoa(ip_ptr->ip_dst); ret_val.destinationPort()=OMIT_VALUE; ret_val.sourceIP()=inet_ntoa(ip_ptr->ip_src); ret_val.sourcePort()=OMIT_VALUE; ret_val.payload__transport()=-1; act_pt->inc_msg(ret_val); } } else { // no esp data found PCAPasp__Types::ASP__PCAP__ESP__Report ret_val; ret_val.status__code()=PCAPasp__Types::ESP__Status::ESP__NOT__DEFINED; ret_val.spi().set_long_long_val(spi); ret_val.destinationIP()=inet_ntoa(ip_ptr->ip_dst); ret_val.destinationPort()=OMIT_VALUE; ret_val.sourceIP()=inet_ntoa(ip_ptr->ip_src); ret_val.sourcePort()=OMIT_VALUE; ret_val.payload__transport()=-1; act_pt->inc_msg(ret_val); } } } else { // Needs more test /* unsigned char* dataptr=(unsigned char*)actEthernetData+hlen*4; if(act_pt->esp.esp_exists( &(ip_ptr->ip_src),(dataptr[0]<<8)+dataptr[1],&(ip_ptr->ip_dst),(dataptr[2]<<8)+dataptr[3],ip_ptr->ip_p)){ // ESP data registered for this address PCAPasp__Types::ASP__PCAP__ESP__Report ret_val; ret_val.status__code()=PCAPasp__Types::ESP__Status::NOT__ESP__PACKET; ret_val.spi()=-1; ret_val.destinationIP()=inet_ntoa(ip_ptr->ip_dst); ret_val.destinationPort()=OMIT_VALUE; ret_val.sourceIP()=inet_ntoa(ip_ptr->ip_src); ret_val.sourcePort()=OMIT_VALUE; ret_val.payload__transport()=-1; act_pt->inc_msg(ret_val); }*/ } if (!(ntohs(ip_ptr->ip_off) & (IP_OFFMASK | IP_MF))) { // no fragmentation /* We found it! */ actIPHeader = ip_ptr; actIPData = (u_char*) actEthernetData+(hlen << 2); TTCN_warning("whole IP datagramm"); return true; } else{ actIPHeader = ip_ptr; actIPData = (u_char*) actEthernetData+(hlen << 2); TTCN_warning("fragfmented IP datagramm"); if(fragment_buffer.add_ip_fragment(&actIPHeader,&actIPData)){ free_ptr = true; TTCN_warning("last fragfment IP datagramm"); return true; } } } else TTCN_warning("Captured only %d bytes of %d-byte IP datagram", actHeader->caplen, len); } else TTCN_warning("Received truncated IP datagram!"); } else if (this->version == 6) { // Warning: IPSec for IP v6 not implemented yet actIPv6Header = (struct ip6_header *) this->actEthernetData; actIPData = this->actEthernetData + IP6_HEADER_LEN; return true; } else { TTCN_warning("Unknown IP version: %d", this->version); } } return false; } TCPSegment* DumpReader::getNextSegment() { while (getNextIP()) { u_int8_t transport_layer_proto; u_int ip_total_len; u_int ip_header_len; TCPSegment* ret_seg = NULL; switch (this->version) { case 4: { ret_seg = new TCPSegment( actIPHeader->ip_src, actIPHeader->ip_dst); ip_total_len = ntohs(actIPHeader->ip_len); ip_header_len = IP_HL(actIPHeader) * 4; // number of 32-bit words // needs to be multiplied by 4 to get number of octets transport_layer_proto = this->actIPHeader->ip_p; } break; case 6:{ ret_seg = new TCPSegment( actIPv6Header->ip_src, actIPv6Header->ip_dst); ip_header_len = IP6_HEADER_LEN; ip_total_len = actIPv6Header->ip_len + ip_header_len; transport_layer_proto = this->actIPv6Header->next_header; } break; } switch (transport_layer_proto) { case IPPROTO_TCP: { actTCPHeader = (struct tcphdr *) actIPData; u_int tcp_header_len = TCP_OFF(actTCPHeader) * 4; actTCPData = (u_char*) actTCPHeader + tcp_header_len; ret_seg->seg_type = TCP_SEG; u_int tcp_total_len = ip_total_len - ip_header_len; u_int tcp_data_len = tcp_total_len - tcp_header_len; ret_seg->port_src = ntohs(actTCPHeader->th_sport); ret_seg->port_dst = ntohs(actTCPHeader->th_dport); ret_seg->seq_num = ntohl(actTCPHeader->th_seq); ret_seg->ack_num = ntohl(actTCPHeader->th_ack); if (actTCPHeader->th_flags & TH_SYN) ret_seg->syn = true; if (actTCPHeader->th_flags & TH_FIN) ret_seg->fin = true; ret_seg->put((char*) actTCPData, (size_t) tcp_data_len); break; } case IPPROTO_UDP: { actUDPHeader = (struct udphdr *) actIPData; u_int udp_total_len = ntohs(actUDPHeader->uh_ulen); actUDPData = ((u_char*) (actUDPHeader))+8; u_int udp_data_len = udp_total_len-8; ret_seg->seg_type = UDP_SEG; ret_seg->port_src = ntohs(actUDPHeader->uh_sport); ret_seg->port_dst = ntohs(actUDPHeader->uh_dport); ret_seg->put((char*) actUDPData, (size_t) udp_data_len); break; } case IPPROTO_SCTP: { actSCTPHeader = (struct sctphdr *) actIPData; const u_int sctp_header_len = 12; actSCTPData = (u_char*) actSCTPHeader + sctp_header_len; u_int sctp_total_len = ip_total_len - ip_header_len; u_int sctp_data_len = sctp_total_len - sctp_header_len; ret_seg->seg_type = SCTP_SEG; ret_seg->port_src = ntohs(actSCTPHeader->sh_sport); ret_seg->port_dst = ntohs(actSCTPHeader->sh_dport); ret_seg->put((char*) actSCTPData, (size_t) sctp_data_len); break; } default: continue; } ret_seg->timestamp = (double)actHeader->ts.tv_sec + (double)actHeader->ts.tv_usec/1.0e6; deallocateMemory(); return ret_seg; } return NULL; } void DumpReader::deallocateMemory() { if(free_ptr){ free_ptr=false; Free(actIPHeader); actIPHeader = NULL; Free(actIPData); } } //////////////////////////////////////////////////////////// // TCPBuffer implementation //////////////////////////////////////////////////////////// TCPBuffer::TCPBuffer() { length = 0; buffer = NULL; read_poi = buffer; total_length = 0; lost_length = 0; closed = false; close_sent = false; } TCPBuffer::~TCPBuffer() { if (buffer) delete [] buffer; } void TCPBuffer::clear() { log("cleared"); length = 0; if (buffer) delete [] buffer; buffer = NULL; read_poi = buffer; closed = false; close_sent = false; } bool TCPBuffer::ack(TCPSegment* segment) { if (segment != NULL) { if (segment->seg_type == TCP_SEG) { //If an acknowledgement arrives that is larger than the last //stored byte in the buffer, than a TCP segment must have been lost previously. //Because it would prevent the assembly of the stream, //we hop the gap - that was created by the lost segment - by clearing the buffer //It doesn't contain a valid message, because it would have already been processed then. //and setting it to sequence number of the acknowledgement. if (segment->ack_num > (seq_num + length+ closed)?1:0) { TTCN_warning("Lost TCP segment detected!: Current sequence number: %lu, size: %zu, acknowledgement number: %lu, closed: %s", seq_num, length, segment->ack_num, closed?"true":"false"); // - The buffer should be cleared. // - Saved segments must be dropped if their seq_num is smaller than the ack_num -> this one goes to the Peer class clear(); lost_length+=(segment->ack_num-seq_num-length); total_length+=(segment->ack_num-seq_num-length); seq_num = segment->ack_num; return false; } } } return true; } void TCPBuffer::log_stat(){ log("Total processed octets, including lost octets: %lu",total_length); log("Total lost octets: %lu",lost_length); if(total_length>0){ log("Quality of the recovered stream: %lu%%",(total_length-lost_length)*100/total_length); } else { log("Quality of the recovered stream: N/A"); } } bool TCPBuffer::put(TCPSegment* segment) { if (segment != NULL) { switch (segment->seg_type) { case TCP_SEG: { log("tcp segment is: seq:%lu size:%ld fin:%s\n", seq_num, length, segment->fin?"yes":"no"); if (segment->fin) {closed=true;} if ( (segment->seq_num <= seq_num + length ) && (segment->seq_num >= seq_num) && (segment->length > 0) ) { //The segment can be appended size_t old_pos = get_pos(); size_t new_size = segment->seq_num - seq_num + segment->length; unsigned char* tmp_buf = new unsigned char[new_size]; size_t from_orig_buffer = segment->seq_num - seq_num; memcpy(tmp_buf, buffer, from_orig_buffer); memcpy( (tmp_buf + from_orig_buffer), segment->payload, segment->length); if (buffer) delete [] buffer; buffer = tmp_buf; length = new_size; read_poi = buffer + old_pos; timestamp = segment->timestamp; total_length+=segment->length; if (logging){ log("tcp segment is appended: seq:%lu size:%ld old_pos:%lu from_orig:%lu\n", seq_num, length, old_pos, from_orig_buffer); } if (segment) { delete segment; segment = NULL; } return true; } else return false; } break; case UDP_SEG: { if (segment->length>0) { size_t old_pos = get_pos(); size_t new_size = length + segment->length; char* tmp_buf = new char[new_size]; memcpy(tmp_buf, buffer, length); memcpy(tmp_buf + length, segment->payload, segment->length); delete [] buffer; buffer = (unsigned char*) tmp_buf; length = new_size; read_poi = buffer + old_pos; timestamp = segment->timestamp; if (segment) { delete segment; segment = NULL; } if (logging) { log("udp segment is appended: seq:%lu size:%ld\n", seq_num, length); } return true; } else return false; } break; } } else return false; return false; } void TCPBuffer::rewind() { read_poi = buffer; } size_t TCPBuffer::get_pos() { return read_poi - buffer; } void TCPBuffer::set_pos(size_t pos) { if (pos > length) read_poi = buffer + length; else read_poi = buffer + pos; } size_t TCPBuffer::get_len() { return length; } unsigned char* TCPBuffer::get_data() { return buffer; } size_t TCPBuffer::get_read_len() { return length - get_pos(); } unsigned char* TCPBuffer::get_read_data() { return read_poi; } void TCPBuffer::cut() { size_t new_size = get_read_len(); int seq_offset = get_pos(); char* tmp_buf = new char[new_size]; if (new_size) memcpy(tmp_buf, read_poi, new_size); delete [] buffer; seq_num = seq_num + seq_offset; buffer = (unsigned char*) tmp_buf; read_poi = buffer; length = new_size; if (logging) { log("buffer is cut: seq:%lu size:%ld\n", seq_num, length); dump(); } } void TCPBuffer::cut(size_t cut_bytes) { if (cut_bytes > get_len()) cut_bytes = get_len(); size_t new_size = get_len()-cut_bytes; int seq_offset = cut_bytes; char* tmp_buf = new char[new_size]; if (new_size) memcpy(tmp_buf, buffer+cut_bytes, new_size); delete [] buffer; seq_num = seq_num + seq_offset; buffer = (unsigned char*) tmp_buf; read_poi = buffer; length = new_size; if (logging) { log("buffer is cut: seq:%lu size:%ld\n", seq_num, length); dump(); } } void TCPBuffer::log(const char *fmt, ...) { TTCN_Logger::begin_event(TTCN_DEBUG); TTCN_Logger::log_event("TCPBuffer: "); va_list ap; va_start(ap, fmt); TTCN_Logger::log_event_va_list(fmt, ap); va_end(ap); TTCN_Logger::end_event(); } void TCPBuffer::dump() { TTCN_Logger::begin_event(TTCN_DEBUG); TTCN_Logger::log_event("TCPBuffer: seq:%lu size:%d\n", seq_num, (int) length); unsigned char* dataptr = buffer; for (u_int i=1; i Vector < Type >::Vector () { size = 0; actual = 0; ar = NULL; } template < class Type > Vector < Type >::Vector (Vector < Type > &a) { ar = new Type *[size = a.size]; for (int i = 0; i < a.size; i++) ar[i] = a.ar[i]; } template < class Type > Vector < Type >::~Vector () { if (ar) delete[]ar; } template < class Type > Vector < Type > &Vector < Type >::operator = (Vector < Type > &a) { if (this != &a) { if (ar) delete[]ar; ar = new Type *[size = a.size]; for (int i = 0; i < a.size; i++) ar[i] = a.ar[i]; } return *this; } template < class Type > Type & Vector < Type >::operator[](int idx) { if (idx >= size) { Type **nar = new Type *[idx + 1]; if (ar) { for (int i = 0; i < size; i++) nar[i] = ar[i]; for (int j = size; j <= idx; j++) nar[j] = NULL; delete[]ar; } size = idx + 1; ar = nar; } actual = idx; return *ar[idx]; } template < class Type > Type * Vector < Type >::elementAt (int idx) { actual = idx; return &((*this)[idx]); } template < class Type > bool Vector < Type >::removeElementAt (int idx) { if ((idx < size) && size > 1) { Type **nar = new Type *[size - 1]; if (ar) { for (int i = 0; i < idx; i++) nar[i] = ar[i]; for (int j = idx; j < size - 1; j++) nar[j] = ar[j + 1]; delete[]ar; } size = size - 1; ar = nar; actual = idx - 1; return true; } else { if (idx >= size) return false; if (size == 1) { delete ar; ar = NULL; size = 0; return true; } } return false; } template < class Type > bool Vector < Type >::remove (int idx) { return removeElementAt (idx); } template < class Type > int Vector < Type >::length () { return size; } template < class Type > void Vector < Type >::append (Type * ptr) { Type **nar = new Type *[size + 1]; if (ar) { for (int i = 0; i < size; i++) nar[i] = ar[i]; delete[]ar; } ar = nar; ar[size] = ptr; actual = size; size++; } template < class Type > void Vector < Type >::addElement (Type * ptr) { append (ptr); } template < class Type > bool Vector < Type >::remove (Type * ptr) { for (int i = 0; i < size; i++) { if (ar[i] == ptr && ptr != NULL) { return removeElementAt (i); } } return false; } template < class Type > bool Vector < Type >::removeElement (Type * ptr) { return remove (ptr); } template < class Type > bool Vector < Type >::removeCurrent () { return removeElementAt (actual); } template < class Type > bool Vector < Type >::removeRef (Type * ptr) { return remove (ptr); } template < class Type > int Vector < Type >::find (Type * ptr) { for (int i = 0; i < size; i++) { if (ar[i] == ptr) { actual = i; return i; } } return -1; } template < class Type > Type * Vector < Type >::first () { if (ar) { actual = 0; return ar[0]; } else return NULL; } template < class Type > Type * Vector < Type >::last () { if (ar) { actual = size - 1; return ar[size - 1]; } else return NULL; } template < class Type > Type * Vector < Type >::next () { if (ar) { actual++; if (actual < size) return ar[actual]; else { actual = 0; return NULL; } } else return NULL; } template < class Type > Type * Vector < Type >::current () { if (ar) { if (actual < size) { return ar[actual]; } else return NULL; } else return NULL; } template < class Type > Type * Vector < Type >::prev () { if (ar) { if ((actual > 1) && (actual < size)) { actual--; return ar[actual]; } } else return NULL; } template < class Type > bool Vector < Type >::isEmpty () { if (size == 0){ return true;} return false; } template < class Type > void Vector < Type >::destruct () { if (ar) for (int i = 0; i < size; i++) { delete ar[i]; } if (ar) delete[]ar; size = 0; actual = 0; ar = NULL; } //////////////////////////////////////////////////////////// // Peer implementation //////////////////////////////////////////////////////////// Peer::Peer() { protocol_type = NO_PROTOCOL; out_of_sync = true; is_sctp = false; } Peer::Peer(TCPSegment* segment) { if (segment != NULL) { port_src = segment->port_src; port_dst = segment->port_dst; ip_src = segment->ip_src; ip_dst = segment->ip_dst; if(segment->seg_type!=SCTP_SEG){ is_sctp=false; if (segment->syn) { tcp_buf.seq_num = segment->seq_num + 1; } else { tcp_buf.seq_num = segment->seq_num; } } else { // stream_list.add_segment_to_stream(segment); is_sctp= true; } protocol_type = segment->protocol_type; transport_type = segment->seg_type; out_of_sync = true; log("created"); } } Peer::~Peer() { seg_list.destruct(); } void Peer::reset() { tcp_buf.clear(); seg_list.destruct(); out_of_sync = true; log("reset"); } void Peer::init(TCPSegment* segment) { if (segment != NULL) { port_src = segment->port_src; port_dst = segment->port_dst; ip_src = segment->ip_src; ip_dst = segment->ip_dst; if(segment->seg_type!=SCTP_SEG){ is_sctp=false; if (segment->syn) { tcp_buf.seq_num = segment->seq_num + 1; } else { tcp_buf.seq_num = segment->seq_num; } } else { // stream_list.add_segment_to_stream(segment); is_sctp= true; } protocol_type = segment->protocol_type; transport_type = segment->seg_type; out_of_sync = true; tcp_buf.put(segment); log("initialized"); } } bool Peer::compare(TCPSegment* segment) { if (segment == NULL) return false; return port_src == segment->port_src && port_dst == segment->port_dst && ip_src == segment->ip_src && ip_dst == segment->ip_dst; } bool Peer::sentBy(TCPSegment* segment) { if (segment == NULL) return false; return port_src == segment->port_dst && port_dst == segment->port_src && ip_src == segment->ip_dst && ip_dst == segment->ip_src; } int Peer::get_msg_len(){ if(is_sctp){ if(has_message()){ return get_first_sctp_data_len(); } } else if(!out_of_sync){ tf__getMsgLen getlen=p_data.get_f_getMsgLen(protocol_type); return getlen.invoke( OCTETSTRING(tcp_buf.get_read_len(),tcp_buf.get_read_data()), tcp_buf.closed, transport_type ); } return -1; } bool Peer::ack(TCPSegment* segment) { if (segment != NULL) { //In case the acknowledgment is larger than the last stored byte //the tcp_buf.ack clears the buffer and sets the seq_num to the ack_num if(!is_sctp){ if (!tcp_buf.ack(segment)) { TCPSegment* seg; log("acknowledgement recovering: out of sync"); out_of_sync = true; //First we locate that saved segment which has the smallest seq_num TCPSegment* first_saved_segment = NULL; int first_saved_segment_idx = 0; if (seg_list.length() > 0) { for (int i=0; iseq_num < first_saved_segment->seq_num) { first_saved_segment = seg; first_saved_segment_idx = i; } } else { first_saved_segment = seg; first_saved_segment_idx = i; } } //Then we put it into the buffer: if (first_saved_segment) { seg_list.removeElementAt(first_saved_segment_idx); tcp_buf.seq_num = first_saved_segment->seq_num; tcp_buf.put(first_saved_segment); //Next we try to put every other saved segments into the buffer //if there is any if (!seg_list.isEmpty()) { log("number of unprocessed segments: %d", seg_list.length()); //Let's try to put the unprocessed segments into the buffer: bool successful_insertion = false; do { successful_insertion = false; TCPSegment* seg = NULL; for (int i=0; iseq_num, seg->length); if (tcp_buf.put(seg)) { log("unprocessed segment inserted"); successful_insertion = true; //delete seg; seg = NULL; seg_list.removeElementAt(i); } // If we won't be able to put it, we drop it else if (seg->seq_num < tcp_buf.seq_num) { TTCN_warning("Unprocessed segment dropped during ack recovering: IP src: %s, dst: %s; Port src: %d, dst: %d seq: %lu", seg->ip_src.c_str(), seg->ip_dst.c_str(), seg->port_src, seg->port_dst, seg->seq_num ); seg_list.removeElementAt(i); delete seg; seg = NULL; } } } while (successful_insertion && seg_list.length()); } } tcp_buf.dump(); log("out_of_sync: %d",out_of_sync); log("protocol_type: %d",protocol_type); if (out_of_sync ) { out_of_sync = !tryToResync(); log("out_of_sync: %d",out_of_sync); tcp_buf.dump(); } } else { tcp_buf.seq_num = segment->ack_num; TCPSegment* seg = NULL; for (int i=0; iseq_num < tcp_buf.seq_num) { TTCN_warning("Unprocessed segment dropped during ack recovering: IP src: %s, dst: %s; Port src: %d, dst: %d seq: %lu", seg->ip_src.c_str(), seg->ip_dst.c_str(), seg->port_src, seg->port_dst, seg->seq_num ); seg_list.removeElementAt(i); delete seg; seg = NULL; } } } return false; } } else { stream_list.ack(segment); } } return true; } void Peer::put(TCPSegment* segment) { if (segment != NULL) { if (compare(segment) && ((segment->length > 0) || segment->fin)) { if(is_sctp){ stream_list.add_segment_to_stream(segment); delete segment; segment = NULL; } else { if (tcp_buf.put(segment)) { log("segment inserted"); if (!seg_list.isEmpty()) { log("number of unprocessed segments: %d", seg_list.length()); //Let's try to put the unprocessed segments into the buffer: bool successful_insertion = false; do { successful_insertion = false; TCPSegment* seg = NULL; for (int i=0; iseq_num, seg->length); if (tcp_buf.put(seg)) { log("unprocessed segment inserted"); successful_insertion = true; seg_list.removeElementAt(i); } // If we won't be able to put it, we drop it else if (seg->seq_num < tcp_buf.seq_num) { TTCN_warning("Unprocessed TCP segment is dropped: IP src: %s, dst: %s; Port src: %d, dst: %d seq: %lu", seg->ip_src.c_str(), seg->ip_dst.c_str(), seg->port_src, seg->port_dst, seg->seq_num ); seg_list.removeElementAt(i); delete seg; seg = NULL; } } } while (successful_insertion && seg_list.length()); } tcp_buf.dump(); log("out_of_sync: %d",out_of_sync); log("protocol_type: %d",protocol_type); if (out_of_sync ) { out_of_sync = !tryToResync(); log("out_of_sync: %d",out_of_sync); tcp_buf.dump(); } } else { if (segment->seq_num < tcp_buf.seq_num) { TTCN_warning("TCP segment is dropped: IP src: %s, dst: %s; Port src: %d, dst: %d seq: %lu", segment->ip_src.c_str(), segment->ip_dst.c_str(), segment->port_src, segment->port_dst, segment->seq_num ); delete segment; segment = NULL; } else if (segment->length > 0) { log("segment saved as unprocessed"); seg_list.addElement(segment); } else {delete segment; segment = NULL;} } } // is_sctp } else {delete segment; segment = NULL;} // end of if (compare(segment) && (segment->length > 0)) } // end of if (segment != NULL) } bool Peer::tryToResync() { log("trying to resync"); bool found = false; if (tcp_buf.get_read_len()>0) { tf__getMsgStartPos getstartpos=p_data.get_f_getMsgStartPos(protocol_type); int startpos=getstartpos.invoke( OCTETSTRING(tcp_buf.get_read_len(),tcp_buf.get_read_data()), tcp_buf.closed, transport_type ); if(startpos>=0){ found=true; tcp_buf.set_pos(tcp_buf.get_pos()+startpos); log("syncronized, Protocol: %d, position %d",protocol_type,startpos); } else { log("not syncronized, Protocol: %d, position %d",protocol_type,startpos); } } return found; } bool Peer::has_message(){ return stream_list.has_message(); } unsigned char* Peer::get_first_sctp_data(){ return stream_list.get_first_sctp_data(); } size_t Peer::get_first_sctp_data_len(){ return stream_list.get_first_sctp_data_len(); } double Peer::get_first_sctp_timestamp(){ return stream_list.get_first_sctp_timestamp(); } void Peer::delete_first_sctp_message(){ return stream_list.delete_first_sctp_message(); } void Peer::log_stat(){ log("Connection statistic:"); if(is_sctp){ stream_list.log_stat(); } else { tcp_buf.log_stat(); } } void Peer::dump() { if(is_sctp){ stream_list.dump(); } else { log("prot_type: %d, seg_list_length: %d", protocol_type, seg_list.length()); tcp_buf.dump(); } } void Peer::log(const char *fmt, ...) { if (logging) { TTCN_Logger::begin_event(TTCN_DEBUG); TTCN_Logger::log_event("Peer (%d->%d): ", port_src, port_dst); va_list ap; va_start(ap, fmt); TTCN_Logger::log_event_va_list(fmt, ap); va_end(ap); TTCN_Logger::end_event(); } } //////////////////////////////////////////////////////////// // PeerList implementation //////////////////////////////////////////////////////////// PeerList::PeerList() { tcp = true; } PeerList::~PeerList() { peer_list.destruct(); } bool PeerList::sendSegmentToPeer(TCPSegment* segment) { bool ret = true; if (segment!=NULL) { //If it is a TCP segment, we examine if the acknowledgement //number of the segment in order to detect lost segments if (segment->seg_type == TCP_SEG || segment->seg_type == SCTP_SEG) { Peer* other_peer; other_peer = getOtherPeer(segment); if (other_peer) if (!other_peer->ack(segment)) ret = false; } //Sending the segment to the destination peer Peer* act_peer; act_peer = getPeer(segment); if (act_peer) { if (segment->syn) { // We have detected this stream already, and now it is // re-initialized log("sendSegmentToPeer: re-initialization"); act_peer->reset(); act_peer->init(segment); } else { // We have already detected this stream and now we send it // the actual segment log("sendSegmentToPeer: sending to corresponding peer"); act_peer->put(segment); } } else { // We haven't detected this stream yet, therefore we must create the // Peer object that will handle this. log("sendSegmentToPeer: creating new stream"); addPeer(segment); } } return ret; // return false if there is an acknoledgement mismatch } void PeerList::addPeer(TCPSegment* segment) { Peer* new_peer; new_peer = new Peer(segment); peer_list.addElement(new_peer); new_peer->put(segment); } Peer* PeerList::getPeer(TCPSegment* segment) { Peer* peer_poi = NULL; for (int i=0; icompare(segment)) return peer_poi; } return NULL; } void PeerList::log_stat(){ Peer* peer_poi = NULL; for (int i=0; ilog_stat(); } } Peer* PeerList::getOtherPeer(TCPSegment* segment) { Peer* peer_poi = NULL; for (int i=0; isentBy(segment)) return peer_poi; } return NULL; } void PeerList::setType(bool t) { tcp = t; } Peer* PeerList::elementAt(int i) { return peer_list.elementAt(i); } int PeerList::length() { return peer_list.size; } void PeerList::dump() { log("#of peers: %d",peer_list.size); Peer* peer_poi; for (int i=0; idump(); } } void PeerList::log(const char *fmt, ...) { if (logging) { TTCN_Logger::begin_event(TTCN_DEBUG); TTCN_Logger::log_event("PeerList ("); if (tcp) TTCN_Logger::log_event("TCP"); else TTCN_Logger::log_event("UDP or SCTP"); TTCN_Logger::log_event("): "); va_list ap; va_start(ap, fmt); TTCN_Logger::log_event_va_list(fmt, ap); va_end(ap); TTCN_Logger::end_event(); } } //////////////////////////////////////////////////////////// // FilterEntry implementation //////////////////////////////////////////////////////////// FilterEntry::FilterEntry(int protocol, std::string src_ip, bool sip_all, std::string dst_ip, unsigned int rport) : protocol_type(protocol), ip_src(src_ip), ip_dst(dst_ip), port_dst(rport), ip_src_all(sip_all) { } FilterEntry::~FilterEntry() { } bool FilterEntry::compare(TCPSegment* seg) { if (seg != NULL) { if ( (port_dst == seg->port_dst) ) { if (ip_src_all) if (ip_dst == seg->ip_dst) return true; else return false; else if (ip_src == seg->ip_src) if (ip_dst == seg->ip_dst) return true; else return false; else return false; } else if ( (port_dst == seg->port_src) ) { if (ip_src_all) if (ip_dst == seg->ip_src) return true; else return false; else if (ip_src == seg->ip_dst) if (ip_dst == seg->ip_src) return true; else return false; else return false; } else return false; } else return false; } void FilterEntry::log(const char *fmt, ...) { TTCN_Logger::begin_event(TTCN_DEBUG); TTCN_Logger::log_event("FilterEntry: "); va_list ap; va_start(ap, fmt); TTCN_Logger::log_event_va_list(fmt, ap); va_end(ap); TTCN_Logger::end_event(); } //////////////////////////////////////////////////////////// // FilterTable implementation //////////////////////////////////////////////////////////// FilterTable::FilterTable() {} FilterTable::~FilterTable() { entry_list.destruct(); } void FilterTable::addEntry(int protocol, std::string src_ip, bool sip_all, std::string dst_ip, unsigned int rport) { FilterEntry* new_entry = new FilterEntry(protocol, src_ip, sip_all, dst_ip, rport); entry_list.addElement(new_entry); log("adding prot: %d, rPort:%d, sIP:%s", protocol, rport, src_ip.c_str()); log(" dIP:%s", dst_ip.c_str()); } int FilterTable::filter(TCPSegment* segment) { if (segment) { if (noFilter) return 1; FilterEntry* entry_poi = NULL; for (int i=0; icompare(segment)) return entry_poi->protocol_type; } } return NO_PROTOCOL; } void FilterTable::log(const char *fmt, ...) { if (logging) { TTCN_Logger::begin_event(TTCN_DEBUG); TTCN_Logger::log_event("FilterTable: "); va_list ap; va_start(ap, fmt); TTCN_Logger::log_event_va_list(fmt, ap); va_end(ap); TTCN_Logger::end_event(); } } void FilterTable::clear() { entry_list.destruct(); } //////////////////////////////////////////////////////////// // Fragment implementation //////////////////////////////////////////////////////////// IP_fragment::IP_fragment(){ id=0; buffer=NULL; header=NULL; buffer_len=0; data_len=0; } IP_fragment::~IP_fragment(){ if(buffer) Free(buffer); if(header) Free(header); holes.destruct(); } void IP_fragment::clear(){ if(buffer) Free(buffer); if(header) Free(header); id=0; buffer=NULL; header=NULL; buffer_len=0; data_len=0; holes.destruct(); } bool IP_fragment::add_fragment(struct ip_header* IPHeader, u_char* IPData){ Holes_list new_holes; u_int16_t fr_first=(ntohs(IPHeader->ip_off) & IP_OFFMASK)<<3; u_int16_t fr_len=ntohs(IPHeader->ip_len)-(IP_HL(IPHeader)<<2); u_int16_t fr_last=fr_first+fr_len-1; if(holes.isEmpty()){ // first arrived fragment id=IPHeader->ip_id; Hole* new_hole=new Hole(0,c_infinite); holes.append(new_hole); } if(buffer_lenlast && fr_last>=hole_ptr->first){ holes.removeCurrent(); if(fr_first>hole_ptr->first){ Hole* new_hole=new Hole(hole_ptr->first,fr_first-1); new_holes.append(new_hole); } if(fr_lastlast && (ntohs(IPHeader->ip_off) & IP_MF)){ Hole* new_hole=new Hole(fr_last+1,hole_ptr->last); new_holes.append(new_hole); } delete hole_ptr; } hole_ptr=holes.next(); } if(!new_holes.isEmpty ()){ for(int a=0;aip_len=htons(buffer_len+(IP_HL(*IPHeader)<<2)); *IPData=(u_char*)Malloc(buffer_len*sizeof(u_char)); memcpy(*IPData,buffer,buffer_len*sizeof(u_char)); } return header && holes.isEmpty(); } IP_fragments::IP_fragments(){ } IP_fragments::~IP_fragments(){ clear(); } void IP_fragments::clear(){ packet_list.destruct(); } bool IP_fragments::check(){ return !packet_list.isEmpty(); } bool IP_fragments::add_ip_fragment(struct ip_header** IPHeader, u_char** IPData){ int packed_id; for(packed_id=0;packed_idip_id) break; } if(packed_id==packet_list.length()){ IP_fragment* new_fr=new IP_fragment; packet_list.append(new_fr); } if(packet_list[packed_id].add_fragment(*IPHeader,*IPData)){ packet_list[packed_id].get_fragment(IPHeader,IPData); IP_fragment* fr= &packet_list[packed_id]; packet_list.removeElementAt(packed_id); delete fr; return true; } return false; } void decode_sctp(TCPSegment* segment, SCTP_chunk_list& list){ unsigned char* payload=segment->payload; int length=segment->length; int type; unsigned char flags; int idx=0; size_t chunk_length; while(length>0){ type=payload[0]; flags=payload[1]; chunk_length=((size_t)(payload[2])<<8)+payload[3]; switch(type){ case 0: // Data genlog("Data segment"); list.append(new SCTP_chunk); list.current()->type=type; genlog("Data segment flags %Xd",flags); list.current()->flags=flags; list.current()->length=chunk_length; list.current()->data.data.tsn=(payload[4]<<24)+(payload[5]<<16)+(payload[6]<<8)+payload[7]; genlog("Data segment tsn %Xd",list.current()->data.data.tsn); list.current()->data.data.sid=(payload[8]<<8)+payload[9]; genlog("Data segment sid %Xd",list.current()->data.data.sid); list.current()->data.data.ssn=(payload[10]<<8)+payload[11]; genlog("Data segment ssn %Xd",list.current()->data.data.ssn); list.current()->data.data.ppid=(payload[12]<<24)+(payload[13]<<16)+(payload[14]<<8)+payload[15]; genlog("Data segment ppid %Xd",list.current()->data.data.ppid); list.current()->data.data.begin=(flags&0x02); genlog("Data segment begin %Xd",list.current()->data.data.begin); list.current()->data.data.end=(flags&0x01); genlog("Data segment end %Xd",list.current()->data.data.end); list.current()->data.data.length=chunk_length-16; genlog("Data segment length %d",list.current()->data.data.length); list.current()->data.data.data=payload+16; idx++; break; case 3: // SACK list.append(new SCTP_chunk); list.current()->type=type; list.current()->flags=flags; list.current()->length=chunk_length; list.current()->data.ack_tsn=(payload[4]<<24)+(payload[5]<<16)+(payload[6]<<8)+payload[7]; idx++; break; default: break; } chunk_length=((chunk_length+3)/4)*4; length-=chunk_length; payload+=chunk_length; } } SCTP_Stream_list::SCTP_Stream_list(){ acked_tsn=0; } SCTP_Stream_list::~SCTP_Stream_list(){ streams.destruct(); } void SCTP_Stream_list::add_segment_to_stream(TCPSegment* segment){ genlog("SCTP_Stream_list::add_segment_to_stream"); SCTP_chunk_list chunk_list; decode_sctp(segment, chunk_list); for(int i=0;itimestamp)){ add_stream(chunk_list[i].data.data,segment->timestamp); } } } } chunk_list.destruct(); genlog("SCTP_Stream_list::add_segment_to_stream end"); } void SCTP_Stream_list::ack(TCPSegment* segment){ genlog("SCTP_Stream_list::ack"); SCTP_chunk_list chunk_list; decode_sctp(segment, chunk_list); for(int i=0;istreams[i].get_first_ts())){ timestamp=streams[i].get_first_ts(); idx=i; } } return streams[idx].get_first_message_data(); } size_t SCTP_Stream_list::get_first_sctp_data_len(){ int idx=0; double timestamp=-1.0; for(int i=0;istreams[i].get_first_ts())){ timestamp=streams[i].get_first_ts(); idx=i; } } return streams[idx].get_first_message_data_len(); } double SCTP_Stream_list::get_first_sctp_timestamp(){ // int idx=0; double timestamp=-1.0; for(int i=0;istreams[i].get_first_ts())){ timestamp=streams[i].get_first_ts(); // idx=i; } } return timestamp; } void SCTP_Stream_list::delete_first_sctp_message(){ int idx=0; double timestamp=-1.0; for(int i=0;istreams[i].get_first_ts())){ timestamp=streams[i].get_first_ts(); idx=i; } } streams[idx].delete_first_message(); } void SCTP_Stream_list::add_stream(SCTP_data_chunk &data, double timestamp){ SCTP_stream *new_stream= new SCTP_stream; streams.append(new_stream); new_stream->add_segment(data,timestamp); } void SCTP_Stream_list::log_stat(){ } void SCTP_Stream_list::dump(){ } SCTP_stream::SCTP_stream(){ stream_id=0; } SCTP_stream::~SCTP_stream(){ message_list.destruct(); } void SCTP_stream::add_segment(SCTP_data_chunk &data, double timestamp){ genlog("SCTP_stream::add_segment"); int data_idx=get_idx(data.ssn); SCTP_message *message; if(data_idx==-1){ message=new SCTP_message; message_list.addElement(message); } else { message=message_list.elementAt(data_idx); } stream_id=data.sid; message->add_segment(data,timestamp); genlog("SCTP_stream::add_segment end"); } bool SCTP_stream::has_message(){ int data_idx=find_first_message(); if(data_idx!=-1) return message_list[data_idx].complete; return false; } double SCTP_stream::get_first_ts(){ int data_idx=find_first_message(); if(data_idx!=-1) return message_list[data_idx].timestamp; return 0.0; } unsigned char* SCTP_stream::get_first_message_data(){ int data_idx=find_first_message(); if(data_idx!=-1) return message_list[data_idx].data; return NULL; } size_t SCTP_stream::get_first_message_data_len(){ int data_idx=find_first_message(); if(data_idx!=-1) return message_list[data_idx].length; return 0; } int SCTP_stream::find_first_message(){ unsigned int ssn=0; int idx=-1; for(int i=0;imessage_list[i].ssn){ ssn=message_list[i].ssn; idx=i; } } return idx; } void SCTP_stream::delete_first_message(){ int data_idx=find_first_message(); if(data_idx!=-1) { delete message_list.elementAt(data_idx); message_list.remove(data_idx); } } void SCTP_stream::ack_message(unsigned int ack_tsn){ SCTP_message *message=message_list.first(); while(message){ if(!message->complete && (message->last_cons_tsnaddElement(fragment); } if(first_rcvd && last_cons_tsnelementAt(idx)->length)*sizeof(unsigned char)); memcpy(data+curr_length,fragments->elementAt(idx)->data,fragments->elementAt(idx)->length); curr_length+=fragments->elementAt(idx)->length; } length=curr_length; complete=true; timestamp=time_stamp; free_segments(); } } void SCTP_message::free_segments(){ if(fragments){ fragments->destruct(); delete fragments; fragments=NULL; } } int SCTP_message::get_idx(unsigned int tsn){ if(fragments){ for(int i=0;ilength();i++){ if(fragments->elementAt(i)->tsn==tsn) return i; } } return -1; } SCTP_data_fragment::SCTP_data_fragment(SCTP_data_chunk &chunk){ begin=chunk.begin; end=chunk.end; tsn=chunk.tsn; length=chunk.length; data= (unsigned char*)Malloc(length*sizeof(unsigned char)); memcpy(data,chunk.data,length); } SCTP_data_fragment::~SCTP_data_fragment(){ Free(data); } Protocol_data::Protocol_data(){ } Protocol_data::~Protocol_data(){ data_list.destruct(); } void Protocol_data::add_protocol(const int id, const tf__getMsgLen& f_getMsgLen, const tf__getMsgStartPos& f_getMsgStartPos){ int idx=get_idx(id); protocol_def *def; if(idx==-1){ def=new protocol_def; data_list.append(def); } else { def=data_list.elementAt(idx); } def->id=id; def->f_getMsgLen=f_getMsgLen; def->f_getMsgStartPos=f_getMsgStartPos; } int Protocol_data::get_idx(int id){ protocol_def *def; for(int i=0; iid==id) return i; } return -1; } const tf__getMsgLen& Protocol_data::get_f_getMsgLen(int id){ int idx=get_idx(id); if(idx==-1) return def_getMsgLen_ref; protocol_def *def=data_list.elementAt(idx); return def->f_getMsgLen; } const tf__getMsgStartPos& Protocol_data::get_f_getMsgStartPos(int id){ int idx=get_idx(id); if(idx==-1) return def_getMsgStartPos_ref; protocol_def *def=data_list.elementAt(idx); return def->f_getMsgStartPos; } }// namespace