"Fossies" - the Fresh Open Source Software Archive

Member "tcpflow-1.6.1/src/tcpip.cpp" (19 Feb 2021, 22544 Bytes) of package /linux/misc/tcpflow-1.6.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "tcpip.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.5.0_vs_1.6.1.

    1 /*
    2  * This file is part of tcpflow by Simson Garfinkel,
    3  * originally by Jeremy Elson <jelson@circlemud.org>
    4  *
    5  * Modified by Greg Drew to add support for creating a packet time / data index
    6  * which allows mapping bytes in the flow back to their relative arrival time.
    7  * This is very useful in reassembling inherently bidirectional conversations
    8  * such as chat or telnet sessions.  --GDD
    9  *
   10  * This source code is under the GNU Public License (GPL).  See
   11  * LICENSE for details.
   12  *
   13  */
   14 
   15 #include "tcpflow.h"
   16 #include "tcpip.h"
   17 #include "tcpdemux.h"
   18 
   19 #include <iostream>
   20 #include <sstream>
   21 #include <vector>
   22 #include <string>
   23 
   24 #pragma GCC diagnostic ignored "-Weffc++"
   25 #pragma GCC diagnostic ignored "-Wshadow"
   26 
   27 
   28 /* Create a new tcp object.
   29  * 
   30  * Creating a new object creates a new passive TCP/IP decoder.
   31  * It will *NOT* append to a flow that is already on the disk or in memory.
   32  *
   33  * called from tcpdemux::create_tcpip()
   34  */
   35 tcpip::tcpip(tcpdemux &demux_,const flow &flow_,be13::tcp_seq isn_):
   36     demux(demux_),myflow(flow_),dir(unknown),isn(isn_),nsn(0),
   37     syn_count(0),fin_count(0),fin_size(0),pos(0),
   38     flow_pathname(),fd(-1),file_created(false),
   39     flow_index_pathname(),idx_file(),
   40     seen(new recon_set()),
   41     last_byte(),
   42     last_packet_number(),out_of_order_count(0),violations(0)
   43 {
   44 }
   45 
   46 
   47 uint32_t tcpip::seen_bytes()
   48 {
   49     if(seen) return seen->size();
   50     return 0;
   51 }
   52 
   53 void tcpip::dump_seen()
   54 {
   55     if(seen){
   56         for(recon_set::const_iterator it = seen->begin(); it!=seen->end(); it++){
   57             std::cerr << *it << ", ";
   58         }
   59         std::cerr << std::endl;
   60     }
   61 }
   62 
   63 void tcpip::dump_xml(class dfxml_writer *xreport,const std::string &xmladd)
   64 {
   65     static const std::string fileobject_str("fileobject");
   66     static const std::string filesize_str("filesize");
   67     static const std::string filename_str("filename");
   68     static const std::string tcpflow_str("tcpflow");
   69 
   70     xreport->push(fileobject_str);
   71     if(flow_pathname.size()) xreport->xmlout(filename_str,flow_pathname);
   72 
   73     xreport->xmlout(filesize_str,last_byte);
   74     
   75     std::stringstream attrs;
   76     attrs << "startime='" << dfxml_writer::to8601(myflow.tstart) << "' ";
   77     attrs << "endtime='"  << dfxml_writer::to8601(myflow.tlast)  << "' ";
   78     if(myflow.has_mac_daddr()) attrs << "mac_daddr='" << macaddr(myflow.mac_daddr) << "' ";
   79     if(myflow.has_mac_saddr()) attrs << "mac_saddr='" << macaddr(myflow.mac_saddr) << "' ";
   80     attrs << "family='"   << (int)myflow.family << "' ";
   81     attrs << "src_ipn='"  << ipaddr_prn(myflow.src, myflow.family) << "' ";
   82     attrs << "dst_ipn='"  << ipaddr_prn(myflow.dst, myflow.family) << "' ";
   83     attrs << "srcport='"  << myflow.sport << "' ";
   84     attrs << "dstport='"  << myflow.dport << "' ";
   85     attrs << "packets='"  << myflow.packet_count << "' ";
   86     if(out_of_order_count) attrs << "out_of_order_count='" << out_of_order_count << "' ";
   87     if(violations)         attrs << "violations='" << violations << "' ";
   88     attrs << "len='"      << myflow.len << "' ";
   89     if(myflow.len != myflow.caplen) attrs << "caplen='"   << myflow.caplen << "' ";
   90     xreport->xmlout(tcpflow_str,"",attrs.str(),false);
   91     if(xmladd.size()>0) xreport->xmlout("",xmladd,"",false);
   92     xreport->pop();
   93     xreport->flush();
   94 }
   95 
   96 
   97 /**
   98  * Destructor is called when flow is closed.
   99  * It implements "after" processing.
  100  * This should only be called from remove_flow() or remove_all_flows()
  101  * when a flow is deleted.
  102  */
  103 tcpip::~tcpip()
  104 {
  105     assert(fd<0);                       // file must be closed
  106     delete seen;                        // no need to check to see if seen is null or not.
  107 }
  108 
  109 #pragma GCC diagnostic warning "-Weffc++"
  110 #pragma GCC diagnostic warning "-Wshadow"
  111 
  112 
  113 /****************************************************************
  114  ** SAVE FILE MANAGEMENT
  115  ****************************************************************
  116  *
  117  * Unlike the tcp/ip object, which is created once, the file can be opened, closed, and
  118  * re-opened depending on the availability of file handles.
  119  * 
  120  * Closing the file does not delete the tcp/ip object.
  121  */
  122 
  123 
  124 /* Closes the file belonging to a flow.
  125  * Does not take tcpip out of flow database.
  126  * Does not change pos. 
  127  */
  128 void tcpip::close_file()
  129 {
  130     if (fd>=0){
  131     struct timeval times[2];
  132     times[0] = myflow.tstart;
  133     times[1] = myflow.tstart;
  134 
  135     DEBUG(5) ("%s: closing file in tcpip::close_file", flow_pathname.c_str());
  136     /* close the file and remember that it's closed */
  137 #if defined(HAVE_FUTIMES)
  138         /* fix microseconds if they are invalid */
  139         for ( int i=0; i<2; i++){
  140             if ( times[i].tv_usec < 0 || times[i].tv_usec >= 1000000 ){
  141                 times[i].tv_usec = 0;
  142             }
  143         }
  144     if (futimes(fd,times)){
  145         fprintf(stderr,"%s: futimes(fd=%d,[%ld:%ld,%ld:%ld])\n",
  146                     strerror(errno),fd,
  147                     times[0].tv_sec,times[1].tv_usec,
  148                     times[1].tv_sec,times[1].tv_usec);
  149     }
  150 #elif defined(HAVE_FUTIMENS) 
  151     struct timespec tstimes[2];
  152     for(int i=0;i<2;i++){
  153         tstimes[i].tv_sec = times[i].tv_sec;
  154         tstimes[i].tv_nsec = times[i].tv_usec * 1000;
  155     }
  156     if(futimens(fd,tstimes)){
  157         perror("futimens(fd=%d)",fd);
  158     }
  159 #endif
  160     close(fd);
  161     fd = -1;
  162     demux.open_flows.erase(this);           // we are no longer open
  163     }
  164     // Also close the flow_index file, if flow indexing is in use --GDD
  165     if(demux.opt.output_packet_index && idx_file.is_open()){
  166         idx_file.close();
  167     }
  168     //std::cerr << "close_file1 " << *this << "\n";
  169 }
  170 
  171 /*
  172  * Opens the file transcript file (creating file if necessary).
  173  * Called by store_packet()
  174  * Does not change pos.
  175  */
  176 
  177 int tcpip::open_file()
  178 {
  179     int create_idx_needed = false;
  180     if(fd<0){
  181         //std::cerr << "open_file0 " << ct << " " << *this << "\n";
  182         /* If we don't have a filename, create the flow */
  183         if(flow_pathname.size()==0) {
  184             flow_pathname = myflow.new_filename(&fd,O_RDWR|O_BINARY|O_CREAT|O_EXCL,0666);
  185             file_created = true;        // remember we made it
  186             create_idx_needed = true;   // We created a new stream, so we need to create a new flow file. --GDD
  187             DEBUG(5) ("%s: created new file",flow_pathname.c_str());
  188         } else {
  189             /* open an existing flow */
  190             fd = demux.retrying_open(flow_pathname,O_RDWR | O_BINARY | O_CREAT,0666);
  191             lseek(fd,pos,SEEK_SET);  
  192             DEBUG(5) ("%s: opening existing file", flow_pathname.c_str());
  193         }
  194         
  195         /* If the file isn't open at this point, there's a problem */
  196         if (fd < 0 ) {
  197             /* we had some problem opening the file -- set FINISHED so we
  198              * don't keep trying over and over again to reopen it
  199              */
  200             perror(flow_pathname.c_str());
  201             return -1;
  202         }
  203         /* Remember that we have this open */
  204         demux.open_flows.push_back(this);
  205         if(demux.open_flows.size() > demux.max_open_flows) demux.max_open_flows = demux.open_flows.size();
  206         //std::cerr << "open_file1 " << *this << "\n";
  207     }
  208     if(demux.opt.output_packet_index){
  209         //Open the file for the flow index.  We don't do this if the flow file could not be
  210         //  opened.  The file must be opened for append, in case this is a reopen.  The filename
  211         //  standard is the flow name followed by ".findx", which google currently says does not
  212         //  conflict with anything major.
  213         flow_index_pathname = flow_pathname + ".findx";
  214         DEBUG(10)("opening index file: %s",flow_index_pathname.c_str());
  215         if(create_idx_needed){
  216             //New flow file, even if there was an old one laying around --GDD
  217             idx_file.open(flow_index_pathname.c_str(),std::ios::trunc|std::ios::in|std::ios::out);
  218         }else{
  219             //Use existing flow file --GDD
  220             idx_file.open(flow_index_pathname.c_str(),std::ios::ate|std::ios::in|std::ios::out);
  221         }
  222         if(idx_file.bad()){
  223             perror(flow_index_pathname.c_str());
  224             // Be nice and be sure the flow has been closed in the demultiplexer.
  225             // demux.close_tcpip_fd(this);  Need to fix this.  Also, when called, it will
  226             // have to differentiate the fact that the open fd cound only needs to be
  227             // decremented by one and not by 2.--GDD
  228             return -1;
  229         }
  230 
  231     }
  232     return 0;
  233 }
  234 
  235 
  236 
  237 /*************************************************************************/
  238 
  239 /* print the contents of this packet to the console.
  240  * This is nice for immediate satisfaction, but it can't handle
  241  * out of order packets, etc.
  242  */
  243 void tcpip::print_packet(const u_char *data, uint32_t length)
  244 {
  245     /* green, blue, read */
  246     const char *color[3] = { "\033[0;32m", "\033[0;34m", "\033[0;31m" };
  247 
  248     if(demux.opt.max_bytes_per_flow>=0){
  249         uint64_t max_bytes_per_flow = (uint64_t)demux.opt.max_bytes_per_flow;
  250 
  251     if(last_byte > max_bytes_per_flow) return; /* too much has been printed */
  252     if(length > max_bytes_per_flow - last_byte){
  253         length = max_bytes_per_flow - last_byte; /* can only output this much */
  254         if(length==0) return;
  255     }
  256     }
  257 
  258 #ifdef HAVE_PTHREAD
  259     if(semlock){
  260     if(sem_wait(semlock)){
  261         fprintf(stderr,"%s: attempt to acquire semaphore failed: %s\n",progname,strerror(errno));
  262         exit(1);
  263     }
  264     }
  265 #endif
  266 
  267     if(flow_pathname.size()==0) flow_pathname = myflow.filename(0, false);
  268     if (demux.opt.use_color) fputs(dir==dir_cs ? color[1] : color[2], stdout);
  269     if (demux.opt.suppress_header == 0 && demux.opt.output_json == 0){
  270         printf("%s: ", flow_pathname.c_str());
  271         if(demux.opt.output_hex) putchar('\n');
  272     }
  273 
  274     size_t written = 0;
  275     if(demux.opt.output_hex){
  276         const size_t bytes_per_line = 32;
  277         size_t max_spaces = 0;
  278         for(u_int i=0;i<length;i+=bytes_per_line){
  279             size_t spaces=0;
  280             
  281             /* Print the offset */
  282             char b[64];
  283             size_t count = snprintf(b,sizeof(b),"%04x: ",(int)i);
  284             if(fwrite(b,1,count,stdout)!=count){
  285           perror("fwrite");
  286         }
  287             spaces += count;
  288             
  289             /* Print the hext bytes */
  290             for(size_t j=0;j<bytes_per_line && i+j<length ;j++){
  291                 unsigned char ch = data[i+j];
  292                 fprintf(stdout,"%02x",ch);  spaces += 2;
  293                 if(j%2==1){
  294                     fputc(' ',stdout);
  295                     spaces += 1;
  296                 }
  297             }
  298             /* space out to where the ASCII region is */
  299             if(spaces>max_spaces) max_spaces=spaces;
  300             for(;spaces<max_spaces;spaces++){
  301                 fputc(' ',stdout);
  302             }
  303             putchar(' ');
  304             /* Print the ascii */
  305             for(size_t j=0;j<bytes_per_line && i+j<length;j++){
  306                 unsigned char ch = data[i+j];
  307                 if(ch>=' ' && ch<='~') fputc(ch,stdout);
  308                 else fputc('.',stdout);
  309             }
  310             fputc('\n',stdout);
  311         }
  312         written = length;               // just fake it.
  313     } else if (demux.opt.output_json) {
  314         // {
  315         //     "src_host": "192.168.0.1",
  316         //     "src_port": 1234,
  317         //     "dst_host": "1.1.1.1",
  318         //     "dst_port": 80,
  319         //     "payload" : [...]
  320         // }    
  321 
  322         std::string hoststr = std::string();
  323 
  324         putchar('{');   
  325         printf("\"src_host\":\"");
  326 
  327         size_t src_pos = 0;
  328         size_t src_end_pos = 0;
  329         size_t src_pos_counter = 0;
  330 
  331         size_t pathname_len = flow_pathname.length();
  332         for(size_t i = 0; i < pathname_len; ++i) {
  333             if(flow_pathname[i] == '.') {
  334                 src_pos_counter++;
  335                 printf("%d%s", atoi(hoststr.c_str()), (src_pos_counter != 4 ? "." : ""));
  336                 hoststr.clear();
  337             } else {
  338                 hoststr = hoststr + flow_pathname[i];
  339             }
  340             if(src_pos_counter == 4) {
  341                 src_pos = i;
  342                 break;
  343             }
  344         }
  345         src_end_pos = src_pos;
  346         for(;src_end_pos < pathname_len; ++src_end_pos) {
  347             if(flow_pathname[src_end_pos] == '-') {
  348                 break;
  349             }
  350         }
  351         printf("\",\"src_port\":%d,\"dst_host\":\"", atoi(flow_pathname.substr(src_pos + 1, src_end_pos - src_pos).c_str()));
  352         
  353         size_t dst_pos = src_end_pos + 1;
  354         size_t dst_end_pos = dst_pos;
  355         size_t dst_pos_counter = 0;
  356         
  357         for(size_t i = dst_pos; i < pathname_len; ++i) {
  358               if(flow_pathname[i] == '.') {
  359                 dst_pos_counter++;
  360                 printf("%d%s", atoi(hoststr.c_str()), (dst_pos_counter != 4 ? "." : ""));
  361                 hoststr.clear();
  362             } else {
  363                 hoststr = hoststr + flow_pathname[i];
  364             }
  365             if(dst_pos_counter == 4) {
  366                 dst_pos = i;
  367                 break;
  368             }
  369         }
  370         dst_end_pos = dst_pos;
  371         for(;dst_end_pos < pathname_len; ++dst_end_pos) {
  372             if(flow_pathname[dst_end_pos] == '-') {
  373                 break;
  374             }
  375         }
  376         printf("\",\"dst_port\":%d,\"payload\": [", atoi(flow_pathname.substr(dst_pos + 1, dst_end_pos - dst_pos).c_str()));
  377 
  378         for(size_t i = 0; i < length; ++i) {
  379             printf("%d%s", data[i], (i != length - 1 ? "," : "]}"));
  380         }
  381     } else if (demux.opt.output_strip_nonprint) {
  382         for(const u_char *cc = data;cc<data+length;cc++){
  383         if(isprint(*cc) || (*cc=='\n') || (*cc=='\r')){
  384                 int ret = fputc(*cc,stdout);
  385                 if(ret==EOF){
  386                     std::cerr << "EOF on write to stdout\n";
  387                     exit(1);
  388                 
  389                 }
  390         }
  391         else fputc('.',stdout);
  392             written += 1; // treat even unprintable characters as "written". It
  393                           // really means "processed"
  394         }
  395     } else {
  396         written = fwrite(data,1,length,stdout);
  397         if(length != written) std::cerr << "\nwrite error to stdout (" << length << "!=" << written << ") \n";
  398     }
  399 
  400     last_byte += length;
  401 
  402     if (demux.opt.use_color) printf("\033[0m");
  403 
  404     if (! demux.opt.console_output_nonewline) putchar('\n');
  405     fflush(stdout);
  406 
  407 #ifdef HAVE_PTHREAD
  408     if(semlock){
  409     if(sem_post(semlock)){
  410         fprintf(stderr,"%s: attempt to post semaphore failed: %s\n",progname,strerror(errno));
  411         exit(1);
  412     }
  413     }
  414 #endif
  415 }
  416 
  417 /*
  418  * extend_file_and_insert():
  419  * A handy function for inserting in the middle or beginning of a file.
  420  *
  421  * Based on:
  422  * http://stackoverflow.com/questions/10467711/c-write-in-the-middle-of-a-binary-file-without-overwriting-any-existing-content
  423  */
  424 
  425 static int shift_file(int fd, size_t inslen)
  426 {
  427     enum { BUFFERSIZE = 64 * 1024 };
  428     char buffer[BUFFERSIZE];
  429     struct stat sb;
  430 
  431     DEBUG(100)("shift_file(%d,%d)",fd,(int)inslen);
  432 
  433     if (fstat(fd, &sb) != 0) return -1;
  434 
  435     /* Move data after offset up by inslen bytes */
  436     size_t bytes_to_move = sb.st_size;
  437     off_t read_end_offset = sb.st_size; 
  438     while (bytes_to_move != 0) {
  439     ssize_t bytes_this_time = bytes_to_move < BUFFERSIZE ? bytes_to_move : BUFFERSIZE ;
  440     ssize_t rd_off = read_end_offset - bytes_this_time;
  441     ssize_t wr_off = rd_off + inslen;
  442     lseek(fd, rd_off, SEEK_SET);
  443     if (read(fd, buffer, bytes_this_time) != bytes_this_time)
  444         return -1;
  445     lseek(fd, wr_off, SEEK_SET);
  446     if (write(fd, buffer, bytes_this_time) != bytes_this_time)
  447         return -1;
  448     bytes_to_move -= bytes_this_time;
  449     }   
  450     return 0;
  451 }
  452 
  453 #pragma GCC diagnostic ignored "-Weffc++"
  454 void update_seen(recon_set *seen,uint64_t pos,uint32_t length)
  455 {
  456     if(seen){
  457         (*seen) += boost::icl::discrete_interval<uint64_t>::closed(pos,pos+length-1);
  458     }
  459 }
  460 
  461 /* store the contents of this packet to its place in its file
  462  * This has to handle out-of-order packets as well as writes
  463  * past the 4GiB boundary. 
  464  *
  465  * 2012-10-24 Originally this code simply computed the 32-bit offset
  466  * from the beginning of the file using the isn. The new version tracks
  467  * nsn (the expected next sequence number for the open file).
  468  *
  469  * A relative seek before the beginning of the file means that we need
  470  * to insert.  A relative seek more than max_seek means that we have a
  471  * different flow that needs to be separately handled.
  472  *
  473  * called from tcpdemux::process_tcp_packet()
  474  */
  475 void tcpip::store_packet(const u_char *data, uint32_t length, int32_t delta,struct timeval ts)
  476 {
  477     if(length==0) return;               // no need to do anything
  478 
  479     uint32_t insert_bytes=0;
  480     uint64_t offset = pos+delta;    // where the data will go in absolute byte positions (first byte is pos=0)
  481 
  482     if((int64_t)offset < 0){
  483     /* We got bytes before the beginning of the TCP connection.
  484      * Either this is a protocol violation,
  485      * or else we never saw a SYN and we got the ISN wrong.
  486      */
  487     if(syn_count>0){
  488         DEBUG(2)("packet received with offset %" PRId64 "; ignoring",offset);
  489         violations++;
  490         return;
  491     }
  492     insert_bytes = -offset;     // open up this much space
  493     offset = 0;         // and write the data here
  494     }
  495 
  496     /* reduce length to write if it goes beyond the number of bytes per flow,
  497      * but remember to seek out to the actual position after the truncated write...
  498      */
  499     uint32_t wlength = length;      // length to write
  500     if (demux.opt.max_bytes_per_flow >= 0){
  501         uint64_t max_bytes_per_flow = (uint64_t)demux.opt.max_bytes_per_flow;
  502 
  503     if(offset >= max_bytes_per_flow){
  504         wlength = 0;
  505     } 
  506     if(offset < max_bytes_per_flow &&  offset+length > max_bytes_per_flow){
  507         DEBUG(2) ("packet truncated by max_bytes_per_flow on %s", flow_pathname.c_str());
  508         wlength = max_bytes_per_flow - offset;
  509     }
  510     }
  511 
  512     /* if we don't have a file open for this flow, try to open it.
  513      * return if the open fails.  Note that we don't have to explicitly
  514      * save the return value because open_tcpfile() puts the file pointer
  515      * into the structure for us.
  516      */
  517     if (fd < 0) {
  518     if (open_file()) {
  519         DEBUG(1)("unable to open TCP file %s  fd=%d  wlength=%d",
  520                      flow_pathname.c_str(),fd,(int)wlength);
  521         return;
  522     }
  523     }
  524     
  525     /* Shift the file now if we were going shift it */
  526 
  527     if(insert_bytes>0){
  528     if(fd>=0) shift_file(fd,insert_bytes);
  529     isn -= insert_bytes;        // it's really earlier
  530     lseek(fd,(off_t)0,SEEK_SET);    // put at the beginning
  531     pos = 0;
  532     nsn = isn+1;
  533     out_of_order_count++;
  534     DEBUG(25)("%s: insert(0,%d); lseek(%d,0,SEEK_SET) out_of_order_count=%" PRId64,
  535           flow_pathname.c_str(), insert_bytes,
  536           fd,out_of_order_count);
  537 
  538         /* TK: If we have seen packets, everything in the recon set needs to be shifted as well.*/
  539         delete seen;
  540         seen = 0;
  541     }
  542 
  543     /* if we're not at the correct point in the file, seek there */
  544     if (offset != pos) {
  545         /* Check for a keepalive */
  546         if(delta == -1 && length == 1) {
  547             DEBUG(25)("%s: RFC1122 keepalive detected and ignored",flow_pathname.c_str());
  548             return;
  549         }
  550 
  551     if(fd>=0) lseek(fd,(off_t)delta,SEEK_CUR);
  552     if(delta<0) out_of_order_count++; // only increment for backwards seeks
  553     DEBUG(25)("%s: lseek(%d,%d,SEEK_CUR) offset=%" PRId64 " pos=%" PRId64 " out_of_order_count=%" PRId64,
  554           flow_pathname.c_str(), fd,(int)delta,offset,pos,out_of_order_count);
  555     pos += delta;           // where we are now
  556     nsn += delta;           // what we expect the nsn to be now
  557     }
  558     
  559     /* write the data into the file */
  560     DEBUG(25) ("%s: %s write %ld bytes @%" PRId64,
  561                flow_pathname.c_str(),
  562                fd>=0 ? "will" : "won't",
  563                (long) wlength, offset);
  564     
  565     if(fd>=0){
  566       if ((uint32_t)write(fd,data, wlength) != wlength) {
  567         DEBUG(1) ("write to %s failed: ", flow_pathname.c_str());
  568         if (debug >= 1) perror("");
  569     }
  570     // Write to the index file if needed.  Note, index file is sorted before close, so no need to jump around --GDD
  571         if (demux.opt.output_packet_index && idx_file.is_open()) {
  572             idx_file << offset << "|" << ts.tv_sec << "." << std::setw(6) << std::setfill('0') << ts.tv_usec << "|"
  573                     << wlength << "\n";
  574             if (idx_file.bad()){
  575                 DEBUG(1)("write to index file %s failed: ",flow_index_pathname.c_str());
  576                 if(debug >= 1){
  577                     perror("");
  578                 }
  579             }
  580         }
  581     if(wlength != length){
  582         off_t p = lseek(fd,length-wlength,SEEK_CUR); // seek out the space we didn't write
  583             DEBUG(100)("   lseek(%" PRId64 ",SEEK_CUR)=%" PRId64,(int64_t)(length-wlength),(int64_t)p);
  584     }
  585     }
  586 
  587     /* Update the database of bytes that we've seen */
  588     if(seen) update_seen(seen,pos,length);
  589 
  590     /* Update the position in the file and the next expected sequence number */
  591     pos += length;
  592     nsn += length;          // expected next sequence number
  593 
  594     if(pos>last_byte) last_byte = pos;
  595 
  596     if(debug>=100){
  597         uint64_t rpos = lseek(fd,(off_t)0,SEEK_CUR);
  598         DEBUG(100)("    pos=%" PRId64 "  lseek(fd,0,SEEK_CUR)=%" PRId64,pos,rpos);
  599         assert(pos==rpos);
  600     }
  601 
  602 #ifdef DEBUG_REOPEN_LOGIC
  603     /* For debugging, force this connection closed */
  604     demux.close_tcpip_fd(this);         
  605 #endif
  606 }
  607 
  608 /*
  609  * Compare two index strings and return the result.  Called by
  610  * the vector::sort in sort_index.
  611  * --GDD
  612  */
  613 bool tcpip::compare(std::string a, std::string b){
  614     std::stringstream ss_a(a),ss_b(b);
  615     long a_l,b_l;
  616 
  617     ss_a >> a_l;
  618     ss_b >> b_l;
  619     return a_l < b_l;
  620 }
  621 
  622 /*
  623  * Sort an index file (presumably from this object) if file indexing is
  624  * turned on and the file exists.  Index files may be out of order due
  625  * to the arrival of out of order packets.  It is cheaper to reorder them
  626  * one time at the end of processing than it is to continually keep them
  627  * in order.
  628  * --GDD
  629  */
  630 void tcpip::sort_index(std::fstream *ix_file) {
  631 
  632     std::vector<std::string> idx;
  633     std::string line;
  634 
  635     if (demux.opt.output_packet_index) {
  636         if (!(idx_file.good() && idx_file.is_open())) {
  637             DEBUG(5)("Skipping index file sort.  Unusual behavior.\n");
  638             return; //Nothing to do
  639         }
  640         //Make sure we are at the beginning.
  641         ix_file->clear();
  642         ix_file->seekg(0);
  643         do {
  644             *ix_file >> line;
  645             if (!ix_file->eof()) {
  646                 idx.push_back(line);
  647             }
  648         } while (ix_file->good());
  649         std::sort(idx.begin(), idx.end(), &tcpip::compare);
  650         ix_file->clear();
  651         ix_file->seekg(0);
  652         for (std::vector<std::string>::iterator s = idx.begin(); s != idx.end();
  653                 s++) {
  654             *ix_file << *s << "\n";
  655         }
  656     }
  657 }
  658 
  659 /*
  660  * Convenience function to cause the local index file to be sorted.
  661  * --GDD
  662  */
  663 void tcpip::sort_index(){
  664     tcpip::sort_index(&(this->idx_file));
  665 }
  666 
  667 #pragma GCC diagnostic ignored "-Weffc++"
  668 #pragma GCC diagnostic ignored "-Wshadow"
  669 
  670 /* Note --- Turn off warning so that creating the seen() map doesn't throw an error */
  671 //#pragma GCC diagnostic ignored "-Weffc++"