title: Socket connection stays ESTABLISHED after I close the socket
body: <p>So I've got a simple little server being started off of a separate thread from my main program (the code for this thread is at the bottom) and all is well, I can connect with telnet to it and send messages and whatnot. If I send "quit", the program does exactly as is expected, it quits, but if I send any other message, I get in the logs that the socket has been closed, but the connection from telnet still remains active - I know this because I lsof and because telnet still acts as if its connected. Why doesn't telnet's connection get severed? How come it stays alive in the "ESTABLISHED" state?</p>
  
  <p>lsof:</p>
  
  <pre><code>bash      24122  Dan  cwd      DIR                1,2       340  3782037 /Users/Dan/Dropbox/PersonalDev/cruentus
  bash      24813  Dan  cwd      DIR                1,2       340  3782037 /Users/Dan/Dropbox/PersonalDev/cruentus
  bash      25782  Dan  cwd      DIR                1,2       340  3782037 /Users/Dan/Dropbox/PersonalDev/cruentus
  bash      26395  Dan  cwd      DIR                1,2       340  3782037 /Users/Dan/Dropbox/PersonalDev/cruentus
  vim       26462  Dan  cwd      DIR                1,2       340  3782037 /Users/Dan/Dropbox/PersonalDev/cruentus
  vim       26462  Dan    4u     REG                1,2     16384 16889838 /Users/Dan/Dropbox/PersonalDev/cruentus/.cruentus.c.swp
  cruentus  26474  Dan  cwd      DIR                1,2       340  3782037 /Users/Dan/Dropbox/PersonalDev/cruentus
  cruentus  26474  Dan  txt      REG                1,2     14840 16889520 /Users/Dan/Dropbox/PersonalDev/cruentus/obj/cruentus
  cruentus  26474  Dan  txt      REG                1,2    600576   748159 /usr/lib/dyld
  cruentus  26474  Dan  txt      REG                1,2 303132672 15641156 /private/var/db/dyld/dyld_shared_cache_x86_64
  cruentus  26474  Dan    0u     CHR               16,0  0t532754      899 /dev/ttys000
  cruentus  26474  Dan    1u     CHR               16,0  0t532754      899 /dev/ttys000
  cruentus  26474  Dan    2u     CHR               16,0  0t532754      899 /dev/ttys000
  cruentus  26474  Dan    3u    IPv4 0x5e17dc80b705100f       0t0      TCP *:terabase (LISTEN)
  cruentus  26474  Dan    5u    IPv4 0x5e17dc80a55f88d7       0t0      TCP localhost:krb524-&gt;localhost:55775 (ESTABLISHED)
  telnet    26482  Dan  cwd      DIR                1,2       340  3782037 /Users/Dan/Dropbox/PersonalDev/cruentus
  lsof      26483  Dan  cwd      DIR                1,2       340  3782037 /Users/Dan/Dropbox/PersonalDev/cruentus
  grep      26484  Dan  cwd      DIR                1,2       340  3782037 /Users/Dan/Dropbox/PersonalDev/cruentus
  </code></pre>
  
  <p>server code:</p>
  
  <pre><code>void *controller_thread(void *a __unused) {
      puts("Starting controller thread");
      int contsock, asock, alen;
      struct sockaddr_in saddr, inaddr;
      struct timeval tv;
      struct linger lingading;
  
      if ((contsock = socket(AF_INET, SOCK_STREAM, 0)) &lt; 0) {
          perror("controller : socket");
          return NULL;
      }
  
      bzero((void*)&amp;saddr, sizeof(struct sockaddr_in));
      saddr.sin_len = sizeof(struct sockaddr_in);
      saddr.sin_family = AF_INET;
      saddr.sin_port = htons(4444);
      saddr.sin_addr.s_addr = inet_addr("127.0.0.1");
  
      if (bind(contsock, (const struct sockaddr*)&amp;saddr, (socklen_t)saddr.sin_len) != 0) {
          perror("controller : bind");
          return NULL;
      }
  
      if (listen(contsock, 1) != 0) {
          perror("controller : listen");
      }
      lingading.l_onoff = 1;
      lingading.l_linger = 5;
      if (setsockopt(contsock, SOL_SOCKET, SO_LINGER_SEC, (const void*)&amp;lingading, (socklen_t)sizeof(struct linger)) != 0) {
          perror("controller : setsockopt1");
          return NULL;
      }
      tv.tv_sec = 5;
      tv.tv_usec = 0;
      if (setsockopt(contsock, SOL_SOCKET, SO_SNDTIMEO, (const void*)&amp;tv, (socklen_t)sizeof(struct timeval)) != 0) {
          perror("controller : setsockopt2");
          return NULL;
      }
      tv.tv_sec = 5;
      tv.tv_usec = 0;
      if (setsockopt(contsock, SOL_SOCKET, SO_RCVTIMEO ,(const void*)&amp;tv, (socklen_t)sizeof(struct timeval)) != 0) {
          perror("controller : setsockopt3");
          return NULL;
      }
  
      bzero((void*)&amp;inaddr, sizeof(struct sockaddr_in));
      alen = sizeof(struct sockaddr_in);
      if ((asock = accept(contsock, (struct sockaddr *)&amp;inaddr, (socklen_t*)&amp;alen)) != -1) {
          printf("Got controller connection: %s:%d\n", inet_ntoa(inaddr.sin_addr), ntohs(inaddr.sin_port));
          tv.tv_sec = 5;
          tv.tv_usec = 0;
          if (setsockopt(asock, SOL_SOCKET, SO_RCVTIMEO ,(const void*)&amp;tv, (socklen_t)sizeof(struct timeval)) != 0) {
              perror("controller : setsockopt3");
              return NULL;
          }
          char abuf[4];
          if (read(asock, abuf, 4) == 4 &amp;&amp; strncmp("quit", abuf, 4) == 0) {
              puts("Quitting now!");
              exit(0);
          }
      } else {
          perror("controller : accept");
      }
  
      puts("Failed to quit from controller");
  
      if (shutdown(contsock, SHUT_WR) != 0) {
          if (errno != ENOTCONN)
              perror("controller : shutdown");
      }
      char tmp;
      while (read(contsock, &amp;tmp, 1) == 1) {
          // remove all packets...
      }
      puts("Shutdown controller socket");
      if (close(contsock) != 0) {
          perror("controller : close");
      }
      puts("Closed controller socket");
      return NULL;
  }
  </code></pre>