Исходные коды спецификаций для LSB Core 3.1

/*
 * Copyright (c) 2005-2006 Institute for System Programming
 * Russian Academy of Sciences
 * All rights reserved.
 *
 * Licensed 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.
 */

/*
 * Portions of this text are reprinted and reproduced in electronic form
 * from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology
 * -- Portable Operating System Interface (POSIX), The Open Group Base
 * Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of
 * Electrical and Electronics Engineers, Inc and The Open Group. In the
 * event of any discrepancy between this version and the original IEEE and
 * The Open Group Standard, the original IEEE and The Open Group Standard
 * is the referee document. The original Standard can be obtained online at
 * http://www.opengroup.org/unix/online.html.
 */

#include "socket/rpc/pmap_config.h"
#include "socket/rpc/pmap_model.seh"
#include "socket/socket/socket_model.seh"
#include "socket/netdata/netdata_model.seh"


#pragma SEC subsystem rpc "socket.rpc"


/*
   The group of functions 'socket.rpc.pmap' consists of:
       pmap_getport [3]
       pmap_set [3]
       pmap_unset [3]
 */

/********************************************************************/
/**                      Interface Functions                       **/
/********************************************************************/

/*
Linux Standard Base Core Specification 3.1
Copyright (c) 2004, 2005 Free Standards Group

WRONG SIGNATURE IN LSB 3.1 STANDART!!!
*/
specification
UShortT pmap_getport_spec( CallContext context, SockaddrT * addr,
                          ULongT prognum, ULongT versnum, ULongT protocol )
{
    pre
    {
        return true;
    }
    post
    {
        PmapPortRec * elem;

       UInt32T sinaddr = getInetSocket_sin_addr(addr);
        if( sinaddr == ntohl_model(SUT_INADDR_LOOPBACK) ) /*addr is localhost*/
        {
            elem = pmap_find_mapping(prognum, versnum, protocol);
            if(elem == NULL)
                elem = pmap_find_mapping_maxver(prognum, protocol);


            if(pmap_getport_spec == 0)
            {
                /*
                 * On failure, if either the program was not registered or the remote
                 * portmapper service could not be reached, the pmap_getport() function shall
                 * return 0.
                 */
                REQ("pmap_getport.04.02",
                    "program was not registered or the remote service could not be reached",
                    (elem==NULL) || (!elem->mapped)
                   );
                return true;
            }

            /*
             * On success, the pmap_getport() function shall return the port number in host
             * byte order of the RPC application registered with the remote portmapper.
             */
            REQ("pmap_getport.04.01", "shall return the port number",
                (elem==NULL) || ( elem->mapped && (elem->port == pmap_getport_spec) )
               );

        }

        /*
         * The pmap_getport() function shall return the port number assigned to a service
         * registered with a RPC Binding service running on a given target system, using
         * the protocol described in RFC 1833: Binding Protocols for ONC RPC
         * Version 2.
         */
        REQ("pmap_getport.01", "", TODO_REQ());

        /*
         * Conforming implementations shall support both IPPROTO_UDP and IPPROTO_TCP
         * protocols.
         */
        REQ("pmap_getport.02", "", TODO_REQ());

        /*
         * The value of address->sin_port shall be ignored, and the standard value
         * for the portmapper port shall always be used.
         */
        REQ("pmap_getport.03", "", TODO_REQ());


        /*
         * If the remote portmap service could not be reached, the status is left in the
         * global variable rpc_createerr.
         */
        REQ("pmap_getport.05", "", TODO_REQ());

        return true;
    }
}


/*
Linux Standard Base Core Specification 3.1
Copyright (c) 2004, 2005 Free Standards Group

NAME

pmap_set -- establishes mapping to machine's RPC Bind service.

SYNOPSIS

#include <rpc/pmap_clnt.h>

bool_t pmap_set(const u_long program, const u_long version, int protocol,
u_short port);

DESCRIPTION

pmap_set() establishes a mapping between the triple [program,version,protocol]
and port on the machine's RPC Bind service. The value of protocol is most
likely IPPROTO_UDP or IPPROTO_TCP. Automatically done by svc_register().

RETURN VALUE

pmap_set() returns non-zero if it suceeds, 0 otherwise.
*/
specification
BoolT pmap_set_spec( CallContext context, ULongT program, ULongT version, IntT protocol, UShortT port )
{
    pre
    {
        return true;
    }
    post
    {
        PmapPortRec * res = pmap_find_mapping(program, version, protocol);

        if ( res == NULL ) {
            /*
             * pmap_set() returns non-zero if it suceeds
             * 0 otherwise
             */
            REQ( "pmap_set.02.02", "pmap_set() returns 0", pmap_set_spec == 0 );
        } else {
            /*
             * pmap_set() establishes a mapping between the triple [program,version,protocol]
             * and port on the machine's RPC Bind service.
             */
            REQ( "pmap_set.01", "pmap_set() establishes a mapping", res->mapped );

            /*
             * pmap_set() returns non-zero if it suceeds
             */
            REQ( "pmap_set.02.01", "pmap_set() returns non-zero", pmap_set_spec != 0 );
        }

        return true;
    }
}

void onPmapSet(CallContext context, ULongT program, ULongT version, IntT protocol, UShortT port, BoolT pmap_set_spec)
{
    if(pmap_set_spec != 0)
    {
        pmap_add_mapping(program, version, protocol, port);
    }
}
/*
Linux Standard Base Core Specification 3.1
Copyright (c) 2004, 2005 Free Standards Group

NAME

  pmap_unset --  destroys RPC Binding

SYNOPSIS

#include <rpc/pmap_clnt.h>

bool_t pmap_unset(u_long prognum, u_long versnum);

DESCRIPTION

As a user interface to the RPC Bind service, pmap_unset() destroys all mapping
between the triple [prognum,versnum, *] and ports on the machine's RPC Bind
service.

RETURN VALUE

pmap_unset() returns non-zero if it succeeds, zero otherwise.
*/
specification
BoolT pmap_unset_spec( CallContext context, ULongT prognum, ULongT versnum )
{
    pre
    {
        return true;
    }
    post
    {
        /*
         * pmap_unset() returns non-zero if it succeeds,
         * zero otherwise.
         */
        if(pmap_unset_spec != 0)
        {
            REQ("pmap_unset.02.02", "", TODO_REQ());

            return true;
        }

        /*
         * pmap_unset() returns non-zero if it succeeds
         */
        REQ("pmap_unset.02.01", "returns non-zero if it succeeds", pmap_unset_spec==0);

        /*
         * As a user interface to the RPC Bind service,
         * pmap_unset() destroys all mapping between the triple
         * [prognum,versnum,*] and ports on the machine's
         * RPC Bind service.
         */
        REQ("?pmap_unset.01", "destroys all mapping of [prognum,versnum,*]",
             pmap_find_mappings(prognum, versnum) == NULL);

        return true;
    }
}

void onPmapUnset(CallContext context, ULongT prognum, ULongT versnum, BoolT pmap_unset_spec)
{
    pmap_unset_mappings(prognum, versnum);
}

/********************************************************************/
/**                       Pmap Types                               **/
/********************************************************************/

specification typedef struct PmapTriple PmapTriple = {};

PmapTriple * create_PmapTriple(ULongT prognum, ULongT versnum, UIntT protocol)
{
    return create(&type_PmapTriple, prognum, versnum, protocol);
}

specification typedef struct PmapPortRec PmapPortRec = {};

PmapPortRec * create_PmapPortRec(bool isknown, UShortT port)
{
    return create(&type_PmapPortRec, isknown, port);
}

Map * pmap_model; // PmapTriple * => PmapPortRec *

bool init_pmap()
{
    pmap_model = create_Map(&type_PmapTriple, &type_PmapPortRec);
    if(!pmap_model)
        return false;

    return true;
}

void pmap_add_mapping(ULongT prognum, ULongT versnum, UIntT protocol, UShortT port)
{
    put_Map(pmap_model, create_PmapTriple(prognum, versnum, protocol), create_PmapPortRec(true, port) );
}

PmapPortRec * pmap_find_mapping(ULongT prognum, ULongT versnum, UIntT protocol)
{
    PmapTriple * key = create_PmapTriple(prognum, versnum, protocol);

    return get_Map(pmap_model, key);
}

void pmap_unset_mappings(ULongT prognum, ULongT versnum)
{
    int i,sz;

    sz = size_Map(pmap_model);

    for(i=0;i<sz;i++)
    {
        PmapTriple * key = key_Map(pmap_model, i);

        if( (key->prognum == prognum) && (key->versnum == versnum) )
        {
            PmapPortRec * elem = get_Map(pmap_model, key);
            elem->mapped = false;
        }
    }
}


PmapPortRec * pmap_find_mappings(ULongT prognum, ULongT versnum)
{
    int i,sz;

    sz = size_Map(pmap_model);

    for(i=0;i<sz;i++)
    {
        PmapTriple * key = key_Map(pmap_model, i);

        if( (key->prognum == prognum) && (key->versnum == versnum) )
        {
            PmapPortRec * elem = get_Map(pmap_model, key);
            if(elem->mapped)
                return elem;
        }
    }
    return NULL;
}

PmapPortRec * pmap_find_mapping_maxver(ULongT prognum, ULongT protocol)
{
    int i,sz;
    UShortT maxver = 0;
    PmapPortRec * maxver_port = NULL;

    sz = size_Map(pmap_model);

    for(i=0;i<sz;i++)
    {
        PmapTriple * key = key_Map(pmap_model, i);

        if( (key->prognum == prognum) && (key->protocol == protocol) && (key->versnum > maxver) )
        {
            PmapPortRec * elem = get_Map(pmap_model, key);
            if(elem->mapped)
            {
                maxver = key->versnum;
                maxver_port = elem;
            }
        }
    }
    return maxver_port;
}

/********************************************************************/
/**                       Helper Functions                         **/
/********************************************************************/