--- tcpserver.org.c	2000-03-19 00:18:42.000000000 +0900
+++ tcpserver.c	2004-07-10 16:28:13.000000000 +0900
@@ -1,6 +1,7 @@
 #include <sys/types.h>
 #include <sys/param.h>
 #include <netdb.h>
+#include <limits.h>
 #include "uint16.h"
 #include "str.h"
 #include "byte.h"
@@ -55,6 +56,8 @@
 
 char strnum[FMT_ULONG];
 char strnum2[FMT_ULONG];
+char strnum3[FMT_ULONG*2+2];
+char strnum4[FMT_ULONG*2+2];
 
 static stralloc tmp;
 static stralloc fqdn;
@@ -63,7 +66,51 @@
 char bspace[16];
 buffer b;
 
+/* ---------------------------- common */
+unsigned long limit = 40;
+unsigned long numchildren = 0;
+
+typedef struct{
+ unsigned long remoteip;
+ int pid;
+} pariplimit_data_t;
+pariplimit_data_t* pariplimit_data=0;
+unsigned long pariplimit=0;
+
+unsigned long pariplimit_cnt(unsigned long remoteip)
+{
+  unsigned long i;
+  unsigned long cnt=0;
+  for(i=0;i<numchildren;i++){
+    if(pariplimit_data[i].remoteip == remoteip){
+      ++cnt;
+      if(cnt >= pariplimit) return cnt;
+    }
+  }
+  return cnt;
+}
+int pariplimit_delete(int pid,unsigned long* remoteip)
+{
+  unsigned long i;
+  for(i=0;i<=numchildren;i++){
+    if(pariplimit_data[i].pid == pid){
+      if(remoteip) *remoteip = pariplimit_data[i].remoteip;
+      pariplimit_data[i].remoteip = pariplimit_data[numchildren].remoteip;
+      pariplimit_data[i].pid = pariplimit_data[numchildren].pid;
+      return 1;
+    }
+  }
+  return 0;
+}
 
+unsigned int parparamstr(char *s,unsigned long u1,unsigned long u2)
+{
+  unsigned int p;
+  p = fmt_ulong(s,u1);
+  s[p++] = '/';
+  p += fmt_ulong(s+p,u2);
+  return p;
+}
 
 /* ---------------------------- child */
 
@@ -141,7 +188,12 @@
 
   if (verbosity >= 2) {
     strnum[fmt_ulong(strnum,getpid())] = 0;
-    strerr_warn4("tcpserver: pid ",strnum," from ",remoteipstr,0);
+    if(pariplimit > 0){
+      strnum3[parparamstr(strnum3,pariplimit_cnt(*((unsigned long*)remoteip)),pariplimit)] = 0;
+      strerr_warn6("tcpserver: pid ",strnum," pariplimit status: ",strnum3," from ",remoteipstr,0);
+    }else{
+      strerr_warn4("tcpserver: pid ",strnum," from ",remoteipstr,0);
+    }
   }
 
   if (flagkillopts)
@@ -230,8 +282,6 @@
   if (flagdeny) _exit(100);
 }
 
-
-
 /* ---------------------------- parent */
 
 #define FATAL "tcpserver: fatal: "
@@ -242,6 +292,7 @@
 tcpserver: usage: tcpserver \
 [ -1UXpPhHrRoOdDqQv ] \
 [ -c limit ] \
+[ -i pariplimit ] \
 [ -x rules.cdb ] \
 [ -B banner ] \
 [ -g gid ] \
@@ -253,9 +304,6 @@
   _exit(100);
 }
 
-unsigned long limit = 40;
-unsigned long numchildren = 0;
-
 int flag1 = 0;
 unsigned long backlog = 20;
 unsigned long uid = 0;
@@ -278,6 +326,7 @@
 {
   int wstat;
   int pid;
+  unsigned long remoteip;
  
   while ((pid = wait_nohang(&wstat)) > 0) {
     if (verbosity >= 2) {
@@ -285,7 +334,26 @@
       strnum2[fmt_ulong(strnum2,wstat)] = 0;
       strerr_warn4("tcpserver: end ",strnum," status ",strnum2,0);
     }
-    if (numchildren) --numchildren; printstatus();
+    if (numchildren){
+      --numchildren;
+      if(pariplimit > 0){
+        if(!pariplimit_delete(pid,&remoteip)){
+          strnum[fmt_ulong(strnum,pid)] = 0;
+          strerr_warn4(DROP,"pid not found in database ",strnum,": please restart tcpserver... ",0);
+        }else{
+          if (verbosity >= 2) {
+            strnum3[parparamstr(strnum3,numchildren,limit)] = 0;
+            strnum4[parparamstr(strnum4,pariplimit_cnt(remoteip),pariplimit)] = 0;
+            remoteipstr[ip4_fmt(remoteipstr,(char*)&remoteip)] = 0;
+            strerr_warn6("tcpserver: status: ",strnum3," pariplimit status: ",strnum4," from ",remoteipstr,0);
+          }
+        }
+      }else{
+        printstatus();
+      }
+    }else{
+      printstatus();
+    }
   }
 }
 
@@ -299,11 +367,14 @@
   unsigned long u;
   int s;
   int t;
+  int cpid;
+  unsigned long remoteipl;
  
-  while ((opt = getopt(argc,argv,"dDvqQhHrR1UXx:t:u:g:l:b:B:c:pPoO")) != opteof)
+  while ((opt = getopt(argc,argv,"dDvqQhHrR1UXx:t:u:g:l:b:B:c:i:pPoO")) != opteof)
     switch(opt) {
       case 'b': scan_ulong(optarg,&backlog); break;
       case 'c': scan_ulong(optarg,&limit); break;
+      case 'i': scan_ulong(optarg,&pariplimit); break;
       case 'X': flagallownorules = 1; break;
       case 'x': fnrules = optarg; break;
       case 'B': banner = optarg; break;
@@ -332,6 +403,12 @@
   argc -= optind;
   argv += optind;
 
+  if(pariplimit > 0){
+    if(limit >= UINT_MAX/sizeof(pariplimit_data_t)-1) strerr_die2x(111,FATAL,"out of memory");
+    pariplimit_data = (pariplimit_data_t*)alloc(sizeof(pariplimit_data_t)*(limit+1));
+    if(!pariplimit_data) strerr_die2x(111,FATAL,"out of memory");
+  }
+
   if (!verbosity)
     buffer_2->fd = -1;
  
@@ -403,9 +480,20 @@
     sig_block(sig_child);
 
     if (t == -1) continue;
+    if(pariplimit > 0){
+      remoteipl = *((unsigned long*)remoteip);
+      if(pariplimit_cnt(remoteipl) >= pariplimit){
+        close(t);
+        remoteipstr[ip4_fmt(remoteipstr,remoteip)] = 0;
+        strerr_warn2(DROP "RemoteIP over pariplimit from ",remoteipstr,0);
+        continue;
+      }
+      pariplimit_data[numchildren].remoteip = remoteipl;
+      pariplimit_data[numchildren].pid = 0;
+    }
     ++numchildren; printstatus();
  
-    switch(fork()) {
+    switch((cpid = fork())) {
       case 0:
         close(s);
         doit(t);
@@ -420,6 +508,11 @@
       case -1:
         strerr_warn2(DROP,"unable to fork: ",&strerr_sys);
         --numchildren; printstatus();
+        break;
+      default:
+        if(pariplimit > 0){
+          pariplimit_data[numchildren-1].pid = cpid;
+        }
     }
     close(t);
   }
