2017-03-31 16:58:14 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* net/usrsock/usrsock_conn.c
|
|
|
|
*
|
2021-11-15 07:53:26 +01:00
|
|
|
* 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
|
2017-03-31 16:58:14 +02:00
|
|
|
*
|
2021-11-15 07:53:26 +01:00
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
2017-03-31 16:58:14 +02:00
|
|
|
*
|
2021-11-15 07:53:26 +01:00
|
|
|
* 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.
|
2017-03-31 16:58:14 +02:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Included Files
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#include <nuttx/config.h>
|
|
|
|
#if defined(CONFIG_NET) && defined(CONFIG_NET_USRSOCK)
|
|
|
|
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <debug.h>
|
|
|
|
|
|
|
|
#include <arch/irq.h>
|
|
|
|
|
2022-01-04 09:33:03 +01:00
|
|
|
#include <nuttx/kmalloc.h>
|
2017-10-25 15:31:14 +02:00
|
|
|
#include <nuttx/semaphore.h>
|
2017-03-31 16:58:14 +02:00
|
|
|
#include <nuttx/net/netconfig.h>
|
|
|
|
#include <nuttx/net/net.h>
|
|
|
|
|
|
|
|
#include "usrsock/usrsock.h"
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Private Data
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
/* The array containing all usrsock connections. */
|
|
|
|
|
2022-01-04 09:33:03 +01:00
|
|
|
#ifndef CONFIG_NET_ALLOC_CONNS
|
2017-10-25 15:31:14 +02:00
|
|
|
static struct usrsock_conn_s g_usrsock_connections[CONFIG_NET_USRSOCK_CONNS];
|
2022-01-04 09:33:03 +01:00
|
|
|
#endif
|
2017-03-31 16:58:14 +02:00
|
|
|
|
|
|
|
/* A list of all free usrsock connections */
|
|
|
|
|
|
|
|
static dq_queue_t g_free_usrsock_connections;
|
|
|
|
static sem_t g_free_sem;
|
|
|
|
|
|
|
|
/* A list of all allocated usrsock connections */
|
|
|
|
|
|
|
|
static dq_queue_t g_active_usrsock_connections;
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Private Functions
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: _usrsock_semtake() and _usrsock_semgive()
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Take/give semaphore
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static void _usrsock_semtake(FAR sem_t *sem)
|
|
|
|
{
|
2020-01-02 17:49:34 +01:00
|
|
|
net_lockedwait_uninterruptible(sem);
|
2017-03-31 16:58:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void _usrsock_semgive(FAR sem_t *sem)
|
|
|
|
{
|
2020-01-02 17:49:34 +01:00
|
|
|
nxsem_post(sem);
|
2017-03-31 16:58:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Public Functions
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: usrsock_alloc()
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Allocate a new, uninitialized usrsock connection structure. This is
|
|
|
|
* normally something done by the implementation of the socket() API
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
FAR struct usrsock_conn_s *usrsock_alloc(void)
|
|
|
|
{
|
|
|
|
FAR struct usrsock_conn_s *conn;
|
2022-01-04 09:33:03 +01:00
|
|
|
#ifdef CONFIG_NET_ALLOC_CONNS
|
|
|
|
int i;
|
|
|
|
#endif
|
2017-03-31 16:58:14 +02:00
|
|
|
|
2018-06-23 22:09:06 +02:00
|
|
|
/* The free list is protected by a semaphore (that behaves like a mutex). */
|
2017-03-31 16:58:14 +02:00
|
|
|
|
|
|
|
_usrsock_semtake(&g_free_sem);
|
2022-01-04 09:33:03 +01:00
|
|
|
#ifdef CONFIG_NET_ALLOC_CONNS
|
|
|
|
if (dq_peek(&g_free_usrsock_connections) == NULL)
|
|
|
|
{
|
|
|
|
conn = kmm_zalloc(sizeof(*conn) * CONFIG_NET_USRSOCK_CONNS);
|
|
|
|
if (conn != NULL)
|
|
|
|
{
|
|
|
|
for (i = 0; i < CONFIG_NET_USRSOCK_CONNS; i++)
|
|
|
|
{
|
|
|
|
dq_addlast(&conn[i].node, &g_free_usrsock_connections);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2019-03-11 19:48:17 +01:00
|
|
|
conn = (FAR struct usrsock_conn_s *)
|
2022-01-04 09:33:03 +01:00
|
|
|
dq_remfirst(&g_free_usrsock_connections);
|
2017-03-31 16:58:14 +02:00
|
|
|
if (conn)
|
|
|
|
{
|
|
|
|
/* Make sure that the connection is marked as uninitialized */
|
|
|
|
|
2019-03-19 16:23:08 +01:00
|
|
|
nxsem_init(&conn->resp.sem, 0, 1);
|
2017-03-31 16:58:14 +02:00
|
|
|
conn->usockid = -1;
|
|
|
|
conn->state = USRSOCK_CONN_STATE_UNINITIALIZED;
|
|
|
|
|
|
|
|
/* Enqueue the connection into the active list */
|
|
|
|
|
|
|
|
dq_addlast(&conn->node, &g_active_usrsock_connections);
|
|
|
|
}
|
|
|
|
|
|
|
|
_usrsock_semgive(&g_free_sem);
|
|
|
|
return conn;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: usrsock_free()
|
|
|
|
*
|
|
|
|
* Description:
|
2020-05-17 16:47:40 +02:00
|
|
|
* Free a usrsock connection structure that is no longer in use. This
|
|
|
|
* should be done by the implementation of close().
|
2017-03-31 16:58:14 +02:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
void usrsock_free(FAR struct usrsock_conn_s *conn)
|
|
|
|
{
|
2018-06-23 22:09:06 +02:00
|
|
|
/* The free list is protected by a semaphore (that behaves like a mutex). */
|
2017-03-31 16:58:14 +02:00
|
|
|
|
|
|
|
DEBUGASSERT(conn->crefs == 0);
|
|
|
|
|
|
|
|
_usrsock_semtake(&g_free_sem);
|
|
|
|
|
|
|
|
/* Remove the connection from the active list */
|
|
|
|
|
|
|
|
dq_rem(&conn->node, &g_active_usrsock_connections);
|
|
|
|
|
|
|
|
/* Reset structure */
|
|
|
|
|
2019-03-19 16:23:08 +01:00
|
|
|
nxsem_destroy(&conn->resp.sem);
|
2017-03-31 16:58:14 +02:00
|
|
|
memset(conn, 0, sizeof(*conn));
|
|
|
|
|
|
|
|
/* Free the connection */
|
|
|
|
|
|
|
|
dq_addlast(&conn->node, &g_free_usrsock_connections);
|
|
|
|
_usrsock_semgive(&g_free_sem);
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: usrsock_nextconn()
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Traverse the list of allocated usrsock connections
|
|
|
|
*
|
|
|
|
* Assumptions:
|
|
|
|
* This function is called from usrsock device logic.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
FAR struct usrsock_conn_s *usrsock_nextconn(FAR struct usrsock_conn_s *conn)
|
|
|
|
{
|
|
|
|
if (!conn)
|
|
|
|
{
|
|
|
|
return (FAR struct usrsock_conn_s *)g_active_usrsock_connections.head;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return (FAR struct usrsock_conn_s *)conn->node.flink;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: usrsock_active()
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Find a connection structure that is the appropriate
|
|
|
|
* connection for usrsock
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
FAR struct usrsock_conn_s *usrsock_active(int16_t usockid)
|
|
|
|
{
|
|
|
|
FAR struct usrsock_conn_s *conn = NULL;
|
|
|
|
|
|
|
|
while ((conn = usrsock_nextconn(conn)) != NULL)
|
|
|
|
{
|
|
|
|
if (conn->usockid == usockid)
|
2019-07-03 02:02:23 +02:00
|
|
|
{
|
|
|
|
return conn;
|
|
|
|
}
|
2017-03-31 16:58:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: usrsock_setup_request_callback()
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
int usrsock_setup_request_callback(FAR struct usrsock_conn_s *conn,
|
|
|
|
FAR struct usrsock_reqstate_s *pstate,
|
|
|
|
FAR devif_callback_event_t event,
|
|
|
|
uint16_t flags)
|
|
|
|
{
|
|
|
|
int ret = -EBUSY;
|
|
|
|
|
2020-01-02 17:49:34 +01:00
|
|
|
nxsem_init(&pstate->recvsem, 0, 0);
|
2020-05-17 15:56:21 +02:00
|
|
|
nxsem_set_protocol(&pstate->recvsem, SEM_PRIO_NONE);
|
2018-08-26 22:59:04 +02:00
|
|
|
|
2022-01-04 09:33:03 +01:00
|
|
|
pstate->conn = conn;
|
|
|
|
pstate->result = -EAGAIN;
|
2017-03-31 16:58:14 +02:00
|
|
|
pstate->completed = false;
|
2022-01-04 09:33:03 +01:00
|
|
|
pstate->unlock = false;
|
2017-03-31 16:58:14 +02:00
|
|
|
|
|
|
|
/* Set up the callback in the connection */
|
|
|
|
|
net/devif/devif_callback.c: corrected the connection event list to work as FIFO instead of LIFO.
In case of enabled packet forwarding mode, packets were forwarded in a reverse order
because of LIFO behavior of the connection event list.
The issue exposed only during high network traffic. Thus the event list started to grow
that resulted in changing the order of packets inside of groups of several packets
like the following: 3, 2, 1, 6, 5, 4, 8, 7 etc.
Remarks concerning the connection event list implementation:
* Now the queue (list) is FIFO as it should be.
* The list is singly linked.
* The list has a head pointer (inside of outer net_driver_s structure),
and a tail pointer is added into outer net_driver_s structure.
* The list item is devif_callback_s structure.
It still has two pointers to two different list chains (*nxtconn and *nxtdev).
* As before the first argument (*dev) of the list functions can be NULL,
while the other argument (*list) is effective (not NULL).
* An extra (*tail) argument is added to devif_callback_alloc()
and devif_conn_callback_free() functions.
* devif_callback_alloc() time complexity is O(1) (i.e. O(n) to fill the whole list).
* devif_callback_free() time complexity is O(n) (i.e. O(n^2) to empty the whole list).
* devif_conn_event() time complexity is O(n).
2021-08-29 22:57:26 +02:00
|
|
|
pstate->cb = devif_callback_alloc(NULL, &conn->list, &conn->list_tail);
|
2017-03-31 16:58:14 +02:00
|
|
|
if (pstate->cb)
|
|
|
|
{
|
2019-03-19 16:23:08 +01:00
|
|
|
/* Take a lock since only one outstanding request is allowed */
|
|
|
|
|
|
|
|
if ((flags & USRSOCK_EVENT_REQ_COMPLETE) != 0)
|
|
|
|
{
|
|
|
|
_usrsock_semtake(&conn->resp.sem);
|
|
|
|
pstate->unlock = true;
|
|
|
|
}
|
|
|
|
|
2017-08-29 22:08:04 +02:00
|
|
|
/* Set up the connection event handler */
|
2017-03-31 16:58:14 +02:00
|
|
|
|
|
|
|
pstate->cb->flags = flags;
|
|
|
|
pstate->cb->priv = (FAR void *)pstate;
|
|
|
|
pstate->cb->event = event;
|
|
|
|
|
|
|
|
ret = OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: usrsock_setup_data_request_callback()
|
|
|
|
****************************************************************************/
|
|
|
|
|
2020-05-17 16:47:40 +02:00
|
|
|
int usrsock_setup_data_request_callback(
|
|
|
|
FAR struct usrsock_conn_s *conn,
|
|
|
|
FAR struct usrsock_data_reqstate_s *pstate,
|
|
|
|
FAR devif_callback_event_t event,
|
|
|
|
uint16_t flags)
|
2017-03-31 16:58:14 +02:00
|
|
|
{
|
|
|
|
pstate->valuelen = 0;
|
|
|
|
pstate->valuelen_nontrunc = 0;
|
2019-03-11 19:48:17 +01:00
|
|
|
return usrsock_setup_request_callback(conn, &pstate->reqstate, event,
|
|
|
|
flags);
|
2017-03-31 16:58:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: usrsock_teardown_request_callback()
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
void usrsock_teardown_request_callback(FAR struct usrsock_reqstate_s *pstate)
|
|
|
|
{
|
|
|
|
FAR struct usrsock_conn_s *conn = pstate->conn;
|
|
|
|
|
2019-03-19 16:23:08 +01:00
|
|
|
if (pstate->unlock)
|
|
|
|
{
|
|
|
|
_usrsock_semgive(&conn->resp.sem);
|
|
|
|
}
|
|
|
|
|
2017-03-31 16:58:14 +02:00
|
|
|
/* Make sure that no further events are processed */
|
|
|
|
|
net/devif/devif_callback.c: corrected the connection event list to work as FIFO instead of LIFO.
In case of enabled packet forwarding mode, packets were forwarded in a reverse order
because of LIFO behavior of the connection event list.
The issue exposed only during high network traffic. Thus the event list started to grow
that resulted in changing the order of packets inside of groups of several packets
like the following: 3, 2, 1, 6, 5, 4, 8, 7 etc.
Remarks concerning the connection event list implementation:
* Now the queue (list) is FIFO as it should be.
* The list is singly linked.
* The list has a head pointer (inside of outer net_driver_s structure),
and a tail pointer is added into outer net_driver_s structure.
* The list item is devif_callback_s structure.
It still has two pointers to two different list chains (*nxtconn and *nxtdev).
* As before the first argument (*dev) of the list functions can be NULL,
while the other argument (*list) is effective (not NULL).
* An extra (*tail) argument is added to devif_callback_alloc()
and devif_conn_callback_free() functions.
* devif_callback_alloc() time complexity is O(1) (i.e. O(n) to fill the whole list).
* devif_callback_free() time complexity is O(n) (i.e. O(n^2) to empty the whole list).
* devif_conn_event() time complexity is O(n).
2021-08-29 22:57:26 +02:00
|
|
|
devif_conn_callback_free(NULL, pstate->cb, &conn->list, &conn->list_tail);
|
2018-08-26 22:59:04 +02:00
|
|
|
nxsem_destroy(&pstate->recvsem);
|
2017-03-31 16:58:14 +02:00
|
|
|
|
|
|
|
pstate->cb = NULL;
|
|
|
|
}
|
|
|
|
|
2018-08-26 23:01:53 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* Name: usrsock_setup_datain
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
void usrsock_setup_datain(FAR struct usrsock_conn_s *conn,
|
|
|
|
FAR struct iovec *iov, unsigned int iovcnt)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
conn->resp.datain.iov = iov;
|
|
|
|
conn->resp.datain.pos = 0;
|
|
|
|
conn->resp.datain.total = 0;
|
|
|
|
conn->resp.datain.iovcnt = iovcnt;
|
|
|
|
|
|
|
|
for (i = 0; i < iovcnt; i++)
|
|
|
|
{
|
|
|
|
conn->resp.datain.total += iov[i].iov_len;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-31 16:58:14 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* Name: usrsock_initialize()
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Initialize the User Socket connection structures. Called once and only
|
|
|
|
* from the networking layer.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
void usrsock_initialize(void)
|
|
|
|
{
|
2022-01-04 09:33:03 +01:00
|
|
|
#ifndef CONFIG_NET_ALLOC_CONNS
|
|
|
|
FAR struct usrsock_conn_s *conn;
|
2017-03-31 16:58:14 +02:00
|
|
|
int i;
|
2022-01-04 09:33:03 +01:00
|
|
|
#endif
|
2017-03-31 16:58:14 +02:00
|
|
|
|
|
|
|
/* Initialize the queues */
|
|
|
|
|
|
|
|
dq_init(&g_free_usrsock_connections);
|
|
|
|
dq_init(&g_active_usrsock_connections);
|
2017-10-03 20:51:15 +02:00
|
|
|
nxsem_init(&g_free_sem, 0, 1);
|
2017-03-31 16:58:14 +02:00
|
|
|
|
2022-01-04 09:33:03 +01:00
|
|
|
#ifndef CONFIG_NET_ALLOC_CONNS
|
2017-03-31 16:58:14 +02:00
|
|
|
for (i = 0; i < CONFIG_NET_USRSOCK_CONNS; i++)
|
|
|
|
{
|
2022-01-04 09:33:03 +01:00
|
|
|
conn = &g_usrsock_connections[i];
|
2017-03-31 16:58:14 +02:00
|
|
|
|
|
|
|
/* Mark the connection closed and move it to the free list */
|
|
|
|
|
|
|
|
conn->usockid = -1;
|
|
|
|
conn->state = USRSOCK_CONN_STATE_UNINITIALIZED;
|
|
|
|
dq_addlast(&conn->node, &g_free_usrsock_connections);
|
|
|
|
}
|
2022-01-04 09:33:03 +01:00
|
|
|
#endif
|
2017-03-31 16:58:14 +02:00
|
|
|
|
|
|
|
/* Register /dev/usrsock character device. */
|
|
|
|
|
|
|
|
usrsockdev_register();
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* CONFIG_NET && CONFIG_NET_USRSOCK */
|