www.pudn.com > saac.rar > main.c


#define _MAIN_C_

#include "main.h"
#include "util.h"
#include "mail.h"
#include "db.h"
#include "saacproto_util.h"
#include "saacproto_serv.h"
// CoolFish: Family 2001/5/9
#include "acfamily.h"
#include "version.h"
#ifdef _SEND_EFFECT				  // WON ADD 送下雪、下雨等特效 
#include "recv.h"
#endif

#include "char.h"

#ifdef _SASQL
#include "sasql.h"
#endif

#include  
#include  

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include "lock.h"
#define BACKLOGNUM 5

int worksockfd;

struct membuf
{
    int use;
    char buf[512];
//    char buf[1024*128];
    int len;
    int next;
};

struct connection
{
    int use;    
    int fd;       
    int mbtop_ri;
    int mbtop_wi;
    struct sockaddr_in remoteaddr;
    int closed_by_remote;
};

struct membuf *mb;
int mbsize;
int mbuse ;

int cpuuse;


int mainsockfd;             /* accept 及  域娄醒卞中木月 */
struct sockaddr_in localaddr;       /* bind 允月失玉伊旦 */
    

struct connection *con;        /* 戊生弁扑亦件     */

static int mb_finder=0;              /* mb及坞五毛腹绸允月凶户及
                               腹绸玄永皿及匏  筏盛迕 */
// WON FIX
//char tmpbuf[65536];
char tmpbuf[1024*32];
//char tmpbuf[65536*3];         /* read迕 */

struct timeval select_timeout;

time_t sys_time =0; // Robin add

extern gmsv gs[MAXCONNECTION];

int tcpstruct_init( char *addr, int port, int timeout_ms, int mem_use, int deb);
int tcpstruct_accept1( void );
int tcpstruct_accept( int *tis , int ticount );
int tcpstruct_close( int ti );
int tcpstruct_read( int ti , char *buf , int len );
int tcpstruct_readline( int ti , char *buf , int len ,int k ,int r);
int tcpstruct_readline_chop( int ti , char *buf, int len );
int tcpstruct_write( int ti , char *buf , int len );
int tcpstruct_countmbuse( void );
int tcpstruct_connect( char *addr , int port );
void set_nodelay( int sock );


#define OK     0        /* 岳   */
#define TCPSTRUCT_ENOMEM -1       /* malloc 撩   */
#define TCPSTRUCT_ESOCK -2        /* socket 撩   */
#define TCPSTRUCT_EBIND -3        /* bind 撩   */
#define TCPSTRUCT_ELISTEN -4      /* listen 撩   */
#define TCPSTRUCT_EBUG -6         /* 田弘匹丐月 */
#define TCPSTRUCT_EINVCIND -7     /* con尺及index互云井仄中方 */
#define TCPSTRUCT_EREADFIN -8     /* read 允月犯□正互卅仁化 closed by remote */
#define TCPSTRUCT_EHOST -9        /* gethostbyname 撩   */
#define TCPSTRUCT_ECONNECT -10    /* connect 撩   */
#define TCPSTRUCT_ECFULL -11      /* con 互中匀天中 */
#define TCPSTRUCT_ETOOLONG -12    /* 垫互卅互允亢 */
#define TCPSTRUCT_EMBFULL -13     /* mb 互中匀天中  */
#define TCPSTRUCT_ECLOSEAGAIN -14 /* close 互2荚今木凶 */


int port;               /* 必□丞扔□田□互涛粮仄化仁月禾□玄 */
int Total_Charlist;
int Expired_mail;
int Del_Family_or_Member;
int Write_Family;

// Nuke start
char *chartime()
{
    static char buf[80];
    time_t t;
    t=time(0);
    strcpy(buf,ctime(&t));
    buf[strlen(buf)-1]=0;
    return(buf);
}

static int initRankTable( void );

/*
  sigaction白弁
 */
void sighandle( int a )
{
  if (a==SIGUSR1) log("sigusr1信号!\n");
  log("得到一个信号! 异常中断......\n" );
  writeFamily(familydir);
  writeFMPoint(fmpointdir);
  writeFMSMemo(fmsmemodir);
  exit(1);
}

// Arminius 7.20 memory unlock
void sigusr1(int a)
{
  int i;
  FILE *f;
  char key[4096],buf[4096];

  signal(SIGUSR1, sigusr1);
  
  f = fopen("./unlock.arg", "r");

  if (f) {
    memset(key, 0, 4096);
    fread(key, 4096, 1, f);
    for (i=0; i ./sigusr1.result", buf);
      system(key);
    break;
#ifdef _SEND_EFFECT		   // WON ADD 送下雪、下雨等特效
	case 'E':	
		log("\nAC 向 GS 发送下雪特效!!\n");
	    SendEffect(&key[1]);
	break;
#endif

	case 'L':  // Robin 列出所有Server连线
		log("\nList All Server Conncet!!!!!\n");
		for( i =0; i 0){
        		log( "同IP允许同时登陆:%d次\n",sameipmun );
        	}else{
        		log( "同IP允许同时登陆:无限制\n" );
        	}
				}
    }

    fclose(fp);
    return 0;
}


static void parseOpts( int argc, char **argv )
{
    int c , option_index;

		while(1){
        static struct option long_options[] = {
            {"nice" , 1 , 0 , 'n'},
            {"help" , 0 , 0 , 'h' },
            {"userinfo",0 , 0 , 'i'},
            {"lockuser",0 , 0 , 'l'}
        };
        c = getopt_long( argc , argv , "n:hil" , long_options , &option_index );
        if( c == -1 )break;
        switch( c ){
        case 'h':
            fprintf( stderr ,
                     "使用方法: saac [-h] [-w port] [-w port] ... \n"
                     "-h : 显示saac的帮助\n"
                     "-w port : 添加一个工作站进程端口\n"
                     "Copyright 2008 forever sq25工作室 "
                     "( forever sq25 System Supply )\n");
            exit(0);
            break;
        case 'i':
#ifdef _SASQL
        		sasql_init();
        		sasql_craete_userinfo();
        		sasql_close();
#endif
						exit(0);
            break;
        case 'l':
#ifdef _SASQL
        		sasql_init();
        		sasql_craete_lock();
        		sasql_close();
#endif
        		exit(0);
            break;
        case 'n':
        		nice(atoi( optarg ));
        		break;
        default:
            log( "不能读懂选项 %c\n" , c );
            exit(0);
        }
    }
}
double time_diff(struct timeval subtrahend,  struct timeval subtractor);


int main( int argc , char **argv )
{
		parseOpts( argc, argv );
		
    // Nuke +1 1012: Loop counter
    int counter1 = 0;
    
    int counter2 = 0;
    
    int counter3 = 0;
    
    int counter4 = 0;

    signal(SIGUSR1, sigusr1);

    log_rotate_interval = 3600 * 24 * 7;

    Lock_Init();	// Arminius 7.17 memory lock

		UNlockM_Init();
    
    if(readConfig( "acserv.cf" )<0){
        log( "无法在当前目录里读取 acserv.cf .\n" );
        exit(1);
    }

#ifdef _SASQL
    sasql_init();
#endif	
    log( "读取数据目录\n" );
    dbRead( dbdir );
#ifdef	_FAMILY
    log("读取 家族庄园\n");
    readFMSMemo(fmsmemodir);
    log("读取 家族留言\n");
    readFMPoint(fmpointdir);
    log("读取 家族目录\n");
    readFamily(familydir);
#endif
    log( "准备 档案目录\n" );
    prepareDirectories( chardir );
    log( "准备 日志目录\n" );
    prepareDirectories( logdir );
    log( "准备 邮件目录\n" );
    prepareDirectories( maildir );

#ifdef _SLEEP_CHAR
    prepareDirectories( sleepchardir );
    log( "准备 睡眠档案目录\n" );
#endif

    /* 凶引匀化月丢□伙毛  心仇戈 */
    if( readMail(maildir) < 0 ){
        log( "不能初始化邮件\n" );
        exit(1);
		}

    /* TCPSTRUCT 毛赓渝祭 */
    {
        int tcpr;
        if( ( tcpr = tcpstruct_init( NULL , port , 0 ,
						CHARDATASIZE * 16 * MAXCONNECTION , 1 /* DEBUG */ ) ) < 0 ){
            log( "不能开启TCP: %d\n", tcpr );
            return 1;
        }
    }
    saacproto_InitServer( netWrite , CHARDATASIZE );

    {
        struct sigaction s,os;
        
        bzero( &s, sizeof(s));
        s.sa_handler = sighandle;
        s.sa_flags = SA_NOMASK;
        sigaction( SIGTERM,  &s, &os );

        bzero( &s, sizeof(s));
        s.sa_handler = sighandle;
        s.sa_flags = SA_NOMASK;
        sigaction( SIGINT,  &s, &os );

        bzero( &s, sizeof( s ));
        s.sa_handler = SIG_IGN;
        s.sa_flags = SA_NOMASK;
        sigaction( SIGPIPE, &s, &os );

    }

#ifdef _AC_SEND_FM_PK		 // WON ADD 庄园对战列表储存在AC
	load_fm_pk_list();
#endif

#ifdef _ACFMPK_LIST
	FMPK_LoadList();
#endif
#ifdef _ALLDOMAN
	LOAD_herolist();  // Syu ADD 排行榜NPC
#endif

#ifdef _VIP
		log( "\n服务端版本: <%s forever sq25版>\n" , SERVER_VERSION );
#else
		log( "\n服务端版本: <%s 普通版>\n" , SERVER_VERSION );
#endif
		log( "\n服务端编译完成时间:%s %s by sq25工作室\n" , __DATE__ , __TIME__ );
		
    log( "\n开始工作...\n" );

    signal(SIGUSR1,sigusr1);	// Arminius 7.20 memory lock
	int itime=0;
	while(1){
		itime++;
		if(itime>cpuuse){
			itime=0;
			usleep(1);
		}
    int newti,i;
    static time_t main_loop_time;
		
		sys_time = time(NULL);

		if( main_loop_time != sys_time){
            main_loop_time = time(NULL);
            counter1++;
            counter2++;
            counter3++;
            counter4++;
			//andy add 2002/06/20
			UNlockM_UnlockPlayer();

            // Nuke *1 1012
            if( counter1 > Total_Charlist ){
            		counter1=0;
                char *c = ctime( &main_loop_time );
                if( c ){
                    struct timeval st,et;
                    log( "\nTIME:%s\n",c );
                    gettimeofday( &st,NULL);
                    dbFlush(dbdir);
                    gettimeofday( &et,NULL);
                    log( "Flushed db(%fsec)\n", time_diff(et,st) );
                    log( "档案表列总数:%d NG:%d\n",
                         total_ok_charlist, total_ng_charlist );
                }
            }
            // Nuke **1 1012
            //if( ( counter % 600 ) == 0 ){
            if( counter2 > Expired_mail ){
            		counter2=0;
                struct timeval st,et;
                gettimeofday( &st,NULL);
                expireMail();
                gettimeofday( &et,NULL);
                log( "过期邮件(%fsec)\n", time_diff(et,st) );
            }
#ifdef	_FAMILY
            //if ((counter % 300) == 0) // 300( -> 60)
      if( counter4 > Write_Family ) // 300( -> 60)
      {
      	  counter4=0;
         	struct timeval st, et;
         	gettimeofday(&st, NULL);
         	writeFamily(familydir);
         	writeFMPoint(fmpointdir);
         	writeFMSMemo(fmsmemodir);
         	gettimeofday(&et, NULL);
         	log("记录家族(%fsec)\n", time_diff(et, st));
      }
#endif
        }
    newti = tcpstruct_accept1();
    if( newti >= 0 ){
			log( "同意: %d\n" , newti );
			gs[newti].use = 1;
    }

        for(i=0;i 0 ){
									char debugfun[256];
                    buf[l]=0;
                    if( saacproto_ServerDispatchMessage( i , buf, debugfun)<0){
                        // Nuke start
                        tcpstruct_close(i);// avoid the shutdown the gmsv ttom
                        log( "GMSV(%s) 消息:%s\n", gs[i].name, debugfun);
                    }
                } else if( l == TCPSTRUCT_ETOOLONG ){
                    log( "很长:%d 服务器名::%s\n", i , gs[i].name );
                    logout_game_server( i );
                } else if( l < 0 ){
                    log( "关闭:%d 服务器名:%s\n", i , gs[i].name );
                    logout_game_server(i);
                } else if( l == 0 ){
                    ;
                }
            }
        }
        {
            static struct timeval tv_loop_store ;
            struct timeval now;
            double dif;
            gettimeofday( &now , NULL );
            dif = time_diff( now, tv_loop_store );
            if( dif > 0.5 ){ // CoolFish 0.1 -> 0.5 2001/5/19
                //log( "Sl:%f" , dif );
            }
            tv_loop_store = now;
        }

        /* 伐□市□及正奶丞失它玄毛譬屯月[
           正奶丞失它玄仄凶日夫弘毛分仄化伐□市□毛诮仄化仄引丹[
           匹必□丞扔□田□卞  蔽读卞反骚襞允月           */
    }
    return 0;       
}
double
time_diff(struct timeval subtrahend,
          struct timeval subtractor)
{
    return( (subtrahend.tv_sec - subtractor.tv_sec)
            + (subtrahend.tv_usec
            - subtractor.tv_usec  ) / (double)1E6 );
}


/*
  夫弘及夫□  □玄市它件玄毛  月[
  云卅元凛渝及手及反允屯化及夫弘白央奶伙互云卅元卞卅月方丹卞允月[

  仇及酷  反醒侬及瑕互云云仁卅月互}    匹奶件正□田伙毛  凳仄化手
    暹屺分[
  
 */
int get_rotate_count(void )
{
    int a;
    unsigned int t = (unsigned int ) time(NULL);
        
    a = ( t / log_rotate_interval ) * log_rotate_interval;
    
    return a;
}

static int findregBlankMemBuf( void );
static int unregMemBuf( int index );
static int findregBlankCon( void );
static int getFreeMem( void );

static int appendReadBuffer( int index, char *data, int len );
static int appendWriteBuffer( int index , char *data, int len );
static int appendMemBufList( int top, char *data, int len );
static int consumeMemBufList( int top, char *out, int len, int flag, int copyflag );
static int getLineReadBuffer( int index, char *buf, int len );

int tcpstruct_init( char *addr , int p , int timeout_ms , int mem_use , int db )
{
    mbsize = mem_use / sizeof( struct membuf );
    mbuse =0;
    mb_finder = 0;
    mb = ( struct membuf * ) calloc( 1, mbsize * sizeof(struct membuf ));

    if( mb == NULL ) return TCPSTRUCT_ENOMEM;
    bzero( mb , mbsize * sizeof( struct membuf ));

    con = ( struct connection *) calloc( 1, MAXCONNECTION * sizeof( struct connection ));
    if( con == NULL ){
        free( mb );
        return TCPSTRUCT_ENOMEM;
    } else {
        int i;
        for(i=0;i= 0 && con[i].closed_by_remote ==0 ){
      FD_SET( con[i].fd , & rfds );
      FD_SET( con[i].fd , & wfds );
      FD_SET( con[i].fd , & efds );
    
          
	    t = select_timeout;
	    sret = select( con[i].fd+1, & rfds , (fd_set*)NULL, (fd_set*)NULL , &t);
			if( sret > 0 ) {
				if( ( con[i].fd >= 0 ) && FD_ISSET( con[i].fd , &rfds ) ){
					int fr = getFreeMem( );
					int rr , readsize ;
					if( fr <= 0 ) continue;
					if( fr > sizeof(tmpbuf ) ){
						readsize = sizeof( tmpbuf);
					} else {
						readsize = fr;
					}
					rr = read( con[i].fd , tmpbuf , readsize );
					if( rr <= 0 ){
						con[i].closed_by_remote = 1;
					} else {
						appendReadBuffer( i , tmpbuf , rr );
#ifdef _DEBUG
						printf("读取内容:%s\n",tmpbuf);
#endif
					}
				}
			}
	
	    t = select_timeout;    
	    sret = select( con[i].fd+1, (fd_set*)NULL, &wfds, (fd_set*)NULL , &t);
			if( sret > 0 ) {
				if( ( con[i].fd >= 0 ) && FD_ISSET( con[i].fd , &wfds )){
					char send_buf[4096];
					memset( send_buf, 0, sizeof( send_buf));
					int l = consumeMemBufList( con[i].mbtop_wi ,send_buf, sizeof(send_buf),0 , 1 );
					if(l>0){
						int rr = write( con[i].fd , send_buf , l );
						if( rr < 0 ){
							con[i].closed_by_remote = 1;
						} else {
#ifdef _DEBUG
							printf("发送内容:%s\n",send_buf);
#endif
							consumeMemBufList( con[i].mbtop_wi , send_buf, l, 1 , 0 );
						}
					}
				}
			}
		}
	}

  for( i=0; i0 to avoid signal interrupt in select
    if( (asret>0) && FD_ISSET( mainsockfd , & rfds )){
      struct sockaddr_in c;
      int len , newsockfd;
      int newcon;
      bzero( &c , sizeof( c ));
      len = sizeof( c );
      fprintf( stderr, "i can accept " );
      newcon = findregBlankCon( );
      if( newcon < 0 ) continue;
        newsockfd = accept( mainsockfd, (struct sockaddr*)&c , &len );
        log( "同意: %d\n" , newsockfd );
        if( newsockfd < 0 ){
          unregMemBuf( newcon );
          continue;
        }
        set_nodelay( newsockfd );
        con[newcon].fd = newsockfd;
        memcpy( &con[newcon].remoteaddr , &c ,sizeof(c));
        tis[accepted] = newcon;
        accepted ++;
     }
   }

   return accepted;
}

int tcpstruct_close( int ti )
{

    if( ti < 0 || ti >= MAXCONNECTION )return TCPSTRUCT_EINVCIND;
    if( con[ti].use == 0 ){
        return TCPSTRUCT_ECLOSEAGAIN;
    }
    close( con[ti].fd );
    con[ti].use = 0;
    con[ti].fd = -1;

    /* 伉旦玄毛凶升匀化蝈  毛弁伉失允月 */
    consumeMemBufList( con[ti].mbtop_ri , NULL,
                   mbsize * sizeof( mb[0].buf ), 1, 0 );
    consumeMemBufList( con[ti].mbtop_wi , NULL,
                   mbsize * sizeof( mb[0].buf ), 1, 0 );
    unregMemBuf( con[ti].mbtop_ri );
    unregMemBuf( con[ti].mbtop_wi );
    con[ti].mbtop_ri = -1;
    con[ti].mbtop_wi = -1;    
    return OK;
}

/*
    心仇戈手及互手丹卅仁化}仄井手 remoteclose 分匀凶日 -1 毛井尹允
  
 */
int tcpstruct_read( int ti , char *buf , int len )
{
    int l;

    if( ti < 0 || ti >= MAXCONNECTION || con[ti].use == 0 )
        return TCPSTRUCT_EINVCIND;
    l = consumeMemBufList( con[ti].mbtop_ri , buf , len , 1 , 1);
    if( l == 0  && con[ti].closed_by_remote ) return TCPSTRUCT_EREADFIN;

    return l;
}

/*
  1垫毛方心仇戈[
  int kend : 1卅日垫  及 \n 毛诮允
  int kend_r : 1卅日垫  及 \r 手诮允(丐木壬)

    心仇戈手及互手丹卅仁化}井勾 remote closed 分匀凶日-1毛井尹允
  // Nuke
	Read 1 line
	if kend==1 then delete \n at the tail
	if kend_r== 1 then delete \r at the tail (if any)
	if no data read, it means 'remote closed' then return -1
 */
int tcpstruct_readline( int ti , char *buf , int len , int kend , int kend_r )
{
    int l;
    int minus = 0;

    if( ti < 0 || ti >= MAXCONNECTION || con[ti].use == 0 )
        return TCPSTRUCT_EINVCIND;

    l = getLineReadBuffer( ti , buf , len );
    if( l == 0 ){
        if( con[ti].closed_by_remote ){
            return TCPSTRUCT_EREADFIN;
        } else {
            return 0;
        }
    }
    
    if( kend ){
        if( buf[l-1]=='\n' ){
            buf[l-1] = 0; minus =-1;
        }
    }
    if( kend_r ){
        if( buf[l-1]=='\r' ){
            buf[l-1] = 0; minus = -1;
        }
        if( buf[l-2]=='\r' ){
            buf[l-2] = 0; minus = -2;
        }
    }
    return l + minus;
}
int tcpstruct_readline_chop( int ti , char *buf, int len )
{
    return tcpstruct_readline( ti , buf , len , 1,1);
}

int tcpstruct_write( int ti , char *buf , int len )
{
    if( ti < 0 || ti >= MAXCONNECTION || con[ti].use == 0 )
        return TCPSTRUCT_EINVCIND;    
    return appendWriteBuffer( ti , buf , len );
}

int tcpstruct_connect( char *addr , int port )
{
    int newti ;
    int s, r;
    struct sockaddr_in svaddr;
    struct hostent *he;
    
    s = socket( AF_INET, SOCK_STREAM , 0 );
    if(s<0)return -2;

    bzero( &svaddr , sizeof( svaddr ));
    svaddr.sin_family = AF_INET;
    svaddr.sin_port = htons( port );

    if( inet_aton( addr, &svaddr.sin_addr ) == 0 ){
        he = gethostbyname( addr );
        if( he == NULL ){
            return TCPSTRUCT_EHOST;
        }
        memcpy( & svaddr.sin_addr.s_addr , he->h_addr ,
                sizeof( struct in_addr));
    }
    r = connect( s , ( struct sockaddr*)&svaddr,sizeof(svaddr));
    if( r < 0 ){
        return TCPSTRUCT_ECONNECT;
    }
    set_nodelay( s );
    newti = findregBlankCon( );
    if( newti < 0 ){
        fprintf( stderr , "连接失败: newti:%d\n", newti );
        return TCPSTRUCT_ECFULL;
    }
    con[newti].fd = s;
    memcpy( & con[newti].remoteaddr , &svaddr ,
            sizeof( struct sockaddr_in));
    return newti;
}

static int appendReadBuffer(  int index , char *data , int len )
{
    int top;

    top = con[index].mbtop_ri;
    for(;;){
        int nextind = mb[top].next;

        if( nextind == -1 ) break;
        top = nextind;
    }
    return appendMemBufList( top , data , len );
}

static int appendWriteBuffer( int index , char *data , int len )
{
    int top;
    top = con[index].mbtop_wi;
    for(;;){
        int nextind = mb[top].next;
        if( nextind == -1 ) break;
        top = nextind;
    }
    return appendMemBufList( top , data , len );
}
static int appendMemBufList( int top , char *data , int len )
{
    int fr = getFreeMem( );
    int rest = len;
    int data_topaddr = 0;
    
    if( len >= fr ){
		FILE *fp;
		if( (fp=fopen( "badsysinfo.txt", "a+")) != NULL ){
			fprintf( fp, "appendMemBufList() len:%d / fr:%d err !! \n", len, fr);
			fclose( fp);
		}
		//andy_log
		log( "appendMemBufList() len:%d / fr:%d err !! \n", len, fr);
        return -1;
    }
	data[len] = 0;
    for(;;){
        int blanksize = sizeof( mb[0].buf ) - mb[top].len;
        int cpsize = ( rest <= blanksize ) ? rest : blanksize;
        memcpy( mb[top].buf + mb[top].len ,
                data + data_topaddr , cpsize );
        mb[top].len += cpsize;
        if( rest <= blanksize ){
            return len;
        } else {
            int newmb;
            rest -= cpsize;
            data_topaddr += cpsize;
            if( (newmb = findregBlankMemBuf( ) ) == TCPSTRUCT_EMBFULL ){
				FILE *fp;
				if( (fp=fopen( "badsysinfo.txt", "a+")) != NULL ){
					fprintf( fp, "find newmb == TCPSTRUCT_EMBFULL err data:%s !!\n", data);
					fclose( fp);
				}
				log( "find newmb == TCPSTRUCT_EMBFULL err data:%s !!\n", data);
			}
            mb[top].next = newmb;
            top = mb[top].next;
        }
    }
    return TCPSTRUCT_EBUG;
}

static int consumeMemBufList( int top , char *out , int len ,
                          int consumeflag , int copyflag )
{
    int total = 0;
    int top_store = top;
    for(;;){
        int cpsize;
        if( top == -1 ) break;
        cpsize = ( mb[top].len <= ( len - total) ) ?
            mb[top].len : ( len - total );

        if( copyflag ) memcpy( out + total , mb[top].buf , cpsize );
        total += cpsize;

        if( consumeflag ){
            mb[top].len -= cpsize;
            if( mb[top].len > 0 ){
                /* 勾井中反凶仄化卅中及匹memmove */
                memmove( mb[top].buf , mb[top].buf + cpsize ,
                         sizeof( mb[top].buf ) - cpsize );
            }
        }
        top = mb[top].next;
        if( total == len ){
            break;
        }
    }

    if( consumeflag ){
        /* 卅互今互0卞卅匀化月卅日荸  [匹手  赓及支勾反荸  仄卅中冗 */
        top = mb[top_store].next;
        for(;;){
            if( top == -1 )break;
            if( mb[top].len == 0 ){
                int prev;
                mb[top_store].next = mb[top].next;
                prev = top;
                top = mb[top].next;
                unregMemBuf( prev );
            } else {
                top = mb[top].next;
            }
        }
    }
    
    return total;
}

static int getLineReadBuffer( int index , char *buf, int len )
{

    int top = con[index].mbtop_ri;
    int ti = 0 , breakflag = 0;

    for(;;){
        int i;        
        int l = mb[top].len;
        if( top == -1 )break;
        for( i=0 ; i < l ; i++){
            if( mb[top].buf[i] == '\n' ){
                breakflag = 1;
                break;
            }
            ti ++;
        }
        if( breakflag )break;
        top = mb[top].next;
    }
    if( ti > len ){
        /* 1垫互卅互允亢月[    卅巨仿□毛井尹六 */
        return TCPSTRUCT_ETOOLONG;
    }
    /* 垫互敦岳仄化卅中 */
    if( breakflag == 0 ){
        return 0;
    }

    return consumeMemBufList( con[index].mbtop_ri , buf , ti+1 , 1 , 1 );
}



/*
    心仇户月    赢今毛忒允
  int index : con index

  return:
    反巨仿□
  0动晓及桦宁反 read 仄化手方中赢今[


  mbsize 井日mbuse 毛娄中化扔奶术毛井仃月分仃[
  仇引井中芴曰及坌反  骰允月[公氏卅称井中袄卞仇分歹日卅仁化手第[
  
 */   
static int getFreeMem( void )
{
    return ( mbsize - mbuse ) * sizeof( mb[0].buf );
}

/*
  
  membuf 及坞五毛茧仄分允[

  return : 心勾井匀凶日 >=0 匹 index.
  心勾井日卅井匀凶日  

  腹绸及午五卞反 mb_finder 毛勾井丹[
  仇木匹腹绸仄化}    卞reg允月[
 */

static int findregBlankMemBuf( void  )
{
    int i;
    for(i=0;i= mbsize || mb_finder < 0 ) mb_finder = 0;

        if( mb[mb_finder].use == 0 ){
            mb[mb_finder].use = 1;
            mb[mb_finder].len = 0;
            mb[mb_finder].next = -1;
            mbuse ++;
            return mb_finder;
        }
    }
    return TCPSTRUCT_EMBFULL;
}

/*
  mb 毛荸  允月
  
 */
static int unregMemBuf(  int index )
{
    mb[index].use=0;
    mb[index].next = -1;
    mb[index].len = 0;
    mbuse --;
    return OK;
}

static int findregBlankCon( void )
{
    int i;
		// Nuke changed 0->1
		//for(i=0;i