Subversion Repositories Spectranet

[/] [trunk/] [tnfs/] [tnfsd/] [datagram.c] - Blame information for rev 570

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 291 winston
/* The MIT License
2
 
3
Copyright (c) 2010 Dylan Smith
4
 
5
Permission is hereby granted, free of charge, to any person obtaining a copy
6
of this software and associated documentation files (the "Software"), to deal
7
in the Software without restriction, including without limitation the rights
8
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
copies of the Software, and to permit persons to whom the Software is
10
furnished to do so, subject to the following conditions:
11
 
12
The above copyright notice and this permission notice shall be included in
13
all copies or substantial portions of the Software.
14
 
15
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
THE SOFTWARE.
22
 
23
TNFS daemon datagram handler
24
 
25
*/
26
 
27 296 winston
#include <sys/types.h>
28 291 winston
#include <stdio.h>
29
#include <string.h>
30
#include <errno.h>
31
 
32 299 winston
#ifdef UNIX
33
#include <sys/socket.h>
34
#include <netinet/in.h>
35 570 winston
#include <sys/select.h>
36 299 winston
#endif
37
 
38
#ifdef WIN32
39
#include <windows.h>
40
#endif
41
 
42 291 winston
#include "tnfs.h"
43
#include "datagram.h"
44
#include "log.h"
45
#include "endian.h"
46
#include "session.h"
47
#include "errortable.h"
48
#include "directory.h"
49
#include "tnfs_file.h"
50
 
51 570 winston
int sockfd;             /* UDP global socket file descriptor */
52
int tcplistenfd;        /* TCP listening socket file descriptor */
53 291 winston
 
54
tnfs_cmdfunc dircmd[NUM_DIRCMDS]=
55 402 winston
        { &tnfs_opendir, &tnfs_readdir, &tnfs_closedir,
56
          &tnfs_mkdir, &tnfs_rmdir };
57 291 winston
tnfs_cmdfunc filecmd[NUM_FILECMDS]=
58 484 winston
        { &tnfs_open_deprecated, &tnfs_read, &tnfs_write, &tnfs_close,
59
          &tnfs_stat, &tnfs_lseek, &tnfs_unlink, &tnfs_chmod, &tnfs_rename,
60
                &tnfs_open      };
61 291 winston
 
62
void tnfs_sockinit()
63
{
64
        struct sockaddr_in servaddr;
65
 
66 299 winston
#ifdef WIN32
67
        WSADATA wsaData;
68
        if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0)
69
                die("WSAStartup() failed");
70
#endif
71
 
72 570 winston
        /* Create the UDP socket */
73 291 winston
        sockfd=socket(AF_INET, SOCK_DGRAM, 0);
74
        if(sockfd < 0)
75
                die("Unable to open socket");
76
 
77
        /* set up the network */
78
        memset(&servaddr, 0, sizeof(servaddr));
79
        servaddr.sin_family=AF_INET;
80
        servaddr.sin_addr.s_addr=htons(INADDR_ANY);
81
        servaddr.sin_port=htons(TNFSD_PORT);
82
 
83
        if(bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
84
                die("Unable to bind");
85 570 winston
 
86
        /* Create the TCP socket */
87
        tcplistenfd=socket(AF_INET, SOCK_STREAM, 0);
88
        if(tcplistenfd < 0) {
89
                die("Unable to create TCP socket");
90
        }
91
 
92
        memset(&servaddr, 0, sizeof(servaddr));
93
        servaddr.sin_family=AF_INET;
94
        servaddr.sin_addr.s_addr=htons(INADDR_ANY);
95
        servaddr.sin_port=htons(TNFSD_PORT);
96
        if (bind(tcplistenfd, (struct sockaddr *) &servaddr,
97
              sizeof(servaddr)) < 0) {
98
                die("Unable to bind TCP socket");
99
        }
100
        listen(tcplistenfd, 5);
101 291 winston
}
102
 
103
void tnfs_mainloop()
104 570 winston
{
105
        int readyfds, i;
106
        fd_set fdset;
107
        fd_set errfdset;
108
        int tcpsocks[MAX_TCP_CONN];
109
 
110
        memset(&tcpsocks, 0, sizeof(tcpsocks));
111
        while(1) {
112
                FD_ZERO(&fdset);
113
 
114
                /* add UDP socket and TCP listen socket to fdset */
115
                FD_SET(sockfd, &fdset);
116
                FD_SET(tcplistenfd, &fdset);
117
 
118
                for(i=0; i<MAX_TCP_CONN; i++) {
119
                        if(tcpsocks[i]) {
120
                                FD_SET(tcpsocks[i], &fdset);
121
                        }
122
                }
123
 
124
                FD_COPY(&fdset, &errfdset);
125
                if((readyfds=select
126
                        (FD_SETSIZE, &fdset, NULL, &errfdset, NULL)) != 0) {
127
                        if(readyfds < 0) {
128
                                die("select() failed\n");
129
                        }
130
 
131
                        /* handle fds ready for reading */
132
                        /* UDP message? */
133
                        if(FD_ISSET(sockfd, &fdset)) {
134
                                tnfs_handle_udpmsg();
135
                        }
136
                        /* Incoming TCP connection? */
137
                        else if(FD_ISSET(tcplistenfd, &fdset)) {
138
                                tcp_accept(&tcpsocks[0]);
139
                        }
140
 
141
                        else {
142
                                for(i=0; i<MAX_TCP_CONN; i++) {
143
                                        if(tcpsocks[i]) {
144
                                                if(FD_ISSET(tcpsocks[i],&fdset))
145
                                                {
146
                                                        tnfs_handle_tcpmsg(tcpsocks[i]);
147
                                                }
148
                                        }
149
                                }
150
                        }
151
                }
152
        }
153
}
154
 
155
void tcp_accept(int *socklist) {
156
        int acc_fd, i;
157
        struct sockaddr_in cli_addr;
158
        int cli_len=sizeof(cli_addr);
159
        int *fdptr;
160
 
161
        acc_fd=accept(tcplistenfd, (struct sockaddr *) &cli_addr, &cli_len);
162
        if(acc_fd < 1) {
163
                fprintf(stderr, "WARNING: unable to accept TCP connection\n");
164
                return;
165
        }
166
 
167
        fdptr=socklist;
168
        for(i=0; i<MAX_TCP_CONN; i++) {
169
                if(*fdptr == 0) {
170
                        *fdptr=acc_fd;
171
                        return;
172
                }
173
        }
174
 
175
        /* tell the client 'too many connections' */
176
}
177
 
178
void tnfs_handle_udpmsg() {
179 291 winston
        socklen_t len;
180
        int rxbytes;
181
        struct sockaddr_in cliaddr;
182
        unsigned char rxbuf[MAXMSGSZ];
183
 
184 570 winston
        len=sizeof(cliaddr);
185
        rxbytes=recvfrom(sockfd, rxbuf, sizeof(rxbuf), 0,
186
                        (struct sockaddr *)&cliaddr, &len);
187
 
188
        if(rxbytes >= TNFS_HEADERSZ)
189 291 winston
        {
190 570 winston
                /* probably a valid TNFS packet, decode it */
191
                tnfs_decode(&cliaddr, rxbytes, rxbuf);
192
        }
193
        else
194
        {
195
                MSGLOG(cliaddr.sin_addr.s_addr,
196
                        "Invalid datagram received");
197
        }
198 291 winston
 
199 570 winston
        *(rxbuf+rxbytes)=0;
200
}
201 291 winston
 
202 570 winston
void tnfs_handle_tcpmsg(int cli_fd) {
203
        char buf[255];
204
        int sz;
205
 
206
        sz=read(cli_fd, buf, sizeof(buf));
207
        printf("DEBUG: rx of tcpmsg: %d bytes: %s\n", sz, buf);
208
 
209 291 winston
}
210
 
211
void tnfs_decode(struct sockaddr_in *cliaddr, int rxbytes, unsigned char *rxbuf)
212
{
213
        Header hdr;
214
        Session *sess;
215
        int sindex;
216
        int datasz=rxbytes-TNFS_HEADERSZ;
217
        int cmdclass, cmdidx;
218
        unsigned char *databuf=rxbuf+TNFS_HEADERSZ;
219
 
220
        memset(&hdr, 0, sizeof(hdr));
221
 
222
        /* note: don't forget about byte alignment issues on some
223
         * architectures... */
224
        hdr.sid=tnfs16uint(rxbuf);
225
        hdr.seqno=*(rxbuf+2);
226
        hdr.cmd=*(rxbuf+3);
227
        hdr.ipaddr=cliaddr->sin_addr.s_addr;
228
        hdr.port=ntohs(cliaddr->sin_port);
229
 
230
#ifdef DEBUG
231
        TNFSMSGLOG(&hdr, "DEBUG: Decoding datagram");
232
        fprintf(stderr, "DEBUG: cmd=%x msgsz=%d\n", hdr.cmd, rxbytes);
233
#endif
234
 
235
        /* The MOUNT command is the only one that doesn't need an
236
         * established session (since MOUNT is actually what will
237
         * establish the session) */
238
        if(hdr.cmd != TNFS_MOUNT)
239
        {
240
                sess=tnfs_findsession_sid(hdr.sid, &sindex);
241
                if(sess == NULL)
242
                {
243
                        TNFSMSGLOG(&hdr, "Invalid session ID");
244
                        return;
245
                }
246
                if(sess->ipaddr != hdr.ipaddr)
247
                {
248
                        TNFSMSGLOG(&hdr, "Session and IP do not match");
249
                        return;
250
                }
251
        }
252
        else
253
        {
254
                tnfs_mount(&hdr, databuf, datasz);
255
                return;
256
        }
257
 
258
        /* client is asking for a resend */
259
        if(hdr.seqno == sess->lastseqno)
260
        {
261
                tnfs_resend(sess, cliaddr);
262
                return;
263
        }
264
 
265
        /* find the command class and pass it off to the right
266
         * function */
267
        cmdclass=hdr.cmd & 0xF0;
268
        cmdidx=hdr.cmd & 0x0F;
269
        switch(cmdclass)
270
        {
271
                case CLASS_SESSION:
272
                        switch(cmdidx)
273
                        {
274
                                case TNFS_UMOUNT:
275
                                tnfs_umount(&hdr, sess, sindex);
276
                                break;
277
                        default:
278
                                tnfs_badcommand(&hdr, sess);
279
                        }
280
                        break;
281
                case CLASS_DIRECTORY:
282
                        if(cmdidx < NUM_DIRCMDS)
283
                                (*dircmd[cmdidx])(&hdr, sess, databuf, datasz);
284
                        else
285
                                tnfs_badcommand(&hdr, sess);
286
                        break;
287
                case CLASS_FILE:
288
                        if(cmdidx < NUM_FILECMDS)
289
                                (*filecmd[cmdidx])(&hdr, sess, databuf, datasz);
290
                        else
291
                                tnfs_badcommand(&hdr, sess);
292
                        break;
293
                default:
294
                        tnfs_badcommand(&hdr, sess);
295
        }
296
}
297
 
298
void tnfs_badcommand(Header *hdr, Session *sess)
299
{
300
        TNFSMSGLOG(hdr, "Bad command");
301
        hdr->status=TNFS_ENOSYS;
302
        tnfs_send(sess, hdr, NULL, 0);
303
}
304
 
305
void tnfs_send(Session *sess, Header *hdr, unsigned char *msg, int msgsz)
306
{
307
        struct sockaddr_in cliaddr;
308
        ssize_t txbytes;
309
        unsigned char *txbuf=sess->lastmsg;
310
 
311
        if(msgsz+TNFS_HEADERSZ > MAXMSGSZ)
312
        {
313
                die("tnfs_send: Message too big");
314
        }
315
 
316
        cliaddr.sin_family=AF_INET;
317
        cliaddr.sin_addr.s_addr=hdr->ipaddr;
318
        cliaddr.sin_port=htons(hdr->port);
319
 
320
        uint16tnfs(txbuf, hdr->sid);
321
        *(txbuf+2)=hdr->seqno;
322
        *(txbuf+3)=hdr->cmd;
323
        *(txbuf+4)=hdr->status;
324
        if(msg)
325
                memcpy(txbuf+5, msg, msgsz);
326
        sess->lastmsgsz=msgsz+TNFS_HEADERSZ+1;  /* header + status code */
327
        sess->lastseqno=hdr->seqno;
328
 
329
        txbytes=sendto(sockfd, txbuf, msgsz+TNFS_HEADERSZ+1, 0,
330
                (struct sockaddr *)&cliaddr, sizeof(cliaddr));
331
        if(txbytes < msgsz+TNFS_HEADERSZ)
332
        {
333
                TNFSMSGLOG(hdr, "Message was truncated");
334
        }
335
}
336
 
337
void tnfs_resend(Session *sess, struct sockaddr_in *cliaddr)
338
{
339
        int txbytes;
340
        txbytes=sendto(sockfd, sess->lastmsg, sess->lastmsgsz, 0,
341
                        (struct sockaddr *)cliaddr, sizeof(struct sockaddr_in));
342
        if(txbytes < sess->lastmsgsz)
343
        {
344
                MSGLOG(cliaddr->sin_addr.s_addr,
345
                        "Retransmit was truncated");
346
        }
347
}
348