Usermode/libpsockets - Added basic services to getaddrinfo
[tpg/acess2.git] / Usermode / Libraries / libpsocket.so_src / socket.c
1 /*
2  * Acess2 POSIX Sockets Library
3  * - By John Hodge (thePowersGang)
4  *
5  * socket.c
6  * - sys/socket.h calls
7  */
8 #include <sys/socket.h>
9 #include <acess/sys.h>
10 #include <stdlib.h>     // malloc/free
11 #include <string.h>
12 #include <netinet/in.h>
13 #include <errno.h>
14 #include "common.h"
15
16 #define MAXFD   32
17
18 #define IOCTL_TCPC_PORT 5
19 #define IOCTL_TCPC_HOST 6
20 #define IOCTL_TCPC_CONNECT      7
21 #define IOCTL_TCPS_PORT 5
22
23 typedef struct s_sockinfo
24 {
25          int    fd;
26         char    domain;
27         char    type;
28         char    protocol;
29         struct sockaddr *local;
30         struct sockaddr *remote;
31 } t_sockinfo;
32
33 // === PROTOTYPES ===
34 void    _CommitClient(int sockfd);
35
36 struct s_sockinfo       gSockInfo[MAXFD];
37 static int      giNumPreinit = 0;
38
39 // === CODE ===
40 static t_sockinfo *_GetInfo(int FD)
41 {
42          int    i, nInit = 0;;
43         if( FD == 0 && giNumPreinit == MAXFD )
44                 return NULL;
45         for( i = 0; i < MAXFD; i ++ )
46         {
47                 if( gSockInfo[i].fd == FD )
48                         return &gSockInfo[i];
49                 if( gSockInfo[i].fd )
50                         nInit ++;
51                 if( FD != 0 && nInit == giNumPreinit )
52                         return NULL;
53         }
54         return NULL;
55 }
56
57 int socket(int domain, int type, int protocol)
58 {
59         t_sockinfo      *si = NULL;
60         
61         if( domain < 0 || domain > AF_INET6 ) {
62                 _SysDebug("socket: Domain %i invalid", domain);
63                 errno = EINVAL;
64                 return -1;
65         }
66         if( type < 0 || type > SOCK_RDM ) {
67                 _SysDebug("socket: Type %i invalid", type);
68                 errno = EINVAL;
69                 return -1;
70         }
71
72         // Allocate an info struct
73         si = _GetInfo(0);
74         if( !si ) {
75                 errno = ENOMEM;
76                 return -1;
77         }
78
79         int fd = _SysOpen("/Devices/null", OPENFLAG_RDWR);
80         if( fd == -1 )  return -1;
81
82         giNumPreinit ++;
83         si->fd = fd;
84         si->domain = domain;
85         si->type = type;
86         si->protocol = protocol;
87         si->local = NULL;
88         si->remote = NULL;
89         
90         _SysDebug("socket(%i,%i,%i) = %i", domain, type, protocol, fd);
91         return fd;
92
93
94 int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
95 {
96         t_sockinfo      *si = _GetInfo(sockfd);;
97         if( !si )       return -1;
98
99         if( si->local ) {
100                 // Oops?
101                 return -1;
102         }
103
104         si->local = malloc( addrlen );
105         memcpy(si->local, addr, addrlen);
106
107         return 0;
108 }
109
110 size_t _getAddrData(const struct sockaddr *addr, const void **dataptr, int *port)
111 {
112         size_t  addrLen = 0;
113         const struct sockaddr_in        *in4 = (void*)addr;
114         const struct sockaddr_in6       *in6 = (void*)addr;
115         switch( addr->sa_family )
116         {
117         case AF_INET:
118                 *dataptr = &in4->sin_addr;
119                 addrLen = 4;
120                 *port = in4->sin_port;
121                 break;
122         case AF_INET6:
123                 *dataptr = &in6->sin6_addr;
124                 addrLen = 16;
125                 *port = in6->sin6_port;
126                 break;
127         default:
128                 _SysDebug("libpsocket _getAddrData: Unkown sa_family %i", addr->sa_family);
129                 return 0;
130         }
131         return addrLen;
132 }
133
134 int _OpenIf(int DestFD, const struct sockaddr *addr, const char *file, int *port)
135 {
136         const uint8_t   *addrBuffer = NULL;
137         size_t addrLen = 0;
138
139         addrLen = _getAddrData(addr, (const void **)&addrBuffer, port);
140         if( addrLen == 0 ) {
141                 errno = EINVAL;
142                 return -1;
143         }
144
145         char    hexAddr[addrLen*2+1];
146          int    bNonZero = 0;
147         for( int i = 0; i < addrLen; i ++ ) {
148                 hexAddr[i*2+0] = "0123456789ABCDEF"[addrBuffer[i] >> 4];
149                 hexAddr[i*2+1] = "0123456789ABCDEF"[addrBuffer[i] & 15];
150                 if(addrBuffer[i]) bNonZero = 1;
151         }
152         hexAddr[addrLen*2] = 0;
153         
154         char    *path;
155         if( bNonZero )
156                 path = mkstr("/Devices/ip/routes/@%i:%s/%s", addr->sa_family, hexAddr, file);
157         else
158                 path = mkstr("/Devices/ip/*%i/%s", addr->sa_family, file);
159
160         int ret = _SysReopen(DestFD, path, OPENFLAG_RDWR);
161         _SysDebug("libpsocket: _SysReopen(%i, '%s') = %i", DestFD, path, ret);
162         free(path);
163         // TODO: Error-check?
164         return ret;
165 }
166
167 int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
168 {
169         t_sockinfo      *si = _GetInfo(sockfd);
170         if( !si ||  si->remote ) {
171                 _SysDebug("connect: FD %i already connected", sockfd);
172                 errno = EALREADY;
173                 return -1;
174         }
175
176         si->remote = malloc( addrlen );
177         memcpy(si->remote, addr, addrlen);
178
179          int    ret = 0;
180         if( si->type == SOCK_STREAM )
181         {
182                 int lport = 0;
183                 const struct sockaddr   *bindaddr = (si->local ? si->local : addr);
184                 ret = _OpenIf(sockfd, bindaddr, "tcpc", &lport);
185                 if(ret == -1)
186                         return ret;
187
188                 if( si->local ) {
189                         //_SysIOCtl(sockfd, IOCTL_TCPC_LPORT, &lport);
190                         _SysDebug("connect: TODO - Bind to local port");
191                 }               
192
193                 int port;
194                 const void *addrdata;
195                 _getAddrData(addr, &addrdata, &port);
196                 
197                 _SysIOCtl(sockfd, IOCTL_TCPC_PORT, &port);
198                 _SysIOCtl(sockfd, IOCTL_TCPC_HOST, (void*)addrdata);
199                 ret = _SysIOCtl(sockfd, IOCTL_TCPC_CONNECT, NULL);
200                 _SysDebug("connect: :%i = %i", port, ret);
201         }
202         else
203         {
204                 _SysDebug("connect: TODO - non-TCP clients (%i)", si->type);
205         }
206                 
207         _CommitClient(sockfd);
208
209         return ret;
210 }
211
212 int listen(int sockfd, int backlog)
213 {
214         // TODO: Save this to the t_sockinfo structure
215         return 0;
216 }
217
218 void _ClearInfo(t_sockinfo *si)
219 {
220         if( si->local ) {
221                 free(si->local);
222                 si->local = NULL;
223         }
224         
225         if( si->remote ) {
226                 free(si->remote);
227                 si->remote = NULL;
228         }
229         
230         si->fd = 0;
231         giNumPreinit --;
232 }
233
234 void _CommitServer(int sockfd)
235 {
236         t_sockinfo      *si = _GetInfo(sockfd);
237         if( !si )       return ;
238
239         if( !si->local ) {
240                 // Um... oops?
241                 return ;
242         }       
243
244         if( si->type != SOCK_STREAM ) {
245                 _SysDebug("TODO: Non-tcp servers");
246                 return ;
247         }
248
249         // Bind to the local address
250         int     port;
251         int ret = _OpenIf(sockfd, si->local, "tcps", &port);
252         if( ret == -1 ) {
253                 return ;
254         }
255         
256         // Bind to port
257         // TODO: Set up socket
258         _SysIOCtl(sockfd, IOCTL_TCPS_PORT, &port);
259
260         _ClearInfo(si);
261 }
262
263 void _CommitClient(int sockfd)
264 {
265         t_sockinfo      *si = _GetInfo(sockfd);
266         if( !si )       return ;
267
268         _ClearInfo(si);
269 }
270
271 int accept(int sockfd, struct sockaddr *clientaddr, socklen_t *addrlen)
272 {
273         _CommitServer(sockfd);
274          int    child;
275
276
277         child = _SysOpenChild(sockfd, "", OPENFLAG_RDWR);
278         if( child == -1 )       return -1;
279         
280         _SysIOCtl(child, 8, clientaddr);
281
282         
283         return child;
284 }
285
286 int recvfrom(int sockfd, void *buffer, size_t length, int flags, struct sockaddr *clientaddr, socklen_t *addrlen)
287 {
288         _CommitClient(sockfd);
289         // TODO: Determine socket type (TCP/UDP) and use a bounce-buffer for UDP
290         return _SysRead(sockfd, buffer, length);
291 }
292
293 int recv(int sockfd, void *buffer, size_t length, int flags)
294 {
295         _CommitClient(sockfd);
296         return _SysRead(sockfd, buffer, length);
297 }
298
299 int sendto(int sockfd, const void *buffer, size_t length, int flags, const struct sockaddr *clientaddr, socklen_t addrlen)
300 {
301         _CommitClient(sockfd);
302         // TODO: Determine socket type (TCP/UDP) and use a bounce-buffer for UDP
303         return _SysWrite(sockfd, buffer, length);
304 }
305
306 int send(int sockfd, void *buffer, size_t length, int flags)
307 {
308         _CommitClient(sockfd);
309         return _SysWrite(sockfd, buffer, length);
310 }
311
312
313 int setsockopt(int socket, int level, int option_name, const void *option_value, socklen_t option_len)
314 {
315         return 0;
316 }
317
318 int getsockopt(int socket, int level, int option_name, void *option_value, socklen_t *option_len)
319 {
320         return 0;
321 }
322
323 int getsockname(int socket, struct sockaddr *addr, socklen_t *addrlen)
324 {
325         return 0;
326 }
327
328 int getpeername(int socket, struct sockaddr *addr, socklen_t *addrlen)
329 {
330         return 0;
331 }
332
333 int shutdown(int socket, int how)
334 {
335         return 0;
336 }
337

UCC git Repository :: git.ucc.asn.au