]> git.pond.sub.org Git - empserver/blob - src/client/ioqueue.c
Fix previous rev.
[empserver] / src / client / ioqueue.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2000, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                           Ken Stevens, Steve McClure
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  *  ---
21  *
22  *  See the "LEGAL", "LICENSE", "CREDITS" and "README" files for all the
23  *  related information and legal notices. It is expected that any future
24  *  projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  ioqueue.c: Manage an i/o queue
29  * 
30  *  Known contributors to this file:
31  *     Steve McClure, 1998
32  */
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <sys/types.h>
38 #ifndef _WIN32
39 #include <sys/uio.h>
40 #include <unistd.h>
41 #endif
42 #include "misc.h"
43 #include "queue.h"
44 #include "ioqueue.h"
45
46 #ifdef _WIN32
47 typedef struct iovec {
48     char *iov_base;
49     int iov_len;
50 } iovec_t;
51 #endif
52
53
54 static int ioqtobuf();
55 static int ioqtoiov();
56 static void enqueuecc();
57 static int dequeuecc();
58
59 void insque();
60 void remque();
61 void initque();
62 struct qelem *makeqt();
63
64 void
65 ioq_init(ioq, bsize)
66 struct ioqueue *ioq;
67 int bsize;
68 {
69     extern s_char num_teles[];
70
71     initque(&ioq->queue);
72     ioq->cc = 0;
73     ioq->bsize = bsize;
74     *num_teles = '\0';
75 }
76
77 /*
78  * copy batch of pointers into the passed
79  * iovec, but don't actually dequeue the data.
80  * return # of iovec initialized.
81  */
82 int
83 ioq_peekiov(ioq, iov, max)
84 struct ioqueue *ioq;
85 struct iovec *iov;
86 int max;
87 {
88     if (ioq->cc <= 0)
89         return 0;
90     return ioqtoiov(ioq, iov, max);
91 }
92
93 /*
94  * Copy the specified number of characters into the buffer
95  * provided, without actually dequeueing the data.  Return
96  * number of bytes actually found.
97  */
98 int
99 ioq_peek(ioq, buf, cc)
100 struct ioqueue *ioq;
101 s_char *buf;
102 int cc;
103 {
104     return ioqtobuf(ioq, buf, cc);
105 }
106
107 int
108 ioq_dequeue(ioq, cc)
109 struct ioqueue *ioq;
110 int cc;
111 {
112     if (dequeuecc(ioq, cc) != cc)
113         return 0;
114     return cc;
115 }
116
117 int
118 ioq_read(ioq, buf, cc)
119 struct ioqueue *ioq;
120 s_char *buf;
121 int cc;
122 {
123     int n;
124
125     n = ioqtobuf(ioq, buf, cc);
126     if (n > 0)
127         dequeuecc(ioq, n);
128     return n;
129 }
130
131 void
132 ioq_write(ioq, buf, cc)
133 struct ioqueue *ioq;
134 s_char *buf;
135 int cc;
136 {
137     enqueuecc(ioq, buf, cc);
138 }
139
140 int
141 ioq_qsize(ioq)
142 struct ioqueue *ioq;
143 {
144     return ioq->cc;
145 }
146
147 void
148 ioq_drain(ioq)
149 struct ioqueue *ioq;
150 {
151     struct io *io;
152     struct qelem *qp;
153
154     while ((qp = ioq->queue.q_forw) != &ioq->queue) {
155         io = (struct io *)qp;
156         free(io->data);
157         (void)remque(&io->queue);
158         (void)free(io);
159     }
160     ioq->cc = 0;
161 }
162
163 s_char *
164 ioq_gets(ioq, buf, cc)
165 struct ioqueue *ioq;
166 s_char *buf;
167 int cc;
168 {
169     register s_char *p;
170     register s_char *end;
171     int nbytes;
172
173     nbytes = ioqtobuf(ioq, buf, cc);
174     if (nbytes < cc)
175         cc = nbytes;
176     end = &buf[cc];
177     for (p = buf; p < end && *p; p++) {
178         if (*p == '\n') {
179             *p = '\0';
180             dequeuecc(ioq, (p - buf) + 1);
181             return buf;
182         }
183     }
184     return 0;
185 }
186
187 /*
188  * all the rest are local to this module
189  */
190
191
192 /*
193  * copy cc bytes from ioq to buf.
194  * this routine doesn't free memory; this is
195  * left for a higher level.
196  */
197 static int
198 ioqtobuf(ioq, buf, cc)
199 register struct ioqueue *ioq;
200 s_char *buf;
201 int cc;
202 {
203     register struct io *io;
204     struct qelem *qp;
205     s_char *offset;
206     int nbytes;
207     int nleft;
208
209     nleft = cc;
210     offset = buf;
211     for (qp = ioq->queue.q_forw; qp != &ioq->queue; qp = qp->q_forw) {
212         io = (struct io *)qp;
213         if ((nbytes = io->nbytes - io->offset) < 0) {
214             fprintf(stderr, "ioqtobuf: offset %d nbytes %d\n",
215                     io->offset, io->nbytes);
216             continue;
217         }
218         if (nbytes > 0) {
219             if (nleft < nbytes)
220                 nbytes = nleft;
221             memcpy(offset, io->data + io->offset, nbytes);
222             offset += nbytes;
223             nleft -= nbytes;
224         }
225     }
226     return offset - buf;
227 }
228
229 /*
230  * translate "around" max bytes to an iovec
231  * array.  The limit max is only advisory,
232  * and more may get buffered.  It is an attempt to limit
233  * really silly sends -- like sending 40k on a socket
234  * with one writev for example.  This makes the processing
235  * of a full ioqueue still be quick.
236  */
237 static int
238 ioqtoiov(ioq, iov, max)
239 register struct ioqueue *ioq;
240 register struct iovec *iov;
241 register int max;
242 {
243     register struct io *io;
244     register int cc;
245     register int niov;
246     struct qelem *qp;
247
248     cc = 0;
249     niov = 0;
250     qp = ioq->queue.q_forw;
251     for (qp = ioq->queue.q_forw; qp != &ioq->queue; qp = qp->q_forw) {
252         io = (struct io *)qp;
253         if (niov >= MAXIOV || cc >= max)
254             break;
255         iov->iov_base = io->data + io->offset;
256         iov->iov_len = io->nbytes - io->offset;
257         cc += io->nbytes - io->offset;
258         niov++;
259         iov++;
260     }
261     return niov;
262 }
263
264 /*
265  * append a buffer to the end of the ioq.
266  */
267 static void
268 enqueuecc(ioq, buf, cc)
269 struct ioqueue *ioq;
270 s_char *buf;
271 int cc;
272 {
273     struct io *io;
274
275     io = (struct io *)malloc(sizeof(*io));
276     io->nbytes = cc;
277     io->offset = 0;
278     io->data = buf;
279     insque(&io->queue, ioq->queue.q_back);
280     ioq->cc += cc;
281 }
282
283 /*
284  * remove cc bytes from ioqueue ioq
285  * free memory, dequeue io elements
286  * which are no longer used.
287  */
288 static int
289 dequeuecc(ioq, cc)
290 register struct ioqueue *ioq;
291 register int cc;
292 {
293     register struct io *io;
294     register struct qelem *qp;
295     register int nbytes;
296     register int there;
297
298     nbytes = 0;
299     while ((qp = ioq->queue.q_forw) != &ioq->queue) {
300         io = (struct io *)qp;
301         there = io->nbytes - io->offset;
302         if (there < 0) {
303             fprintf(stderr, "dequeuecc: nbytes %d, offset %d\n",
304                     io->nbytes, io->offset);
305             continue;
306         }
307         if (cc > there) {
308             cc -= there;
309             nbytes += there;
310             (void)remque(&io->queue);
311             free(io->data);
312         } else {
313             io->offset += cc;
314             nbytes += cc;
315             break;
316         }
317     }
318     ioq->cc -= nbytes;
319     return nbytes;
320 }