Ejemplo n.º 1
0
/*
 *   Log a string with a given length
 */
void vm_log(VMG_ const char *str, size_t len)
{
    /* open the system log file */
    osfildef *fp = osfoprwt(G_syslogfile, OSFTTEXT);
    if (fp != 0)
    {
        /* wrap it in a data source */
        CVmFileSource ds(fp);

        /* get a printable timestamp */
        os_time_t timer = os_time(0);
        struct tm *tblk = os_localtime(&timer);
        char *tmsg = asctime(tblk);

        /* remove the trailing '\n' from the asctime message */
        size_t tmsgl = strlen(tmsg);
        if (tmsgl > 0 && tmsg[tmsgl-1] == '\n')
            tmsg[--tmsgl] = '\0';

        /* build the full message: [<timestamp>] <message> <newline> */
        char *msg = t3sprintf_alloc("[%s] %.*s\n", tmsg, (int)len, str);
        size_t msglen = strlen(msg);

        /* seek to the end of the file */
        ds.seek(0, OSFSK_END);

        /* if we can convert to a local character set, do so */
        if (G_cmap_to_log != 0)
        {
            /* write the message in the local character set */
            G_cmap_to_file->write_file(&ds, msg, msglen);
        }
        else
        {
            /* write the message with no character set conversion */
            (void)osfwb(fp, (unsigned char*)msg, msglen);
        }

        /* done with the formatted text string */
        t3free(msg);
    }
}
Ejemplo n.º 2
0
/*
 *   load a configuration file 
 */
void TadsNetConfig::read(osfildef *fp, CVmMainClientIfc *clientifc)
{
    /* read the file line by line */
    for (int linenum = 1 ; ; ++linenum)
    {
        /* read the next line */
        char buf[512];
        if (osfgets(buf, sizeof(buf), fp) == 0)
            break;

        /* skip leading whitespace */
        char *p;
        for (p = buf ; isspace(*p) ; ++p) ;

        /* skip blank lines and comments */
        if (*p == '\0' || *p == '#')
            continue;

        /* the variable name is the first token on the line */
        char *name = p;

        /* find the end of the name: the next space or '=' */
        for ( ; *p != '\0' && !isspace(*p) && *p != '=' ; ++p) ;
        char *name_end = p;

        /* skip spaces */
        for ( ; isspace(*p) ; ++p) ;

        /* make sure we stopped at a '=' */
        if (*p != '=')
        {
            char *msg = t3sprintf_alloc(
                "Missing '=' in web config file at line %d", linenum);
            clientifc->display_error(0, 0, msg, FALSE);
            t3free(msg);
            continue;
        }

        /* null-terminate the name */
        *name_end = '\0';

        /* skip spaces after the '=' */
        for (++p ; isspace(*p) ; ++p) ;

        /* the value starts here */
        char *val = p;

        /* 
         *   the value is the rest of the line, minus trailing spaces and
         *   newlines 
         */
        for (p += strlen(p) ;
             p > val && (isspace(*(p-1))
                         || *(p-1) == '\n' || *(p-1) == '\r') ;
             --p) ;

        /* null-terminate the value */
        *p = '\0';

        /* add the variable */
        TadsNetConfigVar *var = set(name, val);

        /* check that this is a variable name we recognize */
        static const char *known_vars[] = {
            "serverid",
            "storage.domain",
            "storage.rootpath",
            "storage.apikey",
            "watchdog"
        };

        int found = FALSE;
        for (size_t i = 0 ; i < countof(known_vars) ; ++i)
        {

            if (var->matchname(known_vars[i]))
            {
                found = TRUE;
                break;
            }
        }

        /* warn if we didn't find it among the known variables */
        if (!found)
        {
            char *msg = t3sprintf_alloc(
                "Warning: unknown variable name '%s' in web config file "
                "at line %d\n", name, linenum);
            clientifc->display_error(0, 0, msg, FALSE);
            t3free(msg);
        }
    }
}
Ejemplo n.º 3
0
/*
 *   Get the storage server API reply code and message.  Returns an allocated
 *   buffer that the caller must free with t3free().  The first
 *   space-delimited token in the return buffer is the code, and the rest is
 *   the human-readable error message.  For HTTP or network errors, the code
 *   is simply the numeric error code (positive for HTTP status codes,
 *   negative for internal network errors), with no message text.  
 */
char *vmnet_get_storagesrv_stat(VMG_ int htmlstat, CVmDataSource *reply,
                                const char *headers)
{
    /* check the HTML status */
    if (htmlstat == 200)
    {
        /* 
         *   The HTML transaction succeeded - check the reply.  Start with
         *   the headers, if provided.
         */
        if (headers != 0)
        {
            /* find the X-IFDBStorage-Status header */
            for (const char *p = headers ; ; p += 2)
            {
                /* are we at our header? */
                if (memcmp(p, "X-IFDBStorage-Status:", 21) == 0)
                {
                    /* this is our header - skip spaces and get the value */
                    for (p += 21 ; isspace(*p) ; ++p) ;

                    /* find the end of the line or end of the headers */
                    const char *nl = strstr(p, "\r\n");
                    if (nl == 0)
                        nl = p + strlen(p);

                    /* return the message text */
                    return lib_copy_str(p, nl - p);
                }

                /* not our header - skip to the end of the line */
                p = strstr(p, "\r\n");
                if (p == 0)
                    break;
            }
        }

        /* 
         *   We didn't find the header, so check the reply body.  Read the
         *   first line of the reply, since this contains the result code.  
         */
        reply->seek(0, OSFSK_SET);
        char *txt = reply->read_line_alo();

        /* remove the trailing newline */
        size_t l;
        if ((l = strlen(txt)) != 0 && txt[l-1] == '\n')
            txt[--l] = '\0';

        /* return the message text */
        return txt;
    }
    else
    {
        /* 
         *   HTML or network error.  Return a message containing the numeric
         *   status as the error code, with no text message. 
         */
        return t3sprintf_alloc("%d ", htmlstat);
    }
}
Ejemplo n.º 4
0
/*
 *   Thread main 
 */
void TadsListenerThread::thread_main()
{
    /* 
     *   keep going until we get the general application-wide 'quit' signal
     *   or our own private listener shutdown event 
     */
    while (!quit_evt->test() && !shutdown_evt->test())
    {
        /* 
         *   wait for a new connection request OR the quit signal, whichever
         *   comes first 
         */
        OS_Waitable *w[] = { port, quit_evt, shutdown_evt };
        switch (OS_Waitable::multi_wait(3, w))
        {
        case OSWAIT_EVENT + 0:
            /* the port is ready - reset the event */
            port->reset_event();

            /* read connections as long as they're available */
            for (;;)
            {
                /* check for a connection request */
                OS_Socket *s = port->accept();

                /* if we're out of requests, go back to waiting */
                if (s == 0 && port->last_error() == OS_EWOULDBLOCK)
                    break;

                /* check for other errors */
                if (s == 0)
                {
                    /* failed - flag the error and shut down */
                    errmsg = t3sprintf_alloc(
                        "Listener thread failed: error %d from accept()",
                        port->last_error());
                    shutdown_evt->signal();
                    break;
                }

                /* put the socket into non-blocking mode */
                s->set_non_blocking();

                /* create the server thread (it takes over the socket ref) */
                TadsServerThread *st = create_server_thread(s);
                st->thread_id = next_thread_id++;

                /* launch the server thread */
                if (!st->launch())
                {
                    /* failed - flag the error and shut down */
                    errmsg = lib_copy_str("Listener thread failed: "
                                          "couldn't launch server thread");
                    shutdown_evt->signal();

                    /* release our reference on the thread */
                    st->release_ref();

                    /* done */
                    break;
                }

                /* we're done with our reference to the thread */
                st->release_ref();
            }
            break;

        case OSWAIT_EVENT + 1:
            /* 
             *   The quit signal fired - the whole app is terminating.
             *   Signal our internal shutdown event and abort. 
             */
            shutdown_evt->signal();
            break;

        case OSWAIT_EVENT + 2:
            /* shutdown signal fired - the listener is terminating; abort */
            break;
        }
    }

    /* wait for our server threads to exit */
    for (;;)
    {
        TadsServerThread *st;
        
        /* get the first thread from the list */
        mutex->lock();
        if ((st = servers) != 0)
            st->add_ref();
        mutex->unlock();

        /* if we're out of threads, we're done */
        if (st == 0)
            break;

        /* wait for this thread */
        st->wait();

        /* we're done with this thread */
        st->release_ref();
    }
}