1/*
2 * Copyright 2017, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
8 * See "LICENSE_BSD2.txt" for details.
9 *
10 * @TAG(DATA61_BSD)
11 */
12
13#include <assert.h>
14#include <stdarg.h>
15#include <stdio.h>
16#include <stdlib.h>
17#include <stdint.h>
18#include <string.h>
19#include <errno.h>
20#include <sys/socket.h>
21#include <muslcsys/io.h>
22
23#include "sys_io.h"
24
25int sock_socket(int domain, int type, int protocol) __attribute__((weak));
26long camkes_sys_socket(va_list ap)
27{
28    int domain = va_arg(ap, int);
29    int type = va_arg(ap, int);
30    int protocol = va_arg(ap, int);
31    int fd;
32    muslcsys_fd_t *fdt;
33
34    if (sock_socket) {
35        fd = allocate_fd();
36        fdt = get_fd_struct(fd);
37        fdt->data = malloc(sizeof(int));
38        *(int *)fdt->data = sock_socket(domain, type, protocol);
39        fdt->filetype = FILE_TYPE_SOCKET;
40        return fd;
41    } else {
42        assert(!"sys_socket not implemented");
43    }
44
45    return 0;
46}
47
48int sock_bind(int sockfd, int addrlen) __attribute__((weak));
49long camkes_sys_bind(va_list ap)
50{
51    int fd = va_arg(ap, int);
52    const struct sockaddr *addr = va_arg(ap, const struct sockaddr *);
53    socklen_t addrlen = va_arg(ap, socklen_t);
54    muslcsys_fd_t *fdt;
55    int sockfd;
56
57    if (sock_bind && sock_data) {
58        fdt = get_fd_struct(fd);
59        sockfd = *(int *)fdt->data;
60        memcpy((char *)sock_data, addr, addrlen);
61        return sock_bind(sockfd, addrlen);
62    } else {
63        assert(!"sys_bind not implemented");
64    }
65
66    return -1;
67}
68
69int sock_connect(int sockfd, int addrlen) __attribute__((weak));
70long camkes_sys_connect(va_list ap)
71{
72    int fd = va_arg(ap, int);
73    const struct sockaddr *addr = va_arg(ap, const struct sockaddr *);
74    socklen_t addrlen = va_arg(ap, socklen_t);
75
76    muslcsys_fd_t *fdt;
77    int sockfd;
78
79    if (sock_connect && sock_data) {
80        fdt = get_fd_struct(fd);
81        sockfd = *(int *)fdt->data;
82        memcpy((char *)sock_data, addr, addrlen);
83        return sock_connect(sockfd, addrlen);
84    } else {
85        assert(!"sys_connect not implemented");
86    }
87
88    return -1;
89}
90
91int sock_listen(int sockfd, int backlog) __attribute__((weak));
92long camkes_sys_listen(va_list ap)
93{
94    int fd = va_arg(ap, int);
95    int backlog = va_arg(ap, int);
96    muslcsys_fd_t *fdt;
97    int sockfd;
98
99    if (sock_listen) {
100        fdt = get_fd_struct(fd);
101        sockfd = *(int *)fdt->data;
102        return sock_listen(sockfd, backlog);
103    } else {
104        assert(!"sys_listen not implemented");
105    }
106
107    return -1;
108}
109
110int sock_accept(int sockfd) __attribute__((weak));
111long camkes_sys_accept(va_list ap)
112{
113    int fd = va_arg(ap, int);
114    struct sockaddr *addr = va_arg(ap, struct sockaddr *);
115    socklen_t *addrlen = va_arg(ap, socklen_t *);
116
117    muslcsys_fd_t *fdt;
118    int sockfd;
119    int newsockfd;
120
121    if (sock_accept && sock_data) {
122        fdt = get_fd_struct(fd);
123        sockfd = *(int *)fdt->data;
124
125        /* addr can be NULL, which means ignore the peer address. */
126        if (addr) {
127            memcpy((char *)sock_data, addr, sizeof(struct sockaddr));
128            memcpy((char *)sock_data + sizeof(struct sockaddr), addrlen, sizeof(socklen_t));
129        }
130
131        newsockfd = sock_accept(sockfd);
132
133        /* -1 is returned when the call fails. */
134        if (newsockfd == -1) {
135            memcpy(&errno, (void *)sock_data, sizeof(errno));
136            return newsockfd;
137        }
138
139        if (addr) {
140            memcpy(addr, (char *)sock_data, sizeof(struct sockaddr));
141            memcpy(addrlen, (char *)sock_data + sizeof(struct sockaddr), sizeof(socklen_t));
142        }
143
144        /*
145         * Accept returns a new socket file descriptor, so we need to
146         * allocate a new file descriptor.
147         */
148        fd = allocate_fd();
149        fdt = get_fd_struct(fd);
150        fdt->data = malloc(sizeof(int));
151        *(int *)fdt->data = newsockfd;
152        fdt->filetype = FILE_TYPE_SOCKET;
153
154        return fd;
155    } else {
156        assert(!"sys_accept not implemented");
157    }
158
159    return -1;
160}
161
162int sock_setsockopt(int sockfd, int level, int optname, int optlen) __attribute__((weak));
163long camkes_sys_setsockopt(va_list ap)
164{
165    int fd = va_arg(ap, int);
166    int level = va_arg(ap, int);
167    int optname = va_arg(ap, int);
168    const void *optval = va_arg(ap, const void *);
169    socklen_t optlen = va_arg(ap, socklen_t);
170
171    muslcsys_fd_t *fdt;
172    int sockfd;
173
174    if (sock_setsockopt && sock_data) {
175        fdt = get_fd_struct(fd);
176        sockfd = *(int *)fdt->data;
177
178        memcpy((char *)sock_data, optval, optlen);
179        return sock_setsockopt(sockfd, level, optname, optlen);
180    } else {
181        assert(!"sys_setsockopt not implemented");
182    }
183
184    return -1;
185}
186