/* $Id$ 
 * 
 * Licensed to the Apache Software Foundation (ASF) under one or more 
 * contributor license agreements. See the NOTICE file distributed with  
 * this work for additional information regarding copyright ownership. 
 * The ASF licenses this file to you under the Apache License, Version  
 * 2.0 (the "License"); you may not use this file except in compliance  
 * with the License. You may obtain a copy of the License at 
 * 
 * http://www.apache.org/licenses/LICENSE-2.0 
 * 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and 
 * limitations under the License. 
 */ 

/*
 * etch_conxevent.c
 * event handler overrides for the various connection superclasses
 */

#include "apr_network_io.h"
#include "etchthread.h"
#include "etch_tcpconxn.h"
#include "etch_tcpserver.h"
#include "etchlog.h"
#include "etch_global.h"


/*
 * etch_deftcplistener_on_event()
 * default handler for listener events
 */
int etch_deftcplistener_on_event(etch_tcp_server* l, etch_tcp_connection* c, const int e, int p1, void* p2)
{
    static char cxstr[24], *smask = "server %u";  
       
    if (c)
    {   c->cx.listener = (etch_object*) l;
        return  c->cx.on_event(c, e, p1, p2);   
    }

    sprintf(cxstr, smask, l->listener_id);

    switch(e)
    {
       case ETCH_CONXEVT_CREATED:
            etchlog(ETCHCONX, ETCHLOG_DEBUG, "%s created\n", cxstr);
            break;

       case ETCH_CONXEVT_CREATERR:
            etchlog(ETCHCONX, ETCHLOG_ERROR, "%s not created\n", cxstr);
            break;

       case ETCH_CONXEVT_OPENING:
            etchlog(ETCHCONX, ETCHLOG_DEBUG, "%s opening ...\n", cxstr);
            break;

       case ETCH_CONXEVT_DESTROYING:
            etchlog(ETCHCONX, ETCHLOG_DEBUG, "%s destroying ...\n", cxstr);
            break;

       case ETCH_CONXEVT_DESTROYED:
            etchlog(ETCHCONX, ETCHLOG_DEBUG, "%s destroyed\n", cxstr);
            break;

       case ETCH_CONXEVT_SHUTDOWN:
            etchlog(ETCHCONX, ETCHLOG_WARNING, "%s shutdown request detected\n", cxstr);
            break;
    }

    return 0;
}


/*
 * etch_tcpconx_on_event()
 * default handler for connection events
 */
int etch_tcpconx_on_event(etch_tcp_connection* c, const int e, int p1, void* p2)
{
    int result = 0, lid = 0;
    static char cxstr[32], estr[128]; 
    static char *scmask = "server %u connxn %u", *cmask = "connxn %u";

    if  (is_etch_tcpserver(c->cx.listener))
         lid = ((etch_tcp_server*)(c->cx.listener))->listener_id;
    if  (lid)
         sprintf(cxstr, scmask, lid, c->cx.conxid);     
    else sprintf(cxstr, cmask, c->cx.conxid);

    switch(e)
    {
        case ETCH_CONXEVT_RECEIVING:
             etchlog(ETCHCONX, ETCHLOG_XDEBUG, "%s begin receive (block) ...\n", cxstr);
             break;

        case ETCH_CONXEVT_RECEIVERR:
             apr_strerror(p1, estr, 128);
             if  (IS_ETCH_SOCKET_TIMEOUT(p1))
                  etchlog(ETCHCONX, ETCHLOG_DEBUG, "%s socket receive timed out\n", cxstr); 
             else
             if  (p1 == APR_OTHER_END_CLOSED)
                  etchlog(ETCHCONX, ETCHLOG_WARNING,"%s connection was broken\n", cxstr);  
             else etchlog(ETCHCONX, ETCHLOG_ERROR,  "%s apr_socket_recv() %s\n", cxstr, estr); 
             break;

        case ETCH_CONXEVT_RECEIVED:   /* "eod=%d", p1 */
             etchlog(ETCHCONX, ETCHLOG_DEBUG, "%s end receive %d bytes\n", cxstr, (int)(size_t)p2);    
             break;

       case ETCH_CONXEVT_CONXCLOSED:
             etchlog(ETCHCONX, ETCHLOG_DEBUG, "%s local connection closed\n", cxstr);
             break;

        case ETCH_CONXEVT_PEERCLOSED:
             etchlog(ETCHCONX, ETCHLOG_DEBUG, "%s peer connection closed\n", cxstr);
             break;

        case ETCH_CONXEVT_RECEIVEND:
             etchlog(ETCHCONX, ETCHLOG_XDEBUG, "%s exit receive loop\n", cxstr, p1);                
             break;

        case ETCH_CONXEVT_SENDING:
             etchlog(ETCHCONX, ETCHLOG_XDEBUG, "%s begin send\n", cxstr);
             break;

        case ETCH_CONXEVT_SENDERR:
             apr_strerror(p1, estr, 128);
             if  (IS_ETCH_SOCKET_TIMEOUT(p1))
                  etchlog(ETCHCONX, ETCHLOG_DEBUG, "%s socket send timed out\n", cxstr); 
             else etchlog(ETCHCONX, ETCHLOG_ERROR, "%s apr_socket_send() %s\n", cxstr, estr); 
             break;

        case ETCH_CONXEVT_SENDEND:
             etchlog(ETCHCONX, ETCHLOG_DEBUG, "%s end send %d bytes\n", cxstr, p1);                
             break;

        case ETCH_CONXEVT_RCVPUMP_START:
             etchlog(ETCHCONX, ETCHLOG_DEBUG, "%s start receive pump\n", cxstr, p1);                
             break;

        case ETCH_CONXEVT_RCVPUMP_RECEIVING:
             etchlog(ETCHCONX, ETCHLOG_DEBUG, "%s thread %d receiving ...\n", cxstr, p1);                
             break;

        case ETCH_CONXEVT_RCVPUMP_ERR:
             result = -1;   
             if  (p1 == APR_OTHER_END_CLOSED)
                  etchlog(ETCHCONX, ETCHLOG_WARNING, "%s connection was broken\n", cxstr);  
             else etchlog(ETCHCONX, ETCHLOG_ERROR, "%s receive failed\n", cxstr);  
             break;

        case ETCH_CONXEVT_RCVPUMP_STOP:
             result = p1;
             if (result >= 0)
                 etchlog(ETCHCONX, ETCHLOG_DEBUG, "%s receive pump on thread %d exited\n", 
                    cxstr, (int) (size_t) p2);
             else
                 etchlog(ETCHCONX, ETCHLOG_ERROR, "%s receive pump abnormal exit\n", cxstr);
             etchlog(ETCHCONX, ETCHLOG_DEBUG, "%s destroying accepted connection\n", cxstr);                    
             break;

        case ETCH_CONXEVT_ACCEPTING:
             etchlog(ETCHCONX, ETCHLOG_DEBUG, "%s accepting ...\n", cxstr);
             break;

        case ETCH_CONXEVT_ACCEPTERR:
             result = -1;
             apr_strerror((apr_status_t)(size_t)p2, estr, 128);
             etchlog(ETCHCONX, ETCHLOG_ERROR, "%s apr_socket_accept() %s\n", cxstr, estr);
             break;

        case ETCH_CONXEVT_ACCEPTED:
             etchlog(ETCHCONX, ETCHLOG_DEBUG, "%s accepted\n", cxstr);
             break;

        case ETCH_CONXEVT_CREATED:
             if (p1)
                 etchlog(ETCHCONX, ETCHLOG_DEBUG, "%s created for socket %x\n", cxstr, p1);
             else
                 etchlog(ETCHCONX, ETCHLOG_DEBUG, "%s created\n", cxstr);
             break;

        case ETCH_CONXEVT_CREATERR:
             etchlog(ETCHCONX, ETCHLOG_ERROR, "%s not created\n", cxstr);
             break;

        case ETCH_CONXEVT_OPENING:
             etchlog(ETCHCONX, ETCHLOG_DEBUG, "%s opening ...\n", cxstr);
             break;

        case ETCH_CONXEVT_OPENERR:
             result = -1;

             switch(p1)
             {  case 0:
                    etchlog(ETCHCONX, ETCHLOG_ERROR, "%s not opened\n", cxstr);
                    break;
                case 2:
                    apr_strerror((apr_status_t)(size_t)p2, estr, 128);
                    etchlog(ETCHCONX, ETCHLOG_WARNING,
                         "%s socket connect: %s\n", cxstr, estr);
                    break;
                case 3:
                    apr_strerror((apr_status_t)(size_t)p2, estr, 128);
                    etchlog(ETCHCONX, ETCHLOG_ERROR, 
                        "%s socket create: %s\n", cxstr, estr);
                    break;
                case 4:
                    apr_strerror((apr_status_t)(size_t)p2, estr, 128);
                    etchlog(ETCHCONX, ETCHLOG_ERROR, 
                        "%s sockaddr info: %s\n", cxstr, estr);
                    break;
                case 5:
                    apr_strerror((apr_status_t)(size_t)p2, estr, 128);
                    etchlog(ETCHCONX, ETCHLOG_ERROR, 
                        "%s socket bind: %s\n", cxstr, estr);
                    break;
                case 6:
                    apr_strerror((apr_status_t)(size_t)p2, estr, 128);
                    etchlog(ETCHCONX, ETCHLOG_ERROR, 
                        "%s socket listen: %s\n", cxstr, estr);
                    break;
             }
             break;

        case ETCH_CONXEVT_OPENED:
             etchlog(ETCHCONX, ETCHLOG_DEBUG, "%s opened\n", cxstr);
             break;

        case ETCH_CONXEVT_STARTING:
             etchlog(ETCHCONX, ETCHLOG_DEBUG, "%s starting ...\n", cxstr);
             break;

        case ETCH_CONXEVT_STARTERR:
             result = -1;
             switch(p1)
             {  case 0:
                    etchlog(ETCHCONX, ETCHLOG_ERROR, "%s not started\n", cxstr);
                    break;
                case 1:                     
                    etchlog(ETCHCONX, ETCHLOG_ERROR,
                         "%s etch_threadpool.run()\n", cxstr);
                    break;
             }
             break;

        case ETCH_CONXEVT_STARTED:
             etchlog(ETCHCONX, ETCHLOG_DEBUG, "%s started\n", cxstr);
             break;

        case ETCH_CONXEVT_ACCEPTPUMPEXIT:
             etchlog(ETCHCONX, ETCHLOG_DEBUG, "%s accept pump on thread %d exited\n", cxstr, p1);
             break;

        case ETCH_CONXEVT_ACCEPTPUMPEXITERR:
             etchlog(ETCHCONX, ETCHLOG_DEBUG, "%s accept pump abnormal exit\n", cxstr);
             break;

        case ETCH_CONXEVT_LISTENED:
             etchlog(ETCHCONX, ETCHLOG_DEBUG, "%s server id is %d\n", cxstr, p1);
             break;

        case ETCH_CONXEVT_UP:
        case ETCH_CONXEVT_DOWN:
             break;

        case ETCH_CONXEVT_SOCKOPTERR:
             result = 1; /* to increment counter */
             apr_strerror(p1, estr, 128);
             etchlog(ETCHCONX, ETCHLOG_ERROR, 
                "%s set socket option %s: %s\n", cxstr, p2, estr);
             break;

        case ETCH_CONXEVT_SHUTDOWN:
             etchlog(ETCHCONX, ETCHLOG_WARNING, "%s shutdown request detected\n", cxstr);
             break;

        case ETCH_CONXEVT_STOPPING:
             etchlog(ETCHCONX, ETCHLOG_DEBUG, "%s stopping ...\n", cxstr);
             break;

        case ETCH_CONXEVT_STOPERR:
             result = -1;
             etchlog(ETCHCONX, ETCHLOG_DEBUG, "%s not stopped\n", cxstr);
             break;

        case ETCH_CONXEVT_STOPPED:
             etchlog(ETCHCONX, ETCHLOG_DEBUG, "%s stopped\n", cxstr);
             break;

        case ETCH_CONXEVT_CLOSING:
             etchlog(ETCHCONX, ETCHLOG_DEBUG, "%s closing ...\n", cxstr);
             break;

        case ETCH_CONXEVT_CLOSERR:
             result = -1;

             switch(p1)
             {  case 0:
                    etchlog(ETCHCONX, ETCHLOG_ERROR, "%s not closed\n", cxstr);
                    break;
                case 1:
                    etchlog(ETCHCONX, ETCHLOG_ERROR, "%s close when not open\n", cxstr);
                    break;
                case 2:
                    etchlog(ETCHCONX, ETCHLOG_ERROR, "%s concurrent close denied\n", cxstr);
                    break;
                case 3:
                    etchlog(ETCHCONX, ETCHLOG_ERROR, 
                        "%s apr_socket_close() error %d\n", cxstr, (int)(size_t)p2);
                    break;
             }
             break;

        case ETCH_CONXEVT_CLOSED:    
             etchlog(ETCHCONX, ETCHLOG_DEBUG, "%s closed\n", cxstr);
             break;

        case ETCH_CONXEVT_DESTROYING:
             etchlog(ETCHCONX, ETCHLOG_DEBUG, "%s destroying ...\n", cxstr);
             break;

        case ETCH_CONXEVT_DESTROYED:
             etchlog(ETCHCONX, ETCHLOG_DEBUG, "%s destroyed\n", cxstr);
             break;
    }

    return result;
}

