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

Revision 635, 7.1 kB (checked in by mwhitworth, 7 months ago)

Add SocketGenericReceive function for local sockets (raw sockets will use this function very soon).

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
44LIST_HEAD(localListenSockets);
45struct Cache* localInfoCache=NULL;
46
47/***********************************************************************
48 *
49 * FUNCTION:    LocalSetPeer
50 *
51 * DESCRIPTION: Set one socket as the peer (or endpoint) of another. This
52 *                              function must be called by the local socket code before
53 *                              sending data on the socket.
54 *
55 * PARAMETERS:  first - the socket whose peer value will be set.
56 *                              second - the peer in question. It can be NULL if the first
57 *                              socket is in the process of closing.
58 *
59 * RETURNS:     Nothing.
60 *
61 ***********************************************************************/
62
63static void LocalSetPeer(struct Socket* first, struct Socket* second)
64{
65        struct LocalSockInfo* info;
66
67        if (!first)
68                return;
69
70        info=(struct LocalSockInfo*)(first->protoInfo);
71       
72        if (!info)
73                return;
74
75        info->peer=second;
76}
77
78/***********************************************************************
79 *
80 * FUNCTION:    LocalBind
81 *
82 * DESCRIPTION: Prepare the socket as a server parent socket. LocalBind
83 *                              copies the local network address and sets up the list of
84 *                              sockets that are waiting for a connection to it.
85 *
86 * PARAMETERS:  socket - the socket being bound to an address
87 *
88 * RETURNS:     -EFAULT - if socket->protoInfo is an invalid value. 0
89 *                              otherwise.
90 *
91 ***********************************************************************/
92
93int LocalBind(struct Socket* socket, struct SocketAddr* addr, int length)
94{
95        struct LocalSockInfo* info=(struct LocalSockInfo*)(socket->protoInfo);
96       
97        memcpy(&socket->addr, addr, length);
98        INIT_LIST_HEAD(&info->waitingSocks);
99
100        return 0;
101}
102
103int LocalConnect(struct Socket* socket, struct SocketAddr* addr, int length)
104{
105        struct LocalSocketAddr* socketAddr=(struct LocalSocketAddr*)addr;
106        struct LocalSocketAddr* serverSockAddr;
107        struct LocalSockInfo* serverInfo;
108        struct Socket* curr, *serverSock=NULL;
109
110        /* Can only connect to local sockets. */
111        if (socketAddr->family != PF_LOCAL)
112                return -EINVAL;
113
114        /* Find server socket. */
115        ListForEachEntry(curr, &localListenSockets, next)
116        {
117                serverSockAddr=(struct LocalSocketAddr*)&curr->addr;
118                if (!strncmp(socketAddr->name, serverSockAddr->name, SOCKET_DATA_LENGTH))
119                {
120                        serverSock=curr;
121                        break;
122                }
123        }
124
125        if (!serverSock)
126                return -ENOENT;
127
128        serverInfo=(struct LocalSockInfo*)(serverSock->protoInfo);
129        socket->state=SOCKET_STATE_WAITING;
130
131        /* And if it is a blocking socket, wait.
132         * Add self to the server's waiting sockets, so Accept can pick things up.
133         */
134         
135        ListAddTail(&socket->next, &serverInfo->waitingSocks);   
136
137        while (socket->state != SOCKET_STATE_CONNECTED) /* FIXME: or socket state is error. */ 
138                ThrSchedule();
139               
140        return 0;
141}
142
143int LocalCreate(struct Socket* socket)
144{
145        /* Allocate the protocol-specific information.
146         * The structure is filled in later by the bind or connect functions.
147         */
148        struct LocalSockInfo* info;
149       
150        if (socket->type & SOCKET_TYPE_STREAM)
151                return -ESOCKTYPE;
152       
153        info=(struct LocalSockInfo*)MemCacheAlloc(localInfoCache);
154
155        if (!info)
156                return -ENOMEM;
157
158        info->peer=NULL;
159        socket->protoInfo=info;
160
161        return 0;
162}
163
164int LocalClose(struct Socket* socket)
165{
166        struct LocalSockInfo* info;
167
168        if (!socket)
169                return 0;
170
171        info=(struct LocalSockInfo*)(socket->protoInfo);
172
173        if (!info)
174                return 0;
175       
176        if (!(socket->type & SOCKET_TYPE_SERVER))
177                /* Inform peer of closure. */
178                LocalSetPeer(info->peer, NULL);
179
180        return 0;
181}
182
183int LocalListen(struct Socket* socket, int backlog)
184{
185        /* TODO: Take note of backlog. */
186        ListAdd(&socket->next, &localListenSockets);
187        socket->state=SOCKET_STATE_ACCEPTING;
188        return 0;
189}
190
191int LocalAccept(struct Socket* socket, struct SocketAddr* addr, int* length)
192{
193        struct Socket* client, *child;
194        struct LocalSockInfo* info=(struct LocalSockInfo*)(socket->protoInfo);
195        int ret;
196
197        /* Wait for a connection. Should time out. */
198        while (ListEmpty(&info->waitingSocks))
199                ThrSchedule();
200
201        client=ListEntry(info->waitingSocks.next,struct Socket, next);
202        ListRemove(&client->next);
203
204        ret=SocketDoAccept(socket, client, &child);
205        if (ret < 0)
206                return ret;
207
208        /* Local client sockets don't have a name. */
209        addr->family=PF_LOCAL;
210        ZeroMemory(addr->data, SOCKET_DATA_LENGTH);
211        *length=sizeof(unsigned int);
212       
213        /* Make the child server socket and client socket each other's peers. */
214        LocalSetPeer(child, client);
215        LocalSetPeer(client, child);
216
217        return ret;
218}
219
220int LocalSend(struct Socket* socket, const void* buffer, int length, int flags)
221{
222        struct LocalSockInfo* info=(struct LocalSockInfo*)(socket->protoInfo);
223        struct Socket* peer;
224        struct SocketBuffer* sockBuff;
225        DWORD iFlags;
226               
227        if (socket->state != SOCKET_STATE_CONNECTED)
228                return -EINVAL;
229       
230        peer=info->peer;
231
232        /* The other end has been closed. */
233        if (!peer)
234                return -ECONNRESET;
235       
236        /* Allocate socket buffer. */
237        sockBuff=SocketAllocateBuffer(buffer, length, 0);
238        if (!sockBuff)
239                return -ENOMEM;
240       
241        IrqSaveFlags(iFlags);
242        /* Add to peer's receive queue. */
243        ListAddTail(&sockBuff->next, &peer->recvPackets); /* Lock this. */
244        IrqRestoreFlags(iFlags);
245
246        return length;
247}
248
249/* FIXME: Quick hack! */
250int LocalPoll(struct Socket* socket, struct PollItem* item)
251{
252        struct LocalSockInfo* info=(struct LocalSockInfo*)(socket->protoInfo);
253
254        if (item->events & POLL_IN)
255        {
256                if (socket->type & SOCKET_TYPE_SERVER)
257                {
258                        if (!ListEmpty(&info->waitingSocks))
259                        {
260                                item->revents|=POLL_IN;
261                        }
262                }else if (!ListEmpty(&socket->recvPackets))
263                {
264                        item->revents|=POLL_IN;
265                }
266        }
267
268        if (item->events & 0x02)
269        {
270                item->revents|=0x2;
271        }
272
273        if (item->revents > 0)
274                return 0;
275
276        return -1;
277}
278
279struct SocketOps localOps=
280{
281        .bind = LocalBind,
282        .connect = LocalConnect,
283        .create = LocalCreate,
284        .close = LocalClose,
285        .listen = LocalListen,
286        .accept = LocalAccept,
287        .send = LocalSend,
288        .receive = SocketGenericReceive,
289        .poll = LocalPoll,
290};
291
292int LocalInit()
293{
294        localInfoCache=MemCacheCreate("Local socket info cache", sizeof(struct LocalSockInfo), NULL, NULL, 0);
295        if (!localInfoCache)
296                return -ENOMEM;
297
298        printf("LOCAL: Local network sockets set up.\n");
299
300        SocketRegisterFamily(PF_LOCAL, &localOps);     
301        return 0;
302}
303
304NetInit(LocalInit);
Note: See TracBrowser for help on using the browser.