Program get's stuck...

Joined
Jan 10, 2009
Messages
1
Reaction score
0
Mysterious delay.

Hi,
I have a database/socket program that tends to sit & wait too much. Most of the time, if I send one line over the socket connection, it will handle it, and read 2 lines out of the database. Once in a while, it will process around 50 lines in the database. But then it goes back to 2 lines. I don't understand why it is waiting for receiving something on the socket. I have the program set to start at msg# 8000. There are over 9000 messages. There is no reason it shouldn't be able to process them all without waiting. I am including the main code. If you want to see the entire code in the check out yungblood.com / gateway.tgz

If you need to know anything about the code, please let me know. I believe this issue is the last major problem in getting my code running.

Code:
int sendline(struct client *client, const char *format, ...) {
  int rv=1;
  int len;
  va_list arg;
  char buf[4096];

  va_start(arg, format);
  rv=vsprintf(buf, format, arg);
  va_end(arg);
  
//  logmsg("<<< Sent: %s", buf);
  len=strlen(buf);
  while (client->outcur+len>=client->outsize) {
    client->outbuf=xrealloc(client->outbuf, client->outsize*2);
    client->outsize*=2;
  }
  memcpy(client->outbuf+client->outcur,buf,len+1);
  client->outcur+=len; 
}
Code:
int main(int argc, char** argv) {
  int i,j,res, sql;
  int acfd;
  struct sockaddr_in acsa;
  char readbuf[1000],relaystring[1000];
  struct in_addr targetaddr;

  MYSQL_ROW row;
  long int msgid=8000;
  char user[32], msg[2048], dest[32];

  if(logmsg("Starting gateway daemon.")<0) {
    fprintf(stderr, "Failed to start logging. Exiting.\n");
    return 0;
  }

/* Connect to database */
  if((mysql_init(&mysql))==NULL) {
    logmsg("Failed to initate MySQL connection. Exiting.");
    return 0;
  }

  if(!mysql_real_connect(&mysql, MYSQL_HOST, MYSQL_USERNAME, MYSQL_PASSWD, MYSQL_DATABASE, 0, NULL, 0)) {
    logmsg("Failed to connect to MySQL: Error: %s. Exiting.", mysql_error(&mysql));
    return 0;
  }

  close(0);
  close(1);
  signal(SIGPIPE,SIG_IGN);
  strcpy(relaystring,FAILMESSAGE);
  if (-1==(acfd=socket(PF_INET,SOCK_STREAM,0))) {
    logmsg("socket(accept_socket)");
    exit(1);
  }

  acsa.sin_family=AF_INET;
  acsa.sin_port=htons(SERV_PORT);
  acsa.sin_addr.s_addr=INADDR_ANY;
#ifdef SO_REUSEADDR
  {
    int reuseit=1;
    if (-1==setsockopt(acfd,SOL_SOCKET,SO_REUSEADDR,(char*)&reuseit,sizeof(reuseit))) logmsg("setsockopt SOL_SOCKET SO_REUSEADDR");
  }
#endif
  if (-1==bind(acfd,(struct sockaddr*)&acsa,sizeof(struct sockaddr_in))) {
    logmsg("bind");
    exit(1);
  }
  /* 5 is usual the maximum anyway */
  if (-1==listen(acfd,5)) {
    logmsg("listen");
    exit(1);
  }
  while (1) {
    fd_set readfds,writefds;
    int width;

    width=3;
    if (acfd>=width) width=acfd+1;
restart_select:
    FD_ZERO(&readfds);
    FD_ZERO(&writefds);
    FD_SET(acfd,&readfds);

    sql=0;
    sprintf(readbuf, "SELECT * from chat where msgid > '%d' order by time limit 1", msgid);
    if (mysql_query(&mysql, readbuf) == 0) {
      if (result = mysql_store_result(&mysql)) {
        if (mysql_num_rows(result)) {
          row = mysql_fetch_row(result);
          msgid=atol(row[0]);
          strcpy(user,  row[1]);
          strcpy(msg,   row[2]);
          strcpy(dest,  row[4]);
          sp2nb(user);
          sp2nb(dest);
          logmsg("SQL >> %ld %s %s %s\r\n", msgid, user, msg, dest);
          sql = 1;
        }
        mysql_free_result(result);
      }
    }

    for (i=numofclients;i--;) {
      struct client *client = clients+i;

      /* Do we have a message in the database waiting? */
      if (sql) {
        if (strcmp(user, "System") == 0) {
          sendline(client, ":%s!%s@%s PRIVMSG %s :%s\r\n", user, user, USER_DOMAIN, CHAN_NAME, msg);
        } 
        else if (dest[0] == 0)
          sendline(client, ":%s!%s@%s PRIVMSG %s :%s\r\n", user, user, USER_DOMAIN, CHAN_NAME, msg);
        else if (strcmp(dest, client->nick) == 0)
          sendline(client, ":%s!%s@%s PRIVMSG %s :%s\r\n", user, user, USER_DOMAIN, client->nick, msg);
      }

      /* Clean up excess allocated memory */
      while ((client->insize>DEFAULTSIZE) && (client->incur<client->insize/2)) {
        client->inbuf=xrealloc(client->inbuf,client->insize/2);
        client->insize/=2;
      } 
      while ((client->outsize>DEFAULTSIZE) && (client->outcur<client->outsize/2)) {
        client->outbuf=xrealloc(client->outbuf,client->outsize/2);
        client->outsize/=2;
      } 

      /* Closed? -> clean */
      if (client->flags & FLAG_CLOSED) {
      	clean_connection(client);
	continue;
      }
      /* Quit & transmitted all stuff left to user? -> clean */
      if ((client->flags&FLAG_QUIT)&&(!client->outcur)) {
	clean_connection(client);
	continue;
      }

      if (client->sockfd>=0) {
        /*need to do that... else it will cause load 1*/
        if (client->outcur) FD_SET(client->sockfd,&writefds);
	if (!(client->flags & FLAG_EOF)) FD_SET(client->sockfd,&readfds);
        if (client->sockfd>=width) width=client->sockfd+1;
      }
    }
    if (-1==select(width, (FD_CAST*)&readfds, (FD_CAST*)&writefds, NULL,/*no exceptfds.*/ 0)) {
      if (errno!=EINTR) logmsg("select");
      else goto restart_select;
    }
    if (FD_ISSET(acfd,&readfds)) {
      int afd;
      int aclen;
      struct sockaddr_in conaddr;
      struct client *client = NULL;

      aclen=sizeof(struct sockaddr_in);
      if (-1==(afd=accept(acfd,(struct sockaddr*)&conaddr,&aclen))) logmsg("accept");
      if (clients) clients=(struct client*)xrealloc(clients,sizeof(struct client)*(numofclients+1));
      else clients=(struct client*)xmalloc(sizeof(struct client));
      numofclients++;
      if (numofclients > maxclients) maxclients = numofclients;
      client = clients+(numofclients-1);
      client->inbuf	= xmalloc(DEFAULTSIZE);
      client->outbuf	= xmalloc(DEFAULTSIZE);
      client->insize	= DEFAULTSIZE;
      client->outsize	= DEFAULTSIZE;
      client->flags	= 0;
      client->incur	= 0;
      client->outcur	= 0;
      client->login	= 0;
      client->sockfd	= afd;
      client->state	= STATE_ACCEPTED;
      memcpy(&client->addr,&conaddr,sizeof(struct sockaddr_in));
      if (numofclients>=MAXUSERS) {
        strcpy(client->outbuf,relaystring);
	client->outcur = strlen(relaystring)+1;
	client->state = STATE_OK;
	client->flags = FLAG_QUIT;
      }
#ifdef SO_LINGER
      {
	struct linger sol;
	sol.l_linger = 5;
	sol.l_onoff = 1;
	if (-1==setsockopt(acfd,SOL_SOCKET,SO_LINGER,(char*)&sol,sizeof(sol))) logmsg("setsockopt SOL_SOCKET SO_LINGER");
      }
#endif
    }
    for (i=numofclients;i--;) {
      struct client *client = clients+i;

      if ((client->sockfd>=0) && FD_ISSET(client->sockfd,&readfds)) {
        do {
          if (-1==(res=read(client->sockfd,readbuf,1000))) {
            if (errno==EINTR) break;
            /* user side has broken the connection */
	    close(client->sockfd);
	    client->sockfd=-1;
	    client->flags |= FLAG_CLOSED;
            break;
          }
          break;
        } while (1);
        if (res==0) {
	  /* we read the End Of File marker. but we still have to write the rest of the text */
	  client->flags |= FLAG_EOF;
        }
        if (res>0) {
          readbuf[res]='\0';
          while (client->incur+res>=client->insize) {
            client->inbuf=xrealloc(client->inbuf,client->insize*2);
            client->insize*=2;
          }
          memcpy(client->inbuf+client->incur,readbuf,res+1);
          client->incur+=res;
        }
      }
      /* Do we have any lines in the buffer? Process them. */
      while (gotline(client)) getircmsg(client);
      
      if ((client->sockfd>=0) && FD_ISSET(client->sockfd,&writefds)) {
        j=client->outcur;
        if (-1==(res=write(client->sockfd,client->outbuf,j))) {
          if (errno!=EINTR) {
            close(client->sockfd);
            client->sockfd=-1;
	    client->flags |= FLAG_CLOSED;
          }
        }
        if (res>0) {
          memcpy(client->outbuf,client->outbuf+res,client->outcur-res);
          client->outcur-=res;
        }
      }
    }
  }
}
 
Last edited:

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top