I'm developing a stomp client in c++ using boost library for sockets and threads.
The program consists of two major classes SocketListener which gets frame from the socket and UserInterface which receives commands from the user and sends frames to the server.
I can't figure out a segmentation fault i get when i shutdown the SocketListener. (when i call the shutdown method)
Using valgrind i get this error:
==8450== Thread 2:
==8450== Invalid read of size 8
==8450== at 0x588AF8B: std::string::assign(std::string const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16)
==8450== by 0x417846: SocketListener::shutdown(std::string) (SocketListener.cpp:114)
==8450== by 0x41D2A7: userInterface::shutdown() (UserInterface.cpp:123)
==8450== by 0x41C7ED: userInterface::run() (UserInterface.cpp:37)
==8450== by 0x415F0B: boost::_mfi::mf0<void, userInterface>::operator()(userInterface*) const (mem_fn_template.hpp:49)
==8450== by 0x415DF1: void boost::_bi::list1<boost::_bi::value<userInterface*> >::operator()<boost::_mfi::mf0<void, userInterface>, boost::_bi::list0>(boost::_bi::type<void>, boost::_mfi::mf0<void, userInterface>&, boost::_bi::list0&, int) (bind.hpp:253)
==8450== by 0x415B4E: boost::_bi::bind_t<void, boost::_mfi::mf0<void, userInterface>, boost::_bi::list1<boost::_bi::value<userInterface*> > >::operator()() (bind_template.hpp:20)
==8450== by 0x4157E7: boost::detail::thread_data<boost::_bi::bind_t<void, boost::_mfi::mf0<void, userInterface>, boost::_bi::list1<boost::_bi::value<userInterface*> > > >::run() (thread.hpp:74)
==8450== by 0x5046C2C: thread_proxy (in /usr/local/boost/1.51.0/lib/libboost_thread.so.1.51.0)
==8450== by 0x5260E99: start_thread (pthread_create.c:308)
==8450== by 0x5DF53FC: clone (clone.S:112)
==8450== Address 0x50 is not stack'd, malloc'd or (recently) free'd
==8450==
==8450==
==8450== Process terminating with default action of signal 11 (SIGSEGV)
==8450== Access not within mapped region at address 0x50
==8450== at 0x588AF8B: std::string::assign(std::string const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16)
==8450== by 0x417846: SocketListener::shutdown(std::string) (SocketListener.cpp:114)
==8450== by 0x41D2A7: userInterface::shutdown() (UserInterface.cpp:123)
==8450== by 0x41C7ED: userInterface::run() (UserInterface.cpp:37)
==8450== by 0x415F0B: boost::_mfi::mf0<void, userInterface>::operator()(userInterface*) const (mem_fn_template.hpp:49)
==8450== by 0x415DF1: void boost::_bi::list1<boost::_bi::value<userInterface*> >::operator()<boost::_mfi::mf0<void, userInterface>, boost::_bi::list0>(boost::_bi::type<void>, boost::_mfi::mf0<void, userInterface>&, boost::_bi::list0&, int) (bind.hpp:253)
==8450== by 0x415B4E: boost::_bi::bind_t<void, boost::_mfi::mf0<void, userInterface>, boost::_bi::list1<boost::_bi::value<userInterface*> > >::operator()() (bind_template.hpp:20)
==8450== by 0x4157E7: boost::detail::thread_data<boost::_bi::bind_t<void, boost::_mfi::mf0<void, userInterface>, boost::_bi::list1<boost::_bi::value<userInterface*> > > >::run() (thread.hpp:74)
==8450== by 0x5046C2C: thread_proxy (in /usr/local/boost/1.51.0/lib/libboost_thread.so.1.51.0)
==8450== by 0x5260E99: start_thread (pthread_create.c:308)
==8450== by 0x5DF53FC: clone (clone.S:112)
==8450== If you believe this happened as a result of a stack
==8450== overflow in your program's main thread (unlikely but
==8450== possible), you can try to increase the size of the
==8450== main thread stack using the --main-stacksize= flag.
==8450== The main thread stack size used in this run was 8388608.
here is the code:
main.cpp:
main() {
StompClient* client = new StompClient();
userInterface* ui = new userInterface(client); // this doesnt invoke the segfault but SocketListener::shutdown() is called from this object
SocketListener* socketListener = new SocketListener(client,ui);
boost::thread* uiThread = new boost::thread(&userInterface::run, ui);
boost::thread* socketThread= new boost::thread(&SocketListener::run, socketListener);
socketThread->join();
uiThread->join();
}
SocketListener.h:
class SocketListener {
public:
SocketListener(StompClient* client, userInterface* ui);
virtual ~SocketListener();
void run();
void exportHtml();
void processMessage(StompFrame* frame);
void shutdown(string* fileName);
private:
StompClient* _client;
bool _shutdown;
userInterface* _UI;
string _userName;
};
SocketLisener.cpp:
void SocketListener::run() {
StompParser parser;
StompFrame* frame = 0;
while (!_shutdown) {
if (frame != 0) {
delete frame;
}
frame = _client->getFrame();
if (frame == 0) {
continue;
}
//switch on all the messages cases. the problem happens regardless of message type, even when not receiving anything.
}
void SocketListener::exportHtml() {
//writing to file using poco logger
}
void SocketListener::shutdown(string* fileName) {
cout << "shutting down socket listener" <<endl;
_userName = *fileName; // this is line 114 which valgrind points to
_shutdown = true;
cout << "shutting down socket listener2" <<endl; // this line never gets printed
}
Related
I'm trying to get the fps from multiple cameras. This is the main:
int main(int argc, char* argv[])
{
//Load all cameras IP
map<string, string> camerasIp; //camera ID and Streaming URL
LoadConfig(&camerasIp);
//Get FPS of all cameras
map<string,string>::iterator it_cam;
while(true)
{
for(it_cam = camerasIp.begin(); it_cam != camerasIp.end(); ++it_cam)
{
GetCamFps(it_cam->second);
}
cout << "" << endl;
}
//Send FPS to server
...
return 0;
}
This is the GetCamFps method:
void GetCamFps(string url)
{
cout << "VideoCapture" << endl;
VideoCapture video(url);
cout << "Get frames" << endl;
double fps = video.get(CAP_PROP_FPS);
cout <<"Frames: " << fps << endl;
video.release();
}
And this is the exit:
VideoCapture
Get frames
Frames: 30
VideoCapture
corrupted double-linked list
Aborted (core dumped)
I tried adding a sleep to let some time between opening one url and another but didn't works. I checked the map and it's correct.
When I comment the two firsts cout in the method it works but after a while it fail again.
Output of gdb with backtrace:
Thread 1 "Fps_Monitoring" received signal SIGABRT, Aborted.
__GI_raise (sig=sig#entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
51 ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) backtrace
#0 __GI_raise (sig=sig#entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
#1 0x00007ffff51cc801 in __GI_abort () at abort.c:79
#2 0x00007ffff5215897 in __libc_message (action=action#entry=do_abort, fmt=fmt#entry=0x7ffff5342b9a "%s\n") at ../sysdeps/posix/libc_fatal.c:181
#3 0x00007ffff521c90a in malloc_printerr (str=str#entry=0x7ffff5340cba "corrupted double-linked list") at malloc.c:5350
#4 0x00007ffff521cac4 in malloc_consolidate (av=av#entry=0x7ffff5577c40 <main_arena>) at malloc.c:4456
#5 0x00007ffff52207d8 in _int_malloc (av=av#entry=0x7ffff5577c40 <main_arena>, bytes=bytes#entry=1600) at malloc.c:3703
#6 0x00007ffff52214eb in _int_memalign (av=0x7ffff5577c40 <main_arena>, alignment=64, bytes=<optimized out>) at malloc.c:4694
#7 0x00007ffff5226fba in _mid_memalign (address=<optimized out>, bytes=1496, alignment=<optimized out>) at malloc.c:3314
#8 __posix_memalign (memptr=0x7fffffffdad0, alignment=<optimized out>, size=1496) at malloc.c:5369
#9 0x00007ffff028e7e3 in av_malloc () from /usr/local/lib/libavutil.so.56
#10 0x00007ffff06b253b in avformat_alloc_context () from /usr/local/lib/libavformat.so.58
#11 0x00007ffff5f8b9a3 in CvCapture_FFMPEG::open(char const*) () from /usr/local/lib/libopencv_videoio.so.4.2
#12 0x00007ffff5f8e9ff in cv::cvCreateFileCapture_FFMPEG_proxy(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) ()
from /usr/local/lib/libopencv_videoio.so.4.2
#13 0x00007ffff5f71566 in cv::StaticBackend::createCapture(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) const ()
from /usr/local/lib/libopencv_videoio.so.4.2
#14 0x00007ffff5f4cc17 in cv::VideoCapture::open(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int) ()
from /usr/local/lib/libopencv_videoio.so.4.2
#15 0x00007ffff5f4f595 in cv::VideoCapture::VideoCapture(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int) ()
from /usr/local/lib/libopencv_videoio.so.4.2
#16 0x000055555555f9b3 in GetCamFps(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) ()
#17 0x000055555555d5df in main ()
Any idea why the second videocapture doesn't work?
Thanks.
I'm new and I'm using debian 10 x64. Why is error in the line with SEND? Someone can sugest me how to fix that problem?
send(socket, (char*)m_MsgBuf+sendBytes, std::min(m_MsgSize-sendBytes+2, 1000),
I got that ERROR LOG:
==24819== Thread 3:
==24819== Syscall param socketcall.sendto(msg) points to uninitialised byte(s)
==24819== at 0x51442B4: __libc_send (send.c:28)
==24819== by 0x51442B4: send (send.c:23)
==24819== by 0x1FCFC9: NetworkMessage::WriteToSocket(int) (networkmessage.cpp:117)
==24819== by 0x231624: Protocol76::flushOutputBuffer() (protocol76.cpp:3574)
==24819== by 0x22ECF4: Protocol76::sendThingAppear(Thing const*) (protocol76.cpp:3039)
==24819== by 0x214DE1: Player::onThingAppear(Thing const*) (player.cpp:2165)
==24819== by 0x1829D0: Game::sendAddThing(Player*, Position const&, Thing const*) (game.cpp:7005)
==24819== by 0x16789F: Game::placeCreature(Position&, Creature*, int*) (game.cpp:1260)
==24819== by 0x223995: Protocol76::ConnectPlayer(int*) (protocol76.cpp:66)
==24819== by 0x208C43: ConnectionHandler(void*) (otserv.cpp:575)
==24819== by 0x5139F26: start_thread (pthread_create.c:479)
==24819== by 0x55F12AE: clone (clone.S:95)
==24819== Address 0x111137f1 is 289 bytes inside a block of size 16,912 alloc'd
==24819== at 0x4836DEF: operator new(unsigned long) (vg_replace_malloc.c:344)
==24819== by 0x2086ED: ConnectionHandler(void*) (otserv.cpp:510)
==24819== by 0x5139F26: start_thread (pthread_create.c:479)
==24819== by 0x55F12AE: clone (clone.S:95)
==24819==
CODE:
bool NetworkMessage::WriteToSocket(SOCKET socket)
{
if (m_MsgSize == 0)
return true;
m_MsgBuf[0] = (unsigned char)(m_MsgSize);
m_MsgBuf[1] = (unsigned char)(m_MsgSize >> 8);
bool ret = true;
int32_t sendBytes = 0;
int32_t flags = 0;
int32_t retry = 0;
flags = MSG_DONTWAIT; // 2 ?
do
{
int32_t b = send(socket, (char*)m_MsgBuf+sendBytes, std::min(m_MsgSize-sendBytes+2, 1000), flags);
if(b <= 0)
{
int32_t errnum;
if(errnum == EWOULDBLOCK)
{
b = 0;
OTSYS_SLEEP(10);
retry++;
if(retry == 10)
{
ret = false;
break;
}
}
else
{
ret = false;
break;
}
}
sendBytes += b;
}while(sendBytes < m_MsgSize+2);
return ret;
}
==930== Thread 3:
==930== Conditional jump or move depends on uninitialised value(s)
==930== at 0x1FCFE7: NetworkMessage::WriteToSocket(int) (networkmessage.cpp:106)
==930== by 0x208340: ConnectionHandler(void*) (otserv.cpp:427)
==930== by 0x5139F26: start_thread (pthread_create.c:479)
==930== by 0x55F12AE: clone (clone.S:95)
==930==
==930== Syscall param socketcall.sendto(msg) points to uninitialised byte(s)
==930== at 0x51442B4: __libc_send (send.c:28)
==930== by 0x51442B4: send (send.c:23)
==930== by 0x1FCFD9: NetworkMessage::WriteToSocket(int) (networkmessage.cpp:100)
==930== by 0x231650: Protocol76::flushOutputBuffer() (protocol76.cpp:3574)
==930== by 0x22ED20: Protocol76::sendThingAppear(Thing const*) (protocol76.cpp:3039)
==930== by 0x214E0D: Player::onThingAppear(Thing const*) (player.cpp:2165)
==930== by 0x1829D0: Game::sendAddThing(Player*, Position const&, Thing const*) (game.cpp:7005)
==930== by 0x16789F: Game::placeCreature(Position&, Creature*, int*) (game.cpp:1260)
==930== by 0x2239C1: Protocol76::ConnectPlayer(int*) (protocol76.cpp:66)
==930== by 0x208C6F: ConnectionHandler(void*) (otserv.cpp:575)
==930== by 0x5139F26: start_thread (pthread_create.c:479)
==930== by 0x55F12AE: clone (clone.S:95)
==930== Address 0x111198d1 is 289 bytes inside a block of size 16,912 alloc'd
==930== at 0x4836DEF: operator new(unsigned long) (vg_replace_malloc.c:344)
==930== by 0x208719: ConnectionHandler(void*) (otserv.cpp:510)
==930== by 0x5139F26: start_thread (pthread_create.c:479)
==930== by 0x55F12AE: clone (clone.S:95)
==930==
==930== Conditional jump or move depends on uninitialised value(s)
==930== at 0x1FCFE7: NetworkMessage::WriteToSocket(int) (networkmessage.cpp:106)
==930== by 0x231650: Protocol76::flushOutputBuffer() (protocol76.cpp:3574)
==930== by 0x22ED20: Protocol76::sendThingAppear(Thing const*) (protocol76.cpp:3039)
==930== by 0x214E0D: Player::onThingAppear(Thing const*) (player.cpp:2165)
==930== by 0x1829D0: Game::sendAddThing(Player*, Position const&, Thing const*) (game.cpp:7005)
==930== by 0x16789F: Game::placeCreature(Position&, Creature*, int*) (game.cpp:1260)
==930== by 0x2239C1: Protocol76::ConnectPlayer(int*) (protocol76.cpp:66)
==930== by 0x208C6F: ConnectionHandler(void*) (otserv.cpp:575)
==930== by 0x5139F26: start_thread (pthread_create.c:479)
==930== by 0x55F12AE: clone (clone.S:95)
==930== Thread 2:
==930== Conditional jump or move depends on uninitialised value(s)
==930== at 0x1FCFE7: NetworkMessage::WriteToSocket(int) (networkmessage.cpp:106)
==930== by 0x231650: Protocol76::flushOutputBuffer() (protocol76.cpp:3574)
==930== by 0x214089: Player::flushMsg() (player.cpp:1867)
==930== by 0x182338: Game::flushSendBuffers() (game.cpp:6879)
==930== by 0x17AAB2: Game::checkCreature(unsigned int) (game.cpp:5461)
==930== by 0x1A4B67: std::mem_fun1_t<void, Game, unsigned int>::operator()(Game*, unsigned int) const (stl_function.h:1284)
==930== by 0x1A1668: std::binder2nd<std::mem_fun1_t<void, Game, unsigned int> >::operator()(Game* const&)const (binders.h:158)
==930== by 0x19BCCD: boost::detail::function::void_function_obj_invoker1<std::binder2nd<std::mem_fun1_t<void, Game, unsigned int>>,void, Game*>::invoke(boost::detail::function::function_buffer&, Game*) (function_template.hpp:159)
==930== by 0x23810D: boost::function1<void, Game*>::operator()(Game*) const (function_template.hpp:768)
==930== by 0x237FBC: TSchedulerTask::operator()(Game*) (scheduler.h:63)
==930== by 0x166D2B: Game::eventThread(void*) (game.cpp:1045)
==930== by 0x5139F26: start_thread (pthread_create.c:479)
==930==
==930== Thread 3:
==930== Syscall param socketcall.sendto(msg) points to uninitialised byte(s)
==930== at 0x51442B4: __libc_send (send.c:28)
==930== by 0x51442B4: send (send.c:23)
==930== by 0x1FCFD9: NetworkMessage::WriteToSocket(int) (networkmessage.cpp:100)
==930== by 0x231650: Protocol76::flushOutputBuffer() (protocol76.cpp:3574)
==930== by 0x214089: Player::flushMsg() (player.cpp:1867)
==930== by 0x182338: Game::flushSendBuffers() (game.cpp:6879)
==930== by 0x224573: Protocol76::parsePacket(NetworkMessage&) (protocol76.cpp:405)
==930== by 0x223A3F: Protocol76::ReceiveLoop() (protocol76.cpp:86)
==930== by 0x208E70: ConnectionHandler(void*) (otserv.cpp:611)
==930== by 0x5139F26: start_thread (pthread_create.c:479)
==930== by 0x55F12AE: clone (clone.S:95)
==930== Address 0x11119f5f is 1,967 bytes inside a block of size 16,912 alloc'd
==930== at 0x4836DEF: operator new(unsigned long) (vg_replace_malloc.c:344)
==930== by 0x208719: ConnectionHandler(void*) (otserv.cpp:510)
==930== by 0x5139F26: start_thread (pthread_create.c:479)
==930== by 0x55F12AE: clone (clone.S:95)
==930==
I use code like this:
bool NetworkMessage::WriteToSocket(SOCKET socket)
{
if (m_MsgSize == 0)
return true;
m_MsgBuf[0] = (unsigned char)(m_MsgSize);
m_MsgBuf[1] = (unsigned char)(m_MsgSize >> 8);
bool ret = true;
int32_t sendBytes = 0;
int32_t flags = 0;
int32_t retry = 0;
flags = MSG_DONTWAIT; // 2 ?
while (sendBytes != m_MsgSize)
{ /* != rather than < */
int32_t b = send(socket, (char*)m_MsgBuf+sendBytes, std::min(m_MsgSize-sendBytes+2, 1000), flags);
if(b <= 0)
{
int32_t errnum;
if(errnum == EWOULDBLOCK)
{
b = 0;
OTSYS_SLEEP(10);
retry++;
if(retry == 10)
{
ret = false;
break;
}
}
else
{
ret = false;
break;
}
}
sendBytes += b;
}
return ret;
}
EDIT
the last time when i had similar error I needed to use that code and now everything is working: sigemptyset(&sigh.sa_mask); OR memset(&sigh, 0, sizeof(sigh)); here i found all msgBuf and msg Size in my project files. Do U see something intresting here? m_MsgBuf wklejto.pl/828244 m_MsgSize wklejto.pl/828245
EDIT
so I did this, in file NetworkMessage.cpp I have added under AddString/AddU32/AddU16/AddByte this:
#ifdef CHECKVAL
checkval(m_MsgBuf+m_ReadPos, stringlen);
#endif
on the top this file I have added:
#include "player.h"
#ifdef CHECKVAL
extern int checkval(unsigned char * buff, int len);
#endif
and to the end added this code to player.cpp
#ifdef CHECKVAL
int checkval(unsigned char * buff, int len)
{
int r = 0;
buff -= len;
while (len--)
r += *buff++;
return r;
}
#endif
and also I have changed char to unsigned char - bcs I got error invalid conversion from ‘unsigned char*’ to ‘char*’
to END I added to compilator this -DCHECKVAL
after that I see same error
==15290== Thread 3:
==15290== Syscall param socketcall.sendto(msg) points to uninitialised byte(s)
==15290== at 0x51442B4: __libc_send (send.c:28)
==15290== by 0x51442B4: send (send.c:23)
==15290== by 0x1FCFDC: NetworkMessage::WriteToSocket(int) (networkmessage.cpp:105)
==15290== by 0x231728: Protocol76::flushOutputBuffer() (protocol76.cpp:3574)
==15290== by 0x22EDF8: Protocol76::sendThingAppear(Thing const*) (protocol76. cpp:3039)
==15290== by 0x214E99: Player::onThingAppear(Thing const*) (player.cpp:2165)
==15290== by 0x1829D0: Game::sendAddThing(Player*, Position const&, Thing const*) (game.cpp:7005)
==15290== by 0x16789F: Game::placeCreature(Position&, Creature*, int*) (game.cpp:1260)
==15290== by 0x223A99: Protocol76::ConnectPlayer(int*) (protocol76.cpp:66)
==15290== by 0x208CFB: ConnectionHandler(void*) (otserv.cpp:575)
==15290== by 0x5139F26: start_thread (pthread_create.c:479)
==15290== by 0x55F12AE: clone (clone.S:95)
==15290== Address 0x11116331 is 289 bytes inside a block of size 16,912 alloc'd
==15290== at 0x4836DEF: operator new(unsigned long) (vg_replace_malloc.c:344)
==15290== by 0x2087A5: ConnectionHandler(void*) (otserv.cpp:510)
==15290== by 0x5139F26: start_thread (pthread_create.c:479)
==15290== by 0x55F12AE: clone (clone.S:95)
==15290==
==15290== Syscall param socketcall.sendto(msg) points to uninitialised byte(s)
==15290== at 0x51442B4: __libc_send (send.c:28)
==15290== by 0x51442B4: send (send.c:23)
==15290== by 0x1FCFDC: NetworkMessage::WriteToSocket(int) (networkmessage.cpp:105)
==15290== by 0x231728: Protocol76::flushOutputBuffer() (protocol76.cpp:3574)
==15290== by 0x214115: Player::flushMsg() (player.cpp:1867)
==15290== by 0x182338: Game::flushSendBuffers() (game.cpp:6879)
==15290== by 0x22464B: Protocol76::parsePacket(NetworkMessage&) (protocol76.cpp:405)
==15290== by 0x223B17: Protocol76::ReceiveLoop() (protocol76.cpp:86)
==15290== by 0x208EFC: ConnectionHandler(void*) (otserv.cpp:611)
==15290== by 0x5139F26: start_thread (pthread_create.c:479)
==15290== by 0x55F12AE: clone (clone.S:95)
==15290== Address 0x111169bf is 1,967 bytes inside a block of size 16,912 alloc'd
==15290== at 0x4836DEF: operator new(unsigned long) (vg_replace_malloc.c:344)
==15290== by 0x2087A5: ConnectionHandler(void*) (otserv.cpp:510)
==15290== by 0x5139F26: start_thread (pthread_create.c:479)
==15290== by 0x55F12AE: clone (clone.S:95)
==15290==
hmm.. but this function looks intresting ConnectionHandler in the line 510 is problem?
Protocol76* protocol;
protocol = new Protocol76(s);
and:
Protocol76::Protocol76(SOCKET s)
{
OTSYS_THREAD_LOCKVARINIT(bufferLock);
player = NULL;
pendingLogout = false;
windowTextID = 0;
readItem = NULL;
this->s = s;
}
full ConnectionHandler and password is 123
enter link description here
line 510 in the file is 152
how do u think?
something like this can be enough?
int checkval(unsigned char * buff, int len)
{
buff -= len;
ofstream bufile ("buff.txt");
if (bufile.is_open())
{
while (len--)
{
bufile << "buff: " << *buff << "len: " << len;
}
bufile.close();
}
}
Supposing you initialized m_MsgSize bytes in m_MsgBuf and you want to send them in a loop block by block whose size is
std::min(m_MsgSize-sendBytes+2, 1000)
because of the "+2" depending on the initial value of m_MsgSize you can send 1 or 2 extra bytes after the first m_MsgSize bytes, these extra bytes can be just non initialized or even out of m_MsgBuf with an undefined behavior
Notice also that if you do
int32_t sendBytes = 0
while (sendBytes != m_MsgSize) { /* != rather than < */
int32_t b = send(socket, (char*)m_MsgBuf+sendBytes, std::min(m_MsgSize-sendBytes+2, 1000), ...);
... error management
sendBytes += b;
}
because of the error introduced by the +2 you can have sendBytes greater than m_MsgSize with probable bad effects.
Just remove that "+2"
[edit after you edit you question/you answer]
Your +2 is not a problem in case m_MsgSize do not count the two additional bytes to send the length of the next bytes
valgrind signal few errors and they concern bytes inside the buffer, not the 1 or 2 last ones, for me that means you copy in m_MsgBuf few bytes non initialized. Sometimes valgrind does not signal immediately when a value was not initialized, for instance you can have :
int i; // not initialized
f(i); // nothing signaled by valgrind even i not initialized
...
void f(int i)
{
int j = i + 1; // here valgrind signal a non initialized value
I think you are in that case.
Note this may be a non error, imagine you do that :
// set some elements
char s[20];
...
strcpy(s, "aze");
...
memcpy(m_MsgBuf + 2, /* save 2 bytes for the length */
s, sizeof(s));
m_MsgSize = sizeof(s);
... may be some oher element added from m_MsgSize+2 and updating m_MsgSize
NetworkMessage::WriteToSocket(socket);
only 4 bytes was initialized in s but to have a constant size sent you send (at least) 20 bytes => 16 bytes in the buffer correspond to non initialized values => valgrind will signal them
To know if you are in a 'non error' case or if valgrind signals a real problem you have to analyze the setting of all the values you put in the buffer, but again warning valgrind can take time to signal the use of a non initialized value, that value may be was used by several intermediate location before to reach hte buffer you send
[edit from your remark giving piece of code]
The initialized value probably come from the caller of the methodes NetworkMessage::AddXXX, for instance NetworkMessage::AddByte receive in argument a non initialized byte.
The fact you have that class with dedicated method to add data in the buffer is a chance, you can modify their definitions with additional code to artificially use the bytes from the buffer to allow valgrind to detect a non initialized value. You can put the additional codes protected by #ifdef ... #endif to easily activate/deactivate it
For instance (use the type of m_MsgBuf to type the parameter buff of checkval, I used "char *" because I do not know the type of m_MsgBuf) :
#ifdef CHECKVAL
extern int checkval(char * buff, int len);
#endif
void NetworkMessage::AddByte(unsigned char value)
{
if(!canAdd(1))
return;
m_MsgBuf[m_ReadPos++] = value;
m_MsgSize++;
#ifdef CHECKVAL
checkval(m_MsgBuf+m_ReadPos, 1);
#endif
}
void NetworkMessage::AddU16(uint16_t value)
{
if(!canAdd(2))
return;
m_MsgBuf[m_ReadPos++] = (unsigned char)(value);
m_MsgBuf[m_ReadPos++] = (unsigned char)(value >> 8);
m_MsgSize += 2;
#ifdef CHECKVAL
checkval(m_MsgBuf+m_ReadPos, 2);
#endif
}
void NetworkMessage::AddU32(uint32_t value)
{
if(!canAdd(4))
return;
m_MsgBuf[m_ReadPos++] = (unsigned char)(value);
m_MsgBuf[m_ReadPos++] = (unsigned char)(value >> 8);
m_MsgBuf[m_ReadPos++] = (unsigned char)(value >> 16);
m_MsgBuf[m_ReadPos++] = (unsigned char)(value >> 24);
m_MsgSize += 4;
#ifdef CHECKVAL
checkval(m_MsgBuf+m_ReadPos, 4);
#endif
}
void NetworkMessage::AddString(const char* value)
{
uint32_t stringlen = (uint32_t) strlen(value);
if(!canAdd(stringlen+2) || stringlen > 8192)
return;
#ifdef USING_VISUAL_2005
strcpy_s((char*)m_MsgBuf + m_ReadPos, stringlen, value); //VISUAL
#else
AddU16((uint16_t)stringlen);
strcpy((char*)m_MsgBuf + m_ReadPos, value);
#endif //USING_VISUAL_2005
m_ReadPos += stringlen;
m_MsgSize += stringlen;
#ifdef CHECKVAL
checkval(m_MsgBuf+m_ReadPos, stringlen);
#endif
}
checkval have to access to each byte, for instance :
#ifdef CHECKVAL
int checkval(char * buff, int len)
{
int r = 0;
buff -= len;
while (len--)
r += *buff++;
return r;
}
#endif
and place checkval in an other file than where *NetworkMessage:Addxxx" are defined to be sure the compiler cannot detect it is useless to compute the sum of bytes from the buffer or useless to call checkval because the return value is never used and checkval has no side effect.
If to sum the byte is not enough to force valgrind to check if the bytes are initialized or not, change the definition for instance to save the bytes in a file etc
Of course compile defining CHECKVAL through compiler option, or just adding temporary
#define CHECKVAL
before the definition of checkval and before its declaration
When valgrind will detect a non initialized byte in checkval you will be able to know where the value come from looking at the stack of calls also produced by valgrind
I have a problem in C++ TCP Server(using boost asio).
In normal client, Many clients connect to server is normal.
But if every client connect and disconnect server 10 times/sec, Server core some time.
(1)create server like this:
void ClientConnection::start()
{
socket_.async_read_some(boost::asio::buffer(buffer_),
strand_.wrap(
boost::bind(&connection::handle_read, shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred)));
}
void ClientConnection::closeSocket() {
mStrand.post(boost::bind(&ClientConnection::innerCloseSocket, this->shared_from_this()));
}
void ClientConnection::innerCloseSocket() {
boost::system::error_code error;
mSocket.close(error);
LOG_INFO("Close client[" << mClientId << "] socket connection"); //line:216
}
ClientConnection::~ClientConnection() {
}
(2) hand_read like this:
void ClientConnection::handle_read(const boost::system::error_code& e,
std::size_t bytes_transferred)
{
if (!e)
{
//read data and use it
}
else { //error occurs
closeSocket();
boost::shared_ptr<DisConnectCommand> cmd(new DisConnectCommand());
cmd->setClient(this->weak_from_this()); //here set this connection weak_ptr
putCmd(cmd); //do something in other thread.
}
}
(3) handle_write like this:
void ClientConnection::handle_write(const boost::system::error_code& e)
{
if (!e)
{
//send data
}
else { //error occurs
closeSocket();
boost::shared_ptr<DisConnectCommand> cmd(new DisConnectCommand());
cmd->setClient(this->weak_from_this()); //here set this connection weak_ptr
putCmd(cmd); //do something in other thread.
}
}
core
but, when lots of client connect to server, server core. The core likes a connection has been destructed tow times, the memory is error.
bt like this:
#0 0x00007f6e3aa561f7 in raise () from /lib64/libc.so.6
#1 0x00007f6e3aa578e8 in abort () from /lib64/libc.so.6
#2 0x00007f6e3b35c9d5 in __gnu_cxx::__verbose_terminate_handler() () from /lib64/libstdc++.so.6
#3 0x00007f6e3b35a946 in ?? () from /lib64/libstdc++.so.6
#4 0x00007f6e3b35a973 in std::terminate() () from /lib64/libstdc++.so.6
#5 0x00007f6e3b35ab93 in __cxa_throw () from /lib64/libstdc++.so.6
#6 0x00007f6e3b35b12d in operator new(unsigned long) () from /lib64/libstdc++.so.6
#7 0x00007f6e3b3b9c79 in std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) () from /lib64/libstdc++.so.6
#8 0x00007f6e3b3ba8bb in std::string::_Rep::_M_clone(std::allocator<char> const&, unsigned long) () from /lib64/libstdc++.so.6
#9 0x00007f6e3b3ba964 in std::string::reserve(unsigned long) () from /lib64/libstdc++.so.6
#10 0x00007f6e3b3baa28 in std::string::append(std::string const&) () from /lib64/libstdc++.so.6
#11 0x00007f6e3be5c4c8 in log4cxx::helpers::CharMessageBuffer::operator<< (this=0x7f6e20ff8750, msg=...) at messagebuffer.cpp:31
#12 0x00000000008a3a05 in ClientConnection::internalCloseSocket (this=0x7f6e046fefd0) at src/business/ClientConnection.cpp:216
#13 0x00000000008b620a in boost::_mfi::mf0<void, ClientConnection>::call<boost::shared_ptr<ClientConnection> > (this=0x7f6e20ff89c0, u=...)
at externals/boost/include/boost/bind/mem_fn_template.hpp:40
#14 0x00000000008b5c79 in boost::_mfi::mf0<void, ClientConnection>::operator()<boost::shared_ptr<ClientConnection> > (this=0x7f6e20ff89c0, u=...)
at externals/boost/include/boost/bind/mem_fn_template.hpp:55
#15 0x00000000008b5416 in boost::_bi::list1<boost::_bi::value<boost::shared_ptr<ClientConnection> > >::operator()<boost::_mfi::mf0<void, ClientConnection>, boost::_bi::list0> (
this=0x7f6e20ff89d0, f=..., a=...) at externals/boost/include/boost/bind/bind.hpp:259
#16 0x00000000008b4997 in boost::_bi::bind_t<void, boost::_mfi::mf0<void, ClientConnection>, boost::_bi::list1<boost::_bi::value<boost::shared_ptr<ClientConnection> > > >::operator() (this=0x7f6e20ff89c0) at externals/boost/include/boost/bind/bind.hpp:1294
#17 0x00000000008b3667 in boost::asio::asio_handler_invoke<boost::_bi::bind_t<void, boost::_mfi::mf0<void, ClientConnection>, boost::_bi::list1<boost::_bi::value<boost::shared_ptr<ClientConnection> > > > > (function=...) at externals/boost/include/boost/asio/handler_invoke_hook.hpp:69
#18 0x00000000008b235a in boost_asio_handler_invoke_helpers::invoke<boost::_bi::bind_t<void, boost::_mfi::mf0<void, ClientConnection>, boost::_bi::list1<boost::_bi::value<boost::shared_ptr<ClientConnection> > > >, boost::_bi::bind_t<void, boost::_mfi::mf0<void, ClientConnection>, boost::_bi::list1<boost::_bi::value<boost::shared_ptr<ClientConnection> > > > > (
function=..., context=...) at externals/boost/include/boost/asio/detail/handler_invoke_helpers.hpp:37
#19 0x00000000008b0ee3 in boost::asio::detail::completion_handler<boost::_bi::bind_t<void, boost::_mfi::mf0<void, ClientConnection>, boost::_bi::list1<boost::_bi::value<boost::shared_ptr<ClientConnection> > > > >::do_complete (owner=0x1a5a5c0, base=0x7f6e28018f30) at externals/boost/include/boost/asio/detail/completion_handler.hpp:68
#20 0x00000000007c3ef4 in boost::asio::detail::task_io_service_operation::complete (this=0x7f6e28018f30, owner=..., ec=..., bytes_transferred=0)
at externals/boost/include/boost/asio/detail/task_io_service_operation.hpp:38
#21 0x00000000007c7937 in boost::asio::detail::strand_service::do_complete (owner=0x1a5a5c0, base=0x7f6df001ab40, ec=...) at externals/boost/include/boost/asio/detail/impl/strand_service.ipp:167
#22 0x00000000007c3ef4 in boost::asio::detail::task_io_service_operation::complete (this=0x7f6df001ab40, owner=..., ec=..., bytes_transferred=0)
at externals/boost/include/boost/asio/detail/task_io_service_operation.hpp:38
#23 0x00000000007c5dde in boost::asio::detail::task_io_service::do_run_one (this=0x1a5a5c0, lock=..., this_thread=..., ec=...) at externals/boost/include/boost/asio/detail/impl/task_io_service.ipp:372
#24 0x00000000007c5845 in boost::asio::detail::task_io_service::run (this=0x1a5a5c0, ec=...) at externals/boost/include/boost/asio/detail/impl/task_io_service.ipp:149
#25 0x00000000007c60cf in boost::asio::io_service::run (this=0x1a54b10) at externals/boost/include/boost/asio/impl/io_service.ipp:59
#26 0x00000000008c27b6 in ProcessModule::threadRun (this=0x1a54b10) at src/business/ProcessModule.cpp:149
#27 0x00000000008c82e7 in boost::_mfi::mf0<void, ProcessModule>::operator() (this=0x1b0aee8, p=0x1a54b10) at externals/boost/include/boost/bind/mem_fn_template.hpp:49
#28 0x00000000008c824a in boost::_bi::list1<boost::_bi::value<ProcessModule*> >::operator()<boost::_mfi::mf0<void, ProcessModule>, boost::_bi::list0> (this=0x1b0aef8,
f=..., a=...) at externals/boost/include/boost/bind/bind.hpp:259
#29 0x00000000008c81f9 in boost::_bi::bind_t<void, boost::_mfi::mf0<void, ProcessModule>, boost::_bi::list1<boost::_bi::value<ProcessModule*> > >::operator() (
this=0x1b0aee8) at externals/boost/include/boost/bind/bind.hpp:1294
#30 0x00000000008c811a in boost::detail::thread_data<boost::_bi::bind_t<void, boost::_mfi::mf0<void, ProcessModule>, boost::_bi::list1<boost::_bi::value<ProcessModule*> > > >::run (this=0x1b0ad30) at externals/boost/include/boost/thread/detail/thread.hpp:116
(gdb) p *this
$1 = {<boost::enable_shared_from_this<ClientConnection>> = {weak_this_ = {px = 0x7f981c4cf720, pn = {pi_ = 0x7f981c2feca0}}}, <boost::noncopyable_::noncopyable> = {<No data fields>},
mIoService = #0x1333b10,
mSocket = {<boost::asio::basic_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >> = {<boost::asio::basic_io_object<boost::asio::stream_socket_service<boost::asio::ip::tcp>, true>> = {implementation = {<boost::asio::detail::reactive_socket_service_base::base_implementation_type> = {socket_ = -1, state_ = 0 '\000', reactor_data_ = 0x0}, protocol_ = {family_ = 2}},
service_ = 0x1371560}, <boost::asio::socket_base> = {static message_peek = 2, static message_out_of_band = 1, static message_do_not_route = 4, static message_end_of_record = 128,
static max_connections = 128}, <No data fields>}, <No data fields>}, mStrand = {service_ = #0x13e5510, impl_ = 0x7f98080500a0},
ClientConnection.cpp:216 is
LOG_INFO("Close client[" << mClientId << "] socket connection");//line:216
the mClientId is wrong value. it looks like This class is destroyed.
weak ptr like:
(gdb) frame 12
(gdb) p *(weak_this_.pn.pi_)
$3 = {_vptr.sp_counted_base = 0x957710 <vtable for boost::detail::sp_counted_impl_p<ClientConnection>+16>, use_count_ = {_M_i = 3}, weak_count_ = {_M_i = 2}}
boost_asio/example
I have search it on internet, find https://www.boost.org/doc/libs/1_45_0/doc/html/boost_asio/example/http/server3/connection.cpp
the example have a note like:
int handle_read:
// If an error occurs then no new asynchronous operations are started. This
// means that all shared_ptr references to the connection object will
// disappear and the object will be destroyed automatically after this
// handler returns. The connection class's destructor closes the socket.
int handle_write:
// No new asynchronous operations are started. This means that all shared_ptr
// references to the connection object will disappear and the object will be
// destroyed automatically after this handler returns. The connection class's
// destructor closes the socket.
why?
(i) If an error occurs in handle_read/handle_write, shouldn't I use this connection weak_ptr in other threads?
(ii) The ClientConnection class life cycle is In Asio and is controled by Asio, What's wrong in my code?
(iii) I think it can't use stand.post() and connection's weak_ptr to do something. Should modify code like below?
void ClientConnection::handle_read(const boost::system::error_code& e,
std::size_t bytes_transferred)
{
if (!e)
{
//read data and use it
}
else { //error occurs
//closeSocket();
//boost::shared_ptr<DisConnectCommand> cmd(new DisConnectCommand());
//cmd->setClient(this->weak_from_this()); //here set this connection weak_ptr
//putCmd(cmd); //do something in other thread.
//just close socket
boost::system::error_code error;
mSocket.close(error);
}
}
I am online and looking forward for your help.
thank you. best wish.
Code:
Listener.hpp:
template <typename SocketType>
void Listener<SocketType>::BeginAccept()
{
auto worker = SelectWorker();
auto socket = worker->CreateSocket();
m_acceptor->async_accept(socket->GetAsioSocket(),
[this, worker, socket] (const boost::system::error_code &ec)
{
this->OnAccept(worker, socket, ec);
});
}
template <typename SocketType>
void Listener<SocketType>::OnAccept(NetworkThread<SocketType> *worker, std::shared_ptr<SocketType> const& socket, const boost::system::error_code &ec)
{
// an error has occurred
if (ec)
worker->RemoveSocket(socket.get());
else
socket->Open();
BeginAccept();
}
Socket.cpp:
bool Socket::Open()
{
try
{
const_cast<std::string &>(m_address) = m_socket.remote_endpoint().address().to_string();
const_cast<std::string &>(m_remoteEndpoint) = boost::lexical_cast<std::string>(m_socket.remote_endpoint());
}
catch (boost::system::error_code& error)
{
sLog.outInfo("Socket::Open() failed to get remote address. Error: %s", error.message().c_str());
return false;
}
catch (const std::exception& error)
{
sLog.outInfo("Socket::Open() failed(with std::exception) to get remote address. Error: %s", error.what());
return false;
}
catch (...)
{
sLog.outError("Socket::Open() failed to get remote address. Other error");
return false;
}
m_outBuffer.reset(new PacketBuffer);
m_secondaryOutBuffer.reset(new PacketBuffer);
m_inBuffer.reset(new PacketBuffer);
StartAsyncRead();
return true;
}
Is this related to TCP attack?
EDIT: gdb:
(gdb) p m_socket
$1 = {<boost::asio::basic_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >> = {<boost::asio::basic_io_object<boost::asio::stream_socket_service<boost::asio::ip::tcp>, true>> = {
implementation = {<boost::asio::detail::reactive_socket_service_base::base_implementation_type> = {socket_ = 21, state_ = 80 'P', reactor_data_ = 0x7ffff0005120}, protocol_ = {family_ = 2}}, service_ = 0x7f2b30}, <boost::asio::socket_base> = {
static message_peek = 2, static message_out_of_band = 1, static message_do_not_route = 4, static message_end_of_record = 128, static max_connections = 128}, <No data fields>}, <No data fields>}
(gdb) p m_socket.is_open()
$2 = true
(gdb) bt
#0 MaNGOS::Socket::Open (this=0x7ffff0003c40) at /home/ubuntu/MoltenCore/MoltenCore/src/shared/Network/Socket.cpp:52
#1 0x00000000004fbff1 in MaNGOS::Listener<AuthSocket>::OnAccept (this=0x7fffffffe6c0, worker=0x8041e0, socket=std::shared_ptr (count 2, weak 1) 0x7ffff0003c40, ec=...) at /home/ubuntu/MoltenCore/MoltenCore/src/shared/Network/Listener.hpp:121
#2 0x00000000004fa030 in MaNGOS::Listener<AuthSocket>::BeginAccept()::{lambda(boost::system::error_code const&)#1}::operator()(boost::system::error_code const&) const (__closure=0x7ffff4ec8be0, ec=...)
at /home/ubuntu/MoltenCore/MoltenCore/src/shared/Network/Listener.hpp:110
#3 0x0000000000502a2d in boost::asio::detail::binder1<MaNGOS::Listener<AuthSocket>::BeginAccept()::{lambda(boost::system::error_code const&)#1}, boost::system::error_code>::operator()() (this=0x7ffff4ec8be0) at /usr/include/boost/asio/detail/bind_handler.hpp:47
#4 0x00000000005020c3 in boost::asio::asio_handler_invoke<boost::asio::detail::binder1<MaNGOS::Listener<AuthSocket>::BeginAccept()::{lambda(boost::system::error_code const&)#1}, boost::system::error_code> >(boost::asio::detail::binder1<MaNGOS::Listener<AuthSocket>::BeginAccept()::{lambda(boost::system::error_code const&)#1}, boost::system::error_code>&, ...) (function=...) at /usr/include/boost/asio/handler_invoke_hook.hpp:69
#5 0x00000000005014b8 in boost_asio_handler_invoke_helpers::invoke<boost::asio::detail::binder1<MaNGOS::Listener<AuthSocket>::BeginAccept()::{lambda(boost::system::error_code const&)#1}, boost::system::error_code>, {lambda(boost::system::error_code const&)#1}>(boost::asio::detail::binder1<MaNGOS::Listener<AuthSocket>::BeginAccept()::{lambda(boost::system::error_code const&)#1}, boost::system::error_code>&, {lambda(boost::system::error_code const&)#1}&) (function=..., context=...)
at /usr/include/boost/asio/detail/handler_invoke_helpers.hpp:37
#6 0x0000000000500886 in boost::asio::detail::reactive_socket_accept_op<boost::asio::basic_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >, boost::asio::ip::tcp, MaNGOS::Listener<AuthSocket>::BeginAccept()::{lambda(boost::system::error_code const&)#1}>::do_complete(boost::asio::detail::task_io_service*, boost::asio::detail::task_io_service_operation*, boost::system::error_code const&, unsigned long) (owner=0x8084d0, base=0x804910) at /usr/include/boost/asio/detail/reactive_socket_accept_op.hpp:123
#7 0x00000000004f0300 in boost::asio::detail::task_io_service_operation::complete (this=0x804910, owner=..., ec=..., bytes_transferred=0) at /usr/include/boost/asio/detail/task_io_service_operation.hpp:38
#8 0x00000000004f1d55 in boost::asio::detail::epoll_reactor::descriptor_state::do_complete (owner=0x8084d0, base=0x804140, ec=..., bytes_transferred=1) at /usr/include/boost/asio/detail/impl/epoll_reactor.ipp:651
#9 0x00000000004f0300 in boost::asio::detail::task_io_service_operation::complete (this=0x804140, owner=..., ec=..., bytes_transferred=1) at /usr/include/boost/asio/detail/task_io_service_operation.hpp:38
#10 0x00000000004f2823 in boost::asio::detail::task_io_service::do_run_one (this=0x8084d0, lock=..., this_thread=..., ec=...) at /usr/include/boost/asio/detail/impl/task_io_service.ipp:372
#11 0x00000000004f23a1 in boost::asio::detail::task_io_service::run (this=0x8084d0, ec=...) at /usr/include/boost/asio/detail/impl/task_io_service.ipp:149
#12 0x00000000004f2abc in boost::asio::io_service::run (this=0x7ef540) at /usr/include/boost/asio/impl/io_service.ipp:59
#13 0x00000000004f7c89 in MaNGOS::Listener<AuthSocket>::Listener(int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int)::{lambda()#1}::operator()() const () at /home/ubuntu/MoltenCore/MoltenCore/src/shared/Network/Listener.hpp:84
#14 0x0000000000505624 in std::_Bind_simple<MaNGOS::Listener<AuthSocket>::Listener(int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int)::{lambda()#1} ()>::_M_invoke<>(std::_Index_tuple<>) (this=0x8049c8)
at /usr/include/c++/5/functional:1531
#15 0x0000000000504f38 in std::_Bind_simple<MaNGOS::Listener<AuthSocket>::Listener(int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int)::{lambda()#1} ()>::operator()() (this=0x8049c8) at /usr/include/c++/5/functional:1520
#16 0x0000000000504416 in std::thread::_Impl<std::_Bind_simple<MaNGOS::Listener<AuthSocket>::Listener(int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int)::{lambda()#1} ()> >::_M_run() (this=0x8049b0) at /usr/include/c++/5/thread:115
#17 0x00007ffff6c98c80 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#18 0x00007ffff7bc16ba in start_thread (arg=0x7ffff4ec9700) at pthread_create.c:333
#19 0x00007ffff63fe82d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:109
EDIT:
NetworkThread.hpp:
template <typename SocketType>
class NetworkThread
{
private:
boost::asio::io_service m_service;
std::mutex m_socketLock;
std::unordered_set<std::shared_ptr<SocketType>> m_sockets;
// note that the work member *must* be declared after the service member for the work constructor to function correctly
std::unique_ptr<boost::asio::io_service::work> m_work;
std::thread m_serviceThread;
public:
NetworkThread() : m_work(new boost::asio::io_service::work(m_service))
{
m_serviceThread = std::thread([this] { boost::system::error_code ec; this->m_service.run(ec); });
}
~NetworkThread()
{
// Allow io_service::run() to exit.
m_work.reset();
m_service.stop();
m_serviceThread.join();
// attempt to gracefully close any open connections
for (auto i = m_sockets.begin(); i != m_sockets.end();)
{
auto const current = i;
++i;
if (!(*current)->IsClosed())
(*current)->Close();
}
}
size_t Size() const { return m_sockets.size(); }
std::shared_ptr<SocketType> CreateSocket();
void RemoveSocket(Socket *socket)
{
std::lock_guard<std::mutex> guard(m_socketLock);
m_sockets.erase(socket->shared<SocketType>());
}
};
template <typename SocketType>
std::shared_ptr<SocketType> NetworkThread<SocketType>::CreateSocket()
{
std::lock_guard<std::mutex> guard(m_socketLock);
auto const i = m_sockets.emplace(std::make_shared<SocketType>(m_service, [this] (Socket *socket) { this->RemoveSocket(socket); }));
return *i.first;
}
The problem is totally different:
In your code:
template <typename SocketType>
void Listener<SocketType>::OnAccept(
NetworkThread<SocketType> *worker,
std::shared_ptr<SocketType> const& socket,
const boost::system::error_code &ec )
{
// at this point, socket has 1 reference count, held by the lambda
// in BeginAccept, its reference count cannot increase, since it's
// constant.
// ...
BeginAccept(); // this creates a new, distinct instance of the lambda
// fuinction object in BeginAccept.
// when we exit, constrol is given back to calling lambda in BeginAccept
// its destructor happily deletes the socket, since its reference count
// is still only 1.
}
Bottom line: OnAccept() needs to receive the socket pointer by value, and it needs to transfer or store this shared pointer somehow. This is usually done
by passing the shared_ptr to BeginReceive() BY VALUE. BeginReceive() must then take the responsibility to keep the socket pointer alive until the connection dies, this, it usually does that by passing the pointer back to itself, either as a parameter, or as a lambda capture, always by value.
The easiest way to fix your code is to move the call to StartAsyncRead() to OnAccept(), since there is a convenient copy of a shared_ptr of the socket there.
I'm trying to read from a input source (in this case stdin) with a timeout. Due to the design of the existing application where this have to fit is it not possible to call run on my io_service.
Here is my try so far:
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/optional.hpp>
void set_result( boost::optional<boost::system::error_code> * a, boost::system::error_code b ) {
if( b == 0)
a->reset( b );
}
void receive(boost::asio::io_service & io, boost::asio::posix::stream_descriptor & stream, boost::asio::streambuf & result){
boost::optional<boost::system::error_code> timer_result;
boost::optional<boost::system::error_code> read_result;
boost::asio::deadline_timer timer( io );
timer.expires_from_now( boost::posix_time::milliseconds(5000) );
timer.async_wait( boost::bind(&set_result, &timer_result, _1) );
boost::asio::async_read(
stream,
result,
boost::asio::transfer_at_least(1),
boost::bind( &set_result, &read_result, _1 ));
boost::system::error_code ec;
while(1) {
io.reset();
io.poll_one(ec);
if ( read_result ) {
timer.cancel();
return;
} else if ( timer_result )
throw std::runtime_error("timeout");
}
}
void receive(boost::asio::io_service & io, boost::asio::posix::stream_descriptor & stream, size_t size, boost::asio::streambuf & result){
while( result.size() < size )
receive(io, stream, result);
}
int main(int argc, const char *argv[])
{
boost::asio::io_service io;
boost::asio::posix::stream_descriptor in(io, ::dup(STDIN_FILENO));
for(int i = 0; i < 5; i++){
std::cout << i << " Type in 4 chareters and press enter" << std::endl << std::endl;
std::cout << "in> ";
std::cout.flush();
try {
boost::asio::streambuf buf;
receive(io, in, 5, buf);
std::cout << "out> ";
std::copy(boost::asio::buffer_cast<const char *>(buf.data()), boost::asio::buffer_cast<const char *>(buf.data()) + buf.size(), std::ostream_iterator<char>(std::cout));
} catch (const std::exception & e) {
std::cout << e.what() << std::endl;
}
}
return 0;
}
At my first look, I thought that it was working, but after playing more around with the test app, I got some segmentations faults.
I found that something bad happens if I wait for the first query to timeout, and then enter 5 chars the next.
Here is what valgrind says:
==17216== Memcheck, a memory error detector
==17216== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==17216== Using Valgrind-3.6.1 and LibVEX; rerun with -h for copyright info
==17216== Command: ./ccTalkScan
==17216==
0 Type in 4 chareters and press enter
asdf
0 system:0
1 Type in 4 chareters and press enter
0 system:125
0 system:0
==17216== Invalid read of size 8
==17216== at 0x546EB4A: ??? (setcontext.S:60)
==17216== by 0x425245: receive(boost::asio::io_service&, boost::asio::posix::basic_stream_descriptor<boost::asio::posix::stream_descriptor_service>&, unsigned long, boost::asio::basic_streambuf<std::allocator<char> >&) (ccTalkScan.cxx:321)
==17216== by 0x42535E: main (ccTalkScan.cxx:333)
==17216== Address 0x7feffdfa8 is not stack'd, malloc'd or (recently) free'd
==17216==
==17216== Invalid read of size 8
==17216== at 0x546EB52: ??? (setcontext.S:63)
==17216== by 0x425245: receive(boost::asio::io_service&, boost::asio::posix::basic_stream_descriptor<boost::asio::posix::stream_descriptor_service>&, unsigned long, boost::asio::basic_streambuf<std::allocator<char> >&) (ccTalkScan.cxx:321)
==17216== by 0x42535E: main (ccTalkScan.cxx:333)
==17216== Address 0x7feffdf98 is not stack'd, malloc'd or (recently) free'd
==17216==
==17216== Invalid read of size 8
==17216== at 0x546EB59: ??? (setcontext.S:64)
==17216== by 0x425245: receive(boost::asio::io_service&, boost::asio::posix::basic_stream_descriptor<boost::asio::posix::stream_descriptor_service>&, unsigned long, boost::asio::basic_streambuf<std::allocator<char> >&) (ccTalkScan.cxx:321)
==17216== by 0x42535E: main (ccTalkScan.cxx:333)
==17216== Address 0x7feffdf68 is not stack'd, malloc'd or (recently) free'd
==17216==
==17216== Invalid read of size 8
==17216== at 0x546EB4A: ??? (setcontext.S:60)
==17216== by 0x5E4BD2C: (below main) (in /lib64/libc-2.12.2.so)
==17216== Address 0x7feffe018 is not stack'd, malloc'd or (recently) free'd
==17216==
==17216== Invalid read of size 8
==17216== at 0x546EB52: ??? (setcontext.S:63)
==17216== by 0x5E4BD2C: (below main) (in /lib64/libc-2.12.2.so)
==17216== Address 0x7feffe008 is not stack'd, malloc'd or (recently) free'd
==17216==
==17216== Invalid read of size 8
==17216== at 0x546EB59: ??? (setcontext.S:64)
==17216== by 0x5E4BD2C: (below main) (in /lib64/libc-2.12.2.so)
==17216== Address 0x7feffdfd8 is not stack'd, malloc'd or (recently) free'd
==17216==
timeout
2 Type in 4 chareters and press enter
0 system:0
timeout
3 Type in 4 chareters and press enter
asdf
==17216== Syscall param readv(vector[...]) points to unaddressable byte(s)
==17216== at 0x5EF7A81: readv (in /lib64/libc-2.12.2.so)
==17216== by 0x42A77A: boost::asio::detail::descriptor_ops::non_blocking_read(int, iovec*, unsigned long, boost::system::error_code&, unsigned long&) (descriptor_ops.ipp:153)
==17216== by 0x4355D1: boost::asio::detail::descriptor_read_op_base<boost::asio::mutable_buffers_1>::do_perform(boost::asio::detail::reactor_op*) (descriptor_read_op.hpp:55)
==17216== by 0x4275DA: boost::asio::detail::reactor_op::perform() (reactor_op.hpp:40)
==17216== by 0x4288F9: boost::asio::detail::epoll_reactor::run(bool, boost::asio::detail::op_queue<boost::asio::detail::task_io_service_operation>&) (epoll_reactor.ipp:286)
==17216== by 0x429577: boost::asio::detail::task_io_service::do_one(boost::asio::detail::scoped_lock<boost::asio::detail::posix_mutex>&, boost::asio::detail::task_io_service::idle_thread_info*) (task_io_service.ipp:264)
==17216== by 0x429165: boost::asio::detail::task_io_service::poll_one(boost::system::error_code&) (task_io_service.ipp:188)
==17216== by 0x4299B8: boost::asio::io_service::poll_one(boost::system::error_code&) (io_service.ipp:103)
==17216== by 0x424FDF: receive(boost::asio::io_service&, boost::asio::posix::basic_stream_descriptor<boost::asio::posix::stream_descriptor_service>&, boost::asio::basic_streambuf<std::allocator<char> >&) (ccTalkScan.cxx:308)
==17216== by 0x425245: receive(boost::asio::io_service&, boost::asio::posix::basic_stream_descriptor<boost::asio::posix::stream_descriptor_service>&, unsigned long, boost::asio::basic_streambuf<std::allocator<char> >&) (ccTalkScan.cxx:321)
==17216== by 0x42535E: main (ccTalkScan.cxx:333)
==17216== Address 0x65ba920 is 0 bytes inside a block of size 512 free'd
==17216== at 0x4C25C4F: operator delete(void*) (vg_replace_malloc.c:387)
==17216== by 0x432317: __gnu_cxx::new_allocator<char>::deallocate(char*, unsigned long) (new_allocator.h:95)
==17216== by 0x430D67: std::_Vector_base<char, std::allocator<char> >::_M_deallocate(char*, unsigned long) (stl_vector.h:146)
==17216== by 0x42F4A0: std::_Vector_base<char, std::allocator<char> >::~_Vector_base() (stl_vector.h:132)
==17216== by 0x42CF5E: std::vector<char, std::allocator<char> >::~vector() (stl_vector.h:313)
==17216== by 0x42AEB5: boost::asio::basic_streambuf<std::allocator<char> >::~basic_streambuf() (basic_streambuf.hpp:114)
==17216== by 0x425374: main (ccTalkScan.cxx:333)
==17216==
0 system:0
4 Type in 4 chareters and press enter
0 system:125
0 system:0
timeout
==17216==
==17216== HEAP SUMMARY:
==17216== in use at exit: 168 bytes in 3 blocks
==17216== total heap usage: 63 allocs, 60 frees, 22,070 bytes allocated
I have tried different things to fix it, but I think that I might have misunderstood a thing or two here. So some help would be nice, and an example would be most appreciated ;)
The problem in the above implementation is that the async_reads which times out is never canceled. Here is how to do this:
while(1) {
io.reset();
io.poll_one(ec);
if ( read_result ) {
timer.cancel(); // cancel the timeout operation as it has not completed yet
return;
} else if ( timer_result ) {
stream.cancel(); // cancel the read operation as it has not completed yet
throw std::runtime_error("timeout");
}
}