📄 socdemon.c
字号:
* - Most of the socket setup stuff is taken from Stevens * (the socket(), bind(), listen() and accept() stuff), * the rest is mine.*/main(argc, argv) int argc;char *argv[];{ int client_address_len; t_parms parms; int i; silent_mode = false; debug_mode = false; port_to_use = SOCDEMON_PORT; /* get the name of the executable for use in the print_usage() */ /* call so that the "usage: XXX [options]" will be correct */ strcpy(program_name,argv[0]);#ifdef LOG_TO_DEATH log_to_file = false; command_log = false; strcpy(log_file,program_name); strcat(log_file,".log"); strcpy(cmd_log_file,program_name); strcat(cmd_log_file,".log");#endif if (argc > 1) { /* Collect and process the program arguments */ for (i=1;i<argc;i++) { if ((!strcmp(argv[i],parm_table[parm_help1])) || (!strcmp(argv[i],parm_table[parm_help2]))) { print_usage(); exit(0); } else if ((!strcmp(argv[i],parm_table[parm_silent1])) || (!strcmp(argv[i],parm_table[parm_silent2]))) { silent_mode = true; } else if ((!strcmp(argv[i],parm_table[parm_debug1])) || (!strcmp(argv[i],parm_table[parm_debug2]))) { debug_mode = true; } else if ((!strcmp(argv[i],parm_table[parm_port1])) || (!strcmp(argv[i],parm_table[parm_port2]))) { i++; if (i == argc) { fprintf(stderr,"ERROR(%d): You must specify a port number.\n", BAD_PARAMETERS); exit(BAD_PARAMETERS); } if (sscanf(argv[i],"%d",&port_to_use) <= 0) { soc_fprintf(stderr,out_table[bad_port_use_def]); port_to_use = SOCDEMON_PORT; /* they prob. forgot to put the port number in and */ /* tried to read the next parm, back up the index */ /* and we'll take a peep at what was there.. */ i--; }#ifdef LOG_TO_DEATH } else if ((!strcmp(argv[i],parm_table[parm_log1])) || (!strcmp(argv[i],parm_table[parm_log2]))) { log_to_file = true; i++; if (i == argc) { soc_fprintf(stderr, out_table[no_log_use_def]); } else { if (argv[i][0] == '-') { soc_fprintf(stderr, out_table[no_log_use_def]); i--; } else { strcpy(log_file,argv[i]); } } } else if ((!strcmp(argv[i],parm_table[parm_cmds1])) || (!strcmp(argv[i],parm_table[parm_cmds2]))) { command_log = true; i++; if (i == argc) { soc_fprintf(stderr, out_table[no_cmd_log_use_def]); } else { if (argv[i][0] == '-') { soc_fprintf(stderr, out_table[no_cmd_log_use_def]); i--; } else { strcpy(cmd_log_file,argv[i]); } }#endif } else { fprintf(stderr,"ERROR(%d): Unknown switch \"%s\".\n", BAD_PARAMETERS, argv[i]); print_usage(); exit(BAD_PARAMETERS); } } } soc_fprintf(stdout,"%s ver %s.\n",SOCDEMON_NAME,SOCDEMON_VER); soc_fprintf(stdout,"%s: Initializing.\n",SOCDEMON_NAME); if (getuid() != geteuid()) { /* Our user id is *not* equal to our effective user id */ /* This means that we are a setuid program.. so, let's */ /* Enjoy all the priviledges that we can, call setuid */ /* to set our user id to our effective userid */ soc_fprintf(stdout,"%s: Running setuid.\n",SOCDEMON_NAME); setuid(geteuid()); } if (getgid() != getegid()) { soc_fprintf(stdout,"%s: Running setgid.\n",SOCDEMON_NAME); setgid(getegid()); } soc_fprintf(stdout,"%s: Creating internet socket...",SOCDEMON_NAME); /* create a socket */ socket_address_family = AF_INET; socket_type = SOCK_STREAM; socket_protocol = IPPROTO_TCP; socket_descriptor = socket(socket_address_family, socket_type, socket_protocol); if (socket_descriptor == -1) { soc_fprintf(stdout,"\n"); soc_fprintf(stderr,"ERROR(%d): Unable to create socket [%d].\n", CANT_MAKE_SOCKET, errno); exit(CANT_MAKE_SOCKET); } soc_fprintf(stdout,"done.\n"); soc_fprintf(stdout,"%s: Binding socket to port %d ...", SOCDEMON_NAME, port_to_use); /* now bind it to the port, if the program was just run */ /* this call will fail, because it takes about 45 seconds */ /* after a process exits for the port to be unbound */ bzero((char *) &server_address, sizeof(server_address)); server_address.sin_family = AF_INET; server_address.sin_addr.s_addr = htonl(INADDR_ANY); server_address.sin_port = htons(port_to_use); socket_rc = bind(socket_descriptor, (struct sockaddr *) &server_address, sizeof(server_address)); if (socket_rc != 0) { soc_fprintf(stdout,"\n"); soc_fprintf(stderr,"ERROR(%d): Cannot bind internet socket to specified address and port. [%d]\n", CANT_BIND_SOCKET, errno); if (errno == EADDRINUSE) { soc_fprintf(stderr," This address is inuse. Waiting 15 seconds then re-trying.\n"); /* The following status message is to stderr instead of to stdout */ /* because stdout doesn't flush (at least on HP-UX) until a C/R */ /* but stderr flushes right away, so that way we can have the dots */ /* print one at a time instead of all at once */ soc_fprintf(stderr,"%s: Waiting",SOCDEMON_NAME); for (i=1;i<=15;i++) { sleep(1); soc_fprintf(stderr,"."); } soc_fprintf(stderr,"done.\n"); soc_fprintf(stdout,"%s: Retrying..",SOCDEMON_NAME); socket_rc = bind(socket_descriptor, (struct sockaddr *) &server_address, sizeof(server_address)); if (socket_rc != 0) { soc_fprintf(stdout, " failed.\n"); soc_fprintf(stderr, "ERROR(%d): This port is inuse, either wait a few moments, or use\n", CANT_BIND_SOCKET); soc_fprintf(stderr, " a different port.\n"); socket_demon_shutdown(); exit(CANT_BIND_SOCKET); } } else { socket_demon_shutdown(); exit(CANT_BIND_SOCKET); } } soc_fprintf(stdout,"done.\n"); /* now my favorite part, convert to a daemon.. */ if (fork() != 0) { /* we let the parent die off.. this means that our real parent */ /* will not be the shell, as was this thread right here, but */ /* because this thread is exiting, I believe that the new parent */ /* becomes the process group leader, which may be the shell, but */ /* I think it's the login instead.. whoever to process group */ /* is... */ if (silent_mode == false) { /* now, we hold for a sec, so that the user doesn't get their */ /* shell back until we've completely started up.. this is so */ /* the program doesn't print out it's init messages to the */ /* tty when the user has recieved thier prompt again.. if */ /* we're in silent mode, however, we don't need to pause */ /* because there is no output */ sleep(SOCDEMON_PAUSE); } exit(0); } /* now we dis-associate from our process group leader by creating */ /* our own process group. */ setpgrp(); /* now we ignore hang up signals, so we are effectively nohup-ing */ /* the process now */ signal(SIGHUP,SIG_IGN); /* fork once again to get rid of our parent (the new process group */ /* leader) and now our parent is init(1) so we are now a daemon */ /* (rejoice) */ if (fork() != 0) { exit(0); } soc_fprintf(stdout,"%s: Binding signal handlers to shutdown routines...", SOCDEMON_NAME); /* now bind our shutdown routines to catch the TERMINATE and KILL */ /* I don't think that the KILL signals are caught however, but i'm */ /* not entirely sure.. all I know is that when i kill -9 the daemon */ /* I don't get the shutdown messages, but that doesn't necessarily */ /* mean it's not catching it.. so don't kill with the -9 option and */ /* all will be well.. */ signal(SIGTERM,socket_demon_death_action); signal(SIGKILL,socket_demon_death_action); soc_fprintf(stdout,"done.\n"); /* hokey dokey, now listen to the internet socket... */ socket_rc = listen(socket_descriptor,SOCDEMON_MAX_BACKLOG); if (socket_rc != 0) { soc_fprintf(stderr,"ERROR(%d): Listen failed on internet socket [%d].\n", LISTEN_FAILED, errno); socket_demon_shutdown(); exit(LISTEN_FAILED); } for (;;) { client_address_len = sizeof(client_address); /* now we sit and wait for someone to connect to us... */ /* this will not take up any CPU at all, because the process is */ /* blocked waiting for a connect... what I might do if there's */ /* some need, is to send the process wake up signals every now */ /* and then to change it's process ID, or hide or something, but */ /* until all other little bugs are resolved, that will have to */ /* wait */ client_descriptor = accept(socket_descriptor, (struct sockaddr *) &client_address, &client_address_len); if (client_descriptor < 0) { soc_fprintf(stderr,"ERROR(%d): accept() call failed on internet socket [%d]\n", ACCEPT_FAILED, errno); exit(ACCEPT_FAILED); }#ifdef LOG_TO_DEATH /* ok, now to convert the address to a dotted quad, I guess i */ /* could just cast it on top of the dotted_quad structure, I */ /* dunno if that'd work, so to be safe and portable, let's */ /* do it manually... oh, and note the bit shifts, yeah, it's */ /* messy, but I couldn't think of anything more elegant at the*/ /* time.. same with the leading zeros in the bitwise 'and's */ client_dotted_q.class = (client_address.sin_addr.s_addr >> 24); client_dotted_q.netid = (client_address.sin_addr.s_addr >> 16) & 0x00ff; client_dotted_q.subnetid = (client_address.sin_addr.s_addr >> 8) & 0x0000ff; client_dotted_q.hostid = client_address.sin_addr.s_addr & 0x000000ff; sprintf(dotted_4_str, "%d.%d.%d.%d", client_dotted_q.class, client_dotted_q.netid, client_dotted_q.subnetid, client_dotted_q.hostid);#endif if (fork() != 0) { /* let the parent process handle the user comming in, and */ /* make the shild go on to wait for more requests - this */ /* will avoid defunct processes and have an added bonus side- */ /* effect of having the main daemon have it's process ID change */ /* periodically. */#ifdef LOG_TO_DEATH log_stuff(accepting_connection);#endif /* direct stdin, stdout and stderr to the socket */ dup2(client_descriptor,0); dup2(client_descriptor,1); dup2(client_descriptor,2); if (soc_demon_welcome()) { soc_demon_main_proc(); } shutdown(client_descriptor, 2); close(client_descriptor);#ifdef LOG_TO_DEATH log_stuff(connection_closed);#endif exit(0); } close(client_descriptor); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -