Annotation of sbbs/src/sbbs3/services.c, revision 1.1.1.2

1.1       root        1: /* services.c */
                      2: 
                      3: /* Synchronet Services */
                      4: 
1.1.1.2 ! root        5: /* $Id: services.c,v 1.252 2011/09/18 21:58:21 rswindell Exp $ */
1.1       root        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:  *                                                                                                                                                     *
1.1.1.2 ! root       11:  * Copyright 2011 Rob Swindell - http://www.synchro.net/copyright.html         *
1.1       root       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: /* Platform-specific headers */
                     39: #ifdef __unix__
                     40:        #include <sys/param.h>  /* BSD? */
                     41: #endif
                     42: 
                     43: /* ANSI C Library headers */
                     44: #include <stdio.h>
                     45: #include <stdlib.h>                    /* ltoa in GNU C lib */
                     46: #include <stdarg.h>                    /* va_list */
                     47: #include <string.h>                    /* strrchr */
                     48: #include <ctype.h>                     /* isdigit */
                     49: #include <fcntl.h>                     /* Open flags */
                     50: #include <errno.h>                     /* errno */
                     51: 
                     52: /* Synchronet-specific headers */
                     53: #ifndef JAVASCRIPT
                     54: #define JAVASCRIPT     /* required to include JS API headers */
                     55: #endif
                     56: #define SERVICES_INI_BITDESC_TABLE     /* required to defined service_options */
                     57: #undef SBBS    /* this shouldn't be defined unless building sbbs.dll/libsbbs.so */
                     58: #include "sbbs.h"
                     59: #include "services.h"
                     60: #include "ident.h"     /* identify() */
                     61: #include "sbbs_ini.h"
1.1.1.2 ! root       62: #include "js_rtpool.h"
        !            63: #include "js_request.h"
1.1       root       64: 
                     65: /* Constants */
                     66: 
                     67: #define MAX_UDP_BUF_LEN                        8192    /* 8K */
                     68: #define DEFAULT_LISTEN_BACKLOG 5
                     69: 
                     70: static services_startup_t* startup=NULL;
                     71: static scfg_t  scfg;
1.1.1.2 ! root       72: static volatile BOOL   terminated=FALSE;
1.1       root       73: static time_t  uptime=0;
1.1.1.2 ! root       74: static ulong   served=0;
1.1       root       75: static char            revision[16];
                     76: static str_list_t recycle_semfiles;
                     77: static str_list_t shutdown_semfiles;
                     78: 
                     79: typedef struct {
                     80:        /* These are sysop-configurable */
1.1.1.2 ! root       81:        uint32_t        interface_addr;
        !            82:        uint16_t        port;
        !            83:        char            protocol[34];
        !            84:        char            cmd[128];
        !            85:        uint            max_clients;
        !            86:        uint32_t        options;
        !            87:        int                     listen_backlog;
        !            88:        int                     log_level;
        !            89:        uint32_t        stack_size;
1.1       root       90:        js_startup_t    js;
                     91:        js_server_props_t js_server_props;
                     92:        /* These are run-time state and stat vars */
1.1.1.2 ! root       93:        uint32_t        clients;
        !            94:        ulong           served;
        !            95:        SOCKET          socket;
        !            96:        BOOL            running;
        !            97:        BOOL            terminated;
1.1       root       98: } service_t;
                     99: 
                    100: typedef struct {
                    101:        SOCKET                  socket;
                    102:        SOCKADDR_IN             addr;
                    103:        time_t                  logintime;
                    104:        user_t                  user;
                    105:        client_t*               client;
                    106:        service_t*              service;
                    107:        js_branch_t             branch;
                    108:        /* Initial UDP datagram */
                    109:        BYTE*                   udp_buf;
                    110:        int                             udp_len;
1.1.1.2 ! root      111:        subscan_t               *subscan;
1.1       root      112: } service_client_t;
                    113: 
                    114: static service_t       *service=NULL;
1.1.1.2 ! root      115: static uint32_t                services=0;
1.1       root      116: 
1.1.1.2 ! root      117: static int lprintf(int level, const char *fmt, ...)
1.1       root      118: {
                    119:        va_list argptr;
                    120:        char sbuf[1024];
                    121: 
1.1.1.2 ! root      122:        va_start(argptr,fmt);
        !           123:     vsnprintf(sbuf,sizeof(sbuf),fmt,argptr);
        !           124:        sbuf[sizeof(sbuf)-1]=0;
        !           125:     va_end(argptr);
        !           126: 
        !           127:        if(level <= LOG_ERR) {
        !           128:                errorlog(&scfg,startup==NULL ? NULL:startup->host_name, sbuf);
        !           129:                if(startup!=NULL && startup->errormsg!=NULL)
        !           130:                        startup->errormsg(startup->cbdata,level,sbuf);
        !           131:        }
        !           132: 
        !           133:     if(startup==NULL || startup->lputs==NULL || level > startup->log_level)
1.1       root      134:         return(0);
                    135: 
                    136: #if defined(_WIN32)
                    137:        if(IsBadCodePtr((FARPROC)startup->lputs))
                    138:                return(0);
                    139: #endif
                    140: 
                    141:     return(startup->lputs(startup->cbdata,level,sbuf));
                    142: }
                    143: 
                    144: #ifdef _WINSOCKAPI_
                    145: 
                    146: static WSADATA WSAData;
                    147: #define SOCKLIB_DESC WSAData.szDescription
                    148: static BOOL WSAInitialized=FALSE;
                    149: 
                    150: static BOOL winsock_startup(void)
                    151: {
                    152:        int             status;             /* Status Code */
                    153: 
                    154:     if((status = WSAStartup(MAKEWORD(1,1), &WSAData))==0) {
1.1.1.2 ! root      155:                lprintf(LOG_DEBUG,"%s %s",WSAData.szDescription, WSAData.szSystemStatus);
1.1       root      156:                WSAInitialized=TRUE;
                    157:                return (TRUE);
                    158:        }
                    159: 
                    160:     lprintf(LOG_CRIT,"!WinSock startup ERROR %d", status);
                    161:        return (FALSE);
                    162: }
                    163: 
                    164: #else /* No WINSOCK */
                    165: 
                    166: #define winsock_startup()      (TRUE)
                    167: #define SOCKLIB_DESC NULL
                    168: 
                    169: #endif
                    170: 
                    171: static ulong active_clients(void)
                    172: {
                    173:        ulong i;
                    174:        ulong total_clients=0;
                    175: 
                    176:        for(i=0;i<services;i++) 
                    177:                total_clients+=service[i].clients;
                    178: 
                    179:        return(total_clients);
                    180: }
                    181: 
                    182: static void update_clients(void)
                    183: {
                    184:        if(startup!=NULL && startup->clients!=NULL)
                    185:                startup->clients(startup->cbdata,active_clients());
                    186: }
                    187: 
                    188: static void client_on(SOCKET sock, client_t* client, BOOL update)
                    189: {
                    190:        if(startup!=NULL && startup->client_on!=NULL)
                    191:                startup->client_on(startup->cbdata,TRUE,sock,client,update);
                    192: }
                    193: 
                    194: static void client_off(SOCKET sock)
                    195: {
                    196:        if(startup!=NULL && startup->client_on!=NULL)
                    197:                startup->client_on(startup->cbdata,FALSE,sock,NULL,FALSE);
                    198: }
                    199: 
                    200: static void thread_up(BOOL setuid)
                    201: {
                    202:        if(startup!=NULL && startup->thread_up!=NULL)
                    203:                startup->thread_up(startup->cbdata,TRUE,setuid);
                    204: }
                    205: 
                    206: static void thread_down(void)
                    207: {
                    208:        if(startup!=NULL && startup->thread_up!=NULL)
                    209:                startup->thread_up(startup->cbdata,FALSE,FALSE);
                    210: }
                    211: 
                    212: static SOCKET open_socket(int type, const char* protocol)
                    213: {
                    214:        char    error[256];
                    215:        char    section[128];
                    216:        SOCKET  sock;
                    217: 
                    218:        sock=socket(AF_INET, type, IPPROTO_IP);
                    219:        if(sock!=INVALID_SOCKET && startup!=NULL && startup->socket_open!=NULL) 
                    220:                startup->socket_open(startup->cbdata,TRUE);
                    221:        if(sock!=INVALID_SOCKET) {
                    222:                SAFEPRINTF(section,"services|%s", protocol);
                    223:                if(set_socket_options(&scfg, sock, section, error, sizeof(error)))
                    224:                        lprintf(LOG_ERR,"%04d !ERROR %s",sock, error);
                    225:        }
                    226:        return(sock);
                    227: }
                    228: 
                    229: static int close_socket(SOCKET sock)
                    230: {
                    231:        int             result;
                    232: 
                    233:        if(sock==INVALID_SOCKET)
                    234:                return(-1);
                    235: 
                    236:        shutdown(sock,SHUT_RDWR);       /* required on Unix */
                    237:        result=closesocket(sock);
                    238:        if(startup!=NULL && startup->socket_open!=NULL) 
                    239:                startup->socket_open(startup->cbdata,FALSE);
                    240:        if(result!=0)
                    241:                lprintf(LOG_WARNING,"%04d !ERROR %d closing socket",sock, ERROR_VALUE);
                    242: 
                    243:        return(result);
                    244: }
                    245: 
                    246: static void status(char* str)
                    247: {
                    248:        if(startup!=NULL && startup->status!=NULL)
                    249:            startup->status(startup->cbdata,str);
                    250: }
                    251: 
                    252: /* Global JavaScript Methods */
                    253: 
                    254: static JSBool
                    255: js_read(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
                    256: {
                    257:        char*           buf;
                    258:        int32           len=512;
                    259:        service_client_t* client;
1.1.1.2 ! root      260:        jsrefcount      rc;
1.1       root      261: 
                    262:        if((client=(service_client_t*)JS_GetContextPrivate(cx))==NULL)
                    263:                return(JS_FALSE);
                    264: 
                    265:        if(argc)
                    266:                JS_ValueToInt32(cx,argv[0],&len);
                    267:        
                    268:        if((buf=alloca(len))==NULL)
                    269:                return(JS_TRUE);
                    270: 
1.1.1.2 ! root      271:        rc=JS_SUSPENDREQUEST(cx);
1.1       root      272:        len=recv(client->socket,buf,len,0);
1.1.1.2 ! root      273:        JS_RESUMEREQUEST(cx, rc);
1.1       root      274: 
                    275:        if(len>0)
                    276:                *rval = STRING_TO_JSVAL(JS_NewStringCopyN(cx,buf,len));
                    277: 
                    278:        return(JS_TRUE);
                    279: }
                    280: 
                    281: static JSBool
                    282: js_readln(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
                    283: {
                    284:        char            ch;
                    285:        char*           buf;
                    286:        int                     i;
                    287:        int32           len=512;
                    288:        BOOL            rd;
                    289:        time_t          start;
                    290:        int32           timeout=30;     /* seconds */
                    291:        JSString*       str;
                    292:        service_client_t* client;
1.1.1.2 ! root      293:        jsrefcount      rc;
1.1       root      294: 
                    295:        if((client=(service_client_t*)JS_GetContextPrivate(cx))==NULL)
                    296:                return(JS_FALSE);
                    297: 
                    298:        if(argc)
                    299:                JS_ValueToInt32(cx,argv[0],&len);
                    300: 
                    301:        if((buf=(char*)alloca(len+1))==NULL) {
                    302:                JS_ReportError(cx,"Error allocating %u bytes",len+1);
                    303:                return(JS_FALSE);
                    304:        }
                    305: 
                    306:        if(argc>1)
                    307:                JS_ValueToInt32(cx,argv[1],(int32*)&timeout);
                    308: 
1.1.1.2 ! root      309:        rc=JS_SUSPENDREQUEST(cx);
1.1       root      310:        start=time(NULL);
                    311:        for(i=0;i<len;) {
                    312: 
                    313:                if(!socket_check(client->socket,&rd,NULL,1000))
                    314:                        break;          /* disconnected */
                    315: 
                    316:                if(!rd) {
                    317:                        if(time(NULL)-start>timeout) {
                    318:                                *rval = JSVAL_NULL;
1.1.1.2 ! root      319:                                JS_RESUMEREQUEST(cx, rc);
1.1       root      320:                                return(JS_TRUE);        /* time-out */
                    321:                        }
                    322:                        continue;       /* no data */
                    323:                }
                    324: 
                    325:                if(recv(client->socket, &ch, 1, 0)!=1)
                    326:                        break;
                    327: 
                    328:                if(ch=='\n' /* && i>=1 */) /* Mar-9-2003: terminate on sole LF */
                    329:                        break;
                    330: 
                    331:                buf[i++]=ch;
                    332:        }
                    333:        if(i>0 && buf[i-1]=='\r')
                    334:                buf[i-1]=0;
                    335:        else
                    336:                buf[i]=0;
1.1.1.2 ! root      337:        JS_RESUMEREQUEST(cx, rc);
1.1       root      338: 
                    339:        str = JS_NewStringCopyZ(cx, buf);
                    340:        if(str==NULL)
                    341:                return(JS_FALSE);
                    342: 
                    343:        *rval = STRING_TO_JSVAL(str);
                    344:                
                    345:        return(JS_TRUE);
                    346: }
                    347: 
                    348: static JSBool
                    349: js_write(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
                    350: {
                    351:        uintN           i;
                    352:        char*           cp;
                    353:        JSString*       str;
                    354:        service_client_t* client;
1.1.1.2 ! root      355:        jsrefcount      rc;
1.1       root      356: 
                    357:        if((client=(service_client_t*)JS_GetContextPrivate(cx))==NULL)
                    358:                return(JS_FALSE);
                    359: 
                    360:        *rval = argv[0];
                    361: 
                    362:        for(i=0; i<argc; i++) {
                    363:                if((str=JS_ValueToString(cx, argv[i]))==NULL)
                    364:                        continue;
                    365:                if((cp=JS_GetStringBytes(str))==NULL)
                    366:                        continue;
1.1.1.2 ! root      367:                rc=JS_SUSPENDREQUEST(cx);
1.1       root      368:                sendsocket(client->socket,cp,strlen(cp));
1.1.1.2 ! root      369:                JS_RESUMEREQUEST(cx, rc);
1.1       root      370:        }
                    371: 
                    372:        return(JS_TRUE);
                    373: }
                    374: 
                    375: static JSBool
                    376: js_writeln(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
                    377: {
                    378:        char*           cp;
                    379:        service_client_t* client;
1.1.1.2 ! root      380:        jsrefcount      rc;
1.1       root      381: 
                    382:        if((client=(service_client_t*)JS_GetContextPrivate(cx))==NULL)
                    383:                return(JS_FALSE);
                    384:        
                    385:        js_write(cx,obj,argc,argv,rval);
                    386: 
1.1.1.2 ! root      387:        rc=JS_SUSPENDREQUEST(cx);
1.1       root      388:        cp="\r\n";
                    389:        sendsocket(client->socket,cp,2);
1.1.1.2 ! root      390:        JS_RESUMEREQUEST(cx, rc);
1.1       root      391: 
                    392:        return(JS_TRUE);
                    393: }
                    394: 
                    395: static JSBool
                    396: js_log(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
                    397: {
                    398:        char            str[512];
                    399:     uintN              i=0;
                    400:        int32           level=LOG_INFO;
                    401:     JSString*  js_str;
                    402:        service_client_t* client;
1.1.1.2 ! root      403:        jsrefcount      rc;
1.1       root      404: 
                    405:        if((client=(service_client_t*)JS_GetContextPrivate(cx))==NULL)
                    406:                return(JS_FALSE);
                    407: 
                    408:     if(startup==NULL || startup->lputs==NULL)
                    409:         return(JS_FALSE);
                    410: 
                    411:        if(argc > 1 && JSVAL_IS_NUMBER(argv[i]))
                    412:                JS_ValueToInt32(cx,argv[i++],&level);
                    413: 
                    414:        str[0]=0;
                    415:     for(;i<argc && strlen(str)<(sizeof(str)/2);i++) {
                    416:                if((js_str=JS_ValueToString(cx, argv[i]))==NULL)
                    417:                    return(JS_FALSE);
                    418:                strncat(str,JS_GetStringBytes(js_str),sizeof(str)/2);
                    419:                strcat(str," ");
                    420:        }
                    421: 
1.1.1.2 ! root      422:        rc=JS_SUSPENDREQUEST(cx);
1.1       root      423:        if(service==NULL)
                    424:                lprintf(level,"%04d %s",client->socket,str);
                    425:        else if(level <= client->service->log_level)
                    426:                lprintf(level,"%04d %s %s",client->socket,client->service->protocol,str);
1.1.1.2 ! root      427:        JS_RESUMEREQUEST(cx, rc);
1.1       root      428: 
                    429:        *rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, str));
                    430: 
                    431:     return(JS_TRUE);
                    432: }
                    433: 
1.1.1.2 ! root      434: static void badlogin(SOCKET sock, char* prot, char* user, char* passwd, char* host, SOCKADDR_IN* addr)
        !           435: {
        !           436:        char reason[128];
        !           437:        ulong count;
        !           438: 
        !           439:        SAFEPRINTF(reason,"%s LOGIN", prot);
        !           440:        count=loginFailure(startup->login_attempt_list, addr, prot, user, passwd);
        !           441:        if(startup->login_attempt_hack_threshold && count>=startup->login_attempt_hack_threshold)
        !           442:                hacklog(&scfg, reason, user, passwd, host, addr);
        !           443:        if(startup->login_attempt_filter_threshold && count>=startup->login_attempt_filter_threshold)
        !           444:                filter_ip(&scfg, prot, "- TOO MANY CONSECUTIVE FAILED LOGIN ATTEMPTS"
        !           445:                        ,host, inet_ntoa(addr->sin_addr), user, /* fname: */NULL);
        !           446: 
        !           447:        mswait(startup->login_attempt_delay);
        !           448: }
        !           449: 
1.1       root      450: static JSBool
                    451: js_login(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
                    452: {
1.1.1.2 ! root      453:        char*           user;
        !           454:        char*           pass;
1.1       root      455:        JSBool          inc_logons=JS_FALSE;
                    456:        jsval           val;
                    457:        service_client_t* client;
1.1.1.2 ! root      458:        jsrefcount      rc;
1.1       root      459: 
                    460:        *rval = BOOLEAN_TO_JSVAL(JS_FALSE);
                    461: 
                    462:        if((client=(service_client_t*)JS_GetContextPrivate(cx))==NULL)
                    463:                return(JS_FALSE);
                    464: 
1.1.1.2 ! root      465:        /* User name or number */
        !           466:        if((user=js_ValueToStringBytes(cx, argv[0], NULL))==NULL) 
1.1       root      467:                return(JS_FALSE);
                    468: 
1.1.1.2 ! root      469:        /* Password */
        !           470:        if((pass=js_ValueToStringBytes(cx, argv[1], NULL))==NULL) 
1.1       root      471:                return(JS_FALSE);
                    472: 
1.1.1.2 ! root      473:        rc=JS_SUSPENDREQUEST(cx);
        !           474:        memset(&client->user,0,sizeof(user_t));
1.1       root      475: 
1.1.1.2 ! root      476:        /* ToDo Deuce: did you mean to do this *before* the above memset(0) ? */
        !           477:        if(client->user.number) {
        !           478:                if(client->subscan!=NULL)
        !           479:                        putmsgptrs(&scfg, client->user.number, client->subscan);
        !           480:        }
        !           481: 
        !           482:        if(isdigit(*user))
        !           483:                client->user.number=atoi(user);
        !           484:        else if(*user)
        !           485:                client->user.number=matchuser(&scfg,user,FALSE);
1.1       root      486: 
1.1.1.2 ! root      487:        if(getuserdat(&scfg,&client->user)!=0) {
1.1       root      488:                lprintf(LOG_NOTICE,"%04d %s !USER NOT FOUND: '%s'"
1.1.1.2 ! root      489:                        ,client->socket,client->service->protocol,user);
        !           490:                badlogin(client->socket, client->service->protocol, user, pass, client->client->host, &client->addr);
        !           491:                JS_RESUMEREQUEST(cx, rc);
1.1       root      492:                return(JS_TRUE);
                    493:        }
                    494: 
1.1.1.2 ! root      495:        if(client->user.misc&(DELETED|INACTIVE)) {
1.1       root      496:                lprintf(LOG_WARNING,"%04d %s !DELETED OR INACTIVE USER #%d: %s"
1.1.1.2 ! root      497:                        ,client->socket,client->service->protocol,client->user.number,user);
        !           498:                JS_RESUMEREQUEST(cx, rc);
1.1       root      499:                return(JS_TRUE);
                    500:        }
                    501: 
                    502:        /* Password */
1.1.1.2 ! root      503:        if(client->user.pass[0] && stricmp(client->user.pass,pass)) { /* Wrong password */
        !           504:                lprintf(LOG_WARNING,"%04d %s !INVALID PASSWORD ATTEMPT FOR USER: %s"
        !           505:                        ,client->socket,client->service->protocol,client->user.alias);
        !           506:                badlogin(client->socket, client->service->protocol, user, pass, client->client->host, &client->addr);
        !           507:                JS_RESUMEREQUEST(cx, rc);
        !           508:                return(JS_TRUE);
1.1       root      509:        }
1.1.1.2 ! root      510:        JS_RESUMEREQUEST(cx, rc);
1.1       root      511: 
                    512:        if(argc>2)
                    513:                JS_ValueToBoolean(cx,argv[2],&inc_logons);
                    514: 
1.1.1.2 ! root      515:        rc=JS_SUSPENDREQUEST(cx);
1.1       root      516:        if(client->client!=NULL) {
1.1.1.2 ! root      517:                SAFECOPY(client->user.note,client->client->addr);
        !           518:                SAFECOPY(client->user.comp,client->client->host);
        !           519:                SAFECOPY(client->user.modem,client->service->protocol);
1.1       root      520:        }
                    521: 
                    522:        if(inc_logons) {
1.1.1.2 ! root      523:                client->user.logons++;
        !           524:                client->user.ltoday++;
1.1       root      525:        }       
                    526: 
1.1.1.2 ! root      527:        putuserdat(&scfg,&client->user);
        !           528:        if(client->subscan==NULL) {
        !           529:                client->subscan=(subscan_t*)malloc(sizeof(subscan_t)*scfg.total_subs);
        !           530:                if(client->subscan==NULL)
        !           531:                        lprintf(LOG_CRIT,"!MALLOC FAILURE");
        !           532:        }
        !           533:        if(client->subscan!=NULL) {
        !           534:                getmsgptrs(&scfg,client->user.number,client->subscan);
        !           535:        }
        !           536: 
        !           537:        JS_RESUMEREQUEST(cx, rc);
1.1       root      538: 
1.1.1.2 ! root      539:        if(!js_CreateUserObjects(cx, obj, &scfg, &client->user, client->client, NULL, client->subscan))
1.1       root      540:                lprintf(LOG_ERR,"%04d %s !JavaScript ERROR creating user objects"
                    541:                        ,client->socket,client->service->protocol);
                    542: 
                    543:        if(client->client!=NULL) {
                    544:                client->client->user=client->user.alias;
                    545:                client_on(client->socket,client->client,TRUE /* update */);
                    546:        }
                    547: 
                    548:        client->logintime=time(NULL);
                    549: 
                    550:        lprintf(LOG_INFO,"%04d %s Logging in %s"
                    551:                ,client->socket,client->service->protocol,client->user.alias);
                    552: 
                    553:        val = BOOLEAN_TO_JSVAL(JS_TRUE);
                    554:        JS_SetProperty(cx, obj, "logged_in", &val);
                    555: 
1.1.1.2 ! root      556:        if(client->user.pass[0])
        !           557:                loginSuccess(startup->login_attempt_list, &client->addr);
        !           558: 
1.1       root      559:        *rval=BOOLEAN_TO_JSVAL(JS_TRUE);
                    560: 
                    561:        return(JS_TRUE);
                    562: }
                    563: 
                    564: static JSBool
                    565: js_logout(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
                    566: {
                    567:        jsval val;
                    568:        service_client_t* client;
1.1.1.2 ! root      569:        jsrefcount      rc;
1.1       root      570: 
                    571:        *rval = BOOLEAN_TO_JSVAL(JS_FALSE);
                    572: 
                    573:        if((client=(service_client_t*)JS_GetContextPrivate(cx))==NULL)
                    574:                return(JS_FALSE);
                    575: 
                    576:        if(client->user.number<1)       /* Not logged in */
                    577:                return(JS_TRUE);
                    578: 
1.1.1.2 ! root      579:        rc=JS_SUSPENDREQUEST(cx);
        !           580:        if(!logoutuserdat(&scfg,&client->user,time(NULL),client->logintime))
        !           581:                lprintf(LOG_ERR,"%04d !ERROR in logoutuserdat",client->socket);
1.1       root      582: 
                    583:        lprintf(LOG_INFO,"%04d %s Logging out %s"
                    584:                ,client->socket,client->service->protocol,client->user.alias);
                    585: 
                    586:        memset(&client->user,0,sizeof(client->user));
1.1.1.2 ! root      587:        JS_RESUMEREQUEST(cx, rc);
1.1       root      588: 
                    589:        val = BOOLEAN_TO_JSVAL(JS_FALSE);
                    590:        JS_SetProperty(cx, obj, "logged_in", &val);
                    591: 
                    592:        *rval=BOOLEAN_TO_JSVAL(JS_TRUE);
                    593: 
                    594:        return(JS_TRUE);
                    595: }
                    596: 
                    597: static JSFunctionSpec js_global_functions[] = {
                    598:        {"read",                        js_read,                        0},             /* read from client socket */
                    599:        {"readln",                      js_readln,                      0},             /* read line from client socket */
                    600:        {"write",                       js_write,                       0},             /* write to client socket */
                    601:        {"writeln",                     js_writeln,                     0},             /* write line to client socket */
                    602:        {"print",                       js_writeln,                     0},             /* write line to client socket */
                    603:        {"log",                         js_log,                         0},             /* Log a string */
                    604:        {"login",                       js_login,                       2},             /* Login specified username and password */
                    605:        {"logout",                      js_logout,                      0},             /* Logout user */
                    606:     {0}
                    607: };
                    608: 
                    609: static void
                    610: js_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
                    611: {
                    612:        char    line[64];
                    613:        char    file[MAX_PATH+1];
                    614:        char*   prot="???";
                    615:        SOCKET  sock=0;
                    616:        char*   warning;
                    617:        service_client_t* client;
1.1.1.2 ! root      618:        jsrefcount      rc;
        !           619:        int             log_level;
1.1       root      620: 
                    621:        if((client=(service_client_t*)JS_GetContextPrivate(cx))!=NULL) {
                    622:                prot=client->service->protocol;
                    623:                sock=client->socket;
                    624:        }
                    625: 
                    626:        if(report==NULL) {
                    627:                lprintf(LOG_ERR,"%04d %s !JavaScript: %s", sock,prot,message);
                    628:                return;
                    629:     }
                    630: 
                    631:        if(report->filename)
                    632:                sprintf(file," %s",report->filename);
                    633:        else
                    634:                file[0]=0;
                    635: 
                    636:        if(report->lineno)
                    637:                sprintf(line," line %d",report->lineno);
                    638:        else
                    639:                line[0]=0;
                    640: 
                    641:        if(JSREPORT_IS_WARNING(report->flags)) {
                    642:                if(JSREPORT_IS_STRICT(report->flags))
                    643:                        warning="strict warning";
                    644:                else
                    645:                        warning="warning";
1.1.1.2 ! root      646:                log_level=LOG_WARNING;
        !           647:        } else {
        !           648:                log_level=LOG_ERR;
1.1       root      649:                warning="";
                    650:        }
                    651: 
1.1.1.2 ! root      652:        rc=JS_SUSPENDREQUEST(cx);
        !           653:        lprintf(log_level,"%04d %s !JavaScript %s%s%s: %s",sock,prot,warning,file,line,message);
        !           654:        JS_RESUMEREQUEST(cx, rc);
1.1       root      655: }
                    656: 
                    657: /* Server Methods */
                    658: 
                    659: static JSBool
                    660: js_client_add(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
                    661: {
                    662:        client_t        client;
                    663:        SOCKET          sock=INVALID_SOCKET;
                    664:        socklen_t       addr_len;
                    665:        SOCKADDR_IN     addr;
                    666:        service_client_t* service_client;
1.1.1.2 ! root      667:        jsrefcount      rc;
1.1       root      668: 
                    669:        if((service_client=(service_client_t*)JS_GetContextPrivate(cx))==NULL)
                    670:                return(JS_FALSE);
                    671: 
                    672:        service_client->service->clients++;
                    673:        update_clients();
                    674:        service_client->service->served++;
                    675:        served++;
                    676:        memset(&client,0,sizeof(client));
                    677:        client.size=sizeof(client);
                    678:        client.protocol=service_client->service->protocol;
                    679:        client.time=time(NULL);
                    680:        client.user="<unknown>";
                    681:        SAFECOPY(client.host,client.user);
                    682:        
                    683:        sock=js_socket(cx,argv[0]);
                    684:        
                    685:        addr_len = sizeof(addr);
                    686:        if(getpeername(sock, (struct sockaddr *)&addr, &addr_len)==0) {
                    687:                SAFECOPY(client.addr,inet_ntoa(addr.sin_addr));
                    688:                client.port=ntohs(addr.sin_port);
                    689:        }
                    690: 
                    691:        if(argc>1)
                    692:                client.user=JS_GetStringBytes(JS_ValueToString(cx,argv[1]));
                    693: 
                    694:        if(argc>2)
                    695:                SAFECOPY(client.host,JS_GetStringBytes(JS_ValueToString(cx,argv[2])));
                    696: 
1.1.1.2 ! root      697:        rc=JS_SUSPENDREQUEST(cx);
1.1       root      698:        client_on(sock, &client, /* update? */ FALSE);
                    699: #ifdef _DEBUG
                    700:        lprintf(LOG_DEBUG,"%04d %s client_add(%04u,%s,%s)"
                    701:                ,service_client->service->socket,service_client->service->protocol
                    702:                ,sock,client.user,client.host);
                    703: #endif
1.1.1.2 ! root      704:        JS_RESUMEREQUEST(cx, rc);
1.1       root      705:        return(JS_TRUE);
                    706: }
                    707: 
                    708: static JSBool
                    709: js_client_update(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
                    710: {
                    711:        client_t        client;
                    712:        SOCKET          sock=INVALID_SOCKET;
                    713:        socklen_t       addr_len;
                    714:        SOCKADDR_IN     addr;
                    715:        service_client_t* service_client;
1.1.1.2 ! root      716:        jsrefcount      rc;
1.1       root      717: 
                    718:        if((service_client=(service_client_t*)JS_GetContextPrivate(cx))==NULL)
                    719:                return(JS_FALSE);
                    720: 
                    721:        memset(&client,0,sizeof(client));
                    722:        client.size=sizeof(client);
                    723:        client.protocol=service_client->service->protocol;
                    724:        client.user="<unknown>";
                    725:        SAFECOPY(client.host,client.user);
                    726: 
                    727:        sock=js_socket(cx,argv[0]);
                    728: 
                    729:        addr_len = sizeof(addr);
                    730:        if(getpeername(sock, (struct sockaddr *)&addr, &addr_len)==0) {
                    731:                SAFECOPY(client.addr,inet_ntoa(addr.sin_addr));
                    732:                client.port=ntohs(addr.sin_port);
                    733:        }
                    734: 
                    735:        if(argc>1)
                    736:                client.user=JS_GetStringBytes(JS_ValueToString(cx,argv[1]));
                    737: 
                    738:        if(argc>2)
                    739:                SAFECOPY(client.host,JS_GetStringBytes(JS_ValueToString(cx,argv[2])));
                    740: 
1.1.1.2 ! root      741:        rc=JS_SUSPENDREQUEST(cx);
1.1       root      742:        client_on(sock, &client, /* update? */ TRUE);
                    743: #ifdef _DEBUG
                    744:        lprintf(LOG_DEBUG,"%04d %s client_update(%04u,%s,%s)"
                    745:                ,service_client->service->socket,service_client->service->protocol
                    746:                ,sock,client.user,client.host);
                    747: #endif
1.1.1.2 ! root      748:        JS_RESUMEREQUEST(cx, rc);
1.1       root      749:        return(JS_TRUE);
                    750: }
                    751: 
                    752: 
                    753: static JSBool
                    754: js_client_remove(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
                    755: {
                    756:        SOCKET  sock=INVALID_SOCKET;
                    757:        service_client_t* service_client;
1.1.1.2 ! root      758:        jsrefcount      rc;
1.1       root      759: 
                    760:        if((service_client=(service_client_t*)JS_GetContextPrivate(cx))==NULL)
                    761:                return(JS_FALSE);
                    762: 
                    763:        sock=js_socket(cx,argv[0]);
                    764: 
                    765:        if(sock!=INVALID_SOCKET) {
                    766: 
1.1.1.2 ! root      767:                rc=JS_SUSPENDREQUEST(cx);
1.1       root      768:                client_off(sock);
                    769: 
                    770:                if(service_client->service->clients==0)
                    771:                        lprintf(LOG_WARNING,"%04d %s !client_remove() called with 0 service clients"
                    772:                                ,service_client->service->socket, service_client->service->protocol);
                    773:                else {
                    774:                        service_client->service->clients--;
                    775:                        update_clients();
                    776:                }
1.1.1.2 ! root      777:                JS_RESUMEREQUEST(cx, rc);
1.1       root      778:        }
                    779: 
                    780: #ifdef _DEBUG
                    781:        lprintf(LOG_DEBUG,"%04d %s client_remove(%04u)"
                    782:                ,service_client->service->socket, service_client->service->protocol, sock);
                    783: #endif
                    784:        return(JS_TRUE);
                    785: }
                    786: 
                    787: static JSContext* 
                    788: js_initcx(JSRuntime* js_runtime, SOCKET sock, service_client_t* service_client, JSObject** glob)
                    789: {
                    790:        ulong           stack_frame;
                    791:        JSContext*      js_cx;
                    792:        JSObject*       js_glob;
                    793:        JSObject*       server;
                    794:        BOOL            success=FALSE;
                    795: 
                    796:     if((js_cx = JS_NewContext(js_runtime, service_client->service->js.cx_stack))==NULL)
                    797:                return(NULL);
1.1.1.2 ! root      798:        JS_BEGINREQUEST(js_cx);
1.1       root      799: 
                    800:     JS_SetErrorReporter(js_cx, js_ErrorReporter);
                    801: 
1.1.1.2 ! root      802:        /* ToDo: call js_CreateCommonObjects() instead */
        !           803: 
1.1       root      804:        do {
                    805: 
                    806:                JS_SetContextPrivate(js_cx, service_client);
                    807: 
1.1.1.2 ! root      808:                if((js_glob=js_CreateGlobalObject(js_cx, &scfg, NULL, &service_client->service->js))==NULL) 
1.1       root      809:                        break;
                    810: 
                    811:                if (!JS_DefineFunctions(js_cx, js_glob, js_global_functions))
                    812:                        break;
                    813: 
                    814:                /* Internal JS Object */
1.1.1.2 ! root      815:                if(js_CreateInternalJsObject(js_cx, js_glob, &service_client->branch, &service_client->service->js)==NULL)
1.1       root      816:                        break;
                    817: 
                    818:                /* Client Object */
                    819:                if(service_client->client!=NULL)
                    820:                        if(js_CreateClientObject(js_cx, js_glob, "client", service_client->client, sock)==NULL)
                    821:                                break;
                    822: 
                    823:                /* User Class */
                    824:                if(js_CreateUserClass(js_cx, js_glob, &scfg)==NULL) 
                    825:                        break;
                    826: 
                    827:                /* Socket Class */
                    828:                if(js_CreateSocketClass(js_cx, js_glob)==NULL)
                    829:                        break;
                    830: 
                    831:                /* MsgBase Class */
                    832:                if(js_CreateMsgBaseClass(js_cx, js_glob, &scfg)==NULL)
                    833:                        break;
                    834: 
                    835:                /* File Class */
                    836:                if(js_CreateFileClass(js_cx, js_glob)==NULL)
                    837:                        break;
                    838: 
1.1.1.2 ! root      839:                /* Queue Class */
        !           840:                if(js_CreateQueueClass(js_cx, js_glob)==NULL)
        !           841:                        break;
        !           842: 
        !           843:                /* COM Class */
        !           844:                if(js_CreateCOMClass(js_cx, js_glob)==NULL)
        !           845:                        break;
        !           846: 
1.1       root      847:                /* user-specific objects */
1.1.1.2 ! root      848:                if(!js_CreateUserObjects(js_cx, js_glob, &scfg, /*user: */NULL, service_client->client, NULL, service_client->subscan)) 
1.1       root      849:                        break;
                    850: 
                    851:                if(js_CreateSystemObject(js_cx, js_glob, &scfg, uptime, startup->host_name, SOCKLIB_DESC)==NULL) 
                    852:                        break;
                    853: #if 0          
                    854:                char            ver[256];
                    855:                JSString*       js_str;
                    856:                jsval           val;
                    857: 
                    858:                /* server object */
                    859:                if((server=JS_DefineObject(js_cx, js_glob, "server", &js_server_class
                    860:                        ,NULL,JSPROP_ENUMERATE|JSPROP_READONLY))==NULL)
                    861:                        break;
                    862: 
                    863:                if(!JS_DefineProperties(js_cx, server, js_server_properties))
                    864:                        break;
                    865: 
                    866:                sprintf(ver,"Synchronet Services %s",revision);
                    867:                if((js_str=JS_NewStringCopyZ(js_cx, ver))==NULL)
                    868:                        break;
                    869:                val = STRING_TO_JSVAL(js_str);
                    870:                if(!JS_SetProperty(js_cx, server, "version", &val))
                    871:                        break;
                    872: 
                    873:                if((js_str=JS_NewStringCopyZ(js_cx, services_ver()))==NULL)
                    874:                        break;
                    875:                val = STRING_TO_JSVAL(js_str);
                    876:                if(!JS_SetProperty(js_cx, server, "version_detail", &val))
                    877:                        break;
                    878: 
                    879: #else
                    880: 
                    881:                if(service_client->service->js_server_props.version[0]==0) {
                    882:                        SAFEPRINTF(service_client->service->js_server_props.version
                    883:                                ,"Synchronet Services %s",revision);
                    884:                        service_client->service->js_server_props.version_detail=
                    885:                                services_ver();
                    886:                        service_client->service->js_server_props.clients=
                    887:                                &service_client->service->clients;
                    888:                        service_client->service->js_server_props.interface_addr=
                    889:                                &service_client->service->interface_addr;
                    890:                        service_client->service->js_server_props.options=
                    891:                                &service_client->service->options;
                    892:                }
                    893: 
                    894:                if((server=js_CreateServerObject(js_cx,js_glob
                    895:                        ,&service_client->service->js_server_props))==NULL)
                    896:                        break;
                    897: #endif
                    898: 
                    899:                if(service_client->client==NULL)        /* static service */
                    900:                        if(js_CreateSocketObject(js_cx, server, "socket", service_client->socket)==NULL)
                    901:                                break;
                    902: 
                    903:                JS_DefineFunction(js_cx, server, "client_add"   , js_client_add,        1, 0);
                    904:                JS_DefineFunction(js_cx, server, "client_update", js_client_update,     1, 0);
                    905:                JS_DefineFunction(js_cx, server, "client_remove", js_client_remove, 1, 0);
                    906: 
                    907: 
                    908:                if(glob!=NULL)
                    909:                        *glob=js_glob;
                    910: 
                    911:                if(service_client->service->js.thread_stack) {
                    912: #if JS_STACK_GROWTH_DIRECTION > 0
                    913:                        stack_frame=((ulong)&stack_frame)+service_client->service->js.thread_stack;
                    914: #else
                    915:                        stack_frame=((ulong)&stack_frame)-service_client->service->js.thread_stack;
                    916: #endif
                    917:                        JS_SetThreadStackLimit(js_cx, stack_frame);
                    918:                }
                    919: 
                    920:                success=TRUE;
                    921: 
                    922:        } while(0);
                    923: 
                    924: 
                    925:        if(!success) {
1.1.1.2 ! root      926:                JS_ENDREQUEST(js_cx);
1.1       root      927:                JS_DestroyContext(js_cx);
                    928:                return(NULL);
                    929:        }
                    930: 
                    931:        return(js_cx);
                    932: }
                    933: 
                    934: static JSBool
                    935: js_BranchCallback(JSContext *cx, JSScript *script)
                    936: {
                    937:        service_client_t* client;
                    938: 
                    939:        if((client=(service_client_t*)JS_GetContextPrivate(cx))==NULL)
                    940:                return(JS_FALSE);
                    941: 
                    942:        /* Terminated? */ 
1.1.1.2 ! root      943:        if(client->branch.auto_terminate && terminated) {
        !           944:                JS_ReportWarning(cx,"Terminated");
1.1       root      945:                client->branch.counter=0;
                    946:                return(JS_FALSE);
                    947:        }
                    948: 
                    949:        return js_CommonBranchCallback(cx,&client->branch);
                    950: }
                    951: 
1.1.1.2 ! root      952: #ifdef USE_JS_OPERATION_CALLBACK
        !           953: static JSBool
        !           954: js_OperationCallback(JSContext *cx)
        !           955: {
        !           956:        JSBool  ret;
        !           957: 
        !           958:        JS_SetOperationCallback(cx, NULL);
        !           959:        ret=js_BranchCallback(cx, NULL);
        !           960:        JS_SetOperationCallback(cx, js_OperationCallback);
        !           961:        return ret;
        !           962: }
        !           963: #endif
        !           964: 
1.1       root      965: static void js_init_args(JSContext* js_cx, JSObject* js_obj, const char* cmdline)
                    966: {
                    967:        char                                    argbuf[MAX_PATH+1];
                    968:        char*                                   p;
                    969:        char*                                   args;
                    970:        int                                             argc=0;
                    971:        JSString*                               arg_str;
                    972:        JSObject*                               argv;
                    973:        jsval                                   val;
                    974: 
                    975:        argv=JS_NewArrayObject(js_cx, 0, NULL);
                    976:        JS_DefineProperty(js_cx, js_obj, "argv", OBJECT_TO_JSVAL(argv)
                    977:                ,NULL,NULL,JSPROP_READONLY|JSPROP_ENUMERATE);
                    978: 
                    979:        p=(char*)cmdline;
                    980:        while(*p && *p>' ') p++;        /* find end of filename */
                    981:        while(*p && *p<=' ') p++;       /* find first arg */
                    982:        SAFECOPY(argbuf,p);
                    983: 
                    984:        args=argbuf;
                    985:        while(*args && argv!=NULL) {
                    986:                p=strchr(args,' ');
                    987:                if(p!=NULL)
                    988:                        *p=0;
                    989:                while(*args && *args<=' ') args++; /* Skip spaces */
                    990:                arg_str = JS_NewStringCopyZ(js_cx, args);
                    991:                if(arg_str==NULL)
                    992:                        break;
                    993:                val=STRING_TO_JSVAL(arg_str);
                    994:                if(!JS_SetElement(js_cx, argv, argc, &val))
                    995:                        break;
                    996:                argc++;
                    997:                if(p==NULL)     /* last arg */
                    998:                        break;
                    999:                args+=(strlen(args)+1);
                   1000:        }
                   1001:        JS_DefineProperty(js_cx, js_obj, "argc", INT_TO_JSVAL(argc)
                   1002:                ,NULL,NULL,JSPROP_READONLY|JSPROP_ENUMERATE);
                   1003: }
                   1004: 
                   1005: static void js_service_thread(void* arg)
                   1006: {
                   1007:        char*                                   host_name;
                   1008:        HOSTENT*                                host;
                   1009:        SOCKET                                  socket;
                   1010:        client_t                                client;
                   1011:        service_t*                              service;
                   1012:        service_client_t                service_client;
1.1.1.2 ! root     1013:        ulong                                   login_attempts;
1.1       root     1014:        /* JavaScript-specific */
                   1015:        char                                    spath[MAX_PATH+1];
                   1016:        char                                    fname[MAX_PATH+1];
                   1017:        JSString*                               datagram;
                   1018:        JSObject*                               js_glob;
                   1019:        JSScript*                               js_script;
                   1020:        JSRuntime*                              js_runtime;
                   1021:        JSContext*                              js_cx;
                   1022:        jsval                                   val;
                   1023:        jsval                                   rval;
                   1024: 
                   1025:        /* Copy service_client arg */
                   1026:        service_client=*(service_client_t*)arg;
                   1027:        /* Free original */
                   1028:        free(arg);
                   1029: 
                   1030:        socket=service_client.socket;
                   1031:        service=service_client.service;
                   1032: 
                   1033:        lprintf(LOG_DEBUG,"%04d %s JavaScript service thread started", socket, service->protocol);
                   1034: 
1.1.1.2 ! root     1035:        SetThreadName("JS Service");
1.1       root     1036:        thread_up(TRUE /* setuid */);
                   1037: 
                   1038:        /* Host name lookup and filtering */
                   1039:        if(service->options&BBS_OPT_NO_HOST_LOOKUP 
                   1040:                || startup->options&BBS_OPT_NO_HOST_LOOKUP)
                   1041:                host=NULL;
                   1042:        else
                   1043:                host=gethostbyaddr((char *)&service_client.addr.sin_addr
                   1044:                        ,sizeof(service_client.addr.sin_addr),AF_INET);
                   1045: 
                   1046:        if(host!=NULL && host->h_name!=NULL)
                   1047:                host_name=host->h_name;
                   1048:        else
                   1049:                host_name="<no name>";
                   1050: 
                   1051:        if(!(service->options&BBS_OPT_NO_HOST_LOOKUP)
                   1052:                && !(startup->options&BBS_OPT_NO_HOST_LOOKUP)) {
                   1053:                lprintf(LOG_INFO,"%04d %s Hostname: %s"
                   1054:                        ,socket, service->protocol, host_name);
1.1.1.2 ! root     1055: #if    0 /* gethostbyaddr() is apparently not (always) thread-safe
        !          1056:             and getnameinfo() doesn't return alias information */
1.1       root     1057:                for(i=0;host!=NULL && host->h_aliases!=NULL 
                   1058:                        && host->h_aliases[i]!=NULL;i++)
                   1059:                        lprintf(LOG_INFO,"%04d %s HostAlias: %s"
                   1060:                                ,socket, service->protocol, host->h_aliases[i]);
1.1.1.2 ! root     1061: #endif
1.1       root     1062:        }
                   1063: 
                   1064:        if(trashcan(&scfg,host_name,"host")) {
                   1065:                lprintf(LOG_NOTICE,"%04d !%s CLIENT BLOCKED in host.can: %s"
                   1066:                        ,socket, service->protocol, host_name);
                   1067:                close_socket(socket);
                   1068:                if(service->clients)
                   1069:                        service->clients--;
                   1070:                thread_down();
                   1071:                return;
                   1072:        }
                   1073: 
                   1074: 
                   1075: #if 0  /* Need to export from SBBS.DLL */
                   1076:        identity=NULL;
                   1077:        if(service->options&BBS_OPT_GET_IDENT 
                   1078:                && startup->options&BBS_OPT_GET_IDENT) {
                   1079:                identify(&service_client.addr, service->port, str, sizeof(str)-1);
                   1080:                identity=strrchr(str,':');
                   1081:                if(identity!=NULL) {
                   1082:                        identity++;     /* skip colon */
                   1083:                        while(*identity && *identity<=SP) /* point to user name */
                   1084:                                identity++;
                   1085:                        lprintf(LOG_INFO,"%04d Identity: %s",socket, identity);
                   1086:                }
                   1087:        }
                   1088: #endif
                   1089: 
                   1090:        client.size=sizeof(client);
                   1091:        client.time=time(NULL);
                   1092:        SAFECOPY(client.addr,inet_ntoa(service_client.addr.sin_addr));
                   1093:        SAFECOPY(client.host,host_name);
                   1094:        client.port=ntohs(service_client.addr.sin_port);
                   1095:        client.protocol=service->protocol;
                   1096:        client.user="<unknown>";
                   1097:        service_client.client=&client;
                   1098: 
                   1099:        /* Initialize client display */
                   1100:        client_on(socket,&client,FALSE /* update */);
                   1101: 
1.1.1.2 ! root     1102:        if((js_runtime=jsrt_GetNew(service->js.max_bytes, 5000, __FILE__, __LINE__))==NULL
1.1       root     1103:                || (js_cx=js_initcx(js_runtime,socket,&service_client,&js_glob))==NULL) {
                   1104:                lprintf(LOG_ERR,"%04d !%s ERROR initializing JavaScript context"
                   1105:                        ,socket,service->protocol);
                   1106:                client_off(socket);
                   1107:                close_socket(socket);
                   1108:                if(service->clients)
                   1109:                        service->clients--;
                   1110:                thread_down();
                   1111:                return;
                   1112:        }
                   1113: 
                   1114:        update_clients();
                   1115: 
1.1.1.2 ! root     1116:        if(startup->login_attempt_throttle
        !          1117:                && (login_attempts=loginAttempts(startup->login_attempt_list, &service_client.addr)) > 1) {
        !          1118:                lprintf(LOG_DEBUG,"%04d %s Throttling suspicious connection from: %s (%u login attempts)"
        !          1119:                        ,socket, service->protocol, inet_ntoa(service_client.addr.sin_addr), login_attempts);
        !          1120:                mswait(login_attempts*startup->login_attempt_throttle);
        !          1121:        }
        !          1122: 
1.1       root     1123:        /* RUN SCRIPT */
                   1124:        SAFECOPY(fname,service->cmd);
                   1125:        truncstr(fname," ");
                   1126:        sprintf(spath,"%s%s",scfg.mods_dir,fname);
                   1127:        if(scfg.mods_dir[0]==0 || !fexist(spath))
                   1128:                sprintf(spath,"%s%s",scfg.exec_dir,fname);
                   1129: 
                   1130:        js_init_args(js_cx, js_glob, service->cmd);
                   1131: 
                   1132:        val = BOOLEAN_TO_JSVAL(JS_FALSE);
                   1133:        JS_SetProperty(js_cx, js_glob, "logged_in", &val);
                   1134: 
                   1135:        if(service->options&SERVICE_OPT_UDP 
                   1136:                && service_client.udp_buf != NULL
                   1137:                && service_client.udp_len > 0) {
                   1138:                datagram = JS_NewStringCopyN(js_cx, service_client.udp_buf, service_client.udp_len);
                   1139:                if(datagram==NULL)
                   1140:                        val=JSVAL_VOID;
                   1141:                else
                   1142:                        val = STRING_TO_JSVAL(datagram);
                   1143:        } else
                   1144:                val = JSVAL_VOID;
                   1145:        JS_SetProperty(js_cx, js_glob, "datagram", &val);
                   1146:        FREE_AND_NULL(service_client.udp_buf);
                   1147: 
                   1148:        JS_ClearPendingException(js_cx);
                   1149: 
                   1150:        js_script=JS_CompileFile(js_cx, js_glob, spath);
                   1151: 
                   1152:        if(js_script==NULL) 
                   1153:                lprintf(LOG_ERR,"%04d !JavaScript FAILED to compile script (%s)",socket,spath);
                   1154:        else  {
1.1.1.2 ! root     1155:                js_PrepareToExecute(js_cx, js_glob, spath, /* startup_dir */NULL);
        !          1156: #ifdef USE_JS_OPERATION_CALLBACK
        !          1157:                JS_SetOperationCallback(js_cx, js_OperationCallback);
        !          1158: #else
1.1       root     1159:                JS_SetBranchCallback(js_cx, js_BranchCallback);
1.1.1.2 ! root     1160: #endif
1.1       root     1161:                JS_ExecuteScript(js_cx, js_glob, js_script, &rval);
                   1162:                js_EvalOnExit(js_cx, js_glob, &service_client.branch);
                   1163:                JS_DestroyScript(js_cx, js_script);
                   1164:        }
1.1.1.2 ! root     1165:        JS_ENDREQUEST(js_cx);
1.1       root     1166:        JS_DestroyContext(js_cx);       /* Free Context */
                   1167: 
1.1.1.2 ! root     1168:        jsrt_Release(js_runtime);
1.1       root     1169: 
                   1170:        if(service_client.user.number) {
1.1.1.2 ! root     1171:                if(service_client.subscan!=NULL)
        !          1172:                        putmsgptrs(&scfg, service_client.user.number, service_client.subscan);
1.1       root     1173:                lprintf(LOG_INFO,"%04d %s Logging out %s"
                   1174:                        ,socket, service->protocol, service_client.user.alias);
                   1175:                logoutuserdat(&scfg,&service_client.user,time(NULL),service_client.logintime);
                   1176:        }
1.1.1.2 ! root     1177:        FREE_AND_NULL(service_client.subscan);
1.1       root     1178: 
                   1179:        if(service->clients)
                   1180:                service->clients--;
                   1181:        update_clients();
                   1182: 
                   1183: #ifdef _WIN32
                   1184:        if(startup->hangup_sound[0] && !(startup->options&BBS_OPT_MUTE)
                   1185:                && !(service->options&BBS_OPT_MUTE))
                   1186:                PlaySound(startup->hangup_sound, NULL, SND_ASYNC|SND_FILENAME);
                   1187: #endif
                   1188: 
                   1189:        thread_down();
1.1.1.2 ! root     1190:        lprintf(LOG_INFO,"%04d %s service thread terminated (%u clients remain, %d total, %lu served)"
        !          1191:                ,socket, service->protocol, service->clients, active_clients(), service->served);
1.1       root     1192: 
                   1193:        client_off(socket);
                   1194:        close_socket(socket);
                   1195: }
                   1196: 
                   1197: static void js_static_service_thread(void* arg)
                   1198: {
                   1199:        char                                    spath[MAX_PATH+1];
                   1200:        char                                    fname[MAX_PATH+1];
                   1201:        service_t*                              service;
                   1202:        service_client_t                service_client;
                   1203:        SOCKET                                  socket;
                   1204:        /* JavaScript-specific */
                   1205:        JSObject*                               js_glob;
                   1206:        JSScript*                               js_script;
                   1207:        JSRuntime*                              js_runtime;
                   1208:        JSContext*                              js_cx;
                   1209:        jsval                                   val;
                   1210:        jsval                                   rval;
                   1211: 
                   1212:        /* Copy service_client arg */
                   1213:        service=(service_t*)arg;
                   1214: 
                   1215:        service->running=TRUE;
                   1216:        socket = service->socket;
                   1217: 
                   1218:        lprintf(LOG_DEBUG,"%04d %s static JavaScript service thread started", service->socket, service->protocol);
                   1219: 
1.1.1.2 ! root     1220:        SetThreadName("JS Static Service");
1.1       root     1221:        thread_up(TRUE /* setuid */);
                   1222: 
                   1223:        memset(&service_client,0,sizeof(service_client));
                   1224:        service_client.socket = service->socket;
                   1225:        service_client.service = service;
                   1226:        service_client.branch.limit = service->js.branch_limit;
                   1227:        service_client.branch.gc_interval = service->js.gc_interval;
                   1228:        service_client.branch.yield_interval = service->js.yield_interval;
                   1229:        service_client.branch.terminated = &service->terminated;
                   1230:        service_client.branch.auto_terminate = TRUE;
                   1231: 
1.1.1.2 ! root     1232:        if((js_runtime=jsrt_GetNew(service->js.max_bytes, 5000, __FILE__, __LINE__))==NULL) {
1.1       root     1233:                lprintf(LOG_ERR,"%04d !%s ERROR initializing JavaScript runtime"
                   1234:                        ,service->socket,service->protocol);
                   1235:                close_socket(service->socket);
                   1236:                service->socket=INVALID_SOCKET;
                   1237:                thread_down();
                   1238:                return;
                   1239:        }
                   1240: 
                   1241:        SAFECOPY(fname,service->cmd);
                   1242:        truncstr(fname," ");
                   1243:        sprintf(spath,"%s%s",scfg.mods_dir,fname);
                   1244:        if(scfg.mods_dir[0]==0 || !fexist(spath))
                   1245:                sprintf(spath,"%s%s",scfg.exec_dir,fname);
                   1246: 
                   1247:        do {
                   1248:                if((js_cx=js_initcx(js_runtime,service->socket,&service_client,&js_glob))==NULL) {
                   1249:                        lprintf(LOG_ERR,"%04d !%s ERROR initializing JavaScript context"
                   1250:                                ,service->socket,service->protocol);
                   1251:                        break;
                   1252:                }
                   1253: 
                   1254:                js_init_args(js_cx, js_glob, service->cmd);
                   1255: 
                   1256:                val = BOOLEAN_TO_JSVAL(JS_FALSE);
                   1257:                JS_SetProperty(js_cx, js_glob, "logged_in", &val);
                   1258: 
1.1.1.2 ! root     1259: #ifdef USE_JS_OPERATION_CALLBACK
        !          1260:                JS_SetOperationCallback(js_cx, js_OperationCallback);
        !          1261: #else
1.1       root     1262:                JS_SetBranchCallback(js_cx, js_BranchCallback);
1.1.1.2 ! root     1263: #endif
1.1       root     1264:        
                   1265:                if((js_script=JS_CompileFile(js_cx, js_glob, spath))==NULL)  {
                   1266:                        lprintf(LOG_ERR,"%04d !JavaScript FAILED to compile script (%s)",service->socket,spath);
                   1267:                        break;
                   1268:                }
                   1269: 
1.1.1.2 ! root     1270:                js_PrepareToExecute(js_cx, js_glob, spath, /* startup_dir */NULL);
1.1       root     1271:                JS_ExecuteScript(js_cx, js_glob, js_script, &rval);
                   1272:                js_EvalOnExit(js_cx, js_glob, &service_client.branch);
                   1273:                JS_DestroyScript(js_cx, js_script);
                   1274: 
1.1.1.2 ! root     1275:                JS_ENDREQUEST(js_cx);
1.1       root     1276:                JS_DestroyContext(js_cx);       /* Free Context */
                   1277:                js_cx=NULL;
                   1278:        } while(!service->terminated && service->options&SERVICE_OPT_STATIC_LOOP);
                   1279: 
1.1.1.2 ! root     1280:        if(js_cx!=NULL) {
        !          1281:                JS_ENDREQUEST(js_cx);
1.1       root     1282:                JS_DestroyContext(js_cx);       /* Free Context */
1.1.1.2 ! root     1283:        }
1.1       root     1284: 
1.1.1.2 ! root     1285:        jsrt_Release(js_runtime);
1.1       root     1286: 
                   1287:        if(service->clients) {
                   1288:                lprintf(LOG_WARNING,"%04d %s !service terminating with %u active clients"
                   1289:                        ,socket, service->protocol, service->clients);
                   1290:                service->clients=0;
                   1291:        }
                   1292: 
                   1293:        thread_down();
1.1.1.2 ! root     1294:        lprintf(LOG_INFO,"%04d %s service thread terminated (%lu clients served)"
1.1       root     1295:                ,socket, service->protocol, service->served);
                   1296: 
                   1297:        close_socket(service->socket);
                   1298:        service->socket=INVALID_SOCKET;
                   1299: 
                   1300:        service->running=FALSE;
                   1301: }
                   1302: 
                   1303: static void native_static_service_thread(void* arg)
                   1304: {
                   1305:        char                                    cmd[MAX_PATH];
                   1306:        char                                    fullcmd[MAX_PATH*2];
                   1307:        SOCKET                                  socket;
                   1308:        SOCKET                                  socket_dup;
                   1309:        service_t*                              service;
                   1310: 
                   1311:        service = (service_t*)arg;
                   1312: 
                   1313:        service->running=TRUE;
                   1314:        socket = service->socket;
                   1315: 
                   1316:        lprintf(LOG_DEBUG,"%04d %s static service thread started", socket, service->protocol);
                   1317: 
1.1.1.2 ! root     1318:        SetThreadName("Static Service");
1.1       root     1319:        thread_up(TRUE /* setuid */);
                   1320: 
                   1321: #ifdef _WIN32
                   1322:        if(!DuplicateHandle(GetCurrentProcess(),
                   1323:                (HANDLE)socket,
                   1324:                GetCurrentProcess(),
                   1325:                (HANDLE*)&socket_dup,
                   1326:                0,
                   1327:                TRUE, /* Inheritable */
                   1328:                DUPLICATE_SAME_ACCESS)) {
                   1329:                lprintf(LOG_ERR,"%04d !%s ERROR %d duplicating socket descriptor"
                   1330:                        ,socket,service->protocol,GetLastError());
                   1331:                close_socket(service->socket);
                   1332:                service->socket=INVALID_SOCKET;
                   1333:                thread_down();
                   1334:                return;
                   1335:        }
                   1336: #else
                   1337:        socket_dup = dup(service->socket);
                   1338: #endif
                   1339: 
                   1340:        /* RUN SCRIPT */
                   1341:        if(strpbrk(service->cmd,"/\\")==NULL)
                   1342:                sprintf(cmd,"%s%s",scfg.exec_dir,service->cmd);
                   1343:        else
                   1344:                strcpy(cmd,service->cmd);
                   1345:        sprintf(fullcmd,cmd,socket_dup);
                   1346:        
                   1347:        do {
                   1348:                system(fullcmd);
                   1349:        } while(!service->terminated && service->options&SERVICE_OPT_STATIC_LOOP);
                   1350: 
                   1351:        thread_down();
1.1.1.2 ! root     1352:        lprintf(LOG_INFO,"%04d %s service thread terminated (%lu clients served)"
1.1       root     1353:                ,socket, service->protocol, service->served);
                   1354: 
                   1355:        close_socket(service->socket);
                   1356:        service->socket=INVALID_SOCKET;
                   1357:        closesocket(socket_dup);        /* close duplicate handle */
                   1358: 
                   1359:        service->running=FALSE;
                   1360: }
                   1361: 
                   1362: static void native_service_thread(void* arg)
                   1363: {
                   1364:        char                                    cmd[MAX_PATH];
                   1365:        char                                    fullcmd[MAX_PATH*2];
                   1366:        char*                                   host_name;
                   1367:        HOSTENT*                                host;
                   1368:        SOCKET                                  socket;
                   1369:        SOCKET                                  socket_dup;
                   1370:        client_t                                client;
                   1371:        service_t*                              service;
                   1372:        service_client_t                service_client=*(service_client_t*)arg;
1.1.1.2 ! root     1373:        ulong                                   login_attempts;
1.1       root     1374: 
                   1375:        free(arg);
                   1376: 
                   1377:        socket=service_client.socket;
                   1378:        service=service_client.service;
                   1379: 
                   1380:        lprintf(LOG_DEBUG,"%04d %s service thread started", socket, service->protocol);
                   1381: 
1.1.1.2 ! root     1382:        SetThreadName("Native Service");
1.1       root     1383:        thread_up(TRUE /* setuid */);
                   1384: 
                   1385:        /* Host name lookup and filtering */
                   1386:        if(service->options&BBS_OPT_NO_HOST_LOOKUP 
                   1387:                || startup->options&BBS_OPT_NO_HOST_LOOKUP)
                   1388:                host=NULL;
                   1389:        else
                   1390:                host=gethostbyaddr((char *)&service_client.addr.sin_addr
                   1391:                        ,sizeof(service_client.addr.sin_addr),AF_INET);
                   1392: 
                   1393:        if(host!=NULL && host->h_name!=NULL)
                   1394:                host_name=host->h_name;
                   1395:        else
                   1396:                host_name="<no name>";
                   1397: 
                   1398:        if(!(service->options&BBS_OPT_NO_HOST_LOOKUP)
                   1399:                && !(startup->options&BBS_OPT_NO_HOST_LOOKUP)) {
                   1400:                lprintf(LOG_INFO,"%04d %s Hostname: %s"
                   1401:                        ,socket, service->protocol, host_name);
1.1.1.2 ! root     1402: #if    0 /* gethostbyaddr() is apparently not (always) thread-safe
        !          1403:             and getnameinfo() doesn't return alias information */
1.1       root     1404:                for(i=0;host!=NULL && host->h_aliases!=NULL 
                   1405:                        && host->h_aliases[i]!=NULL;i++)
                   1406:                        lprintf(LOG_INFO,"%04d %s HostAlias: %s"
                   1407:                                ,socket, service->protocol, host->h_aliases[i]);
1.1.1.2 ! root     1408: #endif
1.1       root     1409:        }
                   1410: 
                   1411:        if(trashcan(&scfg,host_name,"host")) {
                   1412:                lprintf(LOG_NOTICE,"%04d !%s CLIENT BLOCKED in host.can: %s"
                   1413:                        ,socket, service->protocol, host_name);
                   1414:                close_socket(socket);
                   1415:                if(service->clients)
                   1416:                        service->clients--;
                   1417:                thread_down();
                   1418:                return;
                   1419:        }
                   1420: 
                   1421: 
                   1422: #if 0  /* Need to export from SBBS.DLL */
                   1423:        identity=NULL;
                   1424:        if(service->options&BBS_OPT_GET_IDENT 
                   1425:                && startup->options&BBS_OPT_GET_IDENT) {
                   1426:                identify(&service_client.addr, service->port, str, sizeof(str)-1);
                   1427:                identity=strrchr(str,':');
                   1428:                if(identity!=NULL) {
                   1429:                        identity++;     /* skip colon */
                   1430:                        while(*identity && *identity<=SP) /* point to user name */
                   1431:                                identity++;
                   1432:                        lprintf(LOG_INFO,"%04d Identity: %s",socket, identity);
                   1433:                }
                   1434:        }
                   1435: #endif
                   1436: 
                   1437:        client.size=sizeof(client);
                   1438:        client.time=time(NULL);
                   1439:        SAFECOPY(client.addr,inet_ntoa(service_client.addr.sin_addr));
                   1440:        SAFECOPY(client.host,host_name);
                   1441:        client.port=ntohs(service_client.addr.sin_port);
                   1442:        client.protocol=service->protocol;
                   1443:        client.user="<unknown>";
                   1444: 
                   1445: #ifdef _WIN32
                   1446:        if(!DuplicateHandle(GetCurrentProcess(),
                   1447:                (HANDLE)socket,
                   1448:                GetCurrentProcess(),
                   1449:                (HANDLE*)&socket_dup,
                   1450:                0,
                   1451:                TRUE, /* Inheritable */
                   1452:                DUPLICATE_SAME_ACCESS)) {
                   1453:                lprintf(LOG_ERR,"%04d !%s ERROR %d duplicating socket descriptor"
                   1454:                        ,socket,service->protocol,GetLastError());
                   1455:                close_socket(socket);
                   1456:                thread_down();
                   1457:                return;
                   1458:        }
                   1459: #else
                   1460:        socket_dup = dup(socket);
                   1461: #endif
                   1462: 
                   1463:        update_clients();
                   1464: 
                   1465:        /* Initialize client display */
                   1466:        client_on(socket,&client,FALSE /* update */);
                   1467: 
1.1.1.2 ! root     1468:        if(startup->login_attempt_throttle
        !          1469:                && (login_attempts=loginAttempts(startup->login_attempt_list, &service_client.addr)) > 1) {
        !          1470:                lprintf(LOG_DEBUG,"%04d %s Throttling suspicious connection from: %s (%u login attempts)"
        !          1471:                        ,socket, service->protocol, inet_ntoa(service_client.addr.sin_addr), login_attempts);
        !          1472:                mswait(login_attempts*startup->login_attempt_throttle);
        !          1473:        }
        !          1474: 
1.1       root     1475:        /* RUN SCRIPT */
                   1476:        if(strpbrk(service->cmd,"/\\")==NULL)
                   1477:                sprintf(cmd,"%s%s",scfg.exec_dir,service->cmd);
                   1478:        else
                   1479:                strcpy(cmd,service->cmd);
                   1480:        sprintf(fullcmd,cmd,socket_dup);
                   1481: 
                   1482:        system(fullcmd);
                   1483: 
                   1484:        if(service->clients)
                   1485:                service->clients--;
                   1486:        update_clients();
                   1487: 
                   1488: #ifdef _WIN32
                   1489:        if(startup->hangup_sound[0] && !(startup->options&BBS_OPT_MUTE)
                   1490:                && !(service->options&BBS_OPT_MUTE))
                   1491:                PlaySound(startup->hangup_sound, NULL, SND_ASYNC|SND_FILENAME);
                   1492: #endif
                   1493: 
                   1494:        thread_down();
1.1.1.2 ! root     1495:        lprintf(LOG_INFO,"%04d %s service thread terminated (%u clients remain, %d total, %lu served)"
1.1       root     1496:                ,socket, service->protocol, service->clients, active_clients(), service->served);
                   1497: 
                   1498:        client_off(socket);
                   1499:        close_socket(socket);
                   1500:        closesocket(socket_dup);        /* close duplicate handle */
                   1501: }
                   1502: 
                   1503: 
                   1504: void DLLCALL services_terminate(void)
                   1505: {
1.1.1.2 ! root     1506:        uint32_t i;
1.1       root     1507: 
                   1508:        lprintf(LOG_INFO,"0000 Services terminate");
                   1509:        terminated=TRUE;
                   1510:        for(i=0;i<services;i++)
                   1511:                service[i].terminated=TRUE;
                   1512: }
                   1513: 
                   1514: #define NEXT_FIELD(p)  FIND_WHITESPACE(p); SKIP_WHITESPACE(p)
                   1515: 
1.1.1.2 ! root     1516: static service_t* read_services_ini(const char* services_ini, service_t* service, uint32_t* services)
1.1       root     1517: {
                   1518:        uint            i,j;
                   1519:        FILE*           fp;
                   1520:        char*           p;
                   1521:        char            cmd[INI_MAX_VALUE_LEN];
                   1522:        char            host[INI_MAX_VALUE_LEN];
                   1523:        char            prot[INI_MAX_VALUE_LEN];
1.1.1.2 ! root     1524:        char            portstr[INI_MAX_VALUE_LEN];
1.1       root     1525:        char**          sec_list;
                   1526:        str_list_t      list;
                   1527:        service_t*      np;
                   1528:        service_t       serv;
                   1529:        int                     log_level;
1.1.1.2 ! root     1530:        int                     listen_backlog;
        !          1531:        uint            max_clients;
        !          1532:        uint32_t        options;
        !          1533:        uint32_t        stack_size;
1.1       root     1534: 
                   1535:        if((fp=fopen(services_ini,"r"))==NULL) {
1.1.1.2 ! root     1536:                lprintf(LOG_CRIT,"!ERROR %d opening %s", errno, services_ini);
1.1       root     1537:                return(NULL);
                   1538:        }
                   1539: 
1.1.1.2 ! root     1540:        lprintf(LOG_DEBUG,"Reading %s",services_ini);
1.1       root     1541:        list=iniReadFile(fp);
                   1542:        fclose(fp);
                   1543: 
1.1.1.2 ! root     1544:        /* Get default key values from "root" section */
        !          1545:        log_level               = iniGetLogLevel(list,ROOT_SECTION,"LogLevel",startup->log_level);
        !          1546:        stack_size              = (uint32_t)iniGetBytes(list,ROOT_SECTION,"StackSize",1,0);
        !          1547:        max_clients             = iniGetInteger(list,ROOT_SECTION,"MaxClients",0);
        !          1548:        listen_backlog  = iniGetInteger(list,ROOT_SECTION,"ListenBacklog",DEFAULT_LISTEN_BACKLOG);
        !          1549:        options                 = iniGetBitField(list,ROOT_SECTION,"Options",service_options,0);
        !          1550: 
        !          1551:        /* Enumerate and parse each service configuration */
1.1       root     1552:        sec_list = iniGetSectionList(list,"");
                   1553:     for(i=0; sec_list!=NULL && sec_list[i]!=NULL; i++) {
1.1.1.2 ! root     1554:                if(!iniGetBool(list,sec_list[i],"Enabled",TRUE)) {
        !          1555:                        lprintf(LOG_WARNING,"Ignoring disabled service: %s",sec_list[i]);
        !          1556:                        continue;
        !          1557:                }
1.1       root     1558:                memset(&serv,0,sizeof(service_t));
                   1559:                SAFECOPY(serv.protocol,iniGetString(list,sec_list[i],"Protocol",sec_list[i],prot));
                   1560:                serv.socket=INVALID_SOCKET;
                   1561:                serv.interface_addr=iniGetIpAddress(list,sec_list[i],"Interface",startup->interface_addr);
1.1.1.2 ! root     1562:                serv.max_clients=iniGetInteger(list,sec_list[i],"MaxClients",max_clients);
        !          1563:                serv.listen_backlog=iniGetInteger(list,sec_list[i],"ListenBacklog",listen_backlog);
        !          1564:                serv.stack_size=(uint32_t)iniGetBytes(list,sec_list[i],"StackSize",1,stack_size);
        !          1565:                serv.options=iniGetBitField(list,sec_list[i],"Options",service_options,options);
        !          1566:                serv.log_level=iniGetLogLevel(list,sec_list[i],"LogLevel",log_level);
1.1       root     1567:                SAFECOPY(serv.cmd,iniGetString(list,sec_list[i],"Command","",cmd));
                   1568: 
1.1.1.2 ! root     1569:                p=iniGetString(list,sec_list[i],"Port",serv.protocol,portstr);
        !          1570:                if(isdigit(*p))
        !          1571:                        serv.port=(ushort)strtol(p,NULL,0);
        !          1572:                else {
        !          1573:                        struct servent* servent = getservbyname(p,serv.options&SERVICE_OPT_UDP ? "udp":"tcp");
        !          1574:                        if(servent==NULL)
        !          1575:                                servent = getservbyname(p,serv.options&SERVICE_OPT_UDP ? "tcp":"udp");
        !          1576:                        if(servent!=NULL)
        !          1577:                                serv.port = ntohs(servent->s_port);
        !          1578:                }
        !          1579: 
        !          1580:                if(serv.port==0) {
        !          1581:                        lprintf(LOG_WARNING,"Ignoring service with invalid port (%s): %s",p, sec_list[i]);
        !          1582:                        continue;
        !          1583:                }
        !          1584: 
1.1       root     1585:                if(serv.cmd[0]==0) {
                   1586:                        lprintf(LOG_WARNING,"Ignoring service with no command: %s",sec_list[i]);
                   1587:                        continue;
                   1588:                }
                   1589: 
                   1590:                /* JavaScript operating parameters */
                   1591:                sbbs_get_js_settings(list, sec_list[i], &serv.js, &startup->js);
                   1592: 
                   1593:                for(j=0;j<*services;j++)
                   1594:                        if(service[j].interface_addr==serv.interface_addr && service[j].port==serv.port
                   1595:                                && (service[j].options&SERVICE_OPT_UDP)==(serv.options&SERVICE_OPT_UDP))
                   1596:                                break;
                   1597:                if(j<*services) { /* ignore duplicate services */
                   1598:                        lprintf(LOG_NOTICE,"Ignoring duplicate service: %s",sec_list[i]);
                   1599:                        continue;
                   1600:                }
                   1601: 
                   1602:                if(stricmp(iniGetString(list,sec_list[i],"Host",startup->host_name,host), startup->host_name)!=0) {
                   1603:                        lprintf(LOG_NOTICE,"Ignoring service (%s) for host: %s", sec_list[i], host);
                   1604:                        continue;
                   1605:                }
                   1606:                p=iniGetString(list,sec_list[i],"NotHost","",host);
                   1607:                if(*p!=0 && stricmp(p, startup->host_name)==0) {
                   1608:                        lprintf(LOG_NOTICE,"Ignoring service (%s) not for host: %s", sec_list[i], host);
                   1609:                        continue;
                   1610:                }
                   1611: 
                   1612:                if((np=(service_t*)realloc(service,sizeof(service_t)*((*services)+1)))==NULL) {
                   1613:                        fclose(fp);
                   1614:                        lprintf(LOG_CRIT,"!MALLOC FAILURE");
                   1615:                        return(service);
                   1616:                }
                   1617:                service=np;
                   1618:                service[*services]=serv;
                   1619:                (*services)++;
                   1620:        }
                   1621:        iniFreeStringList(sec_list);
                   1622:        strListFree(&list);
                   1623: 
                   1624:        return(service);
                   1625: }
                   1626: 
                   1627: static void cleanup(int code)
                   1628: {
                   1629:        FREE_AND_NULL(service);
                   1630:        services=0;
                   1631: 
                   1632:        free_cfg(&scfg);
                   1633: 
                   1634:        semfile_list_free(&recycle_semfiles);
                   1635:        semfile_list_free(&shutdown_semfiles);
                   1636: 
                   1637:        update_clients();
                   1638: 
                   1639: #ifdef _WINSOCKAPI_    
                   1640:        if(WSAInitialized && WSACleanup()!=0) 
                   1641:                lprintf(LOG_ERR,"0000 !WSACleanup ERROR %d",ERROR_VALUE);
                   1642: #endif
                   1643: 
                   1644:        thread_down();
                   1645:        if(terminated || code)
1.1.1.2 ! root     1646:                lprintf(LOG_INFO,"#### Services thread terminated (%lu clients served)",served);
1.1       root     1647:        status("Down");
                   1648:        if(startup!=NULL && startup->terminated!=NULL)
                   1649:                startup->terminated(startup->cbdata,code);
                   1650: }
                   1651: 
                   1652: const char* DLLCALL services_ver(void)
                   1653: {
                   1654:        static char ver[256];
                   1655:        char compiler[32];
                   1656: 
                   1657:        DESCRIBE_COMPILER(compiler);
                   1658: 
1.1.1.2 ! root     1659:        sscanf("$Revision: 1.252 $", "%*s %s", revision);
1.1       root     1660: 
                   1661:        sprintf(ver,"Synchronet Services %s%s  "
                   1662:                "Compiled %s %s with %s"
                   1663:                ,revision
                   1664: #ifdef _DEBUG
                   1665:                ," Debug"
                   1666: #else
                   1667:                ,""
                   1668: #endif
                   1669:                ,__DATE__, __TIME__, compiler
                   1670:                );
                   1671: 
                   1672:        return(ver);
                   1673: }
                   1674: 
                   1675: void DLLCALL services_thread(void* arg)
                   1676: {
                   1677:        char*                   p;
                   1678:        char                    path[MAX_PATH+1];
                   1679:        char                    error[256];
                   1680:        char                    host_ip[32];
                   1681:        char                    compiler[32];
                   1682:        char                    str[128];
1.1.1.2 ! root     1683:        char                    services_ini[MAX_PATH+1];
1.1       root     1684:        SOCKADDR_IN             addr;
                   1685:        SOCKADDR_IN             client_addr;
                   1686:        socklen_t               client_addr_len;
                   1687:        SOCKET                  socket;
                   1688:        SOCKET                  client_socket;
                   1689:        BYTE*                   udp_buf = NULL;
                   1690:        int                             udp_len;
                   1691:        int                             i;
                   1692:        int                             result;
                   1693:        int                             optval;
                   1694:        ulong                   total_running;
                   1695:        time_t                  t;
                   1696:        time_t                  initialized=0;
                   1697:        fd_set                  socket_set;
                   1698:        SOCKET                  high_socket;
                   1699:        ulong                   total_sockets;
                   1700:        struct timeval  tv;
                   1701:        service_client_t* client;
                   1702: 
                   1703:        services_ver();
                   1704: 
                   1705:        startup=(services_startup_t*)arg;
                   1706: 
                   1707:     if(startup==NULL) {
                   1708:        sbbs_beep(100,500);
                   1709:        fprintf(stderr, "No startup structure passed!\n");
                   1710:        return;
                   1711:     }
                   1712: 
                   1713:        if(startup->size!=sizeof(services_startup_t)) { /* verify size */
                   1714:                sbbs_beep(100,500);
                   1715:                sbbs_beep(300,500);
                   1716:                sbbs_beep(100,500);
                   1717:                fprintf(stderr, "Invalid startup structure!\n");
                   1718:                return;
                   1719:        }
                   1720: 
                   1721: #ifdef _THREAD_SUID_BROKEN
                   1722:        if(thread_suid_broken)
                   1723:                startup->seteuid(TRUE);
                   1724: #endif
                   1725: 
                   1726:        /* Setup intelligent defaults */
                   1727:        if(startup->sem_chk_freq==0)                    startup->sem_chk_freq=2;
                   1728:        if(startup->js.max_bytes==0)                    startup->js.max_bytes=JAVASCRIPT_MAX_BYTES;
                   1729:        if(startup->js.cx_stack==0)                             startup->js.cx_stack=JAVASCRIPT_CONTEXT_STACK;
                   1730: 
                   1731:        uptime=0;
                   1732:        served=0;
                   1733:        startup->recycle_now=FALSE;
                   1734:        startup->shutdown_now=FALSE;
                   1735: 
1.1.1.2 ! root     1736:        SetThreadName("Services");
1.1       root     1737: 
                   1738:        do {
                   1739: 
                   1740:                thread_up(FALSE /* setuid */);
                   1741: 
                   1742:                status("Initializing");
                   1743: 
                   1744:                memset(&scfg, 0, sizeof(scfg));
                   1745: 
                   1746:                lprintf(LOG_INFO,"Synchronet Services Revision %s%s"
                   1747:                        ,revision
                   1748: #ifdef _DEBUG
                   1749:                        ," Debug"
                   1750: #else
                   1751:                        ,""
                   1752: #endif
                   1753:                        );
                   1754: 
                   1755:                DESCRIBE_COMPILER(compiler);
                   1756: 
                   1757:                lprintf(LOG_INFO,"Compiled %s %s with %s", __DATE__, __TIME__, compiler);
                   1758: 
                   1759:                sbbs_srand();   /* Seed random number generator */
                   1760: 
                   1761:                if(!winsock_startup()) {
                   1762:                        cleanup(1);
                   1763:                        return;
                   1764:                }
                   1765: 
                   1766:                t=time(NULL);
                   1767:                lprintf(LOG_INFO,"Initializing on %.24s with options: %lx"
1.1.1.2 ! root     1768:                        ,ctime_r(&t,str),startup->options);
        !          1769: 
        !          1770:                if(chdir(startup->ctrl_dir)!=0)
        !          1771:                        lprintf(LOG_ERR,"!ERROR %d changing directory to: %s", errno, startup->ctrl_dir);
1.1       root     1772: 
                   1773:                /* Initial configuration and load from CNF files */
                   1774:                SAFECOPY(scfg.ctrl_dir, startup->ctrl_dir);
                   1775:                lprintf(LOG_INFO,"Loading configuration files from %s", scfg.ctrl_dir);
                   1776:                scfg.size=sizeof(scfg);
                   1777:                SAFECOPY(error,UNKNOWN_LOAD_ERROR);
                   1778:                if(!load_cfg(&scfg, NULL, TRUE, error)) {
1.1.1.2 ! root     1779:                        lprintf(LOG_CRIT,"!ERROR %s",error);
        !          1780:                        lprintf(LOG_CRIT,"!Failed to load configuration files");
1.1       root     1781:                        cleanup(1);
                   1782:                        return;
                   1783:                }
                   1784: 
                   1785:                if(startup->temp_dir[0])
                   1786:                        SAFECOPY(scfg.temp_dir,startup->temp_dir);
                   1787:                else
                   1788:                        SAFECOPY(scfg.temp_dir,"../temp");
                   1789:                prep_dir(scfg.ctrl_dir, scfg.temp_dir, sizeof(scfg.temp_dir));
                   1790:                MKDIR(scfg.temp_dir);
                   1791:                lprintf(LOG_DEBUG,"Temporary file directory: %s", scfg.temp_dir);
                   1792:                if(!isdir(scfg.temp_dir)) {
1.1.1.2 ! root     1793:                        lprintf(LOG_CRIT,"!Invalid temp directory: %s", scfg.temp_dir);
1.1       root     1794:                        cleanup(1);
                   1795:                        return;
                   1796:                }
                   1797: 
                   1798:                if(startup->host_name[0]==0)
                   1799:                        SAFECOPY(startup->host_name,scfg.sys_inetaddr);
                   1800: 
1.1.1.2 ! root     1801:                if((t=checktime())!=0) {   /* Check binary time */
        !          1802:                        lprintf(LOG_ERR,"!TIME PROBLEM (%ld)",t);
1.1       root     1803:                }
                   1804: 
                   1805:                if(uptime==0)
                   1806:                        uptime=time(NULL);      /* this must be done *after* setting the timezone */
                   1807: 
1.1.1.2 ! root     1808:                iniFileName(services_ini,sizeof(services_ini),scfg.ctrl_dir,"services.ini");
        !          1809: 
        !          1810:                if((service=read_services_ini(services_ini, service, &services))==NULL) {
1.1       root     1811:                        cleanup(1);
                   1812:                        return;
                   1813:                }
                   1814: 
                   1815:                update_clients();
                   1816: 
                   1817:                /* Open and Bind Listening Sockets */
                   1818:                total_sockets=0;
                   1819:                for(i=0;i<(int)services;i++) {
                   1820: 
                   1821:                        service[i].socket=INVALID_SOCKET;
                   1822: 
                   1823:                        if((socket = open_socket(
                   1824:                                (service[i].options&SERVICE_OPT_UDP) ? SOCK_DGRAM : SOCK_STREAM
                   1825:                                ,service[i].protocol))
                   1826:                                ==INVALID_SOCKET) {
1.1.1.2 ! root     1827:                                lprintf(LOG_CRIT,"!ERROR %d opening %s socket"
1.1       root     1828:                                        ,ERROR_VALUE, service[i].protocol);
                   1829:                                cleanup(1);
                   1830:                                return;
                   1831:                        }
                   1832: 
                   1833:                        if(service[i].options&SERVICE_OPT_UDP) {
                   1834:                                /* We need to set the REUSE ADDRESS socket option */
                   1835:                                optval=TRUE;
                   1836:                                if(setsockopt(socket,SOL_SOCKET,SO_REUSEADDR
                   1837:                                        ,(char*)&optval,sizeof(optval))!=0) {
                   1838:                                        lprintf(LOG_ERR,"%04d !ERROR %d setting %s socket option"
                   1839:                                                ,socket, ERROR_VALUE, service[i].protocol);
                   1840:                                        close_socket(socket);
                   1841:                                        continue;
                   1842:                                }
                   1843:                           #ifdef BSD
                   1844:                                if(setsockopt(socket,SOL_SOCKET,SO_REUSEPORT
                   1845:                                        ,(char*)&optval,sizeof(optval))!=0) {
                   1846:                                        lprintf(LOG_ERR,"%04d !ERROR %d setting %s socket option"
                   1847:                                                ,socket, ERROR_VALUE, service[i].protocol);
                   1848:                                        close_socket(socket);
                   1849:                                        continue;
                   1850:                                }
                   1851:                           #endif
                   1852:                        }
                   1853:                        memset(&addr, 0, sizeof(addr));
                   1854: 
                   1855:                        addr.sin_addr.s_addr = htonl(service[i].interface_addr);
                   1856:                        addr.sin_family = AF_INET;
                   1857:                        addr.sin_port   = htons(service[i].port);
                   1858: 
1.1.1.2 ! root     1859:                        if(service[i].port < IPPORT_RESERVED) {
        !          1860:                                if(startup->seteuid!=NULL)
        !          1861:                                        startup->seteuid(FALSE);
        !          1862:                        }
1.1       root     1863:                        result=retry_bind(socket, (struct sockaddr *) &addr, sizeof(addr)
                   1864:                                ,startup->bind_retry_count, startup->bind_retry_delay, service[i].protocol, lprintf);
1.1.1.2 ! root     1865:                        if(service[i].port < IPPORT_RESERVED) {
        !          1866:                                if(startup->seteuid!=NULL)
        !          1867:                                        startup->seteuid(TRUE);
        !          1868:                        }
1.1       root     1869:                        if(result!=0) {
                   1870:                                lprintf(LOG_ERR,"%04d %s",socket,BIND_FAILURE_HELP);
                   1871:                                close_socket(socket);
                   1872:                                continue;
                   1873:                        }
                   1874: 
                   1875:                        lprintf(LOG_INFO,"%04d %s socket bound to %s port %u"
                   1876:                                ,socket, service[i].protocol
                   1877:                                ,service[i].options&SERVICE_OPT_UDP ? "UDP" : "TCP"
                   1878:                                ,service[i].port);
                   1879: 
                   1880:                        if(!(service[i].options&SERVICE_OPT_UDP)) {
                   1881:                                if(listen(socket,service[i].listen_backlog)!=0) {
                   1882:                                        lprintf(LOG_ERR,"%04d !ERROR %d listening on %s socket"
                   1883:                                                ,socket, ERROR_VALUE, service[i].protocol);
                   1884:                                        close_socket(socket);
                   1885:                                        continue;
                   1886:                                }
                   1887:                        }
                   1888:                        service[i].socket=socket;
                   1889:                        total_sockets++;
                   1890:                }
                   1891: 
                   1892:                if(!total_sockets) {
                   1893:                        lprintf(LOG_WARNING,"0000 !No service sockets bound");
                   1894:                        cleanup(1);
                   1895:                        return;
                   1896:                }
                   1897: 
                   1898:                /* Setup static service threads */
                   1899:                for(i=0;i<(int)services;i++) {
                   1900:                        if(!(service[i].options&SERVICE_OPT_STATIC))
                   1901:                                continue;
                   1902:                        if(service[i].socket==INVALID_SOCKET)   /* bind failure? */
                   1903:                                continue;
                   1904: 
                   1905:                        /* start thread here */
                   1906:                        if(service[i].options&SERVICE_OPT_NATIVE)       /* Native */
                   1907:                                _beginthread(native_static_service_thread, service[i].stack_size, &service[i]);
                   1908:                        else                                                                            /* JavaScript */
                   1909:                                _beginthread(js_static_service_thread, service[i].stack_size, &service[i]);
                   1910:                }
                   1911: 
                   1912:                status("Listening");
                   1913: 
                   1914:                /* Setup recycle/shutdown semaphore file lists */
                   1915:                shutdown_semfiles=semfile_list_init(scfg.ctrl_dir,"shutdown","services");
                   1916:                recycle_semfiles=semfile_list_init(scfg.ctrl_dir,"recycle","services");
                   1917:                SAFEPRINTF(path,"%sservices.rec",scfg.ctrl_dir);        /* legacy */
                   1918:                semfile_list_add(&recycle_semfiles,path);
1.1.1.2 ! root     1919:                semfile_list_add(&recycle_semfiles,services_ini);
1.1       root     1920:                if(!initialized) {
                   1921:                        semfile_list_check(&initialized,recycle_semfiles);
                   1922:                        semfile_list_check(&initialized,shutdown_semfiles);
                   1923:                }
                   1924: 
                   1925:                terminated=FALSE;
                   1926: 
                   1927:                /* signal caller that we've started up successfully */
                   1928:                if(startup->started!=NULL)
                   1929:                startup->started(startup->cbdata);
                   1930: 
1.1.1.2 ! root     1931:                lprintf(LOG_INFO,"0000 Services thread started (%u service sockets bound)", total_sockets);
        !          1932: 
1.1       root     1933:                /* Main Server Loop */
                   1934:                while(!terminated) {
                   1935: 
                   1936:                        if(active_clients()==0) {
                   1937:                                if(!(startup->options&BBS_OPT_NO_RECYCLE)) {
                   1938:                                        if((p=semfile_list_check(&initialized,recycle_semfiles))!=NULL) {
                   1939:                                                lprintf(LOG_INFO,"0000 Recycle semaphore file (%s) detected",p);
                   1940:                                                break;
                   1941:                                        }
                   1942:                                        if(startup->recycle_now==TRUE) {
                   1943:                                                lprintf(LOG_NOTICE,"0000 Recycle semaphore signaled");
                   1944:                                                startup->recycle_now=FALSE;
                   1945:                                                break;
                   1946:                                        }
                   1947:                                }
                   1948:                                if(((p=semfile_list_check(&initialized,shutdown_semfiles))!=NULL
                   1949:                                                && lprintf(LOG_INFO,"0000 Shutdown semaphore file (%s) detected",p))
                   1950:                                        || (startup->shutdown_now==TRUE
                   1951:                                                && lprintf(LOG_INFO,"0000 Shutdown semaphore signaled"))) {
                   1952:                                        startup->shutdown_now=FALSE;
                   1953:                                        terminated=TRUE;
                   1954:                                        break;
                   1955:                                }
                   1956:                        }
                   1957: 
                   1958:                        /* Setup select() parms */
                   1959:                        FD_ZERO(&socket_set);   
                   1960:                        high_socket=0;
                   1961:                        for(i=0;i<(int)services;i++) {
                   1962:                                if(service[i].options&SERVICE_OPT_STATIC)
                   1963:                                        continue;
                   1964:                                if(service[i].socket==INVALID_SOCKET)
                   1965:                                        continue;
                   1966:                                if(!(service[i].options&SERVICE_OPT_FULL_ACCEPT)
                   1967:                                        && service[i].max_clients && service[i].clients >= service[i].max_clients)
                   1968:                                        continue;
                   1969:                                FD_SET(service[i].socket,&socket_set);
                   1970:                                if(service[i].socket>high_socket)
                   1971:                                        high_socket=service[i].socket;
                   1972:                        }
                   1973:                        if(high_socket==0) {    /* No dynamic services? */
                   1974:                                YIELD();
                   1975:                                continue;
                   1976:                        }
                   1977:                        tv.tv_sec=startup->sem_chk_freq;
                   1978:                        tv.tv_usec=0;
                   1979:                        if((result=select(high_socket+1,&socket_set,NULL,NULL,&tv))<1) {
                   1980:                                if(result==0)
                   1981:                                        continue;
                   1982: 
                   1983:                                if(ERROR_VALUE==EINTR)
                   1984:                                        lprintf(LOG_DEBUG,"0000 Services listening interrupted");
                   1985:                                else if(ERROR_VALUE == ENOTSOCK)
                   1986:                        lprintf(LOG_NOTICE,"0000 Services sockets closed");
                   1987:                                else
                   1988:                                        lprintf(LOG_WARNING,"0000 !ERROR %d selecting sockets",ERROR_VALUE);
                   1989:                                continue;
                   1990:                        }
                   1991: 
                   1992:                        /* Determine who services this socket */
                   1993:                        for(i=0;i<(int)services;i++) {
                   1994: 
                   1995:                                if(service[i].socket==INVALID_SOCKET)
                   1996:                                        continue;
                   1997: 
                   1998:                                if(!FD_ISSET(service[i].socket,&socket_set))
                   1999:                                        continue;
                   2000: 
                   2001:                                client_addr_len = sizeof(client_addr);
                   2002: 
                   2003:                                udp_len=0;
                   2004: 
                   2005:                                if(service[i].options&SERVICE_OPT_UDP) {
                   2006:                                        /* UDP */
                   2007:                                        if((udp_buf = (BYTE*)calloc(1, MAX_UDP_BUF_LEN)) == NULL) {
                   2008:                                                lprintf(LOG_CRIT,"%04d %s !ERROR %d allocating UDP buffer"
                   2009:                                                        ,service[i].socket, service[i].protocol, errno);
                   2010:                                                continue;
                   2011:                                        }
                   2012: 
                   2013:                                        udp_len = recvfrom(service[i].socket
                   2014:                                                ,udp_buf, MAX_UDP_BUF_LEN, 0 /* flags */
                   2015:                                                ,(struct sockaddr *)&client_addr, &client_addr_len);
                   2016:                                        if(udp_len<1) {
                   2017:                                                FREE_AND_NULL(udp_buf);
                   2018:                                                lprintf(LOG_ERR,"%04d %s !ERROR %d recvfrom failed"
                   2019:                                                        ,service[i].socket, service[i].protocol, ERROR_VALUE);
                   2020:                                                continue;
                   2021:                                        }
                   2022: 
                   2023:                                        if((client_socket = open_socket(SOCK_DGRAM, service[i].protocol))
                   2024:                                                ==INVALID_SOCKET) {
                   2025:                                                FREE_AND_NULL(udp_buf);
                   2026:                                                lprintf(LOG_ERR,"%04d %s !ERROR %d opening socket"
                   2027:                                                        ,service[i].socket, service[i].protocol, ERROR_VALUE);
                   2028:                                                continue;
                   2029:                                        }
                   2030: 
                   2031:                                        lprintf(LOG_DEBUG,"%04d %s created client socket: %d"
                   2032:                                                ,service[i].socket, service[i].protocol, client_socket);
                   2033: 
                   2034:                                        /* We need to set the REUSE ADDRESS socket option */
                   2035:                                        optval=TRUE;
                   2036:                                        if(setsockopt(client_socket,SOL_SOCKET,SO_REUSEADDR
                   2037:                                                ,(char*)&optval,sizeof(optval))!=0) {
                   2038:                                                FREE_AND_NULL(udp_buf);
                   2039:                                                lprintf(LOG_ERR,"%04d %s !ERROR %d setting socket option"
                   2040:                                                        ,client_socket, service[i].protocol, ERROR_VALUE);
                   2041:                                                close_socket(client_socket);
                   2042:                                                continue;
                   2043:                                        }
                   2044:                                   #ifdef BSD
                   2045:                                        if(setsockopt(client_socket,SOL_SOCKET,SO_REUSEPORT
                   2046:                                                ,(char*)&optval,sizeof(optval))!=0) {
                   2047:                                                FREE_AND_NULL(udp_buf);
                   2048:                                                lprintf(LOG_ERR,"%04d %s !ERROR %d setting socket option"
                   2049:                                                        ,client_socket, service[i].protocol, ERROR_VALUE);
                   2050:                                                close_socket(client_socket);
                   2051:                                                continue;
                   2052:                                        }
                   2053:                                   #endif
                   2054: 
                   2055:                                        memset(&addr, 0, sizeof(addr));
                   2056:                                        addr.sin_addr.s_addr = htonl(service[i].interface_addr);
                   2057:                                        addr.sin_family = AF_INET;
                   2058:                                        addr.sin_port   = htons(service[i].port);
                   2059: 
                   2060:                                        result=bind(client_socket, (struct sockaddr *) &addr, sizeof(addr));
                   2061:                                        if(result==SOCKET_ERROR) {
                   2062:                                                /* Failed to re-bind to same port number, use user port */
1.1.1.2 ! root     2063:                                                lprintf(LOG_NOTICE,"%04d %s ERROR %d re-binding socket to port %u failed, "
1.1       root     2064:                                                        "using user port"
                   2065:                                                        ,client_socket, service[i].protocol, ERROR_VALUE, service[i].port);
                   2066:                                                addr.sin_port=0;
                   2067:                                                result=bind(client_socket, (struct sockaddr *) &addr, sizeof(addr));
                   2068:                                        }
                   2069:                                        if(result!=0) {
                   2070:                                                FREE_AND_NULL(udp_buf);
                   2071:                                                lprintf(LOG_ERR,"%04d %s !ERROR %d re-binding socket to port %u"
                   2072:                                                        ,client_socket, service[i].protocol, ERROR_VALUE, service[i].port);
                   2073:                                                close_socket(client_socket);
                   2074:                                                continue;
                   2075:                                        }
                   2076: 
                   2077:                                        /* Set client address as default addres for send/recv */
                   2078:                                        if(connect(client_socket
                   2079:                                                ,(struct sockaddr *)&client_addr, client_addr_len)!=0) {
                   2080:                                                FREE_AND_NULL(udp_buf);
                   2081:                                                lprintf(LOG_ERR,"%04d %s !ERROR %d connect failed"
                   2082:                                                        ,client_socket, service[i].protocol, ERROR_VALUE);
                   2083:                                                close_socket(client_socket);
                   2084:                                                continue;
                   2085:                                        }
                   2086: 
                   2087:                                } else { 
                   2088:                                        /* TCP */
                   2089:                                        if((client_socket=accept(service[i].socket
                   2090:                                                ,(struct sockaddr *)&client_addr, &client_addr_len))==INVALID_SOCKET) {
                   2091:                                                if(ERROR_VALUE == ENOTSOCK || ERROR_VALUE == EINVAL)
                   2092:                                        lprintf(LOG_NOTICE,"%04d %s socket closed while listening"
                   2093:                                                                ,service[i].socket, service[i].protocol);
                   2094:                                                else
                   2095:                                                        lprintf(LOG_WARNING,"%04d %s !ERROR %d accepting connection" 
                   2096:                                                                ,service[i].socket, service[i].protocol, ERROR_VALUE);
                   2097: #ifdef _WIN32
                   2098:                                                if(WSAGetLastError()==WSAENOBUFS)       /* recycle (re-init WinSock) on this error */
                   2099:                                                        break;
                   2100: #endif
                   2101:                                                continue;
                   2102:                                        }
                   2103:                                        if(startup->socket_open!=NULL)  /* Callback, increments socket counter */
                   2104:                                                startup->socket_open(startup->cbdata,TRUE);     
                   2105:                                }
                   2106:                                SAFECOPY(host_ip,inet_ntoa(client_addr.sin_addr));
                   2107: 
                   2108:                                if(trashcan(&scfg,host_ip,"ip-silent")) {
                   2109:                                        FREE_AND_NULL(udp_buf);
                   2110:                                        close_socket(client_socket);
                   2111:                                        continue;
                   2112:                                }
                   2113: 
                   2114:                                lprintf(LOG_INFO,"%04d %s connection accepted from: %s port %u"
                   2115:                                        ,client_socket
                   2116:                                        ,service[i].protocol, host_ip, ntohs(client_addr.sin_port));
                   2117: 
                   2118:                                if(service[i].max_clients && service[i].clients+1>service[i].max_clients) {
                   2119:                                        lprintf(LOG_WARNING,"%04d !%s MAXIMUM CLIENTS (%u) reached, access denied"
                   2120:                                                ,client_socket, service[i].protocol, service[i].max_clients);
                   2121:                                        mswait(3000);
                   2122:                                        close_socket(client_socket);
                   2123:                                        continue;
                   2124:                                }
                   2125: 
                   2126: #ifdef _WIN32
                   2127:                                if(startup->answer_sound[0] && !(startup->options&BBS_OPT_MUTE)
                   2128:                                        && !(service[i].options&BBS_OPT_MUTE))
                   2129:                                        PlaySound(startup->answer_sound, NULL, SND_ASYNC|SND_FILENAME);
                   2130: #endif
                   2131: 
                   2132:                                if(trashcan(&scfg,host_ip,"ip")) {
                   2133:                                        FREE_AND_NULL(udp_buf);
                   2134:                                        lprintf(LOG_NOTICE,"%04d !%s CLIENT BLOCKED in ip.can: %s"
                   2135:                                                ,client_socket, service[i].protocol, host_ip);
                   2136:                                        mswait(3000);
                   2137:                                        close_socket(client_socket);
                   2138:                                        continue;
                   2139:                                }
                   2140: 
                   2141:                                if((client=malloc(sizeof(service_client_t)))==NULL) {
                   2142:                                        FREE_AND_NULL(udp_buf);
                   2143:                                        lprintf(LOG_CRIT,"%04d !%s ERROR allocating %u bytes of memory for service_client"
                   2144:                                                ,client_socket, service[i].protocol, sizeof(service_client_t));
                   2145:                                        mswait(3000);
                   2146:                                        close_socket(client_socket);
                   2147:                                        continue;
                   2148:                                }
                   2149: 
                   2150:                                memset(client,0,sizeof(service_client_t));
                   2151:                                client->socket=client_socket;
                   2152:                                client->addr=client_addr;
                   2153:                                client->service=&service[i];
                   2154:                                client->service->clients++;             /* this should be mutually exclusive */
                   2155:                                client->udp_buf=udp_buf;
                   2156:                                client->udp_len=udp_len;
                   2157:                                client->branch.limit                    = service[i].js.branch_limit;
                   2158:                                client->branch.gc_interval              = service[i].js.gc_interval;
                   2159:                                client->branch.yield_interval   = service[i].js.yield_interval;
                   2160:                                client->branch.terminated               = &client->service->terminated;
                   2161:                                client->branch.auto_terminate   = TRUE;
                   2162: 
                   2163:                                udp_buf = NULL;
                   2164: 
                   2165:                                if(service[i].options&SERVICE_OPT_NATIVE)       /* Native */
                   2166:                                        _beginthread(native_service_thread, service[i].stack_size, client);
                   2167:                                else                                                                            /* JavaScript */
                   2168:                                        _beginthread(js_service_thread, service[i].stack_size, client);
                   2169:                                service[i].served++;
                   2170:                                served++;
                   2171:                        }
                   2172:                }
                   2173: 
                   2174:                /* Close Service Sockets */
                   2175:                lprintf(LOG_DEBUG,"0000 Closing service sockets");
                   2176:                for(i=0;i<(int)services;i++) {
                   2177:                        service[i].terminated=TRUE;
                   2178:                        if(service[i].socket==INVALID_SOCKET)
                   2179:                                continue;
                   2180:                        if(service[i].options&SERVICE_OPT_STATIC)
                   2181:                                continue;
                   2182:                        close_socket(service[i].socket);
                   2183:                        service[i].socket=INVALID_SOCKET;
                   2184:                }
                   2185: 
                   2186:                /* Wait for Dynamic Service Threads to terminate */
                   2187:                if(active_clients()) {
                   2188:                        lprintf(LOG_DEBUG,"0000 Waiting for %d clients to disconnect",active_clients());
                   2189:                        while(active_clients()) {
                   2190:                                mswait(500);
                   2191:                        }
                   2192:                        lprintf(LOG_DEBUG,"0000 Done waiting");
                   2193:                }
                   2194: 
                   2195:                /* Wait for Static Service Threads to terminate */
                   2196:                total_running=0;
                   2197:                for(i=0;i<(int)services;i++) 
                   2198:                        total_running+=service[i].running;
                   2199:                if(total_running) {
                   2200:                        lprintf(LOG_DEBUG,"0000 Waiting for %d static services to terminate",total_running);
                   2201:                        while(1) {
                   2202:                                total_running=0;
                   2203:                                for(i=0;i<(int)services;i++) 
                   2204:                                        total_running+=service[i].running;
                   2205:                                if(!total_running)
                   2206:                                        break;
                   2207:                                mswait(500);
                   2208:                        }
                   2209:                        lprintf(LOG_DEBUG,"0000 Done waiting");
                   2210:                }
                   2211: 
                   2212:                cleanup(0);
                   2213:                if(!terminated) {
                   2214:                        lprintf(LOG_INFO,"Recycling server...");
                   2215:                        mswait(2000);
                   2216:                        if(startup->recycle!=NULL)
                   2217:                                startup->recycle(startup->cbdata);
                   2218:                }
                   2219: 
                   2220:        } while(!terminated);
                   2221: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.