Re: Opening 5000 file descriptors in linux??

Mike Goldman (whig@by.net)
Tue, 11 May 1999 12:58:50 -0400


/*
* SHIMD - A simple multi-forking socket-redirecting daemon
* Copyright (C) 1996 by Mike Goldman <whig@by.net>
*
* This program is released under the GNU General Public License
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>

int NeedToDie = 0, sid = 0;
void onsig(int sig)
{
if (sig == SIGTERM && !NeedToDie) {
NeedToDie = 1;
signal(sig, onsig);
kill(-sid, sig);
} else signal(sig, onsig);
}

void ShimCopy(int Dst, int Src)
{
char buf[1024];
int got = read(Src, buf, sizeof (buf));
if (got > 0) write(Dst, buf, got);
else if (errno != EINTR) exit(0);
}

void Shim(int Socket, u_short ServerPort)
{
int Server = 0;
struct sockaddr sockaddr;
int len = sizeof (sockaddr);
struct sockaddr_in inaddr;
fd_set Select;
int Client = accept(Socket, NULL, NULL);
if (Client < 0) return;
if (getsockname(Client, &sockaddr, &len) < 0) goto EndShim;
if ((Server = socket(AF_INET, SOCK_STREAM, 0)) < 0) goto EndShim;
bzero(&inaddr, sizeof (inaddr));
inaddr.sin_family = AF_INET;
inaddr.sin_addr.s_addr =
((struct sockaddr_in *)&sockaddr)->sin_addr.s_addr;
inaddr.sin_port = htons(ServerPort);
if (connect(Server, (void *)&inaddr, sizeof (inaddr)) < 0) goto
EndShim;
if (fork()) goto EndShim;

close (Socket);
while (!NeedToDie) {
FD_ZERO(&Select);
FD_SET(Server, &Select);
FD_SET(Client, &Select);
if (select(((Server > Client)? Server : Client) + 1,
&Select, NULL, NULL, NULL) < 0) continue;
if (FD_ISSET(Server, &Select)) ShimCopy(Client, Server);
if (FD_ISSET(Client, &Select)) ShimCopy(Server, Client);
}
exit(0);

EndShim:
close(Client);
if (Server) close (Server);
}

#define MAXSOCKS 200
void Process(u_short Servic, u_long Range1, u_long Range2, u_short
thisServer)
{
struct sockaddr_in inaddr; int n;
static int Sockets = 0;
static int *Socket = NULL;
static u_short *Server = NULL;
static int Listen;
static fd_set Select, Selected;
if (Servic) for (; Range1 <= Range2; Range1++) {
Socket = realloc(Socket, (Sockets+1) * sizeof (*Socket));
if (Sockets >= MAXSOCKS || (Socket[Sockets] =
socket(AF_INET, SOCK_STREAM, 0)) < 0) {
Range1--;
if (!fork()) break;
while (Sockets) close(Socket[Sockets--]);
continue;
}
n = 1;
setsockopt(Socket[Sockets], SOL_SOCKET, SO_REUSEADDR,
&n, sizeof (n));
bzero(&inaddr, sizeof (inaddr));
inaddr.sin_family = AF_INET;
inaddr.sin_port = htons(Servic);
inaddr.sin_addr.s_addr = htonl(Range1);
bind(Socket[Sockets], (void *)&inaddr, sizeof (inaddr));
listen(Socket[Sockets], 5);
if (!Sockets) {
FD_ZERO(&Select);
Listen = 0;
}
FD_SET(Socket[Sockets], &Select);
if (Socket[Sockets] >= Listen) Listen = Socket[Sockets]+1;
Server = realloc(Server, (Sockets+1) * sizeof (*Server));
Server[Sockets] = thisServer;
Sockets++;
}
if (Range1 > Range2) return;
while (!NeedToDie) {
Selected = Select;
if (select(Listen, &Selected, NULL, NULL, NULL) <= 0)
continue;
for (n = 0; n < Sockets; n++)
if (FD_ISSET(Socket[n], &Selected))
Shim(Socket[n], Server[n]);
}
}

void main(void)
{
char line[255], *delim = "\t\r\n ";
FILE *fp = fopen("/etc/shimd.conf", "r");
if (fp == NULL || fork()) return;
sid = setsid();
signal(SIGCHLD, SIG_IGN);
signal(SIGTERM, onsig);

while (fgets(line, sizeof(line), fp)) {
char *szServic = strtok(line, delim); u_short usServic;
char *szRange1 = strtok(NULL, delim); u_long ulRange1;
char *szRange2 = strtok(NULL, delim); u_long ulRange2;
char *szServer = strtok(NULL, delim); u_short usServer;
if (!szServic || *szServic == '#' ||
!szRange1 || !szRange2 || !szServer) continue;
usServic = atoi(szServic);
ulRange1 = ntohl(inet_addr(szRange1));
ulRange2 = ntohl(inet_addr(szRange2));
usServer = atoi(szServer);
if (!usServic || !usServer ||
ulRange1 == (u_long)-1L || ulRange2 == (u_long)-1L) continue;
if (ulRange1 > ulRange2) {
ulRange1 ^= ulRange2; ulRange2 ^= ulRange1; ulRange1 ^=
ulRange2;
}
Process(usServic, ulRange1, ulRange2, usServer);
}
if (!NeedToDie) Process(0,0,0,0);
}

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/