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

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