initial commit
[xdos] / src / client.c
1 #include <stdlib.h>
2 #include <string.h>
3 #include <sys/socket.h>
4 #include "proto.h"
5 #include "client.h"
6 #include "logger.h"
7
8 static int handle_client_setup(struct client *c);
9 static int send_server_info(struct client *c);
10
11 static struct client *clist;
12
13 int add_client(int s)
14 {
15         struct client *c = malloc(sizeof *c);
16         if(!c) {
17                 printlog("failed to allocate memory for new client\n");
18                 return -1;
19         }
20         memset(c, 0, sizeof *c);
21         c->sock = s;
22         c->state = CLIENT_SETUP;
23
24         c->next = clist;
25         clist = c;
26         return 0;
27 }
28
29 int remove_client(int s)
30 {
31         struct client dummy;
32         struct client *iter = &dummy;
33
34         dummy.next = clist;
35         while(iter->next) {
36                 if(iter->next->sock == s) {
37                         struct client *tmp = iter->next;
38                         iter->next = tmp->next;
39                         free(tmp);
40                         return 0;
41                 }
42                 iter = iter->next;
43         }
44         return -1;
45 }
46
47 /* remove all clients with closed invalid sockets */
48 int remove_closed(void)
49 {
50         int removed = 0;
51         struct client dummy;
52         struct client *iter = &dummy;
53         dummy.next = clist;
54
55         while(iter->next) {
56                 if(iter->next->sock == -1) {
57                         struct client *tmp = iter->next;
58                         iter->next = tmp->next;
59                         free(tmp);
60                         ++removed;
61                 } else {
62                         iter = iter->next;
63                 }
64         }
65         return removed;
66 }
67
68 struct client *find_client_sock(int s)
69 {
70         struct client *c = clist;
71         while(c && c->sock != s) {
72                 c = c->next;
73         }
74         return c;
75 }
76
77 struct client *get_clients(void)
78 {
79         return clist;
80 }
81
82 void free_clients(void)
83 {
84         while(clist) {
85                 struct client *c = clist;
86                 clist = clist->next;
87                 free(c);
88         }
89         clist = 0;
90 }
91
92 /* --- client comms --- */
93
94 /* handles all communications with clients */
95 int handle_client(struct client *c)
96 {
97         if(c->state == CLIENT_SETUP) {
98                 if(handle_client_setup(c) == -1) {
99                         return -1;
100                 }
101                 if(c->bufsz <= 0) {     /* consumed all data, done */
102                         return 0;
103                 }
104         }
105
106         /* TODO handle client requests ... */
107         c->bufsz = 0;
108         return 0;
109 }
110
111 /* handles data coming from a client in the CLIENT_SETUP state */
112 static int handle_client_setup(struct client *c)
113 {
114         int rd, auth_name_len, auth_data_len, fullsz, must_swap = 0;
115         struct xconn_setup_header *setup;
116         char *start = c->inbuf + c->bufsz;
117         int avail = CLIENT_BUF_SIZE - c->bufsz;
118
119         if((rd = recv(c->sock, start, avail, 0)) <= 0) {
120                 return -1;
121         }
122
123         c->bufsz += rd;
124         if(c->bufsz < sizeof(struct xconn_setup_header)) {
125                 return 0;       /* need more data */
126         }
127
128         setup = (struct xconn_setup_header*)c->inbuf;
129         if(setup->byteorder == 'B') {
130                 must_swap = 1;
131                 auth_name_len = ntohs(setup->auth_name_length);
132                 auth_data_len = ntohs(setup->auth_data_length);
133         } else {
134                 must_swap = 0;
135                 auth_name_len = setup->auth_name_length;
136                 auth_data_len = setup->auth_data_length;
137         }
138
139         /* take padding to the next 32bit-aligned address into account */
140         auth_name_len = (auth_name_len + 3) & 0xfffc;
141         auth_data_len = (auth_data_len + 3) & 0xfffc;
142         fullsz = sizeof(struct xconn_setup_header) + auth_name_len + auth_data_len;
143
144         if(c->bufsz < fullsz) {
145                 return 0;       /* more to read... */
146         }
147
148         /* ok we've read it all, act on it... */
149         c->swap = must_swap;
150         if(must_swap) {
151                 printlog("big endian client, protocol: %d.%d\n", ntohs(setup->proto_major), ntohs(setup->proto_minor));
152         } else {
153                 printlog("little endian client, protocol: %d.%d\n", setup->proto_major, setup->proto_minor);
154         }
155         /* TODO send response */
156         c->state = CLIENT_ACTIVE;
157
158         if(c->bufsz > fullsz) {
159                 int rem = c->bufsz - fullsz;
160                 memmove(c->inbuf, c->inbuf + fullsz, rem);
161                 c->bufsz = rem;
162         }
163         return 0;
164 }
165
166 static int send_server_info(struct client *c)
167 {
168         struct xconn_accept_header *hdr;
169
170         return -1;      /* TODO */
171 }