|
|
1.1 ! root 1: /* sexpots.c */ ! 2: ! 3: /* Synchronet External Plain Old Telephone System (POTS) support */ ! 4: ! 5: /* $Id: sexpots.c,v 1.26 2010/11/19 04:10:23 rswindell Exp $ */ ! 6: ! 7: /**************************************************************************** ! 8: * @format.tab-size 4 (Plain Text/Source Code File Header) * ! 9: * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) * ! 10: * * ! 11: * Copyright 2010 Rob Swindell - http://www.synchro.net/copyright.html * ! 12: * * ! 13: * This program is free software; you can redistribute it and/or * ! 14: * modify it under the terms of the GNU General Public License * ! 15: * as published by the Free Software Foundation; either version 2 * ! 16: * of the License, or (at your option) any later version. * ! 17: * See the GNU General Public License for more details: gpl.txt or * ! 18: * http://www.fsf.org/copyleft/gpl.html * ! 19: * * ! 20: * Anonymous FTP access to the most recent released source is available at * ! 21: * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net * ! 22: * * ! 23: * Anonymous CVS access to the development source and modification history * ! 24: * is available at cvs.synchro.net:/cvsroot/sbbs, example: * ! 25: * cvs -d :pserver:[email protected]:/cvsroot/sbbs login * ! 26: * (just hit return, no password is necessary) * ! 27: * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src * ! 28: * * ! 29: * For Synchronet coding style and modification guidelines, see * ! 30: * http://www.synchro.net/source.html * ! 31: * * ! 32: * You are encouraged to submit any modifications (preferably in Unix diff * ! 33: * format) via e-mail to [email protected] * ! 34: * * ! 35: * Note: If this box doesn't appear square, then you need to fix your tabs. * ! 36: ****************************************************************************/ ! 37: ! 38: /* ANSI C */ ! 39: #include <stdarg.h> ! 40: #include <stdio.h> ! 41: ! 42: /* xpdev lib */ ! 43: #include "dirwrap.h" ! 44: #include "datewrap.h" ! 45: #include "sockwrap.h" ! 46: #include "ini_file.h" ! 47: ! 48: /* comio lib */ ! 49: #include "comio.h" ! 50: ! 51: /* sbbs */ ! 52: #include "telnet.h" ! 53: ! 54: /* constants */ ! 55: #define NAME "SEXPOTS" ! 56: #define TITLE "Synchronet External POTS Support" ! 57: #define DESCRIPTION "Connects a communications port (e.g. COM1) to a TCP port (e.g. Telnet)" ! 58: #define MDM_TILDE_DELAY 500 /* milliseconds */ ! 59: ! 60: /* global vars */ ! 61: BOOL daemonize=FALSE; ! 62: char termtype[INI_MAX_VALUE_LEN+1] = NAME; ! 63: char termspeed[INI_MAX_VALUE_LEN+1] = "28800,28800"; /* "tx,rx", max length not defined */ ! 64: char revision[16]; ! 65: ! 66: char mdm_init[INI_MAX_VALUE_LEN] = "AT&F"; ! 67: char mdm_autoans[INI_MAX_VALUE_LEN] = "ATS0=1"; ! 68: char mdm_cid[INI_MAX_VALUE_LEN] = "AT+VCID=1"; ! 69: char mdm_cleanup[INI_MAX_VALUE_LEN] = "ATS0=0"; ! 70: BOOL mdm_null=FALSE; ! 71: int mdm_timeout=5; /* seconds */ ! 72: ! 73: #ifdef _WIN32 ! 74: char com_dev[MAX_PATH+1] = "COM1"; ! 75: #else ! 76: char com_dev[MAX_PATH+1] = "/dev/ttyd0"; ! 77: #endif ! 78: COM_HANDLE com_handle=COM_HANDLE_INVALID; ! 79: BOOL com_handle_passed=FALSE; ! 80: BOOL com_alreadyconnected=FALSE; ! 81: BOOL com_hangup=TRUE; ! 82: ulong com_baudrate=0; ! 83: BOOL dcd_ignore=FALSE; ! 84: int dcd_timeout=10; /* seconds */ ! 85: ulong dtr_delay=100; /* milliseconds */ ! 86: int hangup_attempts=10; ! 87: ! 88: BOOL terminated=FALSE; ! 89: BOOL terminate_after_one_call=FALSE; ! 90: ! 91: SOCKET sock=INVALID_SOCKET; ! 92: char host[MAX_PATH+1] = "localhost"; ! 93: ushort port=IPPORT_TELNET; ! 94: ! 95: /* stats */ ! 96: ulong total_calls=0; ! 97: ulong bytes_sent=0; ! 98: ulong bytes_received=0; ! 99: ! 100: /* .ini over-rideable */ ! 101: int log_level=LOG_INFO; ! 102: BOOL pause_on_exit=FALSE; ! 103: BOOL tcp_nodelay=TRUE; ! 104: ! 105: /* telnet stuff */ ! 106: BOOL telnet=TRUE; ! 107: BOOL debug_telnet=FALSE; ! 108: uchar telnet_local_option[0x100]; ! 109: uchar telnet_remote_option[0x100]; ! 110: BYTE telnet_cmd[64]; ! 111: int telnet_cmdlen; ! 112: BOOL telnet_advertise_cid=FALSE; ! 113: ! 114: /* ident (RFC1413) server stuff */ ! 115: BOOL ident=FALSE; ! 116: ushort ident_port=IPPORT_IDENT; ! 117: ulong ident_interface=INADDR_ANY; ! 118: char ident_response[INI_MAX_VALUE_LEN] = "CALLERID:SEXPOTS"; ! 119: ! 120: /* Caller-ID stuff */ ! 121: char cid_name[64]; ! 122: char cid_number[64]; ! 123: ! 124: /****************************************************************************/ ! 125: /****************************************************************************/ ! 126: int usage(const char* fname) ! 127: { ! 128: printf("usage: %s [ini file] [options]\n" ! 129: "\nOptions:" ! 130: "\n" ! 131: "\n-null No 'AT commands' sent to modem" ! 132: "\n-com <device> Specify communications port device" ! 133: "\n-baud <rate> Specify baud rate for communications port" ! 134: "\n-live [handle] Communications port is already open/connected" ! 135: "\n-nohangup Do not hangup (drop DTR) after call" ! 136: "\n-host <addr | name> Specify TCP server hostname or IP address" ! 137: "\n-port <number> Specify TCP port number" ! 138: "\n-debug Enable debug log output" ! 139: #if defined(_WIN32) ! 140: "\n\nNT Service\n" ! 141: "\n-install install and enable NT service (%s)" ! 142: "\n-service run as an NT service (background execution)" ! 143: "\n-remove remove NT service" ! 144: "\n-enable enable NT service (auto-start during boot)" ! 145: "\n-disable disable NT service" ! 146: #endif ! 147: "\n" ! 148: ,getfname(fname) ! 149: ,NAME); ! 150: ! 151: return 0; ! 152: } ! 153: ! 154: #if defined(_WIN32) ! 155: ! 156: static WORD event_type(int level) ! 157: { ! 158: switch(level) { ! 159: case LOG_WARNING: ! 160: return(EVENTLOG_WARNING_TYPE); ! 161: case LOG_NOTICE: ! 162: case LOG_INFO: ! 163: case LOG_DEBUG: ! 164: return(EVENTLOG_INFORMATION_TYPE); ! 165: } ! 166: /* ! 167: LOG_EMERG ! 168: LOG_ALERT ! 169: LOG_CRIT ! 170: LOG_ERR ! 171: */ ! 172: return(EVENTLOG_ERROR_TYPE); ! 173: } ! 174: ! 175: static int syslog(int level, char *fmt, ...) ! 176: { ! 177: va_list argptr; ! 178: char sbuf[1024]; ! 179: char* p=sbuf; ! 180: int retval; ! 181: static HANDLE event_handle; ! 182: ! 183: va_start(argptr,fmt); ! 184: retval=vsnprintf(sbuf,sizeof(sbuf),fmt,argptr); ! 185: sbuf[sizeof(sbuf)-1]=0; ! 186: va_end(argptr); ! 187: ! 188: if(event_handle == NULL) ! 189: event_handle = RegisterEventSource( ! 190: NULL, // server name for source (NULL = local computer) ! 191: TITLE); // source name for registered handle ! 192: ! 193: if(event_handle != NULL) ! 194: ReportEvent(event_handle, // event log handle ! 195: event_type(level), // event type ! 196: 0, // category zero ! 197: 0, // event identifier ! 198: NULL, // no user security identifier ! 199: 1, // one string ! 200: 0, // no data ! 201: &p, // pointer to string array ! 202: NULL); // pointer to data ! 203: ! 204: return(retval); ! 205: } ! 206: ! 207: #endif ! 208: ! 209: /****************************************************************************/ ! 210: /****************************************************************************/ ! 211: int lputs(int level, const char* str) ! 212: { ! 213: time_t t; ! 214: struct tm tm; ! 215: char tstr[32]; ! 216: #if defined(_WIN32) ! 217: char dbgmsg[1024]; ! 218: _snprintf(dbgmsg,sizeof(dbgmsg),"%s %s", NAME, str); ! 219: if(log_level==LOG_DEBUG) ! 220: OutputDebugString(dbgmsg); ! 221: #else ! 222: char dbgmsg[1024]; ! 223: snprintf(dbgmsg,sizeof(dbgmsg),"%s %s", NAME, str); ! 224: if(log_level==LOG_DEBUG) ! 225: fputs(dbgmsg, stderr); ! 226: #endif ! 227: ! 228: if(level>log_level) ! 229: return 0; ! 230: ! 231: if(daemonize) { ! 232: #if defined(_WIN32) ! 233: return syslog(level,"%s", str); ! 234: #else ! 235: /* syslog() is ! 236: * void syslog(int priority, const char *message, ...); ! 237: */ ! 238: ! 239: syslog(level,"%s", str); ! 240: return strlen(str); ! 241: #endif ! 242: } ! 243: ! 244: t=time(NULL); ! 245: if(localtime_r(&t,&tm)==NULL) ! 246: tstr[0]=0; ! 247: else ! 248: sprintf(tstr,"%d/%d %02d:%02d:%02d " ! 249: ,tm.tm_mon+1,tm.tm_mday ! 250: ,tm.tm_hour,tm.tm_min,tm.tm_sec); ! 251: ! 252: return fprintf(level>=LOG_NOTICE ? stdout:stderr, "%s %s\n", tstr, str); ! 253: } ! 254: ! 255: /****************************************************************************/ ! 256: /****************************************************************************/ ! 257: int lprintf(int level, char *fmt, ...) ! 258: { ! 259: va_list argptr; ! 260: char sbuf[1024]; ! 261: ! 262: va_start(argptr,fmt); ! 263: vsnprintf(sbuf,sizeof(sbuf),fmt,argptr); ! 264: sbuf[sizeof(sbuf)-1]=0; ! 265: va_end(argptr); ! 266: return(lputs(level,sbuf)); ! 267: } ! 268: ! 269: ! 270: #if defined(_WIN32) ! 271: ! 272: #define NTSVC_TIMEOUT_STARTUP 30000 /* Milliseconds */ ! 273: #define NTSVC_TIMEOUT_SHUTDOWN 30000 /* Milliseconds */ ! 274: ! 275: SERVICE_STATUS_HANDLE svc_status_handle; ! 276: SERVICE_STATUS svc_status; ! 277: ! 278: void WINAPI ServiceControlHandler(DWORD dwCtrlCode) ! 279: { ! 280: switch(dwCtrlCode) { ! 281: case SERVICE_CONTROL_STOP: ! 282: case SERVICE_CONTROL_SHUTDOWN: ! 283: lprintf(LOG_NOTICE,"Received termination control signal: %d", dwCtrlCode); ! 284: svc_status.dwWaitHint=NTSVC_TIMEOUT_SHUTDOWN; ! 285: svc_status.dwCurrentState=SERVICE_STOP_PENDING; ! 286: SetServiceStatus(svc_status_handle, &svc_status); ! 287: terminated=TRUE; ! 288: // SetEvent(service_event); ! 289: break; ! 290: case SERVICE_CONTROL_INTERROGATE: ! 291: lprintf(LOG_DEBUG,"Ignoring service control signal: SERVICE_CONTROL_INTERROGATE"); ! 292: break; ! 293: default: ! 294: lprintf(LOG_WARNING,"Received unsupported service control signal: %d", dwCtrlCode); ! 295: break; ! 296: } ! 297: } ! 298: ! 299: /* ChangeServiceConfig2 is a Win2K+ API function, must call dynamically */ ! 300: typedef WINADVAPI BOOL (WINAPI *ChangeServiceConfig2_t)(SC_HANDLE, DWORD, LPCVOID); ! 301: ! 302: static void describe_service(HANDLE hSCMlib, SC_HANDLE hService, char* description) ! 303: { ! 304: ChangeServiceConfig2_t changeServiceConfig2; ! 305: static SERVICE_DESCRIPTION service_desc; ! 306: ! 307: if(hSCMlib==NULL) ! 308: return; ! 309: ! 310: service_desc.lpDescription=description; ! 311: ! 312: if((changeServiceConfig2 = (ChangeServiceConfig2_t)GetProcAddress(hSCMlib, "ChangeServiceConfig2A"))!=NULL) ! 313: changeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, &service_desc); ! 314: } ! 315: ! 316: static BOOL register_event_source(char* name, char* path) ! 317: { ! 318: char keyname[256]; ! 319: HKEY hKey; ! 320: DWORD type; ! 321: DWORD disp; ! 322: LONG retval; ! 323: char* value; ! 324: ! 325: sprintf(keyname,"system\\CurrentControlSet\\services\\eventlog\\application\\%s",name); ! 326: ! 327: retval=RegCreateKeyEx( ! 328: HKEY_LOCAL_MACHINE, /* handle to an open key */ ! 329: keyname, /* address of subkey name */ ! 330: 0, /* reserved */ ! 331: "", /* address of class string */ ! 332: 0, /* special options flag */ ! 333: KEY_ALL_ACCESS, /* desired security access */ ! 334: NULL, /* address of key security structure */ ! 335: &hKey, /* address of buffer for opened handle */ ! 336: &disp /* address of disposition value buffer */ ! 337: ); ! 338: ! 339: if(retval!=ERROR_SUCCESS) { ! 340: fprintf(stderr,"!Error %d creating/opening registry key (HKLM\\%s)\n" ! 341: ,retval,keyname); ! 342: return(FALSE); ! 343: } ! 344: ! 345: value="EventMessageFile"; ! 346: retval=RegSetValueEx( ! 347: hKey, /* handle to key to set value for */ ! 348: value, /* name of the value to set */ ! 349: 0, /* reserved */ ! 350: REG_SZ, /* flag for value type */ ! 351: path, /* address of value data */ ! 352: strlen(path) /* size of value data */ ! 353: ); ! 354: ! 355: if(retval!=ERROR_SUCCESS) { ! 356: RegCloseKey(hKey); ! 357: fprintf(stderr,"!Error %d setting registry key value (%s)\n" ! 358: ,retval,value); ! 359: return(FALSE); ! 360: } ! 361: ! 362: value="TypesSupported"; ! 363: type=EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE; ! 364: retval=RegSetValueEx( ! 365: hKey, /* handle to key to set value for */ ! 366: value, /* name of the value to set */ ! 367: 0, /* reserved */ ! 368: REG_DWORD, /* flag for value type */ ! 369: (BYTE*)&type, /* address of value data */ ! 370: sizeof(type) /* size of value data */ ! 371: ); ! 372: ! 373: RegCloseKey(hKey); ! 374: ! 375: if(retval!=ERROR_SUCCESS) { ! 376: fprintf(stderr,"!Error %d setting registry key value (%s)\n" ! 377: ,retval,value); ! 378: return(FALSE); ! 379: } ! 380: ! 381: return(TRUE); ! 382: } ! 383: ! 384: ! 385: /****************************************************************************/ ! 386: /* Install NT service */ ! 387: /****************************************************************************/ ! 388: static int install(void) ! 389: { ! 390: HANDLE hSCMlib; ! 391: SC_HANDLE hSCManager; ! 392: SC_HANDLE hService; ! 393: char path[MAX_PATH+1]; ! 394: char cmdline[MAX_PATH+1]; ! 395: ! 396: printf("Installing service: %-40s ... ", TITLE); ! 397: ! 398: hSCMlib = LoadLibrary("ADVAPI32.DLL"); ! 399: ! 400: if(GetModuleFileName(NULL,path,sizeof(path))==0) ! 401: { ! 402: fprintf(stderr,"\n!ERROR %d getting module file name\n",GetLastError()); ! 403: return(-1); ! 404: } ! 405: ! 406: hSCManager = OpenSCManager( ! 407: NULL, // machine (NULL == local) ! 408: NULL, // database (NULL == default) ! 409: SC_MANAGER_ALL_ACCESS // access required ! 410: ); ! 411: if(hSCManager==NULL) { ! 412: fprintf(stderr,"\n!ERROR %d opening SC manager\n",GetLastError()); ! 413: return(-1); ! 414: } ! 415: ! 416: /* Install new service */ ! 417: wsprintf(cmdline,"%s service", path); ! 418: hService = CreateService( ! 419: hSCManager, // SCManager database ! 420: NAME, // name of service ! 421: TITLE, // name to display ! 422: SERVICE_ALL_ACCESS, // desired access ! 423: SERVICE_WIN32_OWN_PROCESS, // service type ! 424: SERVICE_AUTO_START, // start type (auto or manual) ! 425: SERVICE_ERROR_NORMAL, // error control type ! 426: cmdline, // service's binary ! 427: NULL, // no load ordering group ! 428: NULL, // no tag identifier ! 429: "", // dependencies ! 430: NULL, // LocalSystem account ! 431: NULL); // no password ! 432: ! 433: if(hService==NULL) ! 434: fprintf(stderr,"\n!ERROR %d creating service\n",GetLastError()); ! 435: else { ! 436: describe_service(hSCMlib, hService, DESCRIPTION); ! 437: CloseServiceHandle(hService); ! 438: printf("Successful\n"); ! 439: ! 440: register_event_source(TITLE,path); ! 441: } ! 442: ! 443: ! 444: if(hSCMlib!=NULL) ! 445: FreeLibrary(hSCMlib); ! 446: ! 447: CloseServiceHandle(hSCManager); ! 448: ! 449: return(0); ! 450: } ! 451: ! 452: /****************************************************************************/ ! 453: /* Utility function to remove a service cleanly (stopping if necessary) */ ! 454: /****************************************************************************/ ! 455: static void remove_service(SC_HANDLE hSCManager, SC_HANDLE hService, char* name, char* disp_name) ! 456: { ! 457: SERVICE_STATUS status; ! 458: ! 459: printf("Removing service: %-40s ... ", disp_name); ! 460: ! 461: if(hService==NULL) { ! 462: ! 463: hService = OpenService(hSCManager, name, SERVICE_ALL_ACCESS); ! 464: ! 465: if(hService==NULL) { ! 466: printf("\n!ERROR %d opening service: %s\n",GetLastError(),name); ! 467: return; ! 468: } ! 469: } ! 470: ! 471: // try to stop the service ! 472: if(ControlService( hService, SERVICE_CONTROL_STOP, &status)) ! 473: { ! 474: printf("\nStopping: %s ... ",name); ! 475: ! 476: while(QueryServiceStatus(hService, &status) && status.dwCurrentState == SERVICE_STOP_PENDING) ! 477: Sleep(1000); ! 478: ! 479: if(status.dwCurrentState == SERVICE_STOPPED) ! 480: printf("Stopped.\n"); ! 481: else ! 482: printf("FAILED!\n"); ! 483: } ! 484: ! 485: // now remove the service ! 486: if(DeleteService(hService)) ! 487: printf("Successful\n"); ! 488: else ! 489: printf("!ERROR %d\n",GetLastError()); ! 490: CloseServiceHandle(hService); ! 491: } ! 492: ! 493: /****************************************************************************/ ! 494: /* Uninstall one or all services */ ! 495: /****************************************************************************/ ! 496: static int uninstall(void) ! 497: { ! 498: SC_HANDLE hSCManager; ! 499: ! 500: hSCManager = OpenSCManager( ! 501: NULL, // machine (NULL == local) ! 502: NULL, // database (NULL == default) ! 503: SC_MANAGER_ALL_ACCESS // access required ! 504: ); ! 505: if(hSCManager==NULL) { ! 506: fprintf(stderr,"!ERROR %d opening SC manager\n",GetLastError()); ! 507: return(-1); ! 508: } ! 509: ! 510: remove_service(hSCManager,NULL,NAME,TITLE); ! 511: ! 512: CloseServiceHandle(hSCManager); ! 513: ! 514: return(0); ! 515: } ! 516: ! 517: /****************************************************************************/ ! 518: /* Utility function to disable a service */ ! 519: /****************************************************************************/ ! 520: static void set_service_start_type(SC_HANDLE hSCManager, DWORD start_type) ! 521: { ! 522: SC_HANDLE hService; ! 523: ! 524: printf("%s service: %-40s ... " ! 525: ,start_type==SERVICE_DISABLED ? "Disabling" : "Enabling", TITLE); ! 526: ! 527: hService = OpenService(hSCManager, NAME, SERVICE_ALL_ACCESS); ! 528: ! 529: if(hService==NULL) { ! 530: printf("\n!ERROR %d opening service: %s\n",GetLastError(),NAME); ! 531: return; ! 532: } ! 533: ! 534: if(!ChangeServiceConfig( ! 535: hService, // handle to service ! 536: SERVICE_NO_CHANGE, // type of service ! 537: start_type, // when to start service ! 538: SERVICE_NO_CHANGE, // severity if service fails to start ! 539: NULL, // pointer to service binary file name ! 540: NULL, // pointer to load ordering group name ! 541: NULL, // pointer to variable to get tag identifier ! 542: NULL, // pointer to array of dependency names ! 543: NULL, // pointer to account name of service ! 544: NULL, // pointer to password for service account ! 545: NULL // pointer to display name ! 546: )) ! 547: printf("\n!ERROR %d changing service config for: %s\n",GetLastError(),NAME); ! 548: else ! 549: printf("Successful\n"); ! 550: ! 551: CloseServiceHandle(hService); ! 552: } ! 553: ! 554: /****************************************************************************/ ! 555: /* Enable (set to auto-start) or disable one or all services */ ! 556: /****************************************************************************/ ! 557: static int enable(BOOL enabled) ! 558: { ! 559: SC_HANDLE hSCManager; ! 560: ! 561: hSCManager = OpenSCManager( ! 562: NULL, // machine (NULL == local) ! 563: NULL, // database (NULL == default) ! 564: SC_MANAGER_ALL_ACCESS // access required ! 565: ); ! 566: if(hSCManager==NULL) { ! 567: fprintf(stderr,"!ERROR %d opening SC manager\n",GetLastError()); ! 568: return(-1); ! 569: } ! 570: ! 571: set_service_start_type(hSCManager ! 572: ,enabled ? SERVICE_AUTO_START : SERVICE_DISABLED); ! 573: ! 574: CloseServiceHandle(hSCManager); ! 575: ! 576: return(0); ! 577: } ! 578: ! 579: #endif ! 580: ! 581: #ifdef _WINSOCKAPI_ ! 582: ! 583: /* Note: Don't call WSACleanup() or TCP session will close! */ ! 584: WSADATA WSAData; ! 585: ! 586: static BOOL winsock_startup(void) ! 587: { ! 588: int status; /* Status Code */ ! 589: ! 590: if((status = WSAStartup(MAKEWORD(1,1), &WSAData))==0) { ! 591: lprintf(LOG_INFO,"%s %s",WSAData.szDescription, WSAData.szSystemStatus); ! 592: return(TRUE); ! 593: } ! 594: ! 595: lprintf(LOG_ERR,"WinSock startup ERROR %d", status); ! 596: return(FALSE); ! 597: } ! 598: ! 599: #else /* No WINSOCK */ ! 600: ! 601: #define winsock_startup() (TRUE) ! 602: ! 603: #endif ! 604: ! 605: /****************************************************************************/ ! 606: /****************************************************************************/ ! 607: BOOL modem_send(COM_HANDLE com_handle, const char* str) ! 608: { ! 609: const char* p; ! 610: char ch; ! 611: ! 612: lprintf(LOG_INFO,"Modem Command: %s", str); ! 613: for(p=str; *p; p++) { ! 614: ch=*p; ! 615: if(ch=='~') { ! 616: SLEEP(MDM_TILDE_DELAY); ! 617: continue; ! 618: } ! 619: if(ch=='^' && *(p+1)) { /* Support ^X for control characters embedded in modem command strings */ ! 620: p++; ! 621: ch=*p; ! 622: if(ch!='^' && ch>='@') /* ^^ to send an '^' char to the modem */ ! 623: ch-='@'; ! 624: } ! 625: if(!comWriteByte(com_handle,ch)) ! 626: return FALSE; ! 627: } ! 628: SLEEP(100); ! 629: comPurgeInput(com_handle); ! 630: return comWriteByte(com_handle, '\r'); ! 631: } ! 632: ! 633: /****************************************************************************/ ! 634: /****************************************************************************/ ! 635: BOOL modem_response(COM_HANDLE com_handle, char *str, size_t maxlen) ! 636: { ! 637: BYTE ch; ! 638: size_t len=0; ! 639: time_t start; ! 640: ! 641: lprintf(LOG_DEBUG,"Waiting for Modem Response ..."); ! 642: start=time(NULL); ! 643: while(1){ ! 644: if(time(NULL)-start >= mdm_timeout) { ! 645: lprintf(LOG_WARNING,"Modem Response TIMEOUT (%lu seconds)", mdm_timeout); ! 646: return FALSE; ! 647: } ! 648: if(len >= maxlen) { ! 649: lprintf(LOG_WARNING,"Modem Response too long (%u >= %u)" ! 650: ,len, maxlen); ! 651: return FALSE; ! 652: } ! 653: if(!comReadByte(com_handle, &ch)) { ! 654: YIELD(); ! 655: continue; ! 656: } ! 657: if(ch<' ' && len==0) /* ignore prepended control chars */ ! 658: continue; ! 659: ! 660: if(ch=='\r') { ! 661: while(comReadByte(com_handle,&ch)) /* eat trailing ctrl chars (e.g. 'LF') */ ! 662: #if 0 ! 663: lprintf(LOG_DEBUG, "eating ch=%02X", ch) ! 664: #endif ! 665: ; ! 666: break; ! 667: } ! 668: str[len++]=ch; ! 669: } ! 670: str[len]=0; ! 671: ! 672: return TRUE; ! 673: } ! 674: ! 675: /****************************************************************************/ ! 676: /****************************************************************************/ ! 677: BOOL modem_command(COM_HANDLE com_handle, const char* cmd) ! 678: { ! 679: char resp[128]; ! 680: ! 681: if(!modem_send(com_handle, cmd)) { ! 682: lprintf(LOG_ERR,"ERROR %u sending modem command (%s)" ! 683: ,COM_ERROR_VALUE, cmd); ! 684: return FALSE; ! 685: } ! 686: ! 687: if(!modem_response(com_handle, resp, sizeof(resp))) ! 688: return FALSE; ! 689: ! 690: lprintf(LOG_INFO,"Modem Response: %s", resp); ! 691: ! 692: return TRUE; ! 693: } ! 694: ! 695: /****************************************************************************/ ! 696: /****************************************************************************/ ! 697: void close_socket(SOCKET* sock) ! 698: { ! 699: if(*sock != INVALID_SOCKET) { ! 700: shutdown(*sock,SHUT_RDWR); /* required on Unix */ ! 701: closesocket(*sock); ! 702: *sock=INVALID_SOCKET; ! 703: } ! 704: } ! 705: ! 706: /****************************************************************************/ ! 707: /****************************************************************************/ ! 708: void cleanup(void) ! 709: { ! 710: terminated=TRUE; ! 711: ! 712: lprintf(LOG_INFO,"Cleaning up ..."); ! 713: ! 714: ! 715: if(com_handle!=COM_HANDLE_INVALID) { ! 716: if(!mdm_null && mdm_cleanup[0]) ! 717: modem_command(com_handle, mdm_cleanup); ! 718: if(!com_handle_passed) ! 719: comClose(com_handle); ! 720: } ! 721: ! 722: close_socket(&sock); ! 723: ! 724: #ifdef _WINSOCKAPI_ ! 725: WSACleanup(); ! 726: #endif ! 727: ! 728: lprintf(LOG_INFO,"Done (handled %lu calls).", total_calls); ! 729: ! 730: #if defined(_WIN32) ! 731: if(daemonize && svc_status_handle!=0) { ! 732: svc_status.dwCurrentState=SERVICE_STOPPED; ! 733: SetServiceStatus(svc_status_handle, &svc_status); ! 734: } else ! 735: #endif ! 736: if(pause_on_exit) { ! 737: printf("Hit enter to continue..."); ! 738: getchar(); ! 739: } ! 740: } ! 741: ! 742: /****************************************************************************/ ! 743: /****************************************************************************/ ! 744: BOOL wait_for_call(COM_HANDLE com_handle) ! 745: { ! 746: char str[128]; ! 747: char* p; ! 748: BOOL result=TRUE; ! 749: DWORD events=0; ! 750: int mdm_status; ! 751: ! 752: ZERO_VAR(cid_name); ! 753: ZERO_VAR(cid_number); ! 754: ! 755: comRaiseDTR(com_handle); ! 756: ! 757: if(com_alreadyconnected) ! 758: return TRUE; ! 759: ! 760: if(!mdm_null) { ! 761: if(mdm_init[0]) { ! 762: lprintf(LOG_INFO,"Initializing modem:"); ! 763: if(!modem_command(com_handle, mdm_init)) ! 764: return FALSE; ! 765: } ! 766: if(mdm_autoans[0]) { ! 767: lprintf(LOG_INFO,"Setting modem to auto-answer:"); ! 768: if(!modem_command(com_handle, mdm_autoans)) ! 769: return FALSE; ! 770: } ! 771: if(mdm_cid[0]) { ! 772: lprintf(LOG_INFO,"Enabling modem Caller-ID:"); ! 773: if(!modem_command(com_handle, mdm_cid)) ! 774: return FALSE; ! 775: } ! 776: } ! 777: ! 778: lprintf(LOG_INFO,"Waiting for incoming call (Carrier Detect) on %s ...", com_dev); ! 779: while(1) { ! 780: if(terminated) ! 781: return FALSE; ! 782: if(comReadLine(com_handle, str, sizeof(str), /* timeout (ms): */250) > 0) { ! 783: truncsp(str); ! 784: p=str; ! 785: SKIP_WHITESPACE(p); ! 786: if(*p) { ! 787: lprintf(LOG_INFO, "Modem Message: %s", p); ! 788: if(strncmp(p,"CONNECT ",8)==0) { ! 789: long rate=atoi(p+8); ! 790: if(rate) ! 791: SAFEPRINTF2(termspeed,"%u,%u", rate, rate); ! 792: } ! 793: else if(strncmp(p,"NMBR",4)==0 || strncmp(p,"MESG",4)==0) { ! 794: p+=4; ! 795: FIND_CHAR(p,'='); ! 796: SKIP_CHAR(p,'='); ! 797: SKIP_WHITESPACE(p); ! 798: if(cid_number[0]==0) /* Don't overwrite, if multiple messages received */ ! 799: SAFECOPY(cid_number, p); ! 800: } ! 801: else if(strncmp(p,"NAME",4)==0) { ! 802: p+=4; ! 803: FIND_CHAR(p,'='); ! 804: SKIP_CHAR(p,'='); ! 805: SKIP_WHITESPACE(p); ! 806: SAFECOPY(cid_name, p); ! 807: } ! 808: else if(strcmp(p,"NO CARRIER")==0) { ! 809: ZERO_VAR(cid_name); ! 810: ZERO_VAR(cid_number); ! 811: } ! 812: } ! 813: continue; /* don't check DCD until we've received all the modem msgs */ ! 814: } ! 815: if((mdm_status=comGetModemStatus(com_handle)) == COM_ERROR) ! 816: lprintf(LOG_ERR,"Error %u getting modem status (line %u)" ! 817: ,COM_ERROR_VALUE, __LINE__); ! 818: else if(mdm_status&COM_DCD) ! 819: break; ! 820: } ! 821: ! 822: if(strcmp(cid_name,"P")==0) ! 823: SAFECOPY(cid_name,"Private"); ! 824: else if(strcmp(cid_name,"O")==0) ! 825: SAFECOPY(cid_name,"Out-of-area"); ! 826: ! 827: if(strcmp(cid_number,"P")==0) ! 828: SAFECOPY(cid_number,"Private"); ! 829: else if(strcmp(cid_number,"O")==0) ! 830: SAFECOPY(cid_number,"Out-of-area"); ! 831: ! 832: lprintf(LOG_INFO,"Carrier detected on %s", com_dev); ! 833: return TRUE; ! 834: } ! 835: ! 836: /****************************************************************************/ ! 837: /****************************************************************************/ ! 838: u_long resolve_ip(const char *addr) ! 839: { ! 840: HOSTENT* host; ! 841: const char* p; ! 842: ! 843: if(*addr==0) ! 844: return((u_long)INADDR_NONE); ! 845: ! 846: for(p=addr;*p;p++) ! 847: if(*p!='.' && !isdigit(*p)) ! 848: break; ! 849: if(!(*p)) ! 850: return(inet_addr(addr)); ! 851: if((host=gethostbyname(addr))==NULL) ! 852: return((u_long)INADDR_NONE); ! 853: return(*((ulong*)host->h_addr_list[0])); ! 854: } ! 855: ! 856: /****************************************************************************/ ! 857: /****************************************************************************/ ! 858: SOCKET connect_socket(const char* host, ushort port) ! 859: { ! 860: SOCKET sock; ! 861: SOCKADDR_IN addr; ! 862: ! 863: if((sock=socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) == INVALID_SOCKET) { ! 864: lprintf(LOG_ERR,"ERROR %u creating socket", ERROR_VALUE); ! 865: return INVALID_SOCKET; ! 866: } ! 867: ! 868: lprintf(LOG_DEBUG,"Setting TCP_NODELAY to %d",tcp_nodelay); ! 869: setsockopt(sock,IPPROTO_TCP,TCP_NODELAY,(char*)&tcp_nodelay,sizeof(tcp_nodelay)); ! 870: ! 871: ZERO_VAR(addr); ! 872: addr.sin_addr.s_addr = resolve_ip(host); ! 873: addr.sin_family = AF_INET; ! 874: addr.sin_port = htons(port); ! 875: ! 876: lprintf(LOG_INFO,"Connecting to %s port %u", host, port); ! 877: if(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) { ! 878: lprintf(LOG_INFO,"Connected from %s to %s port %u on socket %u", com_dev, host, port, sock); ! 879: return sock; ! 880: } ! 881: ! 882: lprintf(LOG_ERR,"SOCKET ERROR %u connecting to %s port %u", ERROR_VALUE, host, port); ! 883: closesocket(sock); ! 884: ! 885: return INVALID_SOCKET; ! 886: } ! 887: ! 888: BOOL call_terminated; ! 889: BOOL input_thread_terminated; ! 890: ! 891: /****************************************************************************/ ! 892: /****************************************************************************/ ! 893: void input_thread(void* arg) ! 894: { ! 895: BYTE ch; ! 896: ! 897: lprintf(LOG_DEBUG,"Input thread started"); ! 898: while(!call_terminated) { ! 899: if(!comReadByte(com_handle, &ch)) { ! 900: YIELD(); ! 901: continue; ! 902: } ! 903: if(telnet && ch==TELNET_IAC) ! 904: sendsocket(sock, &ch, sizeof(ch)); /* escape Telnet IAC char (255) when in telnet mode */ ! 905: sendsocket(sock, &ch, sizeof(ch)); ! 906: bytes_received++; ! 907: } ! 908: lprintf(LOG_DEBUG,"Input thread terminated"); ! 909: input_thread_terminated=TRUE; ! 910: } ! 911: ! 912: void ident_server_thread(void* arg) ! 913: { ! 914: int result; ! 915: SOCKET sock; ! 916: SOCKADDR_IN server_addr={0}; ! 917: fd_set socket_set; ! 918: struct timeval tv; ! 919: ! 920: lprintf(LOG_DEBUG,"Ident server thread started"); ! 921: ! 922: if((sock=socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) == INVALID_SOCKET) { ! 923: lprintf(LOG_ERR,"ERROR %u creating socket", ERROR_VALUE); ! 924: return; ! 925: } ! 926: ! 927: memset(&server_addr, 0, sizeof(server_addr)); ! 928: ! 929: server_addr.sin_addr.s_addr = htonl(ident_interface); ! 930: server_addr.sin_family = AF_INET; ! 931: server_addr.sin_port = htons(ident_port); ! 932: ! 933: if(bind(sock,(struct sockaddr *)&server_addr,sizeof(server_addr))!=0) { ! 934: lprintf(LOG_ERR,"ERROR %u binding ident server socket", ERROR_VALUE); ! 935: close_socket(&sock); ! 936: return; ! 937: } ! 938: ! 939: if(listen(sock, 1)) { ! 940: lprintf(LOG_ERR,"!ERROR %u listening on ident server socket", ERROR_VALUE); ! 941: close_socket(&sock); ! 942: return; ! 943: } ! 944: ! 945: while(!terminated) { ! 946: /* now wait for connection */ ! 947: ! 948: FD_ZERO(&socket_set); ! 949: FD_SET(sock,&socket_set); ! 950: ! 951: tv.tv_sec=5; ! 952: tv.tv_usec=0; ! 953: ! 954: if((result=select(sock+1,&socket_set,NULL,NULL,&tv))<1) { ! 955: if(result==0) ! 956: continue; ! 957: if(ERROR_VALUE==EINTR) ! 958: lprintf(LOG_DEBUG,"Ident Server listening interrupted"); ! 959: else if(ERROR_VALUE == ENOTSOCK) ! 960: lprintf(LOG_NOTICE,"Ident Server sockets closed"); ! 961: else ! 962: lprintf(LOG_WARNING,"!ERROR %d selecting ident socket",ERROR_VALUE); ! 963: continue; ! 964: } ! 965: ! 966: if(FD_ISSET(sock,&socket_set)) { ! 967: SOCKADDR_IN client_addr; ! 968: socklen_t client_addr_len; ! 969: SOCKET client_socket=INVALID_SOCKET; ! 970: char request[128]; ! 971: char response[256]; ! 972: int rd; ! 973: ! 974: client_addr_len = sizeof(client_addr); ! 975: client_socket = accept(sock, (struct sockaddr *)&client_addr, &client_addr_len); ! 976: if(client_socket != INVALID_SOCKET) { ! 977: lprintf(LOG_INFO,"Ident request from %s : %u" ! 978: ,inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port)); ! 979: FD_ZERO(&socket_set); ! 980: FD_SET(client_socket,&socket_set); ! 981: tv.tv_sec=5; ! 982: tv.tv_usec=0; ! 983: if(select(client_socket+1,&socket_set,NULL,NULL,&tv)==1) { ! 984: lprintf(LOG_DEBUG,"Ident select"); ! 985: if((rd=recv(client_socket, request, sizeof(request), 0)) > 0) { ! 986: request[rd]=0; ! 987: truncsp(request); ! 988: lprintf(LOG_INFO,"Ident request: %s", request); ! 989: /* example response: "40931,23:USERID:UNIX:cyan" */ ! 990: SAFEPRINTF4(response,"%s:%s:%s %s\r\n" ! 991: ,request, ident_response, cid_number, cid_name); ! 992: sendsocket(client_socket,response,strlen(response)); ! 993: } else ! 994: lprintf(LOG_DEBUG,"ident recv=%d %d", rd, ERROR_VALUE); ! 995: } ! 996: close_socket(&client_socket); ! 997: } ! 998: } ! 999: } ! 1000: ! 1001: close_socket(&sock); ! 1002: lprintf(LOG_DEBUG,"Ident server thread terminated"); ! 1003: } ! 1004: ! 1005: static void send_telnet_cmd(uchar cmd, uchar opt) ! 1006: { ! 1007: char buf[16]; ! 1008: ! 1009: if(cmd<TELNET_WILL) { ! 1010: if(debug_telnet) ! 1011: lprintf(LOG_INFO,"TX Telnet command: %s" ! 1012: ,telnet_cmd_desc(cmd)); ! 1013: sprintf(buf,"%c%c",TELNET_IAC,cmd); ! 1014: sendsocket(sock,buf,2); ! 1015: } else { ! 1016: if(debug_telnet) ! 1017: lprintf(LOG_INFO,"TX Telnet command: %s %s" ! 1018: ,telnet_cmd_desc(cmd), telnet_opt_desc(opt)); ! 1019: sprintf(buf,"%c%c%c",TELNET_IAC,cmd,opt); ! 1020: sendsocket(sock,buf,3); ! 1021: } ! 1022: } ! 1023: ! 1024: void request_telnet_opt(uchar cmd, uchar opt) ! 1025: { ! 1026: if(cmd==TELNET_DO || cmd==TELNET_DONT) { /* remote option */ ! 1027: if(telnet_remote_option[opt]==telnet_opt_ack(cmd)) ! 1028: return; /* already set in this mode, do nothing */ ! 1029: telnet_remote_option[opt]=telnet_opt_ack(cmd); ! 1030: } else { /* local option */ ! 1031: if(telnet_local_option[opt]==telnet_opt_ack(cmd)) ! 1032: return; /* already set in this mode, do nothing */ ! 1033: telnet_local_option[opt]=telnet_opt_ack(cmd); ! 1034: } ! 1035: send_telnet_cmd(cmd,opt); ! 1036: } ! 1037: ! 1038: /****************************************************************************/ ! 1039: /****************************************************************************/ ! 1040: BYTE* telnet_interpret(BYTE* inbuf, int inlen, BYTE* outbuf, int *outlen) ! 1041: { ! 1042: BYTE command; ! 1043: BYTE option; ! 1044: BYTE* first_iac; ! 1045: int i; ! 1046: ! 1047: if(inlen<1) { ! 1048: *outlen=0; ! 1049: return(inbuf); /* no length? No interpretation */ ! 1050: } ! 1051: ! 1052: first_iac=(BYTE*)memchr(inbuf, TELNET_IAC, inlen); ! 1053: ! 1054: if(!telnet_cmdlen && first_iac==NULL) { ! 1055: *outlen=inlen; ! 1056: return(inbuf); /* no interpretation needed */ ! 1057: } ! 1058: ! 1059: if(first_iac!=NULL) { ! 1060: *outlen=first_iac-inbuf; ! 1061: memcpy(outbuf, inbuf, *outlen); ! 1062: } else ! 1063: *outlen=0; ! 1064: ! 1065: for(i=*outlen;i<inlen;i++) { ! 1066: if(inbuf[i]==TELNET_IAC && telnet_cmdlen==1) { /* escaped 255 */ ! 1067: telnet_cmdlen=0; ! 1068: outbuf[(*outlen)++]=TELNET_IAC; ! 1069: continue; ! 1070: } ! 1071: if(inbuf[i]==TELNET_IAC || telnet_cmdlen) { ! 1072: ! 1073: if(telnet_cmdlen<sizeof(telnet_cmd)) ! 1074: telnet_cmd[telnet_cmdlen++]=inbuf[i]; ! 1075: ! 1076: command = telnet_cmd[1]; ! 1077: option = telnet_cmd[2]; ! 1078: ! 1079: if(telnet_cmdlen>=2 && command==TELNET_SB) { ! 1080: if(inbuf[i]==TELNET_SE ! 1081: && telnet_cmd[telnet_cmdlen-2]==TELNET_IAC) { ! 1082: if(debug_telnet) ! 1083: lprintf(LOG_INFO,"RX Telnet sub-negotiation command: %s" ! 1084: ,telnet_opt_desc(option)); ! 1085: /* sub-option terminated */ ! 1086: if(option==TELNET_TERM_TYPE && telnet_cmd[3]==TELNET_TERM_SEND) { ! 1087: BYTE buf[32]; ! 1088: int len=sprintf(buf,"%c%c%c%c%s%c%c" ! 1089: ,TELNET_IAC,TELNET_SB ! 1090: ,TELNET_TERM_TYPE,TELNET_TERM_IS ! 1091: ,termtype ! 1092: ,TELNET_IAC,TELNET_SE); ! 1093: if(debug_telnet) ! 1094: lprintf(LOG_INFO,"TX Telnet command: Terminal Type is %s", termtype); ! 1095: sendsocket(sock,buf,len); ! 1096: /* request_telnet_opt(TELNET_WILL, TELNET_TERM_SPEED); */ ! 1097: } else if(option==TELNET_TERM_SPEED && telnet_cmd[3]==TELNET_TERM_SEND) { ! 1098: BYTE buf[32]; ! 1099: int len=sprintf(buf,"%c%c%c%c%s%c%c" ! 1100: ,TELNET_IAC,TELNET_SB ! 1101: ,TELNET_TERM_SPEED,TELNET_TERM_IS ! 1102: ,termspeed ! 1103: ,TELNET_IAC,TELNET_SE); ! 1104: if(debug_telnet) ! 1105: lprintf(LOG_INFO,"TX Telnet command: Terminal Speed is %s", termspeed); ! 1106: sendsocket(sock,buf,len); ! 1107: } ! 1108: ! 1109: telnet_cmdlen=0; ! 1110: } ! 1111: } ! 1112: else if(telnet_cmdlen==2 && inbuf[i]<TELNET_WILL) { ! 1113: telnet_cmdlen=0; ! 1114: } ! 1115: else if(telnet_cmdlen>=3) { /* telnet option negotiation */ ! 1116: ! 1117: if(debug_telnet) ! 1118: lprintf(LOG_INFO,"RX Telnet command: %s %s" ! 1119: ,telnet_cmd_desc(command),telnet_opt_desc(option)); ! 1120: ! 1121: if(command==TELNET_DO || command==TELNET_DONT) { /* local options */ ! 1122: if(telnet_local_option[option]!=command) { ! 1123: switch(option) { ! 1124: case TELNET_BINARY_TX: ! 1125: case TELNET_ECHO: ! 1126: case TELNET_TERM_TYPE: ! 1127: case TELNET_TERM_SPEED: ! 1128: case TELNET_SUP_GA: ! 1129: telnet_local_option[option]=command; ! 1130: send_telnet_cmd(telnet_opt_ack(command),option); ! 1131: break; ! 1132: case TELNET_SEND_LOCATION: ! 1133: if(command==TELNET_DO) { ! 1134: BYTE buf[128]; ! 1135: int len=safe_snprintf(buf,sizeof(buf),"%c%c%c%s %s%c%c" ! 1136: ,TELNET_IAC,TELNET_SB ! 1137: ,TELNET_SEND_LOCATION ! 1138: ,cid_number, cid_name ! 1139: ,TELNET_IAC,TELNET_SE); ! 1140: if(debug_telnet) ! 1141: lprintf(LOG_INFO,"TX Telnet command: Location is %s %s", cid_number, cid_name); ! 1142: sendsocket(sock,buf,len); ! 1143: } else ! 1144: send_telnet_cmd(telnet_opt_ack(command),option); ! 1145: break; ! 1146: ! 1147: default: /* unsupported local options */ ! 1148: if(command==TELNET_DO) /* NAK */ ! 1149: send_telnet_cmd(telnet_opt_nak(command),option); ! 1150: break; ! 1151: } ! 1152: } ! 1153: } else { /* WILL/WONT (remote options) */ ! 1154: if(telnet_remote_option[option]!=command) { ! 1155: ! 1156: switch(option) { ! 1157: case TELNET_BINARY_TX: ! 1158: case TELNET_ECHO: ! 1159: case TELNET_TERM_TYPE: ! 1160: case TELNET_SUP_GA: ! 1161: telnet_remote_option[option]=command; ! 1162: send_telnet_cmd(telnet_opt_ack(command),option); ! 1163: break; ! 1164: default: /* unsupported remote options */ ! 1165: if(command==TELNET_WILL) /* NAK */ ! 1166: send_telnet_cmd(telnet_opt_nak(command),option); ! 1167: break; ! 1168: } ! 1169: } ! 1170: } ! 1171: ! 1172: telnet_cmdlen=0; ! 1173: ! 1174: } ! 1175: } else ! 1176: outbuf[(*outlen)++]=inbuf[i]; ! 1177: } ! 1178: return(outbuf); ! 1179: } ! 1180: ! 1181: /****************************************************************************/ ! 1182: /****************************************************************************/ ! 1183: BOOL handle_call(void) ! 1184: { ! 1185: BYTE buf[4096]; ! 1186: BYTE telnet_buf[sizeof(buf)]; ! 1187: BYTE* p; ! 1188: int result; ! 1189: int rd; ! 1190: int wr; ! 1191: int mdm_status; ! 1192: fd_set socket_set; ! 1193: struct timeval tv = {0, 0}; ! 1194: ! 1195: bytes_sent=0; ! 1196: bytes_received=0; ! 1197: call_terminated=FALSE; ! 1198: ! 1199: /* Reset Telnet state information */ ! 1200: telnet_cmdlen=0; ! 1201: ZERO_VAR(telnet_local_option); ! 1202: ZERO_VAR(telnet_remote_option); ! 1203: ! 1204: if(telnet && telnet_advertise_cid && (cid_number[0] || cid_name[0])) /* advertise the ability to send our location */ ! 1205: send_telnet_cmd(TELNET_WILL, TELNET_SEND_LOCATION); ! 1206: ! 1207: input_thread_terminated=FALSE; ! 1208: _beginthread(input_thread, 0, NULL); ! 1209: ! 1210: while(!terminated) { ! 1211: ! 1212: if(!dcd_ignore) { ! 1213: if((mdm_status = comGetModemStatus(com_handle)) == COM_ERROR) { ! 1214: lprintf(LOG_ERR,"Error %u getting modem status (line %u)" ! 1215: ,COM_ERROR_VALUE, __LINE__); ! 1216: break; ! 1217: } ! 1218: if((mdm_status&COM_DCD) == 0) { ! 1219: lprintf(LOG_WARNING,"Loss of Carrier Detect (DCD) detected"); ! 1220: break; ! 1221: } ! 1222: } ! 1223: #if 0 ! 1224: if(comReadByte(com_handle, &ch)) { ! 1225: lprintf(LOG_DEBUG,"read byte: %c", ch); ! 1226: send(sock, &ch, sizeof(ch), 0); ! 1227: } ! 1228: #endif ! 1229: ! 1230: FD_ZERO(&socket_set); ! 1231: FD_SET(sock,&socket_set); ! 1232: if((result = select(sock+1,&socket_set,NULL,NULL,&tv)) == 0) { ! 1233: YIELD(); ! 1234: continue; ! 1235: } ! 1236: if(result == SOCKET_ERROR) { ! 1237: lprintf(LOG_ERR,"SOCKET ERROR %u on select", ERROR_VALUE); ! 1238: break; ! 1239: } ! 1240: ! 1241: rd=recv(sock,buf,sizeof(buf),0); ! 1242: ! 1243: if(rd < 1) { ! 1244: if(rd==0) { ! 1245: lprintf(LOG_WARNING,"Socket Disconnected"); ! 1246: break; ! 1247: } ! 1248: lprintf(LOG_ERR,"SOCKET RECV ERROR %d",ERROR_VALUE); ! 1249: continue; ! 1250: } ! 1251: ! 1252: if(telnet) ! 1253: p=telnet_interpret(buf,rd,telnet_buf,&rd); ! 1254: else ! 1255: p=buf; ! 1256: ! 1257: if((wr=comWriteBuf(com_handle, p, rd)) != COM_ERROR) ! 1258: bytes_sent += wr; ! 1259: } ! 1260: ! 1261: call_terminated=TRUE; /* terminate input_thread() */ ! 1262: while(!input_thread_terminated) { ! 1263: YIELD(); ! 1264: } ! 1265: ! 1266: lprintf(LOG_INFO,"Bytes sent-to, received-from %s: %lu, %lu" ! 1267: , com_dev, bytes_sent, bytes_received); ! 1268: ! 1269: return TRUE; ! 1270: } ! 1271: ! 1272: /****************************************************************************/ ! 1273: /****************************************************************************/ ! 1274: BOOL hangup_call(COM_HANDLE com_handle) ! 1275: { ! 1276: time_t start; ! 1277: int attempt; ! 1278: int mdm_status; ! 1279: ! 1280: if((mdm_status=comGetModemStatus(com_handle)) == COM_ERROR) { ! 1281: lprintf(LOG_ERR,"Error %u getting modem status (line %u)" ! 1282: ,COM_ERROR_VALUE, __LINE__); ! 1283: return TRUE; ! 1284: } ! 1285: if((mdm_status&COM_DCD)==0) /* DCD already low */ ! 1286: return TRUE; ! 1287: ! 1288: lprintf(LOG_DEBUG,"Waiting for transmit buffer to empty"); ! 1289: SLEEP(dtr_delay); ! 1290: for(attempt=0; attempt<hangup_attempts; attempt++) { ! 1291: lprintf(LOG_INFO,"Dropping DTR (attempt #%d)", attempt+1); ! 1292: if(!comLowerDTR(com_handle)) { ! 1293: lprintf(LOG_ERR,"ERROR %u lowering DTR", COM_ERROR); ! 1294: continue; ! 1295: } ! 1296: lprintf(LOG_DEBUG,"Waiting for loss of Carrier Detect (DCD)"); ! 1297: start=time(NULL); ! 1298: while(time(NULL)-start <= dcd_timeout) { ! 1299: if((mdm_status=comGetModemStatus(com_handle)) == COM_ERROR) { ! 1300: lprintf(LOG_ERR,"Error %u getting modem status (line %u)" ! 1301: ,COM_ERROR_VALUE, __LINE__); ! 1302: return TRUE; ! 1303: } ! 1304: if((mdm_status&COM_DCD)==0) ! 1305: return TRUE; ! 1306: SLEEP(1000); ! 1307: } ! 1308: lprintf(LOG_ERR,"TIMEOUT waiting for DCD to drop (attempt #%d of %d)" ! 1309: , attempt+1, hangup_attempts); ! 1310: } ! 1311: ! 1312: return FALSE; ! 1313: } ! 1314: ! 1315: /****************************************************************************/ ! 1316: /****************************************************************************/ ! 1317: void break_handler(int type) ! 1318: { ! 1319: lprintf(LOG_NOTICE,"-> Terminated Locally (signal: %d)",type); ! 1320: terminated=TRUE; ! 1321: } ! 1322: ! 1323: #if defined(_WIN32) ! 1324: BOOL WINAPI ControlHandler(DWORD CtrlType) ! 1325: { ! 1326: break_handler((int)CtrlType); ! 1327: return TRUE; ! 1328: } ! 1329: #endif ! 1330: ! 1331: /****************************************************************************/ ! 1332: /****************************************************************************/ ! 1333: char* iniGetExistingWord(str_list_t list, const char* section, const char* key ! 1334: ,const char* deflt, char* value) ! 1335: { ! 1336: char* p; ! 1337: ! 1338: if((p=iniGetExistingString(list, section, key, deflt, value)) !=NULL) { ! 1339: FIND_WHITESPACE(value); ! 1340: *value=0; ! 1341: } ! 1342: return p; ! 1343: } ! 1344: ! 1345: void parse_ini_file(const char* ini_fname) ! 1346: { ! 1347: FILE* fp; ! 1348: char* section; ! 1349: str_list_t list=NULL; ! 1350: ! 1351: if((fp=fopen(ini_fname,"r"))!=NULL) { ! 1352: lprintf(LOG_INFO,"Reading %s",ini_fname); ! 1353: list=iniReadFile(fp); ! 1354: fclose(fp); ! 1355: } ! 1356: ! 1357: /* Root section */ ! 1358: pause_on_exit = iniGetBool(list,ROOT_SECTION,"PauseOnExit",FALSE); ! 1359: log_level = iniGetLogLevel(list,ROOT_SECTION,"LogLevel",log_level); ! 1360: ! 1361: if(iniGetBool(list,ROOT_SECTION,"Debug",FALSE)) ! 1362: log_level=LOG_DEBUG; ! 1363: ! 1364: /* [COM] Section */ ! 1365: section="COM"; ! 1366: iniGetExistingWord(list, section, "Device", NULL, com_dev); ! 1367: com_baudrate = iniGetLongInt(list, section, "BaudRate", com_baudrate); ! 1368: com_hangup = iniGetBool(list, section, "Hangup", com_hangup); ! 1369: hangup_attempts = iniGetInteger(list, section, "HangupAttempts", hangup_attempts); ! 1370: dcd_timeout = iniGetInteger(list, section, "DCDTimeout", dcd_timeout); ! 1371: dcd_ignore = iniGetBool(list, section, "IgnoreDCD", dcd_ignore); ! 1372: dtr_delay = iniGetLongInt(list, section, "DTRDelay", dtr_delay); ! 1373: mdm_null = iniGetBool(list, section, "NullModem", mdm_null); ! 1374: ! 1375: /* [Modem] Section */ ! 1376: section="Modem"; ! 1377: iniGetExistingWord(list, section, "Init", "", mdm_init); ! 1378: iniGetExistingWord(list, section, "AutoAnswer", "", mdm_autoans); ! 1379: iniGetExistingWord(list, section, "Cleanup", "", mdm_cleanup); ! 1380: iniGetExistingWord(list, section, "EnableCallerID", "", mdm_cid); ! 1381: mdm_timeout = iniGetInteger(list, section, "Timeout", mdm_timeout); ! 1382: ! 1383: /* [TCP] Section */ ! 1384: section="TCP"; ! 1385: iniGetExistingWord(list, section, "Host", NULL, host); ! 1386: port = iniGetShortInt(list, section, "Port", port); ! 1387: tcp_nodelay = iniGetBool(list,section,"NODELAY", tcp_nodelay); ! 1388: ! 1389: /* [Telnet] Section */ ! 1390: section="Telnet"; ! 1391: telnet = iniGetBool(list,section,"Enabled", telnet); ! 1392: debug_telnet = iniGetBool(list,section,"Debug", debug_telnet); ! 1393: telnet_advertise_cid = iniGetBool(list,section,"AdvertiseLocation", telnet_advertise_cid); ! 1394: iniGetExistingWord(list, section, "TermType", NULL, termtype); ! 1395: iniGetExistingWord(list, section, "TermSpeed", NULL, termspeed); ! 1396: ! 1397: /* [Ident] Section */ ! 1398: section="Ident"; ! 1399: ident = iniGetBool(list,section,"Enabled", ident); ! 1400: ident_port = iniGetShortInt(list, section, "Port", ident_port); ! 1401: ident_interface = iniGetIpAddress(list, section, "Interface", ident_interface); ! 1402: iniGetExistingWord(list, section, "Response", NULL, ident_response); ! 1403: ! 1404: } ! 1405: ! 1406: char banner[128]; ! 1407: ! 1408: static void ! 1409: #if defined(_WIN32) ! 1410: WINAPI ! 1411: #endif ! 1412: service_loop(int argc, char** argv) ! 1413: { ! 1414: int argn; ! 1415: char* arg; ! 1416: char str[128]; ! 1417: char compiler[128]; ! 1418: ! 1419: for(argn=1; argn<(int)argc; argn++) { ! 1420: arg=argv[argn]; ! 1421: if(*arg!='-') { /* .ini file specified */ ! 1422: if(!fexist(arg)) { ! 1423: lprintf(LOG_ERR,"Initialization file does not exist: %s", arg); ! 1424: exit(usage(argv[0])); ! 1425: } ! 1426: parse_ini_file(arg); ! 1427: continue; ! 1428: } ! 1429: while(*arg=='-') ! 1430: arg++; ! 1431: if(stricmp(arg,"null")==0) ! 1432: mdm_null=TRUE; ! 1433: else if(stricmp(arg,"com")==0 && argc > argn+1) ! 1434: SAFECOPY(com_dev, argv[++argn]); ! 1435: else if(stricmp(arg,"baud")==0 && argc > argn+1) ! 1436: com_baudrate = (ulong)strtol(argv[++argn],NULL,0); ! 1437: else if(stricmp(arg,"host")==0 && argc > argn+1) ! 1438: SAFECOPY(host, argv[++argn]); ! 1439: else if(stricmp(arg,"port")==0 && argc > argn+1) ! 1440: port = (ushort)strtol(argv[++argn], NULL, 0); ! 1441: else if(stricmp(arg,"live")==0) { ! 1442: if(argc > argn+1 && ! 1443: (com_handle = (COM_HANDLE)strtol(argv[argn+1], NULL, 0)) != 0) { ! 1444: argn++; ! 1445: com_handle_passed=TRUE; ! 1446: } ! 1447: com_alreadyconnected=TRUE; ! 1448: terminate_after_one_call=TRUE; ! 1449: mdm_null=TRUE; ! 1450: } ! 1451: else if(stricmp(arg,"nohangup")==0) { ! 1452: com_hangup=FALSE; ! 1453: } ! 1454: else if(stricmp(arg,"debug")==0) { ! 1455: log_level=LOG_DEBUG; ! 1456: } ! 1457: else if(stricmp(arg,"help")==0 || *arg=='?') ! 1458: exit(usage(argv[0])); ! 1459: else { ! 1460: fprintf(stderr,"Invalid option: %s\n", arg); ! 1461: exit(usage(argv[0])); ! 1462: } ! 1463: } ! 1464: ! 1465: #if defined(_WIN32) ! 1466: /* Convert "1" to "COM1" for Windows */ ! 1467: { ! 1468: int i; ! 1469: ! 1470: if((i=atoi(com_dev)) != 0) ! 1471: SAFEPRINTF(com_dev, "COM%d", i); ! 1472: } ! 1473: ! 1474: if(daemonize) { ! 1475: ! 1476: if((svc_status_handle = RegisterServiceCtrlHandler(NAME, ServiceControlHandler))==0) { ! 1477: lprintf(LOG_ERR,"!ERROR %d registering service control handler",GetLastError()); ! 1478: return; ! 1479: } ! 1480: ! 1481: svc_status.dwServiceType=SERVICE_WIN32_OWN_PROCESS; ! 1482: svc_status.dwControlsAccepted=SERVICE_ACCEPT_SHUTDOWN; ! 1483: svc_status.dwWaitHint=NTSVC_TIMEOUT_STARTUP; ! 1484: ! 1485: svc_status.dwCurrentState=SERVICE_START_PENDING; ! 1486: SetServiceStatus(svc_status_handle, &svc_status); ! 1487: } ! 1488: ! 1489: #endif ! 1490: ! 1491: lprintf(LOG_INFO,"%s", comVersion(str,sizeof(str))); ! 1492: DESCRIBE_COMPILER(compiler); ! 1493: lprintf(LOG_INFO,"Build %s %s %s", __DATE__, __TIME__, compiler); ! 1494: ! 1495: /************************************/ ! 1496: /* Inititalize WinSock and COM Port */ ! 1497: /************************************/ ! 1498: ! 1499: if(!winsock_startup()) ! 1500: exit(1); ! 1501: ! 1502: /* Install clean-up callback */ ! 1503: atexit(cleanup); ! 1504: ! 1505: lprintf(LOG_INFO,"TCP Host: %s", host); ! 1506: lprintf(LOG_INFO,"TCP Port: %u", port); ! 1507: ! 1508: if(!com_handle_passed) { ! 1509: lprintf(LOG_INFO,"Opening Communications Device: %s", com_dev); ! 1510: if((com_handle=comOpen(com_dev)) == COM_HANDLE_INVALID) { ! 1511: lprintf(LOG_ERR,"ERROR %u opening %s", COM_ERROR_VALUE, com_dev); ! 1512: exit(1); ! 1513: } ! 1514: } ! 1515: if(com_baudrate!=0) { ! 1516: if(!comSetBaudRate(com_handle,com_baudrate)) ! 1517: lprintf(LOG_ERR,"ERROR %u setting %s DTE rate to %lu bps" ! 1518: ,COM_ERROR_VALUE, com_dev, com_baudrate); ! 1519: } ! 1520: ! 1521: lprintf(LOG_INFO,"%s set to %ld bps DTE rate", com_dev, comGetBaudRate(com_handle)); ! 1522: ! 1523: if(ident) ! 1524: _beginthread(ident_server_thread, 0, NULL); ! 1525: ! 1526: #if defined(_WIN32) ! 1527: if(daemonize) { ! 1528: svc_status.dwCurrentState=SERVICE_RUNNING; ! 1529: svc_status.dwControlsAccepted|=SERVICE_ACCEPT_STOP; ! 1530: SetServiceStatus(svc_status_handle, &svc_status); ! 1531: } ! 1532: #endif ! 1533: ! 1534: /***************************/ ! 1535: /* Initialization Complete */ ! 1536: /***************************/ ! 1537: ! 1538: /* Main service loop: */ ! 1539: while(!terminated && wait_for_call(com_handle)) { ! 1540: comWriteByte(com_handle,'\r'); ! 1541: comWriteString(com_handle, banner); ! 1542: comWriteString(com_handle, "\r\n"); ! 1543: if((sock=connect_socket(host, port)) == INVALID_SOCKET) { ! 1544: comWriteString(com_handle,"\7\r\n!ERROR connecting to TCP port\r\n"); ! 1545: } else { ! 1546: handle_call(); ! 1547: close_socket(&sock); ! 1548: total_calls++; ! 1549: lprintf(LOG_INFO,"Call completed (%lu total)", total_calls); ! 1550: } ! 1551: if(com_hangup && !hangup_call(com_handle)) ! 1552: break; ! 1553: if(terminate_after_one_call) ! 1554: break; ! 1555: } ! 1556: ! 1557: exit(0); ! 1558: } ! 1559: ! 1560: /****************************************************************************/ ! 1561: /****************************************************************************/ ! 1562: int main(int argc, char** argv) ! 1563: { ! 1564: int argn; ! 1565: char* arg; ! 1566: char* p; ! 1567: char path[MAX_PATH+1]; ! 1568: char fname[MAX_PATH+1]; ! 1569: char ini_fname[MAX_PATH+1]; ! 1570: ! 1571: /*******************************/ ! 1572: /* Generate and display banner */ ! 1573: /*******************************/ ! 1574: sscanf("$Revision: 1.26 $", "%*s %s", revision); ! 1575: ! 1576: sprintf(banner,"\n%s v%s-%s" ! 1577: " Copyright %s Rob Swindell" ! 1578: ,TITLE ! 1579: ,revision ! 1580: ,PLATFORM_DESC ! 1581: ,__DATE__+7 ! 1582: ); ! 1583: ! 1584: fprintf(stdout,"%s\n\n", banner); ! 1585: ! 1586: /**********************/ ! 1587: /* Parse command-line */ ! 1588: /**********************/ ! 1589: ! 1590: for(argn=1; argn<argc; argn++) { ! 1591: arg=argv[argn]; ! 1592: while(*arg=='-') ! 1593: arg++; ! 1594: if(stricmp(arg,"help")==0 || *arg=='?') ! 1595: return usage(argv[0]); ! 1596: #ifdef _WIN32 ! 1597: else if(stricmp(arg,"service")==0) ! 1598: daemonize=TRUE; ! 1599: else if(stricmp(arg,"install")==0) ! 1600: return install(); ! 1601: else if(stricmp(arg,"remove")==0) ! 1602: return uninstall(); ! 1603: else if(stricmp(arg,"disable")==0) ! 1604: return enable(FALSE); ! 1605: else if(stricmp(arg,"enable")==0) ! 1606: return enable(TRUE); ! 1607: #endif ! 1608: } ! 1609: ! 1610: /******************/ ! 1611: /* Read .ini file */ ! 1612: /******************/ ! 1613: /* Generate path/sexpots[.host].ini from path/sexpots[.exe] */ ! 1614: SAFECOPY(path,argv[0]); ! 1615: p=getfname(path); ! 1616: SAFECOPY(fname,p); ! 1617: *p=0; ! 1618: if((p=getfext(fname))!=NULL) ! 1619: *p=0; ! 1620: strcat(fname,".ini"); ! 1621: ! 1622: iniFileName(ini_fname,sizeof(ini_fname),path,fname); ! 1623: parse_ini_file(ini_fname); ! 1624: ! 1625: #if defined(_WIN32) ! 1626: if(daemonize) { ! 1627: ! 1628: SERVICE_TABLE_ENTRY ServiceDispatchTable[] = ! 1629: { ! 1630: { NAME, (void(WINAPI*)(DWORD, char**))service_loop }, ! 1631: { NULL, NULL } /* Terminator */ ! 1632: }; ! 1633: ! 1634: printf("Starting service control dispatcher.\n" ); ! 1635: printf("This may take several seconds. Please wait.\n" ); ! 1636: ! 1637: if(!StartServiceCtrlDispatcher(ServiceDispatchTable)) { ! 1638: lprintf(LOG_ERR,"StartServiceCtrlDispatcher ERROR %d",GetLastError()); ! 1639: return -1; ! 1640: } ! 1641: return 0; ! 1642: } ! 1643: SetConsoleCtrlHandler(ControlHandler, TRUE /* Add */); ! 1644: ! 1645: #endif ! 1646: ! 1647: service_loop(argc,argv); ! 1648: ! 1649: return 0; ! 1650: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.