Link to home
Start Free TrialLog in
Avatar of logicTRANCE
logicTRANCE

asked on

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

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
Avatar of Alf666
Alf666

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.
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.
Avatar of logicTRANCE

ASKER

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!
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.
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!
ASKER CERTIFIED SOLUTION
Avatar of Karl Heinz Kremer
Karl Heinz Kremer
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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!