Modules - Use short command annotation in makefile ([CC] not $(CC))
[tpg/acess2.git] / AcessNative / acesskernel_src / net_wrap.c
1 /*
2  * Acess2 Native Kernel
3  * - Acess kernel emulation on another OS using SDL and UDP
4  *
5  * net.c
6  * - Networking
7  */
8 #define DEBUG   1
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <stdbool.h>
12 #include "../../KernelLand/Kernel/include/logdebug.h"
13 #include "net_wrap.h"
14 #include <string.h>
15 #include <sys/socket.h>
16 #include <netinet/in.h>
17 #include <errno.h>
18 #include <sys/eventfd.h>
19 #include <poll.h>
20
21 #include <SDL/SDL.h>    // for worker
22
23 typedef struct sNetSocket       tNetSocket;
24
25 struct sNetSocket
26 {
27         tNetSocket      *Next;
28         tNetSocket      *Prev;
29         void    *Node;
30          int    FD;
31         char    bSkipRead;
32         char    bSkipWrite;
33         char    bSkipError;
34 };
35
36
37  int    Net_Wrap_WatcherThread(void *arg);
38
39  int    gNet_Wrap_EventFD;
40 tNetSocket      *gNet_Wrap_FirstSocket;
41 tNetSocket      *gNet_Wrap_LastSocket;
42 SDL_Thread      *gNet_Wrap_SelectChecker;
43
44 // === CODE ===
45 void Net_Wrap_Init(void)
46 {
47         gNet_Wrap_EventFD = eventfd(0, 0);
48         gNet_Wrap_SelectChecker = SDL_CreateThread( Net_Wrap_WatcherThread, NULL );
49 }
50
51 static inline void Net_Wrap_ProdWatcher(void)
52 {
53         uint64_t val = 1;
54         write(gNet_Wrap_EventFD, &val, sizeof(val));
55 }
56
57 int Net_Wrap_WatcherThread(void *arg)
58 {
59         for(;;)
60         {
61                  int    maxfd = gNet_Wrap_EventFD;
62                 fd_set  rfds, wfds, efds;
63                 FD_ZERO(&rfds);
64                 FD_ZERO(&wfds);
65                 FD_ZERO(&efds);
66                 // Event FD used to wake this thread when the list changes
67                 FD_SET(gNet_Wrap_EventFD, &rfds);
68                 // Populate socket FDs
69                 for( tNetSocket *s = gNet_Wrap_FirstSocket; s; s = s->Next )
70                 {
71                         if( s->FD > maxfd )
72                                 maxfd = s->FD;
73                         if( !s->bSkipRead )     FD_SET(s->FD, &rfds);
74                         if( !s->bSkipWrite )    FD_SET(s->FD, &wfds);
75                         if( !s->bSkipError )    FD_SET(s->FD, &efds);
76                 }
77         
78                 LOG("select(%i+1, ...)", maxfd);
79                 int rv = select(maxfd+1, &rfds, &wfds, &efds, NULL);
80                 LOG("rv = %i");
81                 if( rv <= 0 )
82                         continue ;
83
84                 if( FD_ISSET(gNet_Wrap_EventFD, &rfds) )
85                 {
86                         uint64_t        val;
87                         read(gNet_Wrap_EventFD, &val, 8);
88                 }       
89
90                 for( tNetSocket *s = gNet_Wrap_FirstSocket; s; s = s->Next )
91                 {
92                         if( FD_ISSET(s->FD, &rfds) ) {
93                                 VFS_MarkAvaliable(s->Node, 1);
94                                 s->bSkipRead = 1;
95                         }
96                         if( FD_ISSET(s->FD, &wfds) ) {
97                                 VFS_MarkFull(s->Node, 0);
98                                 s->bSkipWrite = 1;
99                         }
100                         if( FD_ISSET(s->FD, &efds) ) {
101                                 VFS_MarkError(s->Node, 1);
102                                 s->bSkipError = 1;      // TODO: how will err be acked?
103                         }
104                 }
105         }
106 }
107
108 void *Net_Wrap_ConnectTcp(void *Node, short SrcPort, short DstPort, int Type, const void *Addr)
109 {
110         struct sockaddr_in      addr4;
111         struct sockaddr *addr;
112         socklen_t       addr_size;
113         
114          int    af;
115         switch(Type)
116         {
117         case 4:
118                 af = AF_INET;
119                 addr = (struct sockaddr*)&addr4;
120                 addr_size = sizeof(addr4);
121                 memset(addr, 0, addr_size);
122                 LOG("%02x%02x%02x%02x",
123                         ((uint8_t*)Addr)[0], ((uint8_t*)Addr)[1],
124                         ((uint8_t*)Addr)[2], ((uint8_t*)Addr)[3]);
125                 memcpy(&addr4.sin_addr, Addr, 4);
126                 //addr4.sin_addr.s_addr = htonl( addr4.sin_addr.s_addr);
127                 addr4.sin_port = htons(DstPort);
128                 break;
129         //case 6:       af = AF_INET6;  break;
130         default:
131                 return NULL;
132         }       
133         
134         addr->sa_family = af;
135
136         int fd = socket(af, SOCK_STREAM, 0);
137         if( SrcPort ) {
138                 Log_Warning("NetWrap", "TODO: Support setting TCP source port");
139         }
140         Debug_HexDump("NetWrap: addr=", addr, addr_size);
141         if( connect(fd, addr, addr_size) ) {
142                 close(fd);
143                 Log_Notice("NetWrap", "connect() failed: %s", strerror(errno));
144                 char tmp[64] = {0};
145                 inet_ntop(af, addr->sa_data+2, tmp, sizeof(tmp));
146                 printf("addr = %p %s\n", tmp, tmp);
147                 return NULL;
148         }
149         
150         tNetSocket      *ret = malloc( sizeof(tNetSocket) );
151         if(!ret) {
152                 close(fd);
153                 return NULL;
154         }
155         
156         ret->Next = NULL;
157         ret->Node = Node;
158         ret->FD = fd;
159         ret->bSkipRead = 0;
160         ret->bSkipWrite = 0;
161         ret->bSkipError = 0;
162
163         if( gNet_Wrap_FirstSocket ) {
164                 gNet_Wrap_LastSocket->Next = ret;
165                 ret->Prev = gNet_Wrap_LastSocket;
166         }
167         else {
168                 gNet_Wrap_FirstSocket = ret;
169                 ret->Prev = NULL;
170         }
171         gNet_Wrap_LastSocket = ret;
172
173         Net_Wrap_ProdWatcher(); 
174
175         return ret;
176 }
177
178 static void Net_Wrap_UpdateFlags(tNetSocket *hdl)
179 {
180         struct pollfd fdinfo = {.fd = hdl->FD, .events=POLLIN|POLLOUT, .revents=0};
181         
182         poll(&fdinfo, 1, 0);
183         
184         VFS_MarkAvaliable(hdl->Node, !!(fdinfo.revents & POLLIN));
185         VFS_MarkFull(hdl->Node, !(fdinfo.revents & POLLOUT));
186
187         // If no data can be written, re-enable select  
188         if( !(fdinfo.revents & POLLOUT) )
189                 hdl->bSkipWrite = 0;
190         // Same for if no data to read
191         if( !(fdinfo.revents & POLLIN) )
192                 hdl->bSkipRead = 0;
193         
194         Net_Wrap_ProdWatcher(); 
195 }
196
197 size_t Net_Wrap_ReadSocket(void *Handle, size_t Bytes, void *Dest)
198 {
199         tNetSocket      *hdl = Handle;
200         if(!hdl)        return -1;
201         size_t rv = read(hdl->FD, Dest, Bytes);
202         Net_Wrap_UpdateFlags(hdl);      
203         return rv;
204 }
205
206 size_t Net_Wrap_WriteSocket(void *Handle, size_t Bytes, const void *Dest)
207 {
208         tNetSocket      *hdl = Handle;
209         if(!hdl)        return -1;
210         size_t rv = write(hdl->FD, Dest, Bytes);
211         Net_Wrap_UpdateFlags(hdl);      
212         return rv;
213 }
214
215 void Net_Wrap_CloseSocket(void *Handle)
216 {
217         tNetSocket      *hdl = Handle;
218
219         // TODO: Lock
220         if(hdl->Prev)
221                 hdl->Prev->Next = hdl->Next;
222         else 
223                 gNet_Wrap_FirstSocket = hdl->Next;
224         if(hdl->Next)
225                 hdl->Next->Prev = hdl->Prev;
226         else
227                 gNet_Wrap_LastSocket = hdl->Prev;       
228         Net_Wrap_ProdWatcher(); 
229
230         close(hdl->FD);
231         free(hdl);
232 }
233

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