1
votes

in a function, that gets unsigned char && unsigned char length,

void pcap_callback(u_char *args, const struct pcap_pkthdr* pkthdr, const u_char* packet) 
{
    std::vector<unsigned char> vec(packet, packet+pkthdr->len); // optimized from foo.
    std::stringstream scp;
    for (int i=0;i<pkthdr->len;i++) {
        scp<<vec[i];
    }
    std::string mystr =  std::string(scp.rdbuf()->str());
    std::cout << "WAS: " << packet << std::endl;
    std::cout << "GOOD: " << scp.str() << std::endl;
    std::cout << "BAD: "  << scp.str().c_str() << std::endl;
    std::cout << "TEST: " << mystr.size() << std::endl;
    assert(mystr.size() == pkthdr->len); 
}

Results:

  • WAS: prints nothing (guess there is a pointer to const.. case)
  • GOOD: prints data
  • BAD: prints nothing
  • TEST, assert: prints that mystr.size() is equal to passed unsigned char size.

I tried:

  • string.assign(scp.rdbuf());
  • memcpy(char, scp.str(), 10);
  • different methods of creating/allocating temporary chars, strings

No help.. it is wanted to get a std::cout'able std::string that contains data, (which was picked from foo, which was unsigned char, which was packet data).

Guessing either the original foo may not be null-terminated, or the problem is something like this - simple, but can't get in.. what are the things to look for here?

(this code is another attempt to use libpcap, just to print packets in C++ way, without using known C++ magic wrappers like libpcapp).

3
How is std::cout << "BAD: " << scp.str()->c_str() << std::endl; even compiling?? The member function std::stringstream::str() does not return a pointer. It returns an instance of std::string.Charles Salvia
@Charles Salvia, ouch. got a mistype while trying to remember all faulty attempts to chew it.kagali-san
From looking at your code, the only thing I can think of to explain this behavior is that foo contains a null byte, so when you print it as a C-string nothing is outputted. But your implementation of iostreams prints out std::string by iterating over std::string::length() bytes and printing each character, including characters which appear after the null.Charles Salvia
@mhambra, if your packet buffer is supposed to contain binary data (which it probably is, judging from the u_char type), you can't expect to be able to print it meaningfully to the console as text. You need to iterate over each byte and output it as decimal or hex.Charles Salvia
@mhambra: Err.. std::basic_string<t>::operator[]? Plus it's a valid STL container so you can use anything that would normally iterate over an stl container (i.e. std::copy(str.begin(), str.end(), std::ostream_iterator<char>(std::cout, ""));Billy ONeal

3 Answers

3
votes

For a quick test, throw in a check for scp.str().size() == strlen(scp.str().c_str()) to see if there are embedded '\0' characters in the string, which is what I suspect is happening.

2
votes

I think you're going about this the wrong way. It looks like you're dealing with binary data here, in which case you can't expect to meaningfully output it to the screen as text. What you really need is a hex dump.

const unsigned char* ucopy = packet;
std::ios_base::fmtflags old_flags = std::cout.flags();
std::cout.setf(std::ios::hex, std::ios::basefield);

for (const unsigned char* p = ucopy, *e = p + pkthdr->len; p != e; ++p) {
    std::cout << std::setw(2) << std::setfill('0') << static_cast<unsigned>(*p) << " ";
}

std::cout.flags(old_flags);

This will output the data byte-by-byte, and let you examine the individual hex values of the binary data. A null byte will simply be output as 00.

1
votes

Check std::cout.good() after the failed output attempt. My guess is that there's some failure on output (i.e. trying to write a nonprintable character to the console), which is setting failbit on cout.

Also check to ensure the string does not start with a NULL, which would cause empty output to be the expected behavior :)

(Side note, please use reinterpret_cast for unsigned char *ucopy = (unsigned char*)packet; if you're in C++ ;) )