root / Whitix / branches / scheduler / net / local.c

Revision 608, 8.1 kB (checked in by mwhitworth, 7 months ago)

(Hopefully) convert all source and header files to UNIX line endings.

Line 
1/*  This file is part of Whitix.
2 *
3 *  Whitix is free software; you can redistribute it and/or modify
4 *  it under the terms of the GNU General Public License as published by
5 *  the Free Software Foundation; either version 2 of the License, or
6 *  (at your option) any later version.
7 *
8 *  Whitix is distributed in the hope that it will be useful,
9 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 *  GNU General Public License for more details.
12 *
13 *  You should have received a copy of the GNU General Public License
14 *  along with Whitix; if not, write to the Free Software
15 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
16 *
17 */
18
19#include <console.h>
20#include <error.h>
21#include <init.h>
22#include <net/network.h>
23#include <net/socket.h>
24#include <slab.h>
25#include <sys.h>
26#include <task.h>
27#include <typedefs.h>
28#include <wait.h>
29
30struct LocalSocketAddr
31{
32        unsigned int family;
33        char name[SOCKET_DATA_LENGTH];
34};
35
36struct LocalSockInfo
37{
38        union {
39                struct Socket* peer; /* Used by child sockets and clients. */
40                struct ListHead waitingSocks; /* Used by the parent server socket. */
41        };
42
43        WaitQueue waitQueue;
44};
45
46LIST_HEAD(localListenSockets);
47struct Cache* localInfoCache=NULL;
48
49/***********************************************************************
50 *
51 * FUNCTION:    LocalSetPeer
52 *
53 * DESCRIPTION: Set one socket as the peer (or endpoint) of another. This
54 *                              function must be called by the local socket code before
55 *                              sending data on the socket.
56 *
57 * PARAMETERS:  first - the socket whose peer value will be set.
58 *                              second - the peer in question. It can be NULL if the first
59 *                              socket is in the process of closing.
60 *
61 * RETURNS:     Nothing.
62 *
63 ***********************************************************************/
64
65static void LocalSetPeer(struct Socket* first, struct Socket* second)
66{
67        struct LocalSockInfo* info;
68
69        if (!first)
70                return;
71
72        info=(struct LocalSockInfo*)(first->protoInfo);
73       
74        if (!info)
75                return;
76
77        info->peer=second;
78}
79
80/***********************************************************************
81 *
82 * FUNCTION:    LocalBind
83 *
84 * DESCRIPTION: Prepare the socket as a server parent socket. LocalBind
85 *                              copies the local network address and sets up the list of
86 *                              sockets that are waiting for a connection to it.
87 *
88 * PARAMETERS:  socket - the socket being bound to an address
89 *
90 * RETURNS:     -EFAULT - if socket->protoInfo is an invalid value. 0
91 *                              otherwise.
92 *
93 ***********************************************************************/
94
95int LocalBind(struct Socket* socket, struct SocketAddr* addr, int length)
96{
97        struct LocalSockInfo* info=(struct LocalSockInfo*)(socket->protoInfo);
98       
99        memcpy(&socket->addr, addr, length);
100        INIT_LIST_HEAD(&info->waitingSocks);
101
102        return 0;
103}
104
105int LocalConnect(struct Socket* socket, struct SocketAddr* addr, int length)
106{
107        struct LocalSocketAddr* socketAddr=(struct LocalSocketAddr*)addr;
108        struct LocalSocketAddr* serverSockAddr;
109        struct LocalSockInfo* serverInfo;
110        struct Socket* curr, *serverSock=NULL;
111
112        /* Can only connect to local sockets. */
113        if (socketAddr->family != PF_LOCAL)
114                return -EINVAL;
115
116        /* Find server socket. */
117        ListForEachEntry(curr, &localListenSockets, next)
118        {
119                serverSockAddr=(struct LocalSocketAddr*)&curr->addr;
120                if (!strncmp(socketAddr->name, serverSockAddr->name, SOCKET_DATA_LENGTH))
121                {
122                        serverSock=curr;
123                        break;
124                }
125        }
126
127        if (!serverSock)
128                return -ENOENT;
129
130        serverInfo=(struct LocalSockInfo*)(serverSock->protoInfo);
131        socket->state=SOCKET_STATE_WAITING;
132
133        /* And if it is a blocking socket, wait.
134         * Add self to the server's waiting sockets, so Accept can pick things up.
135         */
136         
137        ListAddTail(&socket->next, &serverInfo->waitingSocks);   
138
139        WakeUp(&serverInfo->waitQueue);
140
141        while (socket->state != SOCKET_STATE_CONNECTED) /* FIXME: or socket state is error. */ 
142                ThrSchedule();
143               
144        return 0;
145}
146
147int LocalCreate(struct Socket* socket)
148{
149        /* Allocate the protocol-specific information.
150         * The structure is filled in later by the bind or connect functions.
151         */
152        struct LocalSockInfo* info;
153       
154        if (socket->type & SOCKET_TYPE_STREAM)
155                return -ESOCKTYPE;
156       
157        info=(struct LocalSockInfo*)MemCacheAlloc(localInfoCache);
158
159        KePrint("info = %#X\n", info);
160
161        if (!info)
162                return -ENOMEM;
163
164        info->peer=NULL;
165        INIT_WAITQUEUE_HEAD(&info->waitQueue);
166
167        socket->protoInfo=info;
168
169        return 0;
170}
171
172int LocalClose(struct Socket* socket)
173{
174        struct LocalSockInfo* info;
175
176        if (!socket)
177                return 0;
178
179        info=(struct LocalSockInfo*)(socket->protoInfo);
180
181        if (!info)
182                return 0;
183       
184        if (!(socket->type & SOCKET_TYPE_SERVER))
185                /* Inform peer of closure. */
186                LocalSetPeer(info->peer, NULL);
187
188        return 0;
189}
190
191int LocalListen(struct Socket* socket, int backlog)
192{
193        /* TODO: Take note of backlog. */
194        ListAdd(&socket->next, &localListenSockets);
195        socket->state=SOCKET_STATE_ACCEPTING;
196        return 0;
197}
198
199int LocalAccept(struct Socket* socket, struct SocketAddr* addr, int* length)
200{
201        struct Socket* client, *child;
202        struct LocalSockInfo* info=(struct LocalSockInfo*)(socket->protoInfo);
203        int ret;
204
205        /* Wait for a connection. Should time out. */
206        WAIT_ON(info->waitQueue, !ListEmpty(&info->waitingSocks));
207
208        client=ListEntry(info->waitingSocks.next,struct Socket, next);
209        ListRemove(&client->next);
210
211        ret=SocketDoAccept(socket, client, &child);
212        if (ret < 0)
213                return ret;
214
215        /* Local client sockets don't have a name. */
216        addr->family=PF_LOCAL;
217        ZeroMemory(addr->data, SOCKET_DATA_LENGTH);
218        *length=sizeof(unsigned int);
219       
220        /* Make the child server socket and client socket each other's peers. */
221        LocalSetPeer(child, client);
222        LocalSetPeer(client, child);
223
224        return ret;
225}
226
227int LocalSend(struct Socket* socket, const void* buffer, int length, int flags)
228{
229        struct LocalSockInfo* info=(struct LocalSockInfo*)(socket->protoInfo);
230        struct Socket* peer;
231        struct LocalSockInfo* peerInfo;
232        struct SocketBuffer* sockBuff;
233        DWORD iFlags;
234               
235        if (socket->state != SOCKET_STATE_CONNECTED)
236                return -EINVAL;
237       
238        peer=info->peer;
239
240        /* The other end has been closed. */
241        if (!peer)
242                return -ECONNRESET;
243       
244        /* Allocate socket buffer. */
245        sockBuff=SocketAllocateBuffer(buffer, length);
246        if (!sockBuff)
247                return -ENOMEM;
248
249        peerInfo=(struct LocalSockInfo*)(peer->protoInfo);
250       
251        IrqSaveFlags(iFlags);
252        /* Add to peer's receive queue. */
253        ListAddTail(&sockBuff->next, &peer->recvPackets);
254        IrqRestoreFlags(iFlags);
255
256        WakeUp(&peerInfo->waitQueue);
257
258        return length;
259}
260
261int LocalReceive(struct Socket* socket, void* buffer, int length, int flags)
262{
263        struct SocketBuffer* sockBuff;
264        struct LocalSockInfo* info;
265        char* pos, *orig;
266        int toRead=0;
267        DWORD iFlags;
268       
269        pos=orig=(char*)buffer;
270
271        info=(struct LocalSockInfo*)(socket->protoInfo);
272
273        WAIT_ON(info->waitQueue, !ListEmpty(&socket->recvPackets));
274
275        /* Go through packets until we've got enough. */
276        while ((pos-orig) < length)
277        {
278                if (ListEmpty(&socket->recvPackets))
279                        break;
280               
281                sockBuff=ListEntry(socket->recvPackets.next,struct SocketBuffer, next);
282
283                toRead=MIN(sockBuff->length-sockBuff->read, length);
284                memcpy(pos, sockBuff->data, toRead);
285
286                sockBuff->read+=toRead;
287                pos+=toRead;
288
289                if (sockBuff->read == sockBuff->length)
290                        SocketDestroyBuffer(sockBuff);
291        }
292       
293        return pos-orig;
294}
295
296/* FIXME: Quick hack! */
297int LocalPoll(struct Socket* socket, struct PollItem* item, struct PollQueue* pollQueue)
298{
299        struct LocalSockInfo* info=(struct LocalSockInfo*)(socket->protoInfo);
300
301        if (item->events & POLL_IN)
302        {
303                if (socket->type & SOCKET_TYPE_SERVER)
304                {
305                        if (!ListEmpty(&info->waitingSocks))
306                                item->revents|=POLL_IN;
307                }else if (!ListEmpty(&socket->recvPackets))
308                        item->revents|=POLL_IN;
309        }
310
311        if (item->events & POLL_OUT)
312                item->revents |= POLL_OUT;
313
314        PollAddWait(pollQueue, &info->waitQueue);
315
316        return 0;
317}
318
319struct SocketOps localOps=
320{
321        .bind = LocalBind,
322        .connect = LocalConnect,
323        .create = LocalCreate,
324        .close = LocalClose,
325        .listen = LocalListen,
326        .accept = LocalAccept,
327        .send = LocalSend,
328        .receive = LocalReceive,
329        .poll = LocalPoll,
330};
331
332int LocalInit()
333{
334        localInfoCache=MemCacheCreate("Local socket info cache", sizeof(struct LocalSockInfo), NULL, NULL, 0);
335        if (!localInfoCache)
336                return -ENOMEM;
337
338        KePrint("LOCAL: Local network sockets set up.\n");
339
340        SocketRegisterFamily(PF_LOCAL, &localOps);     
341        return 0;
342}
343
344NetInit(LocalInit);
Note: See TracBrowser for help on using the browser.