📄 service.c
字号:
/* * $Id: service.c,v 1.30 1998/02/17 09:53:20 mdejonge Exp $ * * $Source: /home/mdejonge/CVS/projects/modem/modemd/service.c,v $ * $Revision: 1.30 $ * Author: Merijn de Jonge * Email: mdejonge@wins.uva.nl * * * * This file is part of the modem communication package. * Copyright (C) 1996-1998 Merijn de Jonge * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * */#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <time.h>#include <sys/types.h>#include <sys/ioctl.h>#if HAVE_SYS_WAIT_H#include <sys/wait.h>#endif#include <unistd.h>#include <errno.h>#include <stdio.h>#include <signal.h>#include <stdlib.h>#include <string.h>#include <setjmp.h>#include <libtty/libtty.h>#include <libtcpip/libtcpip.h>#include <libport/libport.h>#ifndef WEXITSTATUS#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8 )#endif#ifndef WIFEXITED#define WIFEXITED(stat_val) (((stat_val) & 256) == 0 )#endif/* for connectStr and speedStr */#define USE_MODEM_REPLY#include <libmodem/libmodem.h>#include <libconf/libconf.h>#include <liberror/liberror.h>#include <libprotocol/libprotocol.h>#include <modem_defs.h>#include "log.h"#include "syscmd.h"#include "configuration.h"static void serviceSignalHandler( int );static void serviceExit( void );static void serviceModem2Client( void );static void serviceClient2Modem( protType, void*, size_t );static void serviceMainLoop( void );static void serviceCommandHandler( protType, void*, size_t );static void serviceSetup( const char*, const char*, int );static void serviceErrorFunc( const char* err );static void serviceDial( const char* );static void serviceHangup();static char serviceReadModem( void /*int, void*, size_t */);static int serviceCheckNumber( void );struct{ int modem; /* Modem device */ int allocated; /* 0/1: no modem has/has not been alocated */ int client; /* Socket */ int connected; /* 0=not connected, 1=connected */ char* remoteHost; /* Name of host connected to us */ char* remoteUser; /* Name of user connected to us */ char* localHost; /* Name of host server is running on */ char* number; /* Phone number to dial */ time_t connected_since; /* Time the modem connection started */} Data;static char buf[protBufSize];static jmp_buf saved_env;/* * Fork and start handling client on remote host */void handle_client( int sock, const char* host, const char* uName ){ /* Setup the service and start the event loop */ serviceSetup( host, uName, sock ); serviceMainLoop();}/* * Allocate and initialize modem device. * Save information about connection and do some other stuff. */static void serviceSetup( const char* host, const char* uName, int socket ){ char tmp[40]; struct sigaction act; int result; /* Asure clean exit */ atexit( serviceExit ); /* Start new session and become session leader */ if( setsid() == -1 ) { FAIL( "setsid" ); exit( 1 ); } /* Save remoteHost, remoteUser and local hostname */ gethostname( tmp, sizeof tmp ); Data.localHost = strdup( tmp ); Data.remoteHost = strdup( host ); Data.remoteUser = strdup( uName ); /* no modem allocated yet */ Data.allocated = 0; /* Initial value for modem file desc */ Data.modem = -1; /* Start in disconnected state */ Data.connected = 0; /* Save fdesc of client */ Data.client = socket; /* Allocate new modem device defined in MODEM_CONFIG_FILE and in * configuration file as: modem_config_file. Modem device becomes * our controlling terminal. */ Data.modem = ttyOpen( get_modem_config_file() ); if( Data.modem == -1 ) { if( protRequestConfirm( Data.client, PROT_REQUEST_FAILED ) < 0 ) { FAIL( "protRequestConfirm" ); exit( 1 ); } exit( 0 ); }#if defined(TIOCSTTY) && !defined(CIBAUD) /* * 4.3+BSD way to acquire controlling terminal * !CIBAUD to avoid doing this under SunOS * from Advanced Pogramming in the UNIX Environment */ if( ioctl( Data.modem, TIOCSCTTY, NULL ) < 0 ) { FAIL( "ioctl(TIOCSCTTY)" ); exit( 1 ); }#endif /* * Initialize and reset modem using configuration file * MODEM_CONFIG_FILE or modem_config_file in configuration file */ if( mdm_init( Data.modem, ttyDev(), get_modem_config_file() ) == -1 ) { result =protRequestConfirm( Data.client, PROT_REQUEST_FAILED ); if( result < 0 ) { FAIL( "protRequestConfirm" ); exit( 1 ); } if( result == 0 ) exit( 0 ); FAIL( "modem init" ); exit( 1 ); } /* * Install protocol handlers for PROT_DATA and * PROT_COMMAND events. */ protSetHandler( PROT_DATA, serviceClient2Modem ); protSetHandler( PROT_COMMAND, serviceCommandHandler ); sigemptyset( &act.sa_mask ); act.sa_handler = serviceSignalHandler;#ifdef SA_RESTART act.sa_flags = SA_RESTART;#endif sigaction( SIGQUIT, &act, NULL ); sigaction( SIGTERM, &act, NULL ); sigaction( SIGHUP, &act, NULL ); sigaction( SIGPIPE, &act, NULL ); /* Install correct error handler */ setErrorFunc( serviceErrorFunc ); Data.allocated = 1; /* Write log message to access logfile */ fprintf( ACCESS_LOG, "%s[%s] Connect from: \"%s@%s\"\n", timeStamp(), Data.localHost, Data.remoteUser, Data.remoteHost ); fflush( ACCESS_LOG ); /* Modem allocated, we're now ready to serve our client */ result = protRequestConfirm( Data.client, PROT_REQUEST_OK ); if( result < 0 ) { FAIL( "protRequestConfirm" ); exit( 1 ); } if( result == 0 ) exit( 0 );}/* * Main eventhandler of service */static void serviceMainLoop(){ int retval; struct timeval timeout; fd_set fds; while( 1 ) { /* Save state for non-local jump in serviceReadModem */ if( setjmp( saved_env ) == 1 ) /* Non-local jump: start over again */ continue; /* Setup for select */ FD_ZERO( &fds ); FD_SET( Data.client, &fds ); /* * Only add modem device to descriptor * list when we are connected. */ if( Data.connected ) FD_SET( Data.modem, &fds ); /* client timeout in minutes, not seconds */ timeout.tv_sec = CLIENT_TIMEOUT * 60; timeout.tv_usec = 0; TEMP_FAILURE_RETRY( retval, select( FD_SETSIZE, &fds, NULL, NULL, &timeout ) ); if( retval < 0 ) { FAIL( "select" ); exit( 1 ); } /* * Timeout. * User is not connected and didn't do anything for * CLIENT_TIMEOUT seconds. Free modem resources and * exit. */ if( retval == 0 ) { if( !Data.connected ) { error( "you didn't do anything, bye" ); exit( 1 ); } continue; } /* * Data arrived from client. Let protocol * routines handle this. */ if( FD_ISSET( Data.client, &fds ) ) { retval = protReceive( Data.client ); /* EOF reached, client has closed connection */ if( retval == 0 ) { exit( 0 ); } if( retval < 0 ) { FAIL( "protReceive" ); exit( 1 ); } } /* Data arrived from modem */ if( FD_ISSET( Data.modem, &fds ) ) serviceModem2Client(); }}/* * Read data from modem and send it to client */static void serviceModem2Client(){ int bytes; /* Read data from modem */ bytes = modemRead( Data.modem, buf, sizeof buf ); if( bytes < 0 ) { FAIL( "modemRead" ); exit( 1 ); } if( bytes == 0 ) exit( 0 ); /* Send data as PROT_DATA to client */ bytes = protSend( PROT_DATA, Data.client, buf, bytes ); /* EOF */ if( bytes == 0 ) exit( 0 ); if( bytes < 0 ) { FAIL( "protSend" ); exit( 1 ); }}/* * Protocol handler for PROT_DATA. * Just send the data to the modem. */static void serviceClient2Modem( protType type, void* data, size_t length ){ int bytes; /* Only send to modem when we are connected */ if( !Data.connected ) return; /* Send the data to modem */ bytes = modemWrite( Data.modem, data, length ); if( bytes < 0 ) { FAIL( "modemWrite" ); exit( 1 ); } if( bytes == 0 ) exit( 0 );}/* * Error handler * All errors are send as PROT_ERROR messages to client. */static void serviceErrorFunc( const char* err ){ int result; struct sigaction saved; struct sigaction act; /* * A SIGPIPE will normally terminate the program. We do not want * the program to terminate without having sent the error message. * We therefore ignore the signal. Writing the message when the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -