/* * Copyright (c) 2008-2017, 2019-2020, Pelion and affiliates. * SPDX-License-Identifier: Apache-2.0 * * 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. */ /** * * \file socket.h * \brief Socket API definitions. * * Socket API functions and relevant structures. * * */ #ifndef _NS_SOCKET_H #define _NS_SOCKET_H #include "Core/include/ns_error_types.h" #include "Core/include/ns_buffer.h" #include "Core/include/sockbuf.h" #ifndef SOCKET_RX_LIMIT #define SOCKET_RX_LIMIT 3 #endif #ifndef SOCKETS_MAX #define SOCKETS_MAX 16 #endif #ifndef SOCKET_DEFAULT_STREAM_RCVBUF #define SOCKET_DEFAULT_STREAM_RCVBUF 2048 #endif #ifndef SOCKET_DEFAULT_STREAM_SNDBUF #define SOCKET_DEFAULT_STREAM_SNDBUF 2048 #endif #ifndef SOCKET_DEFAULT_STREAM_SNDLOWAT #define SOCKET_DEFAULT_STREAM_SNDLOWAT 512 #endif #ifndef SOCKET_DEFAULT_REFERENCE_LIMIT #define SOCKET_DEFAULT_REFERENCE_LIMIT 512 #endif typedef enum socket_family_e { SOCKET_FAMILY_NONE, SOCKET_FAMILY_IPV6, } socket_family_t; // This is always true because we currently have only 1 type // If we support more types in future it becomes "((socket)->family == SOCKET_FAMILY_IPV6)" #define socket_is_ipv6(socket) true typedef enum socket_type_e { SOCKET_TYPE_DGRAM, SOCKET_TYPE_STREAM, SOCKET_TYPE_RAW } socket_type_t; #define SOCKET_FLAG_CLOSED 128 /* Has been closed by application */ #define SOCKET_FLAG_PENDING 64 /* Is waiting for accept on a listening socket */ #define SOCKET_FLAG_CANT_RECV_MORE 32 #define SOCKET_FLAG_SHUT_WR 16 #define SOCKET_FLAG_CONNECTED 8 /* Connection completed (and possibly since broken) */ #define SOCKET_LISTEN_STATE 4 #define SOCKET_BUFFER_CB 2 #define SOCKET_FLAG_CONNECTING 1 /* Connection in progress */ #ifndef SOCKET_IPV6_TCLASS_DEFAULT #define SOCKET_IPV6_TCLASS_DEFAULT 0 /** Default traffic class for a new socket */ #endif #ifndef SOCKET_LISTEN_BACKLOG_MAX #define SOCKET_LISTEN_BACKLOG_MAX 10 #endif typedef enum { ARM_SOCKET_INIT = 0, ARM_SOCKET_EVENT_CB = 1, ARM_SOCKET_DATA_CB = 2, // Original data event - one buffer stored in event ARM_SOCKET_DATA_QUEUED_CB = 3, // New data event - no buffer in event, buffer in queue ARM_SOCKET_TCP_TIMER_CB, } arm_socket_event_id_e; typedef struct socket_buffer_callback_t { uint8_t event_type; int8_t socket_id; int8_t interface_id; buffer_t *buf; void *session_ptr; } socket_buffer_callback_t; typedef enum { SOCKET_SRC_ADDRESS_PRIMARY = 0, SOCKET_SRC_ADDRESS_SECONDARY = 1, } socket_src_address_type; struct inet_pcb_s; struct ns_msghdr; struct socket; typedef NS_LIST_HEAD_INCOMPLETE(struct socket) socket_queue_list_t; struct socket_pending { ns_list_link_t link; /*!< Link as member of connection queue */ struct socket *listen_head; /*!< Pointer to listening socket we're queued against */ }; struct socket_live { socket_queue_list_t queue; /*!< Incoming connection queue */ void (*fptr)(void *); }; /** Socket structure */ typedef struct socket { /* This listen queue must be first, due to need to use incomplete list head */ union { struct socket_pending pending; /* !< Info if PENDING flag set (pending connection) */ struct socket_live live; /* !< Info if PENDING flag clear (normal socket) */ } u; int8_t id; /*!< socket id */ uint8_t flags; /*!< Socket option flags */ int8_t tasklet; /*!< Receiver tasklet */ uint16_t refcount; socket_family_t family; socket_type_t type; int8_t default_interface_id; int8_t broadcast_pan; uint8_t listen_backlog; /*!< Limit if pending connection queue */ struct inet_pcb_s *inet_pcb; /*!< shortcut to Internet control block */ sockbuf_t rcvq; sockbuf_t sndq; ns_list_link_t link; /*!< link */ } socket_t; NS_STATIC_ASSERT(offsetof(socket_t, u.pending.link) == 0, "Listen queue link must be first (NS_LIST_HEAD_INCOMPLETE)") typedef struct inet_group { uint8_t group_addr[16]; int8_t interface_id; ns_list_link_t link; } inet_group_t; /** Internet protocol control block */ typedef struct inet_pcb_s { socket_t *socket; #ifndef NO_TCP void *session; /*!< Session for transport protocol - only used by TCP at present */ #endif uint8_t local_address[16]; /*!< Local address */ uint8_t remote_address[16]; /*!< Destination address */ uint16_t local_port; /*!< Local port */ uint16_t remote_port; /*!< Destination port */ int16_t unicast_hop_limit; /*!< May be -1, which will give per-interface default */ uint8_t multicast_hop_limit; int8_t multicast_if; uint32_t addr_preferences; uint8_t protocol; /*!< IP type IPV6_NH_TCP, IPV6_NH_UDP, IPV6_NH_ICMPV6... */ int8_t link_layer_security; #ifndef NO_IPV6_PMTUD int8_t use_min_mtu; /*!< RFC 3542 socket option */ #endif #ifndef NO_IP_FRAGMENT_TX int8_t dontfrag; #endif uint8_t tclass; bool multicast_loop: 1; bool recvpktinfo: 1; bool recvhoplimit: 1; bool recvtclass: 1; bool edfe_mode: 1; int_least24_t flow_label; NS_LIST_HEAD(inet_group_t, link) mc_groups; } inet_pcb_t; typedef NS_LIST_HEAD(socket_t, link) socket_list_t; extern socket_list_t socket_list; extern const uint8_t ns_in6addr_any[16]; extern void socket_init(void); extern int8_t socket_event_handler_id_get(void); extern bool socket_data_queued_event_push(socket_t *socket); extern void socket_event_push(uint8_t sock_event, socket_t *socket, int8_t interface_id, void *session_ptr, uint16_t length); extern socket_error_t socket_create(socket_family_t family, socket_type_t type, uint8_t protocol, int8_t *sid, uint16_t port, void (*passed_fptr)(void *), bool buffer_type); extern socket_t *socket_new_incoming_connection(socket_t *listen_socket); void socket_connection_abandoned(socket_t *socket, int8_t interface_id, uint8_t reason); void socket_connection_complete(socket_t *socket, int8_t interface_id); extern void socket_leave_pending_state(socket_t *socket, void (*fptr)(void *)); void socket_cant_recv_more(socket_t *socket, int8_t interface_id); extern int8_t socket_id_assign_and_attach(socket_t *socket); extern void socket_id_detach(int8_t sid); extern buffer_t *socket_buffer_read(socket_t *socket); extern socket_t *socket_lookup(socket_family_t family, uint8_t protocol, const sockaddr_t *local_addr, const sockaddr_t *remote_addr); extern socket_t *socket_lookup_ipv6(uint8_t protocol, const sockaddr_t *local_addr, const sockaddr_t *remote_addr, bool allow_wildcards); extern socket_error_t socket_port_validate(uint16_t port, uint8_t protocol); extern socket_error_t socket_up(buffer_t *buf); extern bool socket_message_validate_iov(const struct ns_msghdr *msg, uint16_t *length_out); extern int16_t socket_buffer_sendmsg(int8_t sid, buffer_t *buf, const struct ns_msghdr *msg, int flags); extern socket_t *socket_pointer_get(int8_t socket); extern void socket_inet_pcb_set_buffer_hop_limit(const inet_pcb_t *socket, buffer_t *buf, const int16_t *msg_hoplimit); extern bool socket_validate_listen_backlog(const socket_t *socket_ptr); extern void socket_list_print(route_print_fn_t *print_fn, char sep); extern socket_t *socket_reference(socket_t *); extern socket_t *socket_dereference(socket_t *); extern void socket_release(socket_t *socket); extern void socket_tx_buffer_event_and_free(buffer_t *buf, uint8_t status); extern buffer_t *socket_tx_buffer_event(buffer_t *buf, uint8_t status); extern inet_pcb_t *socket_inet_pcb_allocate(void); extern inet_pcb_t *socket_inet_pcb_clone(const inet_pcb_t *orig); /** * Free reserved inet_pcb */ extern inet_pcb_t *socket_inet_pcb_free(inet_pcb_t *inet_pcb); extern int8_t socket_inet_pcb_join_group(inet_pcb_t *inet_pcb, int8_t interface_id, const uint8_t group[__static 16]); extern int8_t socket_inet_pcb_leave_group(inet_pcb_t *inet_pcb, int8_t interface_id, const uint8_t group[__static 16]); /** * Determine interface based on socket_id and address */ extern struct protocol_interface_info_entry *socket_interface_determine(const socket_t *socket, buffer_t *buf); extern uint16_t socket_generate_random_port(uint8_t protocol); #endif /*_NS_SOCKET_H*/