diff options
| author | chenyong <[email protected]> | 2018-07-17 20:29:33 +0800 |
|---|---|---|
| committer | chenyong <[email protected]> | 2018-07-18 13:34:13 +0800 |
| commit | 8cda48a1323dc3cb1f947eb86d895595ebc30b38 (patch) | |
| tree | 2adcb7fef3f4e735196973821aa298e5f6af98e7 /components/net/sal_socket/src | |
| parent | 4ca1d03bdffef9e79456df3e696b7efb7f5b79aa (diff) | |
[net][sal] Add SAL (socket abstraction layer) framework
Diffstat (limited to 'components/net/sal_socket/src')
| -rw-r--r-- | components/net/sal_socket/src/sal_ipaddr.c | 271 | ||||
| -rw-r--r-- | components/net/sal_socket/src/sal_socket.c | 730 |
2 files changed, 1001 insertions, 0 deletions
diff --git a/components/net/sal_socket/src/sal_ipaddr.c b/components/net/sal_socket/src/sal_ipaddr.c new file mode 100644 index 0000000000..0060ccec45 --- /dev/null +++ b/components/net/sal_socket/src/sal_ipaddr.c @@ -0,0 +1,271 @@ +/* + * File : sal_ipaddr.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2018-05-18 ChenYong First version + */ + +#include <sal_ipaddr.h> +#include <rtthread.h> + +/* Here for now until needed in other places in lwIP */ +#ifndef isprint +#define in_range(c, lo, up) ((u8_t)c >= lo && (u8_t)c <= up) +#define isprint(c) in_range(c, 0x20, 0x7f) +#define isdigit(c) in_range(c, '0', '9') +#define isxdigit(c) (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F')) +#define islower(c) in_range(c, 'a', 'z') +#define isspace(c) (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v') +#endif + + +/** + * Check whether "cp" is a valid ascii representation + * of an Internet address and convert to a binary address. + * Returns 1 if the address is valid, 0 if not. + * This replaces inet_addr, the return value from which + * cannot distinguish between failure and a local broadcast address. + * + * @param cp IP address in ascii representation (e.g. "127.0.0.1") + * @param addr pointer to which to save the ip address in network order + * @return 1 if cp could be converted to addr, 0 on failure + */ +int sal_ip4addr_aton(const char *cp, ip4_addr_t *addr) +{ + u32_t val; + u8_t base; + char c; + u32_t parts[4]; + u32_t *pp = parts; + + c = *cp; + for (;;) + { + /* + * Collect number up to ``.''. + * Values are specified as for C: + * 0x=hex, 0=octal, 1-9=decimal. + */ + if (!isdigit(c)) + { + return 0; + } + val = 0; + base = 10; + if (c == '0') + { + c = *++cp; + if (c == 'x' || c == 'X') + { + base = 16; + c = *++cp; + } + else + { + base = 8; + } + } + for (;;) + { + if (isdigit(c)) + { + val = (val * base) + (u32_t) (c - '0'); + c = *++cp; + } + else if (base == 16 && isxdigit(c)) + { + val = (val << 4) | (u32_t) (c + 10 - (islower(c) ? 'a' : 'A')); + c = *++cp; + } + else + { + break; + } + } + if (c == '.') + { + /* + * Internet format: + * a.b.c.d + * a.b.c (with c treated as 16 bits) + * a.b (with b treated as 24 bits) + */ + if (pp >= parts + 3) + { + return 0; + } + *pp++ = val; + c = *++cp; + } + else + { + break; + } + } + /* + * Check for trailing characters. + */ + if (c != '\0' && !isspace(c)) + { + return 0; + } + /* + * Concoct the address according to + * the number of parts specified. + */ + switch (pp - parts + 1) + { + + case 0: + return 0; /* initial nondigit */ + + case 1: /* a -- 32 bits */ + break; + + case 2: /* a.b -- 8.24 bits */ + if (val > 0xffffffUL) + { + return 0; + } + if (parts[0] > 0xff) + { + return 0; + } + val |= parts[0] << 24; + break; + + case 3: /* a.b.c -- 8.8.16 bits */ + if (val > 0xffff) + { + return 0; + } + if ((parts[0] > 0xff) || (parts[1] > 0xff)) + { + return 0; + } + val |= (parts[0] << 24) | (parts[1] << 16); + break; + + case 4: /* a.b.c.d -- 8.8.8.8 bits */ + if (val > 0xff) + { + return 0; + } + if ((parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xff)) + { + return 0; + } + val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); + break; + default: + RT_ASSERT(0); + break; + } + if (addr) + { + ip4_addr_set_u32(addr, htonl(val)); + } + return 1; +} + +/** + * Same as ipaddr_ntoa, but reentrant since a user-supplied buffer is used. + * + * @param addr ip address in network order to convert + * @param buf target buffer where the string is stored + * @param buflen length of buf + * @return either pointer to buf which now holds the ASCII + * representation of addr or NULL if buf was too small + */ +char *sal_ip4addr_ntoa_r(const ip4_addr_t *addr, char *buf, int buflen) +{ + u32_t s_addr; + char inv[3]; + char *rp; + u8_t *ap; + u8_t rem; + u8_t n; + u8_t i; + int len = 0; + + s_addr = ip4_addr_get_u32(addr); + + rp = buf; + ap = (u8_t *) &s_addr; + for (n = 0; n < 4; n++) + { + i = 0; + do + { + rem = *ap % (u8_t) 10; + *ap /= (u8_t) 10; + inv[i++] = (char) ('0' + rem); + } while (*ap); + while (i--) + { + if (len++ >= buflen) + { + return NULL; + } + *rp++ = inv[i]; + } + if (len++ >= buflen) + { + return NULL; + } + *rp++ = '.'; + ap++; + } + *--rp = 0; + return buf; +} + + +/** + * Convert numeric IP address into decimal dotted ASCII representation. + * returns ptr to static buffer; not reentrant! + * + * @param addr ip address in network order to convert + * @return pointer to a global static (!) buffer that holds the ASCII + * representation of addr + */ +char *sal_ip4addr_ntoa(const ip4_addr_t *addr) +{ + static char str[IP4ADDR_STRLEN_MAX]; + return sal_ip4addr_ntoa_r(addr, str, IP4ADDR_STRLEN_MAX); +} + + +/** + * Ascii internet address interpretation routine. + * The value returned is in network order. + * + * @param cp IP address in ascii representation (e.g. "127.0.0.1") + * @return ip address in network order + */ +in_addr_t sal_ipaddr_addr(const char *cp) +{ + ip4_addr_t val; + + if (sal_ip4addr_aton(cp, &val)) { + return ip4_addr_get_u32(&val); + } + return (IPADDR_NONE); +} diff --git a/components/net/sal_socket/src/sal_socket.c b/components/net/sal_socket/src/sal_socket.c new file mode 100644 index 0000000000..71aaa2c658 --- /dev/null +++ b/components/net/sal_socket/src/sal_socket.c @@ -0,0 +1,730 @@ +/* + * File : sal_socket.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2018-05-23 ChenYong First version + */ + +#include <rtthread.h> +#include <rthw.h> + +#include <sal_socket.h> +#include <sal_netdb.h> +#include <sal.h> + +#define DBG_ENABLE +#define DBG_SECTION_NAME "SAL_SOC" +#define DBG_LEVEL DBG_INFO +#define DBG_COLOR +#include <rtdbg.h> + +/* the socket table used to dynamic allocate sockets */ +struct sal_socket_table +{ + uint32_t max_socket; + struct sal_socket **sockets; +}; + +/* The global array of available protocol families */ +static struct proto_family proto_families[SAL_PROTO_FAMILIES_NUM]; +/* The global socket table */ +static struct sal_socket_table socket_table; +static struct rt_mutex sal_core_lock; +static rt_bool_t init_ok = RT_FALSE; + +/** + * SAL (Socket Abstraction Layer) initialization. + * + * @return result + * >= 0: initialize success + */ +int sal_init(void) +{ + if(init_ok) + { + LOG_D("Socket Abstraction Layer is already initialized."); + return 0; + } + + /* clean sal socket table */ + memset(&socket_table, 0, sizeof(socket_table)); + /* create sal socket lock */ + rt_mutex_init(&sal_core_lock, "sal_lock", RT_IPC_FLAG_FIFO); + + LOG_I("Socket Abstraction Layer initialize success."); + init_ok = RT_TRUE; + + return 0; +} +INIT_COMPONENT_EXPORT(sal_init); + +/** + * this function will register the current protocol family to the global array of protocol families. + * + * @param pf protocol families structure + * + * @return 0 : protocol families structure index + * -1 : the global array of available protocol families is full + */ +int sal_proto_family_register(const struct proto_family *pf) +{ + rt_base_t level; + int idx; + + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + + /* find an empty protocol family entry */ + for(idx = 0; idx < SAL_PROTO_FAMILIES_NUM && proto_families[idx].create; idx++); + + /* can't find an empty protocol family entry */ + if(idx == SAL_PROTO_FAMILIES_NUM) + { + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + return -1; + } + + proto_families[idx].family = pf->family; + proto_families[idx].sec_family = pf->sec_family; + proto_families[idx].create = pf->create; + + proto_families[idx].gethostbyname = pf->gethostbyname; + proto_families[idx].gethostbyname_r = pf->gethostbyname_r; + proto_families[idx].freeaddrinfo = pf->freeaddrinfo; + proto_families[idx].getaddrinfo = pf->getaddrinfo; + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + return 0; +} + +/** + * this function will get socket structure by sal socket descriptor + * + * @param socket sal socket index + * + * @return socket structure of the current sal socket index + */ +struct sal_socket *sal_get_socket(int socket) +{ + struct sal_socket_table *st = &socket_table; + + if (socket < 0 || socket >= (int) st->max_socket) + { + return RT_NULL; + } + + socket = socket - SAL_SOCKET_OFFSET; + /* check socket structure valid or not */ + if (st->sockets[socket]->magic != SAL_SOCKET_MAGIC) + { + return RT_NULL; + } + + return st->sockets[socket]; +} + +/** + * this function will lock sal socket. + * + * @note please don't invoke it on ISR. + */ +static void sal_lock(void) +{ + rt_err_t result; + + result = rt_mutex_take(&sal_core_lock, RT_WAITING_FOREVER); + if (result != RT_EOK) + { + RT_ASSERT(0); + } +} + +/** + * this function will lock sal socket. + * + * @note please don't invoke it on ISR. + */ +static void sal_unlock(void) +{ + rt_mutex_release(&sal_core_lock); +} + +/** + * this function will get protocol family structure by family type + * + * @param family protocol family + * + * @return protocol family structure address + */ +static struct proto_family *get_proto_family(int family) +{ + int idx; + + for (idx = 0; idx < SAL_PROTO_FAMILIES_NUM; idx++) + { + if (proto_families[idx].family == family && proto_families[idx].create) + { + return &proto_families[idx]; + } + } + /* compare the secondary protocol families when primary protocol families find failed */ + for (idx = 0; idx < SAL_PROTO_FAMILIES_NUM; idx++) + { + if (proto_families[idx].sec_family == family && proto_families[idx].create) + { + return &proto_families[idx]; + } + } + + return RT_NULL; +} + +/** + * this function will initialize socket structure and set socket options + * + * @param family protocol family + * @param type socket type + * @param protocol transfer Protocol + * @param res socket structure address + * + * @return 0 : socket initialize success + * -1 : input the wrong family + * -2 : input the wrong socket type + * -3 : get protocol family structure failed + * -4 : set socket options failed + */ +static int socket_init(int family, int type, int protocol, struct sal_socket **res) +{ + struct sal_socket *sock; + struct proto_family *pf; + + if (family < 0 || family > AF_MAX) + { + return -1; + } + + if (type < 0 || type > SOCK_MAX) + { + return -2; + } + + sock = *res; + sock->domain = family; + sock->type = type; + sock->protocol = protocol; + + /* get socket protocol family structure */ + if ((pf = get_proto_family(family)) == RT_NULL) + { + return -3; + } + + /* registered the current socket options */ + if (pf->create(sock, type, protocol) != 0) + { + return -4; + } + + return 0; +} + +static int socket_alloc(struct sal_socket_table *st, int f_socket) +{ + int idx; + + /* find an empty socket entry */ + for (idx = f_socket; idx < (int) st->max_socket; idx++) + { + if (st->sockets[idx] == RT_NULL) + break; + if (st->sockets[idx]->ops == RT_NULL) + break; + } + + /* allocate a larger sockte container */ + if (idx == (int) st->max_socket && st->max_socket < SAL_SOCKETS_NUM) + { + int cnt, index; + struct sal_socket **sockets; + + /* increase the number of FD with 4 step length */ + cnt = st->max_socket + 4; + cnt = cnt > SAL_SOCKETS_NUM ? SAL_SOCKETS_NUM : cnt; + + sockets = rt_realloc(st->sockets, cnt * sizeof(struct sal_socket *)); + if (sockets == RT_NULL) + goto __result; /* return st->max_socket */ + + /* clean the new allocated fds */ + for (index = st->max_socket; index < cnt; index++) + { + sockets[index] = RT_NULL; + } + + st->sockets = sockets; + st->max_socket = cnt; + } + + /* allocate 'struct sal_socket' */ + if (idx < (int) st->max_socket && st->sockets[idx] == RT_NULL) + { + st->sockets[idx] = rt_malloc(sizeof(struct sal_socket)); + if (st->sockets[idx] == RT_NULL) + { + idx = st->max_socket; + } + } + +__result: + return idx; + +} + +/** + * this function will return a empty sal socket structure address + * + * @return sal socket structure address + */ +static int socket_new(void) +{ + struct sal_socket *sock; + struct sal_socket_table *st = &socket_table; + int idx; + + sal_lock(); + + /* find an empty sal socket entry */ + idx = socket_alloc(st, 0); + + /* can't find an empty sal socket entry */ + if (idx == (int) st->max_socket) + { + idx = -(1 + SAL_SOCKET_OFFSET); + goto __result; + } + + sock = st->sockets[idx]; + sock->socket = idx + SAL_SOCKET_OFFSET; + sock->magic = SAL_SOCKET_MAGIC; + +__result: + sal_unlock(); + return idx + SAL_SOCKET_OFFSET; +} + +int sal_accept(int socket, struct sockaddr *addr, socklen_t *addrlen) +{ + int new_socket; + struct sal_socket *sock; + + sock = sal_get_socket(socket); + if (!sock) + { + return -1; + } + + if (sock->ops->accept == RT_NULL) + { + return -RT_ENOSYS; + } + + new_socket = sock->ops->accept((int) sock->user_data, addr, addrlen); + if (new_socket != -1) + { + int retval; + int new_socket; + struct sal_socket *new_sock; + + /* allocate a new socket structure and registered socket options */ + new_socket = socket_new(); + if (new_socket < 0) + { + return -1; + } + new_sock = sal_get_socket(new_socket); + + retval = socket_init(sock->domain, sock->type, sock->protocol, &new_sock); + if (retval < 0) + { + LOG_E("New socket registered failed, return error %d.", retval); + return -1; + } + + /* socket struct user_data used to store the acquired new socket */ + new_sock->user_data = (void *) new_socket; + + return new_sock->socket; + } + + return -1; +} + +int sal_bind(int socket, const struct sockaddr *name, socklen_t namelen) +{ + struct sal_socket *sock; + + sock = sal_get_socket(socket); + if (!sock) + { + return -1; + } + + if (sock->ops->bind == RT_NULL) + { + return -RT_ENOSYS; + } + + return sock->ops->bind((int) sock->user_data, name, namelen); +} + +int sal_shutdown(int socket, int how) +{ + struct sal_socket *sock; + + sock = sal_get_socket(socket); + if (!sock) + { + return -1; + } + + if (sock->ops->shutdown == RT_NULL) + { + return -RT_ENOSYS; + } + + if (sock->ops->shutdown((int) sock->user_data, how) == 0) + { + memset(sock, 0x00, sizeof(struct sal_socket)); + return 0; + } + + return -1; +} + +int sal_getpeername(int socket, struct sockaddr *name, socklen_t *namelen) +{ + struct sal_socket *sock; + + sock = sal_get_socket(socket); + if (!sock) + { + return -1; + } + + if (sock->ops->getpeername == RT_NULL) + { + return -RT_ENOSYS; + } + + return sock->ops->getpeername((int) sock->user_data, name, namelen); +} + +int sal_getsockname(int socket, struct sockaddr *name, socklen_t *namelen) +{ + struct sal_socket *sock; + + sock = sal_get_socket(socket); + if (!sock) + { + return -1; + } + + if (sock->ops->getsockname == RT_NULL) + { + return -RT_ENOSYS; + } + + return sock->ops->getsockname((int) sock->user_data, name, namelen); +} + +int sal_getsockopt(int socket, int level, int optname, void *optval, socklen_t *optlen) +{ + struct sal_socket *sock; + + sock = sal_get_socket(socket); + if (!sock) + { + return -1; + } + + if (sock->ops->getsockopt == RT_NULL) + { + return -RT_ENOSYS; + } + + return sock->ops->getsockopt((int) sock->user_data, level, optname, optval, optlen); +} + +int sal_setsockopt(int socket, int level, int optname, const void *optval, socklen_t optlen) +{ + struct sal_socket *sock; + + sock = sal_get_socket(socket); + if (!sock) + { + return -1; + } + + if (sock->ops->setsockopt == RT_NULL) + { + return -RT_ENOSYS; + } + + return sock->ops->setsockopt((int) sock->user_data, level, optname, optval, optlen); +} + +int sal_connect(int socket, const struct sockaddr *name, socklen_t namelen) +{ + struct sal_socket *sock; + + sock = sal_get_socket(socket); + if (!sock) + { + return -1; + } + + if (sock->ops->connect == RT_NULL) + { + return -RT_ENOSYS; + } + + return sock->ops->connect((int) sock->user_data, name, namelen); +} + +int sal_listen(int socket, int backlog) +{ + struct sal_socket *sock; + + sock = sal_get_socket(socket); + if (!sock) + { + return -1; + } + + if (sock->ops->listen == RT_NULL) + { + return -RT_ENOSYS; + } + + return sock->ops->listen((int) sock->user_data, backlog); +} + +int sal_recvfrom(int socket, void *mem, size_t len, int flags, + struct sockaddr *from, socklen_t *fromlen) +{ + struct sal_socket *sock; + + sock = sal_get_socket(socket); + if (!sock) + { + return -1; + } + + if (sock->ops->recvfrom == RT_NULL) + { + return -RT_ENOSYS; + } + + return sock->ops->recvfrom((int) sock->user_data, mem, len, flags, from, fromlen); +} + +int sal_sendto(int socket, const void *dataptr, size_t size, int flags, + const struct sockaddr *to, socklen_t tolen) +{ + struct sal_socket *sock; + + sock = sal_get_socket(socket); + if (!sock) + { + return -1; + } + + if (sock->ops->sendto == RT_NULL) + { + return -RT_ENOSYS; + } + + return sock->ops->sendto((int) sock->user_data, dataptr, size, flags, to, tolen); +} + +int sal_socket(int domain, int type, int protocol) +{ + int retval; + int socket, proto_socket; + struct sal_socket *sock; + + /* allocate a new socket and registered socket options */ + socket = socket_new(); + if (socket < 0) + { + return -1; + } + sock = sal_get_socket(socket); + + retval = socket_init(domain, type, protocol, &sock); + if (retval < 0) + { + LOG_E("SAL socket protocol family input failed, return error %d.", retval); + return -1; + } + + if (sock->ops->socket == RT_NULL) + { + return -RT_ENOSYS; + } + + proto_socket = sock->ops->socket(domain, type, protocol); + if (proto_socket >= 0) + { + sock->user_data = (void *) proto_socket; + + return sock->socket; + } + + return -1; +} + +int sal_closesocket(int socket) +{ + struct sal_socket *sock; + + sock = sal_get_socket(socket); + if (!sock) + { + return -1; + } + + if (sock->ops->closesocket == RT_NULL) + { + return -RT_ENOSYS; + } + + if (sock->ops->closesocket((int) sock->user_data) == 0) + { + memset(sock, 0x00, sizeof(struct sal_socket)); + return 0; + } + + return -1; +} + +int sal_ioctlsocket(int socket, long cmd, void *arg) +{ + struct sal_socket *sock; + + sock = sal_get_socket(socket); + if (!sock) + { + return -1; + } + + if (sock->ops->ioctlsocket == RT_NULL) + { + return -RT_ENOSYS; + } + + return sock->ops->ioctlsocket((int) sock->user_data, cmd, arg); +} + +int sal_poll(struct dfs_fd *file, struct rt_pollreq *req) +{ + struct sal_socket *sock; + int socket = (int) file->data; + + sock = sal_get_socket(socket); + if (!sock) + { + return -1; + } + + if (sock->ops->poll == RT_NULL) + { + return -RT_ENOSYS; + } + + return sock->ops->poll(file, req); +} + +struct hostent *sal_gethostbyname(const char *name) +{ + int i; + + for (i = 0; i < SAL_PROTO_FAMILIES_NUM; ++i) + { + if (proto_families[i].gethostbyname) + { + return proto_families[i].gethostbyname(name); + } + } + + return RT_NULL; +} + +int sal_gethostbyname_r(const char *name, struct hostent *ret, char *buf, + size_t buflen, struct hostent **result, int *h_errnop) +{ + int i; + + for (i = 0; i < SAL_PROTO_FAMILIES_NUM; ++i) + { + if (proto_families[i].gethostbyname_r) + { + return proto_families[i].gethostbyname_r(name, ret, buf, buflen, result, h_errnop); + } + } + + return -1; +} + +void sal_freeaddrinfo(struct addrinfo *ai) +{ + int i; + + for (i = 0; i < SAL_PROTO_FAMILIES_NUM; ++i) + { + if (proto_families[i].freeaddrinfo) + { + proto_families[i].freeaddrinfo(ai); + return; + } + } +} + +int sal_getaddrinfo(const char *nodename, + const char *servname, + const struct addrinfo *hints, + struct addrinfo **res) +{ + int i; + + for (i = 0; i < SAL_PROTO_FAMILIES_NUM; ++i) + { + if (proto_families[i].getaddrinfo) + { + return proto_families[i].getaddrinfo(nodename, servname, hints, res); + } + } + + return -1; +} |
