📄 spm.c
字号:
/* Spm: The PortMaster * This program is expected to run as a daemon on every machine * which uses Terry McRoberts' Socket Library. * * Its purpose in life is to: * a) receive messages from processes starting up servers to maintain * a list of process names and associated ports, * b) to inform processes starting up client sockets about the port * numbers of designed servers. * * This program's services are generally hidden from the users, and is * accessed by the Sopen() functions. Since processes from anywhere * need to access this process, it has a fixed port number (PORTMASTER) * unless overridden from the command line. This information is hard-coded * into the <sockets.h> header file. * * Routines Include: <Spm.c> * int main( int argc, char **argv) * static Socket *Sopen_prtmstr() * static PortTable *makePortTable(SKTEVENT port,char *sharehost) * static void delPortTable(PortTable *p) * void pm_server(Socket *client) * void pm_client(Socket *client) * void pm_close(Socket *client) * void pm_quit( Socket *server, Socket *client) * void pm_table(Socket *client) * void pm_rmserver(Socket *client) * int firewall(Socket *skt) * void firewall_init(char *fwfile) * void pm_fwinit(Socket *skt) */#include <stdio.h>#include "sockets.h"#include <setjmp.h>#ifdef __WIN32__# include <windows.h>#endif#ifdef unix# include <sys/types.h># include <unistd.h>#endif/* ---------------------------------------------------------------------- * Definitions: */#define SPMFIREWALL /* select PortMaster firewall code */#define BUFSIZE 128 /* size of character buffers */#define SPMFWDATA 6 /* SSL PortMaster Firewall data quantity */#define TIMEOUT 20L /* wait no more than 20 seconds at a Sread... */# ifdef unix/* # define CloseStdio */# endif/* ---------------------------------------------------------------------- * Typedefs: */#ifdef SPMFIREWALLtypedef struct spmfw_str SpmFW;#endiftypedef struct PortTablestr PortTable;/* ---------------------------------------------------------------------- * Data Structures: *//* PortTable: this data structure supports matching host/process name * to ports */struct PortTablestr { char *sktname; /* name of skt */ char *sharehost; /* optional Portmaster-sharing hostname */ SKTEVENT port; /* port of socket */ PortTable *nxt,*prv; /* linked list */ };#ifdef SPMFIREWALLstruct spmfw_str { int data[SPMFWDATA]; SpmFW *nxt; };#endif/* ---------------------------------------------------------------------- * Global Data: */static struct sockaddr_in sin;static char hostname[BUFSIZE];static char hostaddr[4];static char sktname[BUFSIZE];static SKTEVENT ok = 0;static SKTEVENT sorry = 0;static SKTEVENT resend = 0;static SKTEVENT okshare= 0;static PortTable *phd = NULL;static PortTable *ptl = NULL;static jmp_buf timedout;#ifdef SPMFIREWALLstatic SpmFW *spmfwhd=NULL;#endif/* ---------------------------------------------------------------------- * Usage: */static char *usage[]={ XYELLOW,"Spm ",XGREEN,"[",XCYAN,"-f firewallfilename",XGREEN,"]\n\n", XUWHITE,"Author",XGREEN,": Dr. Charles E. Campbell, Jr.\n\n", XUWHITE,"Options:\n\n", XCYAN," -f firewallfilename",XGREEN,": optional firewall file\n", XUWHITE,"Explanation:\n\n",XGREEN, "The ",XYELLOW,"Spm",XGREEN," is the PortMaster for the Sockets library\n", "written by Dr. Charles E. Campbell, Jr. and Terry McRoberts of NASA.\n", "The Spm program provides a \"phonebook\" of server names and their\n", "associated port identifiers used by the Sopen function. The data\n", "is maintained in an internal \"PortTable\" linked list in memory.\n", "The PortMaster (Spm) must be run on any machine using the Sockets\n", "library.\n\n", "The PortMaster is not intended to be used directly by the user.\n", "Instead, Sopen, Sclose, and Srmsrvr are the primary interfaces to the\n", "PortMaster for the user. These functions follow a simple protocol and\n", "pass PortMaster \"event\"s to and from the PortMaster.\n\n", "There are some additional functions that the PortMaster provides: one\n", "may use PortMaster events to close down the PortMaster (PM_QUIT) and\n", "to query the PortMaster as to what servers are available (PM_TABLE).\n", "These functions do not have nice interfaces provided; one must be\n", "conversant with the PortMaster protocol to get them to work.\n\n", "\n",XUWHITE,"Version",XGREEN,": ",#ifdef unix "unix",#endif#ifdef vms "vms",#endif#ifdef msdos "msdos",#endif "\n", "",""};/* ---------------------------------------------------------------------- * Prototypes: */#ifdef __PROTOTYPE__int main( int, char **); /* Spm.c */static Socket *Sopen_prtmstr(void); /* Spm.c */static PortTable *makePortTable(SKTEVENT,char *); /* Spm.c */static void delPortTable(PortTable *); /* Spm.c */void pm_server(Socket *,SKTEVENT); /* Spm.c */void pm_client(Socket *); /* Spm.c */void pm_close(Socket *); /* Spm.c */void pm_quit( Socket *, Socket *); /* Spm.c */void pm_table(Socket *); /* Spm.c */void pm_rmserver(Socket *); /* Spm.c */#ifdef SPMFIREWALLint firewall(Socket *); /* Spm.c */void firewall_init(char *); /* Spm.c */void pm_fwinit(Socket *); /* Spm.c */#endif#elseextern int main(); /* Spm.c */static Socket *Sopen_prtmstr(); /* Spm.c */static PortTable *makePortTable(); /* Spm.c */static void delPortTable(); /* Spm.c */extern void pm_server(); /* Spm.c */extern void pm_client(); /* Spm.c */extern void pm_close(); /* Spm.c */extern void pm_quit(); /* Spm.c */extern void pm_table(); /* Spm.c */extern void pm_rmserver(); /* Spm.c */#ifdef SPMFIREWALLextern int firewall(); /* Spm.c */extern void firewall_init(); /* Spm.c */extern void pm_fwinit(); /* Spm.c */#endif#endif /* __PROTOTYPE__ *//* ---------------------------------------------------------------------- *//* main: this is where it starts, ladies and gentlemen! */#ifdef __WIN32__// WinMain: Entry point of all Windows programsint APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)#else# ifdef __PROTOTYPE__int main( int argc, char **argv)# elseint main( argc, argv)int argc;char **argv;# endif#endif{SKTEVENT event;Socket *client = NULL;Socket *server = NULL;int resend_cnt = 0;struct hostent *he = NULL;#ifdef unixint daemon=0;int tty_fd;daemon= fork();if(daemon < 0) error(XTDIO_ERROR,"Spm: PortMaster cannot fork");else if(daemon) { /* we're the parent, so bye-bye! */ /* give out credits */ fprintf(stderr,"\n"); fprintf(stderr," *** Simple Sockets PortMaster ***\n"); fprintf(stderr," Authors: Charles E. Campbell, Jr., Ph.D.\n"); fprintf(stderr," Terry McRoberts\n"); fprintf(stderr,"\n"); fprintf(stderr,"of Goddard Space Flight Center, Maryland, USA\n"); fprintf(stderr," (uses port %4d)\n",PORTMASTER); exit(0); }setsid(); /* release controlling terminal */#elif defined(__WIN32__)static int argc = 1;static char argv[1][4]={"Spm"};#else/* give out credits */fprintf(stderr,"\n");fprintf(stderr," *** Simple Sockets PortMaster ***\n");fprintf(stderr," Authors: Charles E. Campbell, Jr., Ph.D.\n");fprintf(stderr," Terry McRoberts\n");fprintf(stderr,"\n");fprintf(stderr,"of Goddard Space Flight Center, Maryland, USA\n");fprintf(stderr," (uses port %4d)\n",PORTMASTER);#endif /* #if unix .. else if windoz ... endif */rdcolor(); /* read color strings */Sinit(); /* initialize sockets *//* handle command line */if(argc > 1 && !strcmp(argv[1],"?")) { /* give usage message */ char **u; for(u= usage; u[0][0] || u[1][0]; ++u) rdcputs(*u,stdout); exit(0); }/* initialize */ok = htons(PM_OK);okshare= htons(PM_OKSHARE);sorry = htons(PM_SORRY);resend = htons(PM_RESEND);/* get the current hostname */gethostname(hostname,BUFSIZE);#ifdef SPMFIREWALLhe= gethostbyname(hostname); /* get host address */if(he) { hostaddr[0]= he->h_addr_list[0][0]; hostaddr[1]= he->h_addr_list[0][1]; hostaddr[2]= he->h_addr_list[0][2]; hostaddr[3]= he->h_addr_list[0][3]; if(hostaddr[0] < 0) hostaddr[0]+= 256; if(hostaddr[1] < 0) hostaddr[1]+= 256; if(hostaddr[2] < 0) hostaddr[2]+= 256; if(hostaddr[3] < 0) hostaddr[3]+= 256; /* initialize firewall: -f <firewallfile> * If no such option, then the "SPMFIREWALL" environment variable * is examined */ if(argc > 1 && argv[1][0] == '-' && argv[1][1] == 'f') firewall_init(argv[1]+2); else firewall_init(""); }else hostaddr[0]= hostaddr[1]= hostaddr[2]= hostaddr[3]= '\0';#endif/* open a server for the PortMaster */server= Sopen_prtmstr();if(!server) { error(XTDIO_ERROR,"%s PortMaster's port (#%d) already in use!!!\n", hostname, PORTMASTER);#ifdef vms exit(1);#else exit(0);#endif }#ifdef CloseStdio/* get rid of things we no longer need */fflush(stdin);fflush(stdout);fflush(stderr);fclose(stdin);fclose(stdout);fclose(stderr);#endif/* set up a timeout return point */(void) setjmp(timedout);/* accept clients */while(1) { /* close out old connection */ if(client) { shutdown(client->skt,2); close(client->skt); client->skt= NULL; freeSocket(client); /* free client Socket */ client= NULL; /* paranoia is good medicine */ } /* accept a client connection */ client= Saccept(server); if(!client) { continue; }#ifdef SPMFIREWALL if(firewall(client)) { /* reject clients not inside firewall */ Swrite(client,(char *) &sorry,sizeof(sorry)); shutdown(client->skt,2); close(client->skt); client->skt= NULL; freeSocket(client); client = NULL; continue; }#endif /* SPMFIREWALL */ /* get a PrtMstrEvent */ resend_cnt= 0; do { /* get the event that PortMaster is to handle */ if(Stimeoutwait(client,TIMEOUT,0L) < 0) longjmp(timedout,1); Sreadbytes(client,(char *) &event,sizeof(event)); event= ntohs( event); /* The PortMaster handles several events: /===============================================\ | Client PortMaster | | Event Sends Sends | |===============================================| | PM_SERVER PM_OK / PM_RESEND | | sktname | | port | | PM_OK / PM_SORRY | |-----------------------------------------------| | PM_CLIENT | | PM_OK / PM_RESEND | | sktname | | PM_OK / PM_SORRY | | port | |-----------------------------------------------| | PM_CLOSE | | PM_OK / PM_RESEND | | port | | PM_OK / PM_SORRY | |-----------------------------------------------| | PM_TABLE | | PM_OK / PM_RESEND | | count of servers | | "server : port#" | |-----------------------------------------------| | PM_QUIT | | PM_OK / PM_RESEND | | "PortMaster" | |-----------------------------------------------| | PM_FWINIT | | PM_OK / PM_RESEND | |-----------------------------------------------| | PM_SHARE PM_OK / PM_RESEND | Supports new portmaster | hostname | sharing mode. Now, a | sktname | single Portmaster can support | port | a number of different machines. | PM_OK / PM_SORRY | The main reason for this is to |-----------------------------------------------| support PC-only shops, but it | PM_CLIENT | will work with any PortMaster. | PM_OK / PM_RESEND | | sktname | | PM_OKSHARE / PM_SORRY| | hostname | | port | \===============================================/ */ switch(event) { case PM_SERVER: /* enter port into database */ case PM_SHARE: /* enter hostname & port into database */ pm_server(client,event); resend_cnt= 0; break; case PM_CLIENT: /* return port from database */ pm_client(client); resend_cnt= 0; break; case PM_CLOSE: /* delete port from database */ pm_close(client); resend_cnt= 0; break; case PM_QUIT: /* this function terminates the PortMaster */ pm_quit(server,client); resend_cnt= 0; break; case PM_TABLE: /* print out the PortTable */ pm_table(client); resend_cnt= 0; break; case PM_RMSERVER: /* remove a server entry from the PortMaster */ pm_rmserver(client); resend_cnt= 0; break;#ifdef SPMFIREWALL case PM_FWINIT: /* re-read firewall file */ pm_fwinit(client); resend_cnt= 0; break;#endif default: /* huh? whaddaIdonow? */ Swrite(client,(char *) &resend,sizeof(resend)); /* terminate resending after PM_MAXTRY attempts */ if(++resend_cnt > PM_MAXTRY) { resend_cnt= 0; shutdown(client->skt,2); close(client->skt); client->skt= NULL; freeSocket(client); client = NULL; } break; } } while(resend_cnt); }}/* ---------------------------------------------------------------------- *//* Sopen_prtmstr: this function opens a socket handle for the Portmaster */static Socket *Sopen_prtmstr(){int length;int status=1;Socket *skt;/* allocate a Socket */skt= makeSocket(hostname,"PortMaster",PM_SERVER);/* create a socket */if((skt->skt= socket(AF_INET, SOCK_STREAM, 0)) <0 ) { freeSocket(skt); skt= NULL; return skt; }#ifndef SSLNOSETSOCKOPT/* allow PortMaster to be brought back up quickly (this should seldom be necessary!) */status= 1;if(setsockopt(skt->skt,SOL_SOCKET,SO_REUSEADDR,(char *) &status,sizeof(status)) < 0) { }#endif/* initialize socket data structure */sin.sin_family = AF_INET;sin.sin_addr.s_addr = INADDR_ANY;sin.sin_port = htons((u_short) PORTMASTER);/* bind socket data structure to this socket */if(bind(skt->skt,(struct sockaddr *) &sin,sizeof(sin))) { freeSocket(skt); skt= NULL; return skt; }/* getsockname fills in the socket structure with information,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -