sockets.c

来自「mcf5307实验源代码」· C语言 代码 · 共 1,494 行 · 第 1/5 页

C
1,494
字号
                                               this server/task_id */
    uint16       counter;                   /* used for initialization of
                                               Task_Entry */
      
    /*  Validate the socket number.  */
    if ((socketd < 0) || (socketd >= NSOCKETS) ||
        (socket_list[socketd] == NU_NULL))
        return(NU_INVALID_SOCKET);

    /*  Don't let any other users in until we are done.  */
#ifdef PLUS
    NU_Obtain_Semaphore(&TCP_Resource, NU_SUSPEND);
#else
    NU_Request_Resource(TCP_Resource, NU_WAIT_FOREVER);
#endif
      
    /* Allocate memory required for a Task_Entry structure, connection status
       array, and portlist entry array all at once.  This is done for efficiency
       (1 service call as opposed to 3).  Also, each of the 3 indepedent
       allocations was less than the default min allocation size (50 bytes) of
       PLUS, so memory was being wasted.
    */
#ifdef PLUS
    status = NU_Allocate_Memory(&System_Memory, (VOID *) &return_ptr,
                                (UNSIGNED)(sizeof(struct TASK_TABLE_STRUCT) +
                                (backlog * sizeof(unsigned short)) +
                                (backlog * sizeof(int16))),
                                (UNSIGNED)NU_NO_SUSPEND);
#else
    status = NU_Alloc_Memory(sizeof(struct TASK_TABLE_STRUCT) +
                            (backlog * sizeof(unsigned short)) +
                            (backlog * sizeof(int16)),
                            (unsigned int **)&return_ptr,
                            NU_NO_TIMEOUT);
#endif
      
    /* verify a successful allocation */
    if (status == NU_SUCCESS)
    {
        return_ptr = normalize_ptr(return_ptr);

        /* Break up the block of memory allocated into three seperate chunks. */
        Task_Entry = (struct TASK_TABLE_STRUCT *)return_ptr;

        Task_Entry->stat_entry = (short *)(return_ptr +
                                           sizeof(struct TASK_TABLE_STRUCT));

        Task_Entry->port_entry = (int16 *)(return_ptr +
                                           sizeof(struct TASK_TABLE_STRUCT) +
                                          (backlog * sizeof(unsigned short)));

        /* retrieve the local port number from the socket descriptor
           for the task table */
        Task_Entry->local_port_num =
                   (uint16)socket_list[socketd]->local_addr.port_num;

        /* record the socket number in the socketd field of Task_Entry */
        Task_Entry->socketd = socketd;

        /* retrieve the current task id for the task table */
#ifdef PLUS
        task_id = NU_Current_Task_Pointer();
        /* verify that a task is running */
        if (task_id != NU_NULL)
#else
        task_id = NU_Current_Task_ID();
        /* verify that a task is running */
        if (task_id != NU_SYSTEM)
#endif

            Task_Entry->Task_ID = task_id;
        else
            /* return the error to the caller */
            return_status = NU_NOT_A_TASK;

        /* initialize the port_entries and stat_entries */
        for (counter = 0; counter < backlog; counter++)
        {
            Task_Entry->port_entry[counter] = NU_IGNORE_VALUE;
            Task_Entry->stat_entry[counter] = NU_IGNORE_VALUE;
        }

        /* initialize the current connection pointer to the first
           space in the table */
        Task_Entry->current_idx = 0;

        /* store the number of backlog queues possible */
        Task_Entry->total_entries = backlog;

        /* Initialize the accept flag. */
        Task_Entry->acceptFlag = 0;

        /* initialize the next pointer to NU_NULL */
        Task_Entry->next = NU_NULL;

        /* call a routine to attach this structure to the
           linked list of structures */
        NU_TaskTableAdd(Task_Entry);

        /* Mark this socket as a listener. */
        socket_list[socketd]->listener = NU_TRUE;

    }
    else
    {
        NU_Tcp_Log_Error(TCP_SESS_MEM, TCP_RECOVERABLE,
                         __FILE__, __LINE__);

        /* Tell them no more memory. */
        return_status = NU_NO_SOCK_MEMORY;
    }
      
    /* allow others to use the TCP resource */
#ifdef PLUS
    NU_Release_Semaphore(&TCP_Resource);
#else
    NU_Release_Resource(TCP_Resource);
#endif
      
    /* Turn on blocking for this socket so that blocking is the default for the
       NU_Accept call */
    NU_fcntl(socketd, NU_SETFLAG, NU_BLOCK, 0);

    /* return to the caller */
    return(return_status);

} /*  end of NU_Listen */

/*************************************************************************/
/*                                                                       */
/* FUNCTION                                                              */
/*                                                                       */
/*      NU_Accept                                                        */
/*                                                                       */
/* DESCRIPTION                                                           */
/*                                                                       */
/*   This function is responsible for establishing a new socket          */
/*   descriptor containing info on both the server and a client          */
/*   with whom a connection has been successfully established.           */
/*                                                                       */
/*  CALLED FROM                                                          */
/*                                                                       */
/*      User Applications                                                */
/*                                                                       */
/* CALLS                                                                 */
/*                                                                       */
/*      NU_Obtain_Semaphore                                              */
/*      NU_Release_Semaphore                                             */
/*      NU_Allocate_Memory                                               */
/*      NU_Current_Task_Pointer                                          */
/*      suspend_task                                                     */
/*      NU_SearchTaskList                                                */
/*                                                                       */
/*   History:                                                            */
/*       created - 10/22/92, bgh                                         */
/*                                                                       */
/*************************************************************************/
int16 NU_Accept(int16 socketd, struct addr_struct *peer, int16 *addrlen)
{
    uint        server_port_num;
#ifdef PLUS
    NU_TASK     *Task_ID;        /* current task pointer */
#else
    sint         Task_ID;        /* current task id */
#endif
    struct port *pprt, *prt;     /* port pointer */
    struct TASK_TABLE_STRUCT   *Task_Entry = NU_NULL;  /* structure of connections
                                                          for this server/task_id */
    int16         pnum;           /* portlist index */
    int16         new_sock;       /* index of new socket in socket_list */
    int16         return_status = NU_INVALID_SOCKET;

    /*  Clean up warnings.  This parameter is used for socket compatibility
        but we are currently not making any use of it.  */
    server_port_num = (uint)*addrlen;

    /*  Validate the socket number.  */
    if ((socketd < 0) || (socketd >= NSOCKETS) ||
        (socket_list[socketd] == NU_NULL) ||
        (socket_list[socketd]->listener == NU_FALSE))
    {
        return(return_status);
    }

    /* init the new_sock value for the possible return if not set */
    new_sock = NU_NO_SOCKET_SPACE;

    /*  Prior to the NU_Accept() service call, an application must call
     *  NU_Listen().  NU_Listen() sets up a table to accept connection
     *  requests.  This table must be ready before NU_Accept() begins
     *  to wait for connection attempts. */

    /*  Don't let anyone else in until we are through.  */
#ifdef PLUS
    NU_Obtain_Semaphore(&TCP_Resource, NU_SUSPEND);
#else
    NU_Request_Resource(TCP_Resource, NU_WAIT_FOREVER);
#endif

    /* get the current task id for the next 2 service calls */
#ifdef PLUS
    Task_ID = NU_Current_Task_Pointer();
#else
    Task_ID = NU_Current_Task_ID();
#endif

    /* retrieve the local port number from the socket descriptor
       for comparison to the task table */
    server_port_num = (uint16)socket_list[socketd]->local_addr.port_num;

    /*  Check for an established connection.  If there isn't one, then
        suspend the calling task until the connection is made.  */
    do
    {

        /* search the task table for this port number/task id */
        Task_Entry = NU_SearchTaskList(Task_Entry, Task_ID,
                                       server_port_num, SEST, -1);

        /* continue only if a match was found in the task table */
        if (Task_Entry != NU_NULL)
        {
            /* get a pointer into the port list table at the oldest
               table entry */
            pprt =
                portlist[Task_Entry->port_entry[Task_Entry->current_idx]];

            /* release the resource because NU_Socket will be needing it */
#ifdef PLUS
            NU_Release_Semaphore(&TCP_Resource);
#else
            NU_Release_Resource(TCP_Resource);
#endif

            /* let NU_Socket allocate a new socket structure */
            new_sock = NU_Socket(NU_FAMILY_IP, NU_TYPE_STREAM, 0);

            /*  Make sure we got one.  */
            if (new_sock >= 0)
            {
                /* get the resource back now that NU_Socket is finished */
#ifdef PLUS
                NU_Obtain_Semaphore(&TCP_Resource, NU_SUSPEND);
#else
                NU_Request_Resource(TCP_Resource, NU_WAIT_FOREVER);
#endif

               /* copy known information from the original socket
                  descriptor */
               memcpy (socket_list[new_sock], socket_list[socketd],
                        sizeof(struct sock_struct));

               /* fill the client portion of the new socket descriptor */
               socket_list[new_sock]->foreign_addr.port_num =
                                   (int16)intswap (pprt->tcpout.t.dest);
               memcpy((uchar *)
                   &(socket_list[new_sock]->foreign_addr.ip_num),
                     pprt->tcps.dest,4);

               /* store the new socket descriptor for return */
               return_status = new_sock;

               peer->family = NU_FAMILY_IP;
               peer->port = (uint16)socket_list[new_sock]->foreign_addr.port_num;
               memcpy (&peer->id, pprt->tcpout.i.ipdest, 4);

               /* call a routine to delete this entry from the task
                  table and increment the current task entry pointer */
               NU_UpdateTaskTable(Task_Entry);

               /* Get the port number so that we can clear the transmit
                  Task ID */
               if ((pnum = NU_GetPnum(socket_list[new_sock])) >= 0)
               {
                   /* get the pointer */
                   prt = portlist[pnum];

                   /* Clear out the task entry information. */
                   prt->task_entry = NU_NULL;

                   /* clear the portlist task id */
#ifdef PLUS
                    prt->TXTask = NU_NULL;
#else
                    prt->TXTask = -1;
#endif
                }
                else
                    return_status = NU_NO_PORT_NUMBER;
            }
            else
            {
                /* return the error status returned from the socket call */
                return_status = new_sock;
            }
        }

        /* There are no connections to accept so check to see if the application
           wants to block pending a connection. */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?