root/Whitix/trunk/net/local.c

Revision 1800, 8.5 KB (checked in by mwhitworth, 3 years ago)

Update socket code to reflect new file table code, fix connection problems for local sockets, add POLL_ERR case.

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 <net/network.h>
22#include <net/socket.h>
23#include <slab.h>
24#include <sys.h>
25#include <task.h>
26#include <typedefs.h>
27#include <wait.h>
28#include <print.h>
29#include <module.h>
30
31struct LocalSocketAddr
32{
33        unsigned int family;
34        char name[SOCKET_DATA_LENGTH];
35};
36
37struct LocalSockInfo
38{
39//      union {
40                struct Socket* peer; /* Used by child sockets and clients. */
41                struct ListHead waitingSocks; /* Used by the parent server socket. */
42//      };
43
44        WaitQueue waitQueue;
45};
46
47LIST_HEAD(localListenSockets);
48struct Cache* localInfoCache=NULL;
49
50/***********************************************************************
51 *
52 * FUNCTION:    LocalSetPeer
53 *
54 * DESCRIPTION: Set one socket as the peer (or endpoint) of another. This
55 *                              function must be called by the local socket code before
56 *                              sending data on the socket.
57 *
58 * PARAMETERS:  first - the socket whose peer value will be set.
59 *                              second - the peer in question. It can be NULL if the first
60 *                              socket is in the process of closing.
61 *
62 * RETURNS:     Nothing.
63 *
64 ***********************************************************************/
65
66static void LocalSetPeer(struct Socket* first, struct Socket* second)
67{
68        struct LocalSockInfo* info;
69
70        if (!first)
71                return;
72
73        info=(struct LocalSockInfo*)(first->protoInfo);
74       
75        if (!info)
76                return;
77
78        info->peer=second;
79}
80
81/***********************************************************************
82 *
83 * FUNCTION:    LocalBind
84 *
85 * DESCRIPTION: Prepare the socket as a server parent socket. LocalBind
86 *                              copies the local network address and sets up the list of
87 *                              sockets that are waiting for a connection to it.
88 *
89 * PARAMETERS:  socket - the socket being bound to an address
90 *
91 * RETURNS:     -EFAULT - if socket->protoInfo is an invalid value. 0
92 *                              otherwise.
93 *
94 ***********************************************************************/
95
96int LocalBind(struct Socket* socket, struct SocketAddr* addr, int length)
97{
98        struct LocalSockInfo* info=(struct LocalSockInfo*)(socket->protoInfo);
99       
100        memcpy(&socket->addr, addr, length);
101        INIT_LIST_HEAD(&info->waitingSocks);
102
103        return 0;
104}
105
106int LocalConnect(struct Socket* socket, struct SocketAddr* addr, int length)
107{
108        struct LocalSocketAddr* socketAddr=(struct LocalSocketAddr*)addr;
109        struct LocalSocketAddr* serverSockAddr;
110        struct LocalSockInfo* serverInfo, *clientInfo;
111        struct Socket* curr, *curr2, *serverSock=NULL;
112
113        /* Can only connect to local sockets. */
114        if (socketAddr->family != PF_LOCAL)
115                return -EINVAL;
116
117        /* Find server socket. */
118        ListForEachEntrySafe(curr, curr2, &localListenSockets, next)
119        {
120                serverSockAddr=(struct LocalSocketAddr*)&curr->addr;
121                if (!strncmp(socketAddr->name, serverSockAddr->name, SOCKET_DATA_LENGTH))
122                {
123                        serverSock=curr;
124                        break;
125                }
126        }
127
128        if (!serverSock)
129                return -ENOENT;
130
131        clientInfo = (struct LocalSockInfo*)(socket->protoInfo);
132
133        serverInfo=(struct LocalSockInfo*)(serverSock->protoInfo);
134        socket->state=SOCKET_STATE_WAITING;
135
136        /* And if it is a blocking socket, wait.
137         * Add self to the server's waiting sockets, so Accept can pick things up.
138         */
139         
140        ListAdd(&socket->next, &serverInfo->waitingSocks);       
141
142        WakeUp(&serverInfo->waitQueue);
143
144        WAIT_ON(&clientInfo->waitQueue, socket->state == SOCKET_STATE_CONNECTED);
145               
146        return 0;
147}
148
149int LocalCreate(struct Socket* socket)
150{
151        /* Allocate the protocol-specific information.
152         * The structure is filled in later by the bind or connect functions.
153         */
154        struct LocalSockInfo* info;
155       
156        if (socket->type & SOCKET_TYPE_STREAM)
157                return -ESOCKTYPE;
158       
159        info=(struct LocalSockInfo*)MemCacheAlloc(localInfoCache);
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        struct LocalSockInfo* clientInfo;
204        int ret;
205
206        /* Wait for a connection. TODO: Should time out. */
207        WAIT_ON(&info->waitQueue, !ListEmpty(&info->waitingSocks));
208
209        client=ListEntry(info->waitingSocks.next, struct Socket, next);
210       
211        ListRemove(&client->next);
212
213        ret=SocketDoAccept(socket, client, &child);
214       
215        if (ret < 0)
216                return ret;
217       
218        if (addr)
219        {
220                /* Local client sockets don't have a name. */
221                addr->family=PF_LOCAL;
222                ZeroMemory(addr->data, SOCKET_DATA_LENGTH);
223        }
224       
225        INIT_WAITQUEUE_HEAD(&info->waitQueue);
226       
227        if (length)
228                *length=sizeof(unsigned int);
229       
230        /* Make the child server socket and client socket each other's peers. */
231        LocalSetPeer(child, client);
232        LocalSetPeer(client, child);
233
234        clientInfo = (struct LocalSockInfo*)(client->protoInfo);
235        WakeUp(&clientInfo->waitQueue);
236
237        return ret;
238}
239
240int LocalSend(struct Socket* socket, const void* buffer, int length, int flags)
241{
242        struct LocalSockInfo* info=(struct LocalSockInfo*)(socket->protoInfo);
243        struct Socket* peer;
244        struct LocalSockInfo* peerInfo;
245        struct SocketBuffer* sockBuff;
246        DWORD iFlags;
247
248        if (socket->state != SOCKET_STATE_CONNECTED)
249                return -EINVAL;
250       
251        peer=info->peer;
252
253        /* The other end has been closed. */
254        if (!peer)
255                return -ECONNRESET;
256       
257        /* Allocate socket buffer. */
258        sockBuff=SocketAllocateBuffer(buffer, length);
259        if (!sockBuff)
260                return -ENOMEM;
261
262        peerInfo=(struct LocalSockInfo*)(peer->protoInfo);
263       
264        IrqSaveFlags(iFlags);
265        /* Add to peer's receive queue. */
266        ListAddTail(&sockBuff->next, &peer->recvPackets);
267        IrqRestoreFlags(iFlags);
268       
269        WakeUp(&peerInfo->waitQueue);
270
271        return length;
272}
273
274int LocalReceive(struct Socket* socket, void* buffer, int length, int flags)
275{
276        struct SocketBuffer* sockBuff;
277        struct LocalSockInfo* info, *peerInfo;
278        char* pos, *orig;
279        int toRead=0;
280       
281        pos=orig=(char*)buffer;
282
283        info=(struct LocalSockInfo*)(socket->protoInfo);
284        peerInfo=(struct LocalSockInfo*)(info->peer->protoInfo);
285
286        if (ListEmpty(&socket->recvPackets))
287                WAIT_ON(&info->waitQueue, !ListEmpty(&socket->recvPackets));
288
289        /* Go through packets until we've got enough. */
290        while ((pos-orig) < length)
291        {
292                if (ListEmpty(&socket->recvPackets))
293                        break;
294               
295                PreemptDisable();
296                sockBuff=ListEntry(socket->recvPackets.next,struct SocketBuffer, next);
297
298                toRead=MIN(sockBuff->length-sockBuff->read, length);
299                memcpy(pos, sockBuff->data, toRead);
300
301                sockBuff->read+=toRead;
302                pos+=toRead;
303
304                if (sockBuff->read == sockBuff->length)
305                        SocketDestroyBuffer(sockBuff);
306                       
307                PreemptEnable();
308        }
309       
310        return pos-orig;
311}
312
313int LocalPoll(struct Socket* socket, struct PollItem* item, struct PollQueue* pollQueue)
314{
315        struct LocalSockInfo* info=(struct LocalSockInfo*)(socket->protoInfo);
316       
317        PollAddWait(pollQueue, &info->waitQueue);
318       
319        if ((socket->type & SOCKET_TYPE_SERVER) && !ListEmpty(&info->waitingSocks))
320                item->revents |= POLL_IN;
321               
322        if ((!(socket->type & SOCKET_TYPE_SERVER) && !ListEmpty(&socket->recvPackets)))
323                item->revents |= POLL_IN;
324
325        item->revents |= POLL_OUT;
326
327        if (!(socket->type & SOCKET_TYPE_SERVER) && !info->peer)
328                item->revents |= POLL_ERR;
329
330        return 0;
331}
332
333struct SocketOps localOps=
334{
335        .bind = LocalBind,
336        .connect = LocalConnect,
337        .create = LocalCreate,
338        .close = LocalClose,
339        .listen = LocalListen,
340        .accept = LocalAccept,
341        .send = LocalSend,
342        .receive = LocalReceive,
343        .poll = LocalPoll,
344};
345
346int LocalInit()
347{
348        localInfoCache=MemCacheCreate("LocalSockets", sizeof(struct LocalSockInfo), NULL, NULL, 0);
349        if (!localInfoCache)
350                return -ENOMEM;
351
352        KePrint("LOCAL: Local network sockets set up.\n");
353
354        SocketRegisterFamily(PF_LOCAL, &localOps);     
355        return 0;
356}
357
358ModuleInit(LocalInit);
Note: See TracBrowser for help on using the browser.