Solved

Socket programming; server side; signal 11(segmentation fault) ??!!

Posted on 2004-04-09
7
2,971 Views
Last Modified: 2012-05-04
Hi!
I'm implementing a simple chat server.
It starts up fine, binding et.al. is fine...
then when i connect to it using telnet 127.0.0.1 19471
(this is the port number i'm listening on #define CONTROL_PORT 19471),
the server crashes.
the messege at server terminal is:

Program has been terminated receiving signal 11 (Segmentation fault)
Press the Enter key to close this terminal ...

on the client(telnet) terminal, the msg is:

telnet 127.0.0.1 19471
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Connection closed by foreign host.

What is going wrong?

Here's a snippet of my server code:

int main()
{
      int DataTempSock, CtrlTempSock;      //these will temporarily hold the sockets numbers for every client that connects
      int ListenerSock = socket(AF_INET,SOCK_STREAM,0);
      if(ListenerSock == -1)
      {
            perror("socket()");
            return 0;
      }

      int yes = 1;
      if(setsockopt(ListenerSock,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1)
      {
            perror("setsockopt()");
            close(ListenerSock);
            return 0;
      }

      struct sockaddr_in LisSockAddr;

      bzero(&LisSockAddr,sizeof(struct sockaddr_in));
      LisSockAddr.sin_family  = AF_INET;
      LisSockAddr.sin_port = htons(CONTROL_PORT);
      LisSockAddr.sin_addr.s_addr = inet_addr("127.0.0.1");

      if(bind(ListenerSock, (struct sockaddr*) &LisSockAddr, sizeof(struct sockaddr_in)))
      {
            perror("bind()");
            close(ListenerSock);
            return 0;
      }

      if(listen(ListenerSock,2))
      {
            perror("listen()");
            close(ListenerSock);
            return 0;
      }

      OnlineUsersList OUL;      //this is the one and only OnlineUsersList object
      fd_set MasterFDSet,TempFDSet;      //fdsets to hold active socket lists

      //after every 5 seconds, the server will check if all connected clients are still online or not
      //this is to make the server resilient against remote system crashes etc. which diconnects remote client
      //before proper logout!
      struct timeval ServerCheckTimer;
      ServerCheckTimer.tv_sec = 5;
      ServerCheckTimer.tv_usec = 0;

      int MaxSock = ListenerSock;      //maintain maximum socket number for select() call

      char ReadBuffer[1501];      //all messeages received will be temporarily stored here
      int readlen = 0;      //number of bytes received

      FD_ZERO(&MasterFDSet);
      FD_ZERO(&TempFDSet);

      FD_SET(ListenerSock,&MasterFDSet);

      int RetValofSelectFn=0;

      while(1)
      {
            TempFDSet = MasterFDSet;
            if((RetValofSelectFn = select(MaxSock+1,&TempFDSet,NULL,NULL,&ServerCheckTimer)) == -1)
            {
                  perror("select()");
                  close(ListenerSock);
                  return 0;
            }
            else if(RetValofSelectFn)      //something's incoming, let's find out what
            {
                  for(int i=0; i<=MaxSock; i++)
                  {
                        if(FD_ISSET(i,&TempFDSet))
                        {
                              if(i == ListenerSock)      //someone new wants to connect
                              {
                                    ConnectNewClient(OUL, ListenerSock, &MaxSock, &MasterFDSet);
/*                                    int sockaddrlen = sizeof(TempSockAddr);
                                    if((TempSock = accept(ListenerSock,(struct sockaddr*)&TempSockAddr,(socklen_t*)&sockaddrlen)) == -1)
                                    {
                                          perror("accept()");
                                    }
                                    else
                                    {
                                          if(TempSock > MaxSock)      MaxSock=TempSock;
                                          FD_SET(TempSock,&MasterFDSet);
                                          printf("\nNew connection accepted from %s on socket %d\n",inet_ntoa(TempSockAddr.sin_addr),TempSock);
                                    }*/
                              }
                              else
                              {
                                    bzero(&ReadBuffer,sizeof(ReadBuffer));
                                    if((readlen = recv(i,ReadBuffer,sizeof(ReadBuffer),0)) <= 0)
                                    {
                                          if(readlen == 0)
                                          {
                                                printf("\nClient at socket %d closed connection!\n",i);
                                          }
                                          else
                                          {
                                                perror("recv()");
                                                printf("\nError reading socket %d, closing that connection\n",i);
                                          }
                                          FD_CLR(i,&MasterFDSet);
                                          close(i);
                                    }
                                    else      //recv() successful
                                    {
                                          for(int j=0; j<=MaxSock; j++)
                                          {
                                                if(FD_ISSET(j,&MasterFDSet))
                                                {
                                                      if(j != i && j != ListenerSock)
                                                      {
                                                            if(safesend(j,ReadBuffer,readlen,0) == -1)
                                                            {
                                                                  perror("send()");
                                                                  printf("Couldn't send messege to client at socket %d, closing that socket\n",j);
                                                                  FD_CLR(j,&MasterFDSet);
                                                                  close(j);
                                                            }
                                                      }
                                                }
                                          }
                                    }
                              }
                        }
                  }
            }
            else      //this will be the case when timeout occurs on call to select
                  //now check if all clients in OUL are still online
            {
            }
      }
      return 0;
}

int safesend(int SendSock,char *SendBuffer,int SendBytesCount,int SendFlag)
{
      int BytesSent = send(SendSock,SendBuffer,SendBytesCount,SendFlag);
      if(BytesSent == -1)
      {
            perror("send()");
            return -1;
      }
      else if(BytesSent < SendBytesCount)
      {
            int RemainingBytes = SendBytesCount - BytesSent;
            int temp = 0;
            while(RemainingBytes)
            {
                  temp = send(SendSock,SendBuffer+BytesSent,RemainingBytes,SendFlag);
                  if(temp == -1)
                  {
                        perror("send()");
                        return -1;
                  }
                  BytesSent += temp;
                  RemainingBytes -= temp;
            }
      }
      return BytesSent;
}

//whenever a client tries to connect, this function will be called
//this function
int ConnectNewClient(OnlineUsersList OUL, int ListenerSock, int *MaxSock, fd_set *MasterFDSet)
{
      //a sockaddr_in structure where information about a client requesting to get online
      struct sockaddr_in TempSockAddr;
      bzero(&TempSockAddr,sizeof(struct sockaddr_in));
      int sockaddrlen = sizeof(TempSockAddr);
      
      int TempSock;      //socket number allocated to the new client will be temporarily stored here
      
      if((TempSock = accept(ListenerSock,(struct sockaddr*)&TempSockAddr,(socklen_t*)&sockaddrlen)) == -1)
      {
            perror("accept()");
            return (-1);
      }
      else
      {
            if(TempSock > *MaxSock)      *MaxSock=TempSock;
            FD_SET(TempSock,MasterFDSet);
            printf("\nNew connection accepted from %s on socket %d\n",inet_ntoa(TempSockAddr.sin_addr),TempSock);
            printf("\nMaxSock = %d",*MaxSock);
            return (TempSock);
      }
}

As you can see...in function ConnectNewClient(),
the line printf("\nNew connection accepted from %s on socket %d\n",inet_ntoa(TempSockAddr.sin_addr),TempSock);
is getting executed..but not the printf() following it?! why so?

Please help!
Regards,
logicTRANCE
0
Comment
Question by:logicTRANCE
  • 3
  • 3
7 Comments
 
LVL 9

Expert Comment

by:Alf666
ID: 10796478
A first glance, it looks ok. Not strictly ANSI C, but...

It took me a few minutes to modify your code so that I could compile it, and it works fine on my system.

What I suggest is the following :

1) Compile with the "-g" option.

2) Execute under gdb :

gdb myprog
r

and, when it segfaults :
where
quit


And post the result.
0
 
LVL 44

Expert Comment

by:Karl Heinz Kremer
ID: 10796528
I can also confirm that it works. What Alf666 means with "not strictly ANSI C" is that you declare your loop variables in the for loop. This is valid C++ (and C99), but is not ANSI C.

I've seen stuff like this happen before (one printf gets executed, but one just a few lines down will not work). This is usually due to a memory error. And, the problem is very likely not in the code that you provided. Do what Alf666 suggested, and run your program in the debugger.
0
 
LVL 1

Author Comment

by:logicTRANCE
ID: 10796594
i changed the pointer arguments to reference arguments (in call to ConnectNewClient()).
stil it wasnt working
then i used DDD, the graphical debugger that comes with Suse->KDE..it in turn used gdb..

it worked fine in DDD..and now it works fine in normal mode too (without the debuger!)
god knows what happened!
;-)

Happy Programming!
0
Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

 
LVL 44

Expert Comment

by:Karl Heinz Kremer
ID: 10796637
The version that you compiled with the -g switch works when you run it outside the debugger, is this also true for an optimized version?

It's possible that you are facing a compiler bug, but it's more likely that you still have a bug somewhere in your code that corrupts memory or the stack. If it now also works without the -g switch (you also could try compiling with -O), it's possible that you had an old object file somewhere that got linked in instead of an updated one. Usually make is pretty good with getting the dependencies right (I do however encounter this a lot under Windows), but it's not totally impossible.
0
 
LVL 1

Author Comment

by:logicTRANCE
ID: 10798010
Er...actually i'm a linux newbie, and dunno much about using debuggers and compiler optimizations...and frankly, i dint understand what you actually meant by:
"The version that you compiled with the -g switch works when you run it outside the debugger, is this also true for an optimized version?"

are talking about the compiler version??

i'll lookup the manpagefor -g and -O options...but any help from youwill be really good as i want to understand the working of linux properly...and manpages are surely not enough!

before using anjuta, i was writing programme in kwrite and compile with g++ -o at Konsole...now in anjuta, i just have to press F9 and it compiles, but it give a bit different command:
g++ -Wall -g -c "XChatServer.cpp" -o "XChatServer.o"

At konsole, i used only
g++ -o XChatServer XChatServer.cpp

but the catch is even after compiling in anjuta, it was giving that error (segmentation fault)..and after once running it trhu the debugger, it stopped giving error...i'm puzzled...i did not make any changes at all to the programme, and still it works fine!
0
 
LVL 44

Accepted Solution

by:
Karl Heinz Kremer earned 100 total points
ID: 10799409
The -g and -O switches are command line parameters for the g++ compiler. As you can see from the two command lines you've quoted, teh anjuta command line does use the -g switch for the debugger.

When you compile a program with the -g switch, the compiler adds debug information to the object files, and when linked to the executable. This information is used by the debugger to display source code and line number information. You can also add (instead, or in addition) to the -g switch the -O (or -O1 -O2 -O3) switch to select optimization. This will change again how the program is compiled. For some functions, the compiler will no longer call a function, but will instead use a macro (which is faster than a function call). This does change how the program is executed, and can potentially make a program work that crashed without any optimization.

So, you should compile your program using these command lines:

g++ -o XChatServer XChatServer.cpp
g++ -g -o XChatServer XChatServer.cpp
g++ -O3 -o XChatServer XChatServer.cpp

Does one or more of these versions crash? Does any one or more of these versions run without a crash?
0
 
LVL 1

Author Comment

by:logicTRANCE
ID: 10800258
g++ -o XChatServer XChatServer.cpp
g++ -g -o XChatServer XChatServer.cpp
g++ -O3 -o XChatServer XChatServer.cpp

all these compiled properly, though with some warnings (i've added a lot of code to th earlier one, thats why)

these are the warnings:

kapil@linux:~/ProjectStuff> g++ -O3 -o XChatServer XChatServer.cpp
XChatServer.cpp: In member function `void OnlineUser::SetClientDetails(char*,
   sockaddr_in*, int, int, int)':
XChatServer.cpp:57: warning: NULL used in arithmetic
XChatServer.cpp:58: warning: NULL used in arithmetic
XChatServer.cpp:59: warning: NULL used in arithmetic
XChatServer.cpp: In member function `void
   OnlineUser::UpdateClientDetails(char*, sockaddr_in*, int, int, int)':
XChatServer.cpp:91: warning: NULL used in arithmetic
XChatServer.cpp:93: warning: NULL used in arithmetic
XChatServer.cpp:95: warning: NULL used in arithmetic
XChatServer.cpp: In function `int main()':
XChatServer.cpp:467: warning: passing NULL used for non-pointer argument 3 of `
   void OnlineUser::UpdateClientDetails(char*, sockaddr_in*, int, int, int)'
XChatServer.cpp: In function `int ConnectNewClient(OnlineUsersList&, int, int&,
   fd_set&)':
XChatServer.cpp:583: warning: passing NULL used for non-pointer argument 4 of `
   int OnlineUsersList::AddClient(char*, sockaddr_in, int, int, int)'
XChatServer.cpp: In function `int HandleCtrlMessage(OnlineUsersList*,
   OnlineUser*)':
XChatServer.cpp:614: warning: passing NULL used for non-pointer argument 3 of `
   void OnlineUser::SetClientDetails(char*, sockaddr_in*, int, int, int)'
XChatServer.cpp:614: warning: passing NULL used for non-pointer argument 4 of `
   void OnlineUser::SetClientDetails(char*, sockaddr_in*, int, int, int)'

But the server code compiled.. and runs without crashing...since i hvent developed the client yet...i cannot test it properly...but i telneted it and the connection was made properly...

so far so good!!

but i might have to deal with these warnings..they are at some critical points in the programmes..i'll post a qn. related to that if the server doesnt work when proper clients are made...
i really need to get the stuff about NULLs clear!!

I'll get back in a day or two..gotta develop the client in QT.

Thanks and Regards,
Kapil

Happy Programming!
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Suggested Solutions

The purpose of this article is to fix the unknown display problem in Linux Mint operating system. After installing the OS if you see Display monitor is not recognized then we can install "MESA" utilities to fix this problem or we can install additio…
The purpose of this article is to demonstrate how we can upgrade Python from version 2.7.6 to Python 2.7.10 on the Linux Mint operating system. I am using an Oracle Virtual Box where I have installed Linux Mint operating system version 17.2. Once yo…
It is a freely distributed piece of software for such tasks as photo retouching, image composition and image authoring. It works on many operating systems, in many languages.
Illustrator's Shape Builder tool will let you combine shapes visually and interactively. This video shows the Mac version, but the tool works the same way in Windows. To follow along with this video, you can draw your own shapes or download the file…

707 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now