I try to write Windows server app that accepts requests. I wan to use select() function to receive new connections and requests -- to monitor listen socket and previously established connections.
The problem is that FD_ISSET always returns 0. Here's the code. Can you please point me the mistake?
WORD wVersionRequested;
WSADATA wsaData;
int iResult;
// Initializing WSA
wVersionRequested = MAKEWORD( 2, 2 );
iResult = WSAStartup( wVersionRequested, &wsaData );
if ( iResult != 0 )
{
std::cout << "WSAStartup failed with error: " << WSAGetLastError() << std::endl;
return false;
}
if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2 )
{
WSACleanup();
std::cout << "Could not find a usable version of Winsock.dll" << std::endl;
return false;
}
int iResult;
struct addrinfo *result = NULL;
struct addrinfo hints;
std::stringstream ss;
ss << DEFAULT_PORT;
memset( &hints, 0, sizeof( hints ) );
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
// Resolve the server address and port
iResult = getaddrinfo( NULL, ss.str().c_str(), &hints, &result );
if ( iResult != 0 )
{
std::cout << "getaddrinfo() failed with error: " << WSAGetLastError() << std::endl;
return false;
}
// Create a SOCKET for connecting to server
m_listenSocket = socket( result->ai_family, result->ai_socktype, result->ai_protocol );
if ( m_listenSocket == INVALID_SOCKET )
{
std::cout << "socket() failed with error: " << WSAGetLastError() << std::endl;
return false;
}
// Setup the TCP listening socket
iResult = bind( m_listenSocket, result->ai_addr, ( int ) result->ai_addrlen );
if ( iResult == SOCKET_ERROR )
{
std::cout << "bind() failed with error: " << WSAGetLastError() << std::endl;
freeaddrinfo( result );
return false;
}
freeaddrinfo( result );
// Listen for the TCP listening socket
if ( listen( m_listenSocket, SOMAXCONN ) == SOCKET_ERROR )
{
std::cout << "listen() failed with error: " << WSAGetLastError() << std::endl;
return false;
}
fd_set active_fd_set;
fd_set read_fd_set;
// Initialize the set of active sockets.
FD_ZERO( &active_fd_set );
FD_SET( m_listenSocket, &active_fd_set );
while ( !m_forceStopMessages )
{
read_fd_set = active_fd_set;
int retVal = select( FD_SETSIZE, &read_fd_set, NULL, NULL, NULL );
if ( retVal < 0 )
{
std::cout << "select() failed with error: " << WSAGetLastError() << std::endl;
}
int readySockets = ( FD_SETSIZE < retVal ) ? FD_SETSIZE : retVal;
// Service all the sockets with input pending.
for ( int i = 0; i < readySockets; ++i )
{
if ( FD_ISSET( i, &read_fd_set ) )
{
if ( i == m_listenSocket )
{
// Accept a client socket
FD_SET( clientSocket, &active_fd_set );
}
else
{
/* Data arriving on an already-connected socket. */
FD_CLR( i, &active_fd_set );
}
}
}
}
FD_ISSET takes a socket handle as the first parameter, not an index.
Related
The following program tries to scan read/write pages of a foreign application with ReadProcessMemory():
#include <Windows.h>
#include <iostream>
#include <vector>
#include <charconv>
#include <cstring>
#include <vector>
#include <stdexcept>
#include <sstream>
#include <cctype>
#include <fstream>
#include <cmath>
using namespace std;
vector<vector<MEMORY_BASIC_INFORMATION>> pageTree( HANDLE hProcess, DWORD dwMask );
using XHANDLE = unique_ptr<void, decltype([]( HANDLE h ) { h && h != INVALID_HANDLE_VALUE && CloseHandle( h ); })>;
int main( int argc, char **argv )
{
if( argc < 2 )
return EXIT_FAILURE;
try
{
DWORD dwProcessId = [&]() -> DWORD
{
DWORD dwRet;
if( from_chars_result fcr = from_chars( argv[1], argv[1] + strlen( argv[1] ), dwRet ); fcr.ec != errc() || *fcr.ptr )
throw invalid_argument( "process-id unparseable" );
return dwRet;
}();
XHANDLE hProcess( [&]() -> HANDLE
{
HANDLE hRet = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwProcessId );
if( !hRet )
throw system_error( (int)GetLastError(), system_category(), "can't open process" );
return hRet;
}() );
vector<vector<MEMORY_BASIC_INFORMATION>> vvmbi = pageTree( hProcess.get(), PAGE_READWRITE );
vector<char> processRegion;
size_t
succs = 0, partialErrs = 0, errs = 0,
total = 0, read = 0, skipped = 0;
for( vector<MEMORY_BASIC_INFORMATION> const &vmbi : vvmbi )
for( MEMORY_BASIC_INFORMATION const &vmbi : vmbi )
{
processRegion.resize( vmbi.RegionSize );
size_t actuallyRead;
bool succ = ReadProcessMemory( hProcess.get(), vmbi.BaseAddress, to_address( processRegion.begin() ), vmbi.RegionSize, &actuallyRead );
succs += succ;
partialErrs += !succ && GetLastError() == ERROR_PARTIAL_COPY;
errs += !succ;
bool bytesCopied = succ || GetLastError() == ERROR_PARTIAL_COPY;
actuallyRead = bytesCopied ? actuallyRead : 0;
total += processRegion.size(),
read += actuallyRead;
skipped += bytesCopied ? processRegion.size() - actuallyRead : processRegion.size();
}
cout << "successes: " << succs << endl;
cout << "partial errs: " << partialErrs << endl;
cout << "errs: " << errs << endl;
cout << "read: " << read << endl;
cout << "skipped: " << skipped;
auto pct = []( double a, double b ) -> double { return trunc( a / b * 1000.0 + 0.5 ) / 10.0; };
cout << " (" << pct( (double)(ptrdiff_t)skipped, (double)(ptrdiff_t)total ) << "%)" << endl;
}
catch( exception const &exc )
{
cout << exc.what() << endl;
}
}
template<typename Fn>
requires requires( Fn fn, MEMORY_BASIC_INFORMATION &mbi ) { { fn( mbi ) } -> std::convertible_to<bool>; }
void enumProcessMemory( HANDLE hProcess, Fn fn );
vector<vector<MEMORY_BASIC_INFORMATION>> pageTree( HANDLE hProcess, DWORD dwMask )
{
vector<vector<MEMORY_BASIC_INFORMATION>> vvmbis;
enumProcessMemory( hProcess, [&]( MEMORY_BASIC_INFORMATION &mbi ) -> bool
{
if( !(mbi.AllocationProtect & dwMask) )
return true;
if( !vvmbis.size() || vvmbis.back().back().BaseAddress != mbi.BaseAddress )
vvmbis.emplace_back( vector<MEMORY_BASIC_INFORMATION>() );
vvmbis.back().emplace_back( mbi );
return true;
} );
return vvmbis;
}
template<typename Fn>
requires requires( Fn fn, MEMORY_BASIC_INFORMATION &mbi ) { { fn( mbi ) } -> std::convertible_to<bool>; }
void enumProcessMemory( HANDLE hProcess, Fn fn )
{
MEMORY_BASIC_INFORMATION mbi;
for( char *last = nullptr; ; last = (char *)mbi.BaseAddress + mbi.RegionSize )
{
size_t nBytes = VirtualQueryEx( hProcess, last, &mbi, sizeof mbi );
if( nBytes != sizeof mbi )
if( DWORD dwErr = GetLastError(); dwErr == ERROR_INVALID_PARAMETER )
break;
else
throw system_error( (int)dwErr, system_category(), "can't query process pages" );
if( !fn( mbi ) )
break;
}
}
This is the result from scanning explorer.exe:
successes: 316
partial errs: 282
errs: 282
read: 139862016
skipped: 4452511744 (97%)
I.e. 316 copies from the foreign address space are successful, 282 are errors with partial reads, the same number are errors at all (i.e. all errors are partial reads), and the given number of bytes are read and skipped. The total memory that has skipped is 97%.
Why does ReadProcessMemory() fail so often, or what am I doing wrong here?
Remy was mostly right. Here's the corrected code with a filter-callback on pageTree instead of a protection mask.
#include <Windows.h>
#include <iostream>
#include <vector>
#include <charconv>
#include <cstring>
#include <vector>
#include <stdexcept>
#include <sstream>
#include <cctype>
#include <fstream>
#include <cmath>
using namespace std;
template<typename FilterFn>
requires requires( FilterFn fn, MEMORY_BASIC_INFORMATION &mbi ) { { fn( mbi ) } -> std::convertible_to<bool>; }
vector<vector<MEMORY_BASIC_INFORMATION>> pageTree( HANDLE hProcess, FilterFn filterFn );
using XHANDLE = unique_ptr<void, decltype([]( HANDLE h ) { h && h != INVALID_HANDLE_VALUE && CloseHandle( h ); })>;
int main( int argc, char **argv )
{
if( argc < 2 )
return EXIT_FAILURE;
try
{
DWORD dwProcessId = [&]() -> DWORD
{
DWORD dwRet;
if( from_chars_result fcr = from_chars( argv[1], argv[1] + strlen( argv[1] ), dwRet ); fcr.ec != errc() || *fcr.ptr )
throw invalid_argument( "process-id unparseable" );
return dwRet;
}();
XHANDLE hProcess( [&]() -> HANDLE
{
HANDLE hRet = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwProcessId );
if( !hRet )
throw system_error( (int)GetLastError(), system_category(), "can't open process" );
return hRet;
}() );
vector<vector<MEMORY_BASIC_INFORMATION>> vvmbi = pageTree( hProcess.get(),
[]( MEMORY_BASIC_INFORMATION &mbi ) -> bool
{
return mbi.State == MEM_COMMIT;
} );
vector<char> processRegion;
size_t
succs = 0, partialErrs = 0, errs = 0,
total = 0, read = 0, skipped = 0;
for( vector<MEMORY_BASIC_INFORMATION> const &vmbi : vvmbi )
for( MEMORY_BASIC_INFORMATION const &vmbi : vmbi )
{
processRegion.resize( vmbi.RegionSize );
size_t actuallyRead;
bool succ = ReadProcessMemory( hProcess.get(), vmbi.BaseAddress, to_address( processRegion.begin() ), vmbi.RegionSize, &actuallyRead );
succs += succ;
partialErrs += !succ && GetLastError() == ERROR_PARTIAL_COPY;
errs += !succ;
bool bytesCopied = succ || GetLastError() == ERROR_PARTIAL_COPY;
actuallyRead = bytesCopied ? actuallyRead : 0;
total += processRegion.size(),
read += actuallyRead;
skipped += bytesCopied ? processRegion.size() - actuallyRead : processRegion.size();
}
cout << "successes: " << succs << endl;
cout << "partial errs: " << partialErrs << endl;
cout << "errs: " << errs << endl;
cout << "read: " << read << endl;
cout << "skipped: " << skipped;
auto pct = []( double a, double b ) -> double { return trunc( a / b * 1000.0 + 0.5 ) / 10.0; };
cout << " (" << pct( (double)(ptrdiff_t)skipped, (double)(ptrdiff_t)total ) << "%)" << endl;
}
catch( exception const &exc )
{
cout << exc.what() << endl;
}
}
template<typename Fn>
requires requires( Fn fn, MEMORY_BASIC_INFORMATION &mbi ) { { fn( mbi ) } -> std::convertible_to<bool>; }
void enumProcessMemory( HANDLE hProcess, Fn fn );
template<typename FilterFn>
requires requires( FilterFn fn, MEMORY_BASIC_INFORMATION &mbi ) { { fn( mbi ) } -> std::convertible_to<bool>; }
vector<vector<MEMORY_BASIC_INFORMATION>> pageTree( HANDLE hProcess, FilterFn filterFn )
{
vector<vector<MEMORY_BASIC_INFORMATION>> vvmbis;
enumProcessMemory( hProcess, [&]( MEMORY_BASIC_INFORMATION &mbi ) -> bool
{
if( !filterFn( mbi ) )
return true;
if( !vvmbis.size() || vvmbis.back().back().BaseAddress != mbi.BaseAddress )
vvmbis.emplace_back( vector<MEMORY_BASIC_INFORMATION>() );
vvmbis.back().emplace_back( mbi );
return true;
} );
return vvmbis;
}
template<typename Fn>
requires requires( Fn fn, MEMORY_BASIC_INFORMATION &mbi ) { { fn( mbi ) } -> std::convertible_to<bool>; }
void enumProcessMemory( HANDLE hProcess, Fn fn )
{
MEMORY_BASIC_INFORMATION mbi;
for( char *last = nullptr; ; last = (char *)mbi.BaseAddress + mbi.RegionSize )
{
size_t nBytes = VirtualQueryEx( hProcess, last, &mbi, sizeof mbi );
if( nBytes != sizeof mbi )
if( DWORD dwErr = GetLastError(); dwErr == ERROR_INVALID_PARAMETER )
break;
else
throw system_error( (int)dwErr, system_category(), "can't query process pages" );
if( !fn( mbi ) )
break;
}
}
Unfortunately I still get about 6% skipped memory:
successes: 2159
partial errs: 225
errs: 225
read: 706748416
skipped: 42897408 (5.7%)
Why is that ?
I've written a little program to query the page-map of a process:
#include <Windows.h>
#include <iostream>
#include <vector>
#include <charconv>
#include <cstring>
#include <stdexcept>
using namespace std;
int main( int argc, char **argv )
{
if( argc < 2 )
return EXIT_FAILURE;
try
{
DWORD dwProcessId = [&]() -> DWORD
{
DWORD dwRet;
from_chars_result fcr = from_chars( argv[1], argv[1] + strlen( argv[1] ), dwRet );
if( fcr.ec != errc() || *fcr.ptr )
throw invalid_argument( "process-id unparseable" );
return dwRet;
}();
HANDLE hProcess = [&]() -> HANDLE
{
HANDLE hRet = OpenProcess( PROCESS_QUERY_INFORMATION, FALSE, dwProcessId );
if( !hRet )
throw system_error( (int)GetLastError(), system_category(), "can't open process" );
return hRet;
}();
size_t pageSize = []() -> size_t
{
SYSTEM_INFO si;
GetSystemInfo( &si );
return si.dwPageSize;
}();
using mbi_t = MEMORY_BASIC_INFORMATION;
vector<mbi_t> mbis( 0x100 );
size_t nRegions;
while( !(nRegions = VirtualQueryEx( hProcess, nullptr, to_address( mbis.begin() ), mbis.size() * sizeof(mbi_t) )) )
if( GetLastError() == ERROR_BAD_LENGTH )
mbis.resize( mbis.size() * 2 );
else
throw system_error( (int)GetLastError(), system_category(), "can't query process pages" );
mbis.resize( nRegions );
for( mbi_t const &mbi : mbis )
{
cout << "base address: " << hex << mbi.BaseAddress << endl;
cout << "allocation base: " << hex << mbi.AllocationBase << endl;
cout << dec << mbi.RegionSize / pageSize << " pages" << endl;
static struct
{
DWORD dwProtect;
char const *str;
} const protectMaps[] =
{
{ PAGE_EXECUTE, "PAGE_EXECUTE" },
{ PAGE_EXECUTE_READ, "PAGE_EXECUTE_READ" },
{ PAGE_EXECUTE_READWRITE, "PAGE_EXECUTE_READWRITE" },
{ PAGE_EXECUTE_WRITECOPY, "PAGE_EXECUTE_WRITECOPY" },
{ PAGE_NOACCESS, "PAGE_NOACCESS" },
{ PAGE_READONLY, "PAGE_READONLY" },
{ PAGE_READWRITE, "PAGE_READWRITE" },
{ PAGE_WRITECOPY, "PAGE_WRITECOPY" }
};
for( auto const &pm : protectMaps )
if( pm.dwProtect == mbi.AllocationProtect )
{
cout << "state: " << pm.str << endl;
break;
}
if( mbi.Type == MEM_IMAGE )
cout << "image";
else if( mbi.Type == MEM_MAPPED )
cout << "mapped";
else if( mbi.Type == MEM_PRIVATE )
cout << "private";
cout << endl << endl;
}
}
catch( exception const &exc )
{
cout << exc.what() << endl;
}
}
Unfortunately the program returns mostly null-data except from the number of pages with the first entry, which is the number of logical pages of the process minus 32.
What am I doing wrong here ?
The process I tried to query runs under the same token, so there coudln't be any privilege issues.
Thank you Hans ! You were right. I thoughth VirtualQueryEx() fills just a number of MEMORY_BASIC_INFORMATION. If you don't see something obvious you say in Germany that you've got tomatoes on your eyes, and yes, I had tomatoes on my eyes (not because of my style ;-)).
Here's the working code:
#include <Windows.h>
#include <iostream>
#include <vector>
#include <charconv>
#include <cstring>
#include <vector>
#include <stdexcept>
using namespace std;
vector<vector<MEMORY_BASIC_INFORMATION>> pageTree( HANDLE hProcess );
int main( int argc, char **argv )
{
if( argc < 2 )
return EXIT_FAILURE;
try
{
DWORD dwProcessId = [&]() -> DWORD
{
DWORD dwRet;
from_chars_result fcr = from_chars( argv[1], argv[1] + strlen( argv[1] ), dwRet );
if( fcr.ec != errc() || *fcr.ptr )
throw invalid_argument( "process-id unparseable" );
return dwRet;
}();
HANDLE hProcess = [&]() -> HANDLE
{
HANDLE hRet = OpenProcess( PROCESS_QUERY_INFORMATION, FALSE, dwProcessId );
if( !hRet )
throw system_error( (int)GetLastError(), system_category(), "can't open process" );
return hRet;
}();
size_t pageSize = []() -> size_t
{
SYSTEM_INFO si;
GetSystemInfo( &si );
return si.dwPageSize;
}();
vector<vector<MEMORY_BASIC_INFORMATION>> vvmbi = pageTree( hProcess );
for( vector<MEMORY_BASIC_INFORMATION> const &vmbi : vvmbi )
{
cout << "allocation base: " << hex << vmbi.front().AllocationBase << endl;
for( MEMORY_BASIC_INFORMATION const &mbi : vmbi )
{
cout << "\tbase address: " << hex << mbi.BaseAddress << endl;
cout << "\t" << dec << mbi.RegionSize / pageSize << " pages" << endl;
static struct
{
DWORD dwProtect;
char const *str;
} const protectMaps[] =
{
{ PAGE_EXECUTE, "PAGE_EXECUTE" },
{ PAGE_EXECUTE_READ, "PAGE_EXECUTE_READ" },
{ PAGE_EXECUTE_READWRITE, "PAGE_EXECUTE_READWRITE" },
{ PAGE_EXECUTE_WRITECOPY, "PAGE_EXECUTE_WRITECOPY" },
{ PAGE_NOACCESS, "PAGE_NOACCESS" },
{ PAGE_READONLY, "PAGE_READONLY" },
{ PAGE_READWRITE, "PAGE_READWRITE" },
{ PAGE_WRITECOPY, "PAGE_WRITECOPY" }
};
for( auto const &pm : protectMaps )
if( pm.dwProtect == mbi.AllocationProtect )
{
cout << "\tstate: " << pm.str << endl;
break;
}
if( mbi.Type == MEM_IMAGE )
cout << "\timage" << endl;
else if( mbi.Type == MEM_MAPPED )
cout << "\tmapped" << endl;
else if( mbi.Type == MEM_PRIVATE )
cout << "\tprivate" << endl;
cout << endl;
}
}
}
catch( exception const &exc )
{
cout << exc.what() << endl;
}
}
template<typename Fn>
requires requires( Fn fn, MEMORY_BASIC_INFORMATION &mbi ) { { fn( mbi ) } -> std::convertible_to<bool>; }
void enumProcessMemory( HANDLE hProcess, Fn fn );
vector<vector<MEMORY_BASIC_INFORMATION>> pageTree( HANDLE hProcess )
{
vector<vector<MEMORY_BASIC_INFORMATION>> vvmbis;
enumProcessMemory( hProcess, [&]( MEMORY_BASIC_INFORMATION &mbi ) -> bool
{
if( !vvmbis.size() || vvmbis.back().back().BaseAddress != mbi.BaseAddress )
vvmbis.emplace_back( vector<MEMORY_BASIC_INFORMATION>() );
vvmbis.back().emplace_back( mbi );
return true;
} );
return vvmbis;
}
template<typename Fn>
requires requires( Fn fn, MEMORY_BASIC_INFORMATION &mbi ) { { fn( mbi ) } -> std::convertible_to<bool>; }
void enumProcessMemory( HANDLE hProcess, Fn fn )
{
MEMORY_BASIC_INFORMATION mbi;
for( char *last = nullptr; ; last = (char *)mbi.BaseAddress + mbi.RegionSize )
{
size_t nBytes = VirtualQueryEx( hProcess, last, &mbi, sizeof mbi );
if( nBytes != sizeof mbi )
if( DWORD dwErr = GetLastError(); dwErr == ERROR_INVALID_PARAMETER )
break;
else
throw system_error( (int)dwErr, system_category(), "can't query process pages" );
if( !fn( mbi ) )
break;
}
}
The code now groups the allocation bases. Its segemented that parts can be extended without changing the framework.
I have created a basic client/server c++ socket program. I can write integers over the socket reliably, but when I try to write a string over the socket the receiving end only receives the data about 25% of the time. I have used Wireshark to verify that the data is being sent. I am new to c++ and network programming so any input would be appreciated. The code is below.
class compressionServer{
int PORT = 4000;
int LISTEN_QUEUE = 1024;
int sock;
int conn;
struct sockaddr_in socketAddress;
int receivedMagicData[8+1];
int receivedStatusCode[2];
int receivedPayloadLength[2];
char receivedCompressionData[2048];
int requestCode = 0;
int payloadLength;
uint32_t inBytes = 0;
uint32_t outBytes = 0;
double compressionRatio = 0;
string dataToCompress;
public:
void start(){
if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0){
printf("Socket Error");
exit(1);
}
bzero(&socketAddress, sizeof(socketAddress));
socketAddress.sin_family = AF_INET;
socketAddress.sin_addr.s_addr = htonl(INADDR_ANY);
socketAddress.sin_port = htons(PORT);
int enable = 1;
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0){ // so we can rebind quickly while testing
printf("setsockopt(SO_REUSEADDR) failed");
}
if(::bind(sock, (struct sockaddr *) &socketAddress, sizeof(socketAddress)) < 0){
printf("Bind Error\n");
std::cout << std::strerror(errno) << std::endl;
exit(1);
}
if(listen(sock, LISTEN_QUEUE) < 0){
printf("Listen Error");
exit(1);
}
for ( ; ; ) {
if((conn = accept(sock, (struct sockaddr *) NULL, NULL)) < 0){
printf("Accept Error");
exit(1);
}
ssize_t n;
if((n = read(conn, receivedMagicData, 8)) > 0){
int magicWord = ntohl(*receivedMagicData);
if(magicWord == 53545259){
std::cout << "DOES NOT MATCH" << std::endl;
break;
}
}
if((n = read(conn, receivedPayloadLength, 2)) > 0){
payloadLength = ntohs(*receivedPayloadLength);
std::cout << "payloadLength = " << std::hex << payloadLength << std::endl;
}
if((n = read(conn, receivedStatusCode, 2)) > 0){
requestCode = ntohs(*receivedStatusCode);
std::cout << "requestCode = " << std::hex << requestCode << std::endl;
}
while((n = read(conn, receivedCompressionData, 2048)) > 0){
receivedCompressionData[n] = 0;
cout << "data: " << receivedCompressionData << endl;
dataToCompress = receivedCompressionData;
if(strlen(receivedCompressionData) > 0){
break;
}
}
}
if (close(conn) < 0){
printf("Close Error");
exit(1);
}
}
};
The server class essential is expecting to receive 12 bytes of data as the header and after that up to 2048 bytes as the characters. This is the part only coming through a fraction of the time.
class compressionClient{
public:
void start(std::string ipAddr){
int MAX_LINE = 4096;
int sockfd;
struct sockaddr_in servaddr;
if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
printf("socket error");
exit(1);
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(4000);
if (inet_pton(AF_INET, ipAddr.c_str(), &servaddr.sin_addr) <= 0){
printf("inet_pton error for %s", ipAddr.c_str());
exit(1);
}
if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0){
printf("connect error");
exit(1);
}
long headerHex = htonl(0x53545259);
long header2Hex = htonl(0x31300034);
std::cout << "send: " << std::hex << headerHex << std::endl;
std::cout << "send2: " << std::hex << header2Hex << std::endl;
//server receives this
if(send(sockfd, (char *) (&headerHex), sizeof(headerHex), 0) < 0){
printf("Write Error");
exit(1);
}
//server receives this too
if(send(sockfd, (char *) (&header2Hex), sizeof(header2Hex), 0) < 0){
printf("Write Error2");
exit(1);
}
char data[100];
snprintf(data, sizeof(data), "aaabbcddd");
//server only recieves this sometimes
if(write(sockfd, data, strlen(data)) < 0){
printf("write error3");
exit(1);
}
}
};
I wrote 2 threads to decode RTSP stream from IP camera as below:
RTSP_read_paket function used to read Packets from RTSP link, packets stored in a queue named Packet_buf.
std::queue<AVPacket> Packet_buf;
bool pkt_pending_k = false;
int RTSP_read_packet (string url)
{
rtsp_init(url);
int ret;
AVPacket packet;
av_init_packet(&packet);
while(1)
{
ret = av_read_frame(pFormatCtx,&packet);
if(ret==0)
{
if (packet.stream_index == video_stream_index)
{
Packet_buf.push(packet);
if((ready1 == false))
{
ready1 = true;
conv1.notify_one();
}
}
av_packet_unref(&packet);
cout<<"number of RTSP packet: "<<Packet_buf.size()<<endl;
}
}
return 0;
}
ffmpeg_decode read packets from Packet_buf to decode frames
AVFrame ffmpeg_decode( void )
{
AVPacket avpkt;
av_init_packet(&avpkt);
int ret;
conv1.wait(lk1,[]{return ready1;});
while(1)
{
while(1)
{
ret = avcodec_receive_frame(pCodecCtx,pFrame);
if(ret == AVERROR(EAGAIN)||ret==AVERROR_EOF){
break;
}
return pFrame;
}
if(!Packet_buf.empty())
{
if(pkt_pending_k == false)
{
avpkt = Packet_buf.front();
Packet_buf.pop();
}else{
pkt_pending_k = false;
}
}
ret = avcodec_send_packet(pCodecCtx, &avpkt); //program halting here
cout<<"-------------> ret = "<<ret<<endl;
if(ret==AVERROR(EAGAIN))
{
pkt_pending_k = true;
}
if(ret<0||ret==AVERROR_EOF)
{
cout<<"avcodec_send_packet: "<<ret<<endl;
break;
}
}
}
int main () {
thread Camera2_readPackets(RTSP_read_packet,url);
thread Camera2_decode(ffmpeg_decode,url);
Camera2_decode.join();
return 0;
}
My program halt at line:
ret = avcodec_send_packet(pCodecCtx, &avpkt);
Anyone can help me find the problem, thanks !
P/s:
rtsp_init function:
int rtsp_init (string url)
{
av_register_all();
avdevice_register_all();
avcodec_register_all();
avformat_network_init();
const char *filenameSrc = url.c_str();
pFormatCtx = avformat_alloc_context();
if ( pFormatCtx == NULL )
return -8;
AVDictionary *options = NULL;
av_dict_set(&options,"rtsp_flags","prefer_tcp",0);
av_dict_set(&options,"stimeout","1000000",0);
int avret = avformat_open_input( &pFormatCtx, filenameSrc, NULL, &options );
av_dict_free(&options);
if ( avret != 0 ) {
std::cout << "Open File Error 12" << std::endl;
return -12;
}
avret = avformat_find_stream_info( pFormatCtx, NULL );
if ( avret < 0 ) {
std::cout << "Get Stream Information Error 13" << std::endl;
avformat_close_input( &pFormatCtx );
pFormatCtx = NULL;
return -13;
}
av_dump_format( pFormatCtx, 0, filenameSrc, 0 );
video_stream_index = av_find_best_stream(pFormatCtx,AVMEDIA_TYPE_VIDEO,-1,-1,NULL,0);
if ( video_stream_index < 0 ) {
std::cout << "Video stream was not found Error 14" << std::endl;
avformat_close_input( &pFormatCtx );
pFormatCtx = NULL;
return -14;
}
pCodecCtx = avcodec_alloc_context3(NULL);
avret = avcodec_parameters_to_context(pCodecCtx,pFormatCtx->streams[video_stream_index]->codecpar);
if(avret<0)
{
std::cout << "codec not found Error 15" << std::endl;
return -15;
}
pCodec = avcodec_find_decoder( pCodecCtx->codec_id );
avret = avcodec_open2( pCodecCtx, pCodec, NULL );
if ( avret < 0) {
std::cout << "Open Codec Error 16" << std::endl;
return -16;
}
pFrame = av_frame_alloc();
pFrameRGB = av_frame_alloc();
pFrame->width = pCodecCtx->width;
pFrame->height = pCodecCtx->height;
pFrame->format = pCodecCtx->pix_fmt;
avret = av_frame_get_buffer(pFrame,0);
if (avret < 0)
{
return -17;
}
pFrameRGB->width = pCodecCtx->width;
pFrameRGB->height = pCodecCtx->height;
pFrameRGB->format = AV_PIX_FMT_BGR24;
avret = av_frame_get_buffer(pFrameRGB, 0);
if (avret < 0)
{
return -18;
}
return ( EXIT_SUCCESS );
}
So I'm building a multithreaded socket library in windows and I'm getting the WSA Not Started error when I call recv, even though I successfully get a client to connect to the server. I also had it working before I threaded it, but I don't know what happened since then. Any help would be appreciated.
Spocket.hpp
#include <iostream>
#include <string>
#include <Windows.h>
#pragma comment (lib,"ws2_32.lib")
static bool initialized_ = false;
class Spocket
{
protected:
WSADATA wsaData_;
SOCKET hSocket_;
sockaddr_in service_;
std::string addr_;
USHORT port_;
int exitCode_;
public:
Spocket() {
initialize();
create_socket();
}
Spocket(std::string addr, USHORT port)
: addr_( addr ), port_( port ) {
initialize();
create_socket();
}
Spocket(Spocket spock, SOCKET sock)
: hSocket_( sock ),
wsaData_( spock.wsaData_ ),
service_( spock.service_ ),
addr_( spock.addr_ ),
port_( spock.port_ )
{
initialize();
}
virtual ~Spocket() { close(); }
void initialize();
void create_socket();
void close();
template<typename T>
int recv_data(T* i) {
int ret = recv( hSocket_, reinterpret_cast<char*>(i), 32, 0 );
if( ret == SOCKET_ERROR )
cerr << WSAGetLastError() << endl;
return ret;
}
template<typename T>
int send_data(T* i) {
int ret = send( hSocket_, reinterpret_cast<char*>(i), sizeof(i), 0 );
if( ret == SOCKET_ERROR )
cerr << WSAGetLastError() << endl;
return ret;
}
};
class ServerSpocket : public Spocket
{
public:
ServerSpocket(std::string addr, USHORT port);
Spocket* accept_clients();
};
class ClientSpocket : public Spocket
{
public:
ClientSpocket(std::string addr, USHORT port);
};
Spocket.cpp
#include <iostream>
using namespace std;
#include "../include/spocket.hpp"
void Spocket::initialize() {
if(!initialized_)
{
cout << "Initializing socket..." << endl;
exitCode_ = EXIT_SUCCESS;
int iResult = WSAStartup( MAKEWORD(2,2), &wsaData_ );
if( iResult != NO_ERROR ) {
cerr << "WSAStartup failed" << endl;
exitCode_ = EXIT_FAILURE;
close();
}
initialized_ = true;
}
}
void Spocket::create_socket() {
hSocket_ = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
if( hSocket_ == INVALID_SOCKET )
{
cerr << "Error at socket(): " << WSAGetLastError() << endl;
exitCode_ = EXIT_FAILURE;
close();
}
service_.sin_family = AF_INET;
service_.sin_addr.s_addr = inet_addr(addr_.c_str());
service_.sin_port = htons(port_);
}
void Spocket::close() {
closesocket( hSocket_ );
WSACleanup();
}
ServerSpocket::ServerSpocket(std::string addr, USHORT port) : Spocket(addr, port) {
if( bind( hSocket_, (SOCKADDR*)&service_, sizeof(service_) ) == SOCKET_ERROR )
{
cerr << "Failed to bind" << endl;
exitCode_ = EXIT_FAILURE;
close();
}
if( listen( hSocket_, 1 ) == SOCKET_ERROR )
{
cerr << "Error listening on socket" << endl;
exitCode_ = EXIT_FAILURE;
close();
}
}
Spocket* ServerSpocket::accept_clients() {
cout << "Waiting for connection...\n";
SOCKET hAccepted = INVALID_SOCKET;
while( hAccepted == INVALID_SOCKET )
hAccepted = accept( hSocket_, NULL, NULL );
return new Spocket( *this, hAccepted );
}
ClientSpocket::ClientSpocket(std::string addr, USHORT port) : Spocket(addr, port) {
if( connect( hSocket_, (SOCKADDR*)&service_, sizeof(service_) ) == SOCKET_ERROR )
{
cerr << "Failed to connect" << endl;
exitCode_ = EXIT_FAILURE;
close();
}
}
Server_main.cpp
#include <iostream>
#include <fstream>
#include <vector>
#include <spocket.hpp>
using namespace std;
vector<HANDLE> hThreads;
vector<DWORD> dwThreadIds;
struct ConnectionInfo
{
string ip;
unsigned int port;
ConnectionInfo( string ip_, unsigned int port_ ) : ip(ip_), port(port_){}
};
static ConnectionInfo ci( "127.0.0.1", 27015 );
DWORD WINAPI clientSession( LPVOID lpParam )
{
// create new socket to listen for connection attempts
ConnectionInfo arg = *reinterpret_cast<ConnectionInfo*>(lpParam);
ServerSpocket listenSock( arg.ip, arg.port );
// spawn a duplicate thread when a connection is made, and close the current listening socket
Spocket* sessionSock = listenSock.accept_clients();
listenSock.close();
cout << "client connected..." << endl;
/*
hThreads.push_back( CreateThread( NULL, 0, clientSession, &ci, 0, NULL ) );
*/
// service the connected client
string msg;
while( sessionSock->recv_data(&msg) != SOCKET_ERROR && msg != "goodbye!" )
{
cout << msg << endl;
msg.clear();
}
cout << "finished with client..." << endl;
// wait quietly for server shutdown
while( true )
Sleep( 200 );
return 0;
}
int main() {
cout << "[Server]" << endl;
cout << "starting up..." << endl;
hThreads.push_back( CreateThread( NULL, 0, clientSession, &ci, 0, NULL ) );
string input = "";
do
cin >> input;
while( input != "exit" );
// close all thread handles here
cout << "shutting down..." << endl;
return 0;
}
I beleive you must keep the "original" socket alive. Move listenSock.close(); after the sessionSock->recv_data() loop.