ArchWizard

DGD/

source navigation ]
diff markup ]
identifier search ]
file search ]
Version: [ 1.0.a0 ] [ 1.1 ] [ 1.2 ] [ 1.2p1 ] [ 1.2p2 ] [ 1.2p3 ] [ 1.2p4 ] [ 1.2.151 ]

  1 # define INCLUDE_TELNET
  2 # include "dgd.h"
  3 # include "str.h"
  4 # include "array.h"
  5 # include "object.h"
  6 # include "interpret.h"
  7 # include "data.h"
  8 # include "comm.h"
  9 # include "version.h"
 10 
 11 # ifndef TELOPT_LINEMODE
 12 # define TELOPT_LINEMODE        34      /* linemode option */
 13 # define LM_MODE                1
 14 # define MODE_EDIT              0x01
 15 # endif
 16 
 17 # define MAXIACSEQLEN           7       /* longest IAC sequence sent */
 18 
 19 typedef struct _user_ {
 20     uindex oindex;              /* associated object index */
 21     struct _user_ *prev;        /* preceding user */
 22     struct _user_ *next;        /* next user */
 23     struct _user_ *flush;       /* next in flush list */
 24     char flags;                 /* connection flags */
 25     char state;                 /* telnet state */
 26     short newlines;             /* # of newlines in input buffer */
 27     connection *conn;           /* connection */
 28     char *inbuf;                /* input buffer */
 29     array *extra;               /* object's extra value */
 30     string *outbuf;             /* output buffer string */
 31     ssizet inbufsz;             /* bytes in input buffer */
 32     ssizet osdone;              /* bytes of output string done */
 33 } user;
 34 
 35 /* flags */
 36 # define CF_BINARY      0x00    /* binary connection */
 37 # define  CF_UDP        0x02    /* receive UDP datagrams */
 38 # define  CF_UDPDATA    0x04    /* UDP data received */
 39 # define CF_TELNET      0x01    /* telnet connection */
 40 # define  CF_ECHO       0x02    /* client echoes input */
 41 # define  CF_GA         0x04    /* send GA after prompt */
 42 # define  CF_PROMPT     0x08    /* prompt in telnet output */
 43 # define CF_BLOCKED     0x10    /* input blocked */
 44 # define CF_FLUSH       0x20    /* in flush list */
 45 # define CF_OUTPUT      0x40    /* pending output */
 46 # define CF_ODONE       0x80    /* output done */
 47 
 48 /* state */
 49 # define TS_DATA        0
 50 # define TS_CRDATA      1
 51 # define TS_IAC         2
 52 # define TS_DO          3
 53 # define TS_DONT        4
 54 # define TS_WILL        5
 55 # define TS_WONT        6
 56 # define TS_SB          7
 57 # define TS_SE          8
 58 
 59 static user *users;             /* array of users */
 60 static user *lastuser;          /* last user checked */
 61 static user *freeuser;          /* linked list of free users */
 62 static user *flush;             /* flush list */
 63 static int maxusers;            /* max # of users */
 64 static int nusers;              /* # of users */
 65 static int odone;               /* # of users with output done */
 66 static long newlines;           /* # of newlines in all input buffers */
 67 static uindex this_user;        /* current user */
 68 static int ntport, nbport;      /* # telnet/binary ports */
 69 static int nexttport;           /* next telnet port to check */
 70 static int nextbport;           /* next binary port to check */
 71 static char ayt[20];            /* are you there? */
 72 
 73 /*
 74  * NAME:        comm->init()
 75  * DESCRIPTION: initialize communications
 76  */
 77 bool comm_init(n, thosts, bhosts, tports, bports, ntelnet, nbinary)
 78 int n, ntelnet, nbinary;
 79 char **thosts, **bhosts;
 80 unsigned short *tports, *bports;
 81 {
 82     register int i;
 83     register user *usr;
 84 
 85     users = ALLOC(user, maxusers = n);
 86     for (i = n, usr = users + i; i > 0; --i) {
 87         --usr;
 88         usr->oindex = OBJ_NONE;
 89         usr->next = usr + 1;
 90     }
 91     users[n - 1].next = (user *) NULL;
 92     freeuser = usr;
 93     lastuser = (user *) NULL;
 94     flush = (user *) NULL;
 95     nusers = odone = newlines = 0;
 96     this_user = OBJ_NONE;
 97 
 98     sprintf(ayt, "\15\12[%s]\15\12", VERSION);
 99 
100     nexttport = nextbport = 0;
101     return conn_init(n, thosts, bhosts, tports, bports, ntport = ntelnet,
102                      nbport = nbinary);
103 }
104 
105 /*
106  * NAME:        comm->finish()
107  * DESCRIPTION: terminate connections
108  */
109 void comm_finish()
110 {
111     conn_finish();
112 }
113 
114 /*
115  * NAME:        comm->listen()
116  * DESCRIPTION: start listening on telnet port and binary port
117  */
118 void comm_listen()
119 {
120     conn_listen();
121 }
122 
123 /*
124  * NAME:        addtoflush()
125  * DESCRIPTION: add a user to the flush list
126  */
127 static void addtoflush(usr, arr)
128 register user *usr;
129 register array *arr;
130 {
131     usr->flags |= CF_FLUSH;
132     usr->flush = flush;
133     flush = usr;
134     arr_ref(usr->extra = arr);
135 
136     /* remember initial buffer */
137     if (d_get_elts(arr)[1].type == T_STRING) {
138         str_ref(usr->outbuf = arr->elts[1].u.string);
139     }
140 }
141 
142 /*
143  * NAME:        comm->new()
144  * DESCRIPTION: accept a new connection
145  */
146 static user *comm_new(f, obj, conn, telnet)
147 frame *f;
148 object *obj;
149 connection *conn;
150 bool telnet;
151 {
152     static char init[] = { (char) IAC, (char) WONT, (char) TELOPT_ECHO,
153                            (char) IAC, (char) DO,   (char) TELOPT_LINEMODE };
154     register user *usr;
155     dataspace *data;
156     array *arr;
157     value val;
158 
159     if (obj->flags & O_SPECIAL) {
160         error("User object is already special purpose");
161     }
162     /* initialize dataspace before the object receives the user role */
163     if (!O_HASDATA(obj) &&
164         i_call(f, obj, (array *) NULL, (char *) NULL, 0, TRUE, 0)) {
165         i_del_value(f->sp++);
166     }
167 
168     usr = freeuser;
169     freeuser = usr->next;
170     if (lastuser != (user *) NULL) {
171         usr->prev = lastuser->prev;
172         usr->prev->next = usr;
173         usr->next = lastuser;
174         lastuser->prev = usr;
175     } else {
176         usr->prev = usr;
177         usr->next = usr;
178         lastuser = usr;
179     }
180 
181     d_wipe_extravar(data = o_dataspace(obj));
182     arr = arr_new(data, 3L);
183     arr->elts[0] = zero_int;
184     arr->elts[1] = arr->elts[2] = nil_value;
185     PUT_ARRVAL_NOREF(&val, arr);
186     d_set_extravar(data, &val);
187 
188     usr->oindex = obj->index;
189     obj->flags |= O_USER;
190     obj->etabi = usr - users;
191     usr->conn = conn;
192     usr->outbuf = (string *) NULL;
193     usr->osdone = 0;
194     if (telnet) {
195         /* initialize connection */
196         usr->flags = CF_TELNET | CF_ECHO | CF_OUTPUT;
197         usr->state = TS_DATA;
198         usr->newlines = 0;
199         usr->inbufsz = 0;
200         m_static();
201         usr->inbuf = ALLOC(char, INBUF_SIZE + 1);
202         *usr->inbuf++ = LF;     /* sentinel */
203         m_dynamic();
204         addtoflush(usr, arr);
205 
206         arr->elts[0].u.number = CF_ECHO;
207         PUT_STRVAL_NOREF(&val, str_new(init, (long) sizeof(init)));
208         d_assign_elt(data, arr, &arr->elts[1], &val);
209     } else {
210         usr->flags = 0;
211     }
212     nusers++;
213 
214     return usr;
215 }
216 
217 /*
218  * NAME:        comm->del()
219  * DESCRIPTION: delete a connection
220  */
221 static void comm_del(f, usr, obj, destruct)
222 register frame *f;
223 register user *usr;
224 object *obj;
225 bool destruct;
226 {
227     dataspace *data;
228     uindex olduser;
229 
230     data = o_dataspace(obj);
231     if (!destruct) {
232         /* if not destructing, make sure the connection terminates */
233         if (!(usr->flags & CF_FLUSH)) {
234             addtoflush(usr, d_get_extravar(data)->u.array);
235         }
236         obj->flags &= ~O_USER;
237     }
238     olduser = this_user;
239     if (ec_push((ec_ftn) NULL)) {
240         this_user = olduser;
241         error((char *) NULL);
242     } else {
243         this_user = obj->index;
244         PUSH_INTVAL(f, destruct);
245         if (i_call(f, obj, (array *) NULL, "close", 5, TRUE, 1)) {
246             i_del_value(f->sp++);
247         }
248         this_user = olduser;
249         ec_pop();
250     }
251     if (destruct) {
252         /* if destructing, don't disconnect if there's an error in close() */
253         if (!(usr->flags & CF_FLUSH)) {
254             addtoflush(usr, d_get_extravar(data)->u.array);
255         }
256         obj->flags &= ~O_USER;
257     }
258 }
259 
260 /*
261  * NAME:        comm->challenge()
262  * DESCRIPTION: set the UDP challenge for a binary connection
263  */
264 void comm_challenge(obj, str)
265 object *obj;
266 string *str;
267 {
268     register user *usr;
269     dataspace *data;
270     array *arr;
271     register value *v;
272     value val;
273 
274     usr = &users[obj->etabi];
275     if (usr->flags & CF_TELNET) {
276         error("Datagram channel cannot be attached to telnet connection");
277     }
278     arr = d_get_extravar(data = obj->data)->u.array;
279     if (!(usr->flags & CF_FLUSH)) {
280         addtoflush(usr, arr);
281     }
282 
283     v = arr->elts + 2;
284     if ((usr->flags & CF_UDP) || v->type == T_STRING) {
285         error("Datagram challenge already set");
286     }
287     usr->flags |= CF_OUTPUT;
288     PUT_STRVAL_NOREF(&val, str);
289     d_assign_elt(data, arr, v, &val);
290 }
291 
292 /*
293  * NAME:        comm->write()
294  * DESCRIPTION: add bytes to output buffer
295  */
296 static int comm_write(usr, obj, str, text, len)
297 register user *usr;
298 object *obj;
299 register string *str;
300 char *text;
301 unsigned int len;
302 {
303     dataspace *data;
304     array *arr;
305     register value *v;
306     register ssizet osdone, olen;
307     value val;
308 
309     arr = d_get_extravar(data = o_dataspace(obj))->u.array;
310     if (!(usr->flags & CF_FLUSH)) {
311         addtoflush(usr, arr);
312     }
313 
314     v = arr->elts + 1;
315     if (v->type == T_STRING) {
316         /* append to existing buffer */
317         osdone = (usr->outbuf == v->u.string) ? usr->osdone : 0;
318         olen = v->u.string->len - osdone;
319         if (olen + len > MAX_STRLEN) {
320             len = MAX_STRLEN - olen;
321             if (len == 0 ||
322                 ((usr->flags & CF_TELNET) && text[0] == (char) IAC &&
323                  len < MAXIACSEQLEN)) {
324                 return 0;
325             }
326         }
327         str = str_new((char *) NULL, (long) olen + len);
328         memcpy(str->text, v->u.string->text + osdone, olen);
329         memcpy(str->text + olen, text, len);
330     } else {
331         /* create new buffer */
332         if (usr->flags & CF_ODONE) {
333             usr->flags &= ~CF_ODONE;
334             --odone;
335         }
336         usr->flags |= CF_OUTPUT;
337         if (str == (string *) NULL) {
338             str = str_new(text, (long) len);
339         }
340     }
341 
342     PUT_STRVAL_NOREF(&val, str);
343     d_assign_elt(data, arr, v, &val);
344     return len;
345 }
346 
347 /*
348  * NAME:        comm->send()
349  * DESCRIPTION: send a message to a user
350  */
351 int comm_send(obj, str)
352 object *obj;
353 string *str;
354 {
355     register user *usr;
356 
357     usr = &users[EINDEX(obj->etabi)];
358     if (usr->flags & CF_TELNET) {
359         char outbuf[OUTBUF_SIZE];
360         register char *p, *q;
361         register unsigned int len, size, n, length;
362 
363         /*
364          * telnet connection
365          */
366         p = str->text;
367         len = str->len;
368         q = outbuf;
369         size = 0;
370         length = 0;
371         for (;;) {
372             if (len == 0 || size >= OUTBUF_SIZE - 1 || UCHAR(*p) == IAC) {
373                 n = comm_write(usr, obj, (string *) NULL, outbuf, size);
374                 if (n != size) {
375                     /*
376                      * count how many bytes of original string were written
377                      */
378                     for (n = size - n; n != 0; --n) {
379                         if (*--p == *--q) {
380                             len++;
381                             if (UCHAR(*p) == IAC) {
382                                 break;
383                             }
384                         } else if (*q == CR) {
385                             /* inserted CR */
386                             p++;
387                         } else {
388                             /* skipped char */
389                             q++;
390                             len++;
391                         }
392                     }
393                     return str->len - len;
394                 }
395                 if (len == 0) {
396                     return str->len;
397                 }
398                 size = 0;
399                 q = outbuf;
400             }
401             if (UCHAR(*p) == IAC) {
402                 /*
403                  * double the telnet IAC character
404                  */
405                 *q++ = (char) IAC;
406                 size++;
407             } else if (*p == LF) {
408                 /*
409                  * insert CR before LF
410                  */
411                 *q++ = CR;
412                 size++;
413             } else if ((*p & 0x7f) < ' ' && *p != HT && *p != BEL && *p != BS) {
414                 /*
415                  * illegal character
416                  */
417                 p++;
418                 --len;
419                 continue;
420             }
421             *q++ = *p++;
422             --len;
423             size++;
424         }
425     } else {
426         /*
427          * binary connection
428          */
429         return comm_write(usr, obj, str, str->text, str->len);
430     }
431 }
432 
433 /*
434  * NAME:        comm->udpsend()
435  * DESCRIPTION: send a message on the UDP channel of a binary connection
436  */
437 int comm_udpsend(obj, str)
438 object *obj;
439 string *str;
440 {
441     register user *usr;
442     dataspace *data;
443     array *arr;
444     register value *v;
445     value val;
446 
447     usr = &users[EINDEX(obj->etabi)];
448     if ((usr->flags & (CF_TELNET | CF_UDP)) != CF_UDP) {
449         error("Object has no datagram channel");
450     }
451     if (!(usr->flags & CF_UDPDATA)) {
452         error("No response to datagram challenge received yet");
453     }
454 
455     arr = d_get_extravar(data = obj->data)->u.array;
456     if (!(usr->flags & CF_FLUSH)) {
457         addtoflush(usr, arr);
458     }
459 
460     v = arr->elts + 2;
461     if (v->type == T_STRING) {
462         return 0;       /* datagram queued already */
463     }
464     usr->flags |= CF_OUTPUT;
465     PUT_STRVAL_NOREF(&val, str);
466     d_assign_elt(data, arr, v, &val);
467 
468     return str->len;
469 }
470 
471 /*
472  * NAME:        comm->echo()
473  * DESCRIPTION: turn on/off input echoing for a user
474  */
475 bool comm_echo(obj, echo)
476 object *obj;
477 int echo;
478 {
479     register user *usr;
480     register dataspace *data;
481     array *arr;
482     register value *v;
483 
484     usr = &users[EINDEX(obj->etabi)];
485     if (usr->flags & CF_TELNET) {
486         arr = d_get_extravar(data = obj->data)->u.array;
487         v = d_get_elts(arr);
488         if (echo != (v->u.number & CF_ECHO) >> 1) {
489             value val;
490 
491             if (!(usr->flags & CF_FLUSH)) {
492                 addtoflush(usr, arr);
493             }
494             val = *v;
495             val.u.number ^= CF_ECHO;
496             d_assign_elt(data, arr, v, &val);
497         }
498         return TRUE;
499     }
500     return FALSE;
501 }
502 
503 /*
504  * NAME:        comm->block()
505  * DESCRIPTION: suspend or release input from a user
506  */
507 void comm_block(obj, block)
508 object *obj;
509 int block;
510 {
511     register user *usr;
512     register dataspace *data;
513     array *arr;
514     register value *v;
515 
516     usr = &users[EINDEX(obj->etabi)];
517     arr = d_get_extravar(data = obj->data)->u.array;
518     v = d_get_elts(arr);
519     if (block != (v->u.number & CF_BLOCKED) >> 4) {
520         value val;
521 
522         if (!(usr->flags & CF_FLUSH)) {
523             addtoflush(usr, arr);
524         }
525         val = *v;
526         val.u.number ^= CF_BLOCKED;
527         d_assign_elt(data, arr, v, &val);
528     }
529 }
530 
531 /*
532  * NAME:        comm->uflush()
533  * DESCRIPTION: flush output buffers for a single user only
534  */
535 static void comm_uflush(usr, obj, data, arr)
536 register user *usr;
537 object *obj;
538 register dataspace *data;
539 array *arr;
540 {
541     register value *v;
542     register int n;
543 
544     v = d_get_elts(arr);
545 
546     if (v[1].type == T_STRING) {
547         if (conn_wrdone(usr->conn)) {
548             n = conn_write(usr->conn, v[1].u.string->text + usr->osdone,
549                            v[1].u.string->len - usr->osdone);
550             if (n >= 0) {
551                 n += usr->osdone;
552                 if (n == v[1].u.string->len) {
553                     /* buffer fully drained */
554                     n = 0;
555                     usr->flags &= ~CF_OUTPUT;
556                     usr->flags |= CF_ODONE;
557                     odone++;
558                     d_assign_elt(data, arr, &v[1], &nil_value);
559                 }
560                 usr->osdone = n;
561             } else {
562                 /* wait for conn_read() to discover the problem */
563                 usr->flags &= ~CF_OUTPUT;
564             }
565         }
566     } else {
567         /* just a datagram */
568         usr->flags &= ~CF_OUTPUT;
569     }
570 
571     if (v[2].type == T_STRING) {
572         if (usr->flags & CF_UDP) {
573             conn_udpwrite(usr->conn, v[2].u.string->text, v[2].u.string->len);
574         } else if (conn_udp(usr->conn, v[2].u.string->text, v[2].u.string->len))
575         {
576             usr->flags |= CF_UDP;
577         }
578         d_assign_elt(data, arr, &v[2], &nil_value);
579     }
580 }
581 
582 /*
583  * NAME:        comm->flush()
584  * DESCRIPTION: flush state, output and connections
585  */
586 void comm_flush()
587 {
588     register user *usr;
589     object *obj;
590     array *arr;
591     register value *v;
592 
593     while (flush != (user *) NULL) {
594         usr = flush;
595         flush = usr->flush;
596 
597         /*
598          * status change
599          */
600         obj = OBJ(usr->oindex);
601         arr = usr->extra;
602         v = arr->elts;
603         if (usr->flags & CF_TELNET) {
604             if ((v->u.number ^ usr->flags) & CF_ECHO) {
605                 char buf[3];
606 
607                 /* change echo */
608                 buf[0] = (char) IAC;
609                 buf[1] = (v->u.number & CF_ECHO) ? WONT : WILL;
610                 buf[2] = TELOPT_ECHO;
611                 if (comm_write(usr, obj, (string *) NULL, buf, 3) != 0) {
612                     usr->flags ^= CF_ECHO;
613                 }
614             }
615             if (usr->flags & CF_PROMPT) {
616                 usr->flags &= ~CF_PROMPT;
617                 if ((usr->flags & CF_GA) && v[1].type == T_STRING &&
618                     usr->outbuf != v[1].u.string) {
619                     static char ga[] = { (char) IAC, (char) GA };
620 
621                     /* append go-ahead */
622                     comm_write(usr, obj, (string *) NULL, ga, 2);
623                 }
624             }
625         }
626         if ((v->u.number ^ usr->flags) & CF_BLOCKED) {
627             usr->flags ^= CF_BLOCKED;
628             conn_block(usr->conn, ((usr->flags & CF_BLOCKED) != 0));
629         }
630 
631         /*
632          * write
633          */
634         if (usr->outbuf != (string *) NULL) {
635             if (usr->outbuf != v[1].u.string) {
636                 usr->osdone = 0;        /* new mesg before buffer drained */
637             }
638             str_del(usr->outbuf);
639             usr->outbuf = (string *) NULL;
640         }
641         if (usr->flags & CF_OUTPUT) {
642             comm_uflush(usr, obj, obj->data, arr);
643         }
644 
645         /*
646          * disconnect
647          */
648         if ((obj->flags & O_SPECIAL) != O_USER) {
649             d_wipe_extravar(obj->data);
650             conn_del(usr->conn);
651             if (usr->flags & CF_TELNET) {
652                 newlines -= usr->newlines;
653                 FREE(usr->inbuf - 1);
654             }
655             if (usr->flags & CF_ODONE) {
656                 --odone;
657             }
658 
659             usr->oindex = OBJ_NONE;
660             if (usr->next == usr) {
661                 lastuser = (user *) NULL;
662             } else {
663                 usr->next->prev = usr->prev;
664                 usr->prev->next = usr->next;
665                 if (usr == lastuser) {
666                     lastuser = usr->next;
667                 }
668             }
669             usr->next = freeuser;
670             freeuser = usr;
671             --nusers;
672         }
673 
674         arr_del(arr);
675         usr->flags &= ~CF_FLUSH;
676     }
677 }
678 
679 /*
680  * NAME:        comm->taccept()
681  * DESCRIPTION: accept a telnet connection
682  */
683 static void comm_taccept(f, conn, port)
684 register frame *f;
685 struct _connection_ *conn;
686 int port;
687 {
688     user *usr;
689     object *obj;
690 
691     if (ec_push((ec_ftn) NULL)) {
692         conn_del(conn);         /* delete connection */
693         error((char *) NULL);   /* pass on error */
694     }
695     PUSH_INTVAL(f, port);
696     call_driver_object(f, "telnet_connect", 1);
697     if (f->sp->type != T_OBJECT) {
698         fatal("driver->telnet_connect() did not return persistent object");
699     }
700     obj = OBJ(f->sp->oindex);
701     f->sp++;
702     usr = comm_new(f, obj, conn, TRUE);
703     ec_pop();
704     endthread();
705 
706     usr->flags |= CF_PROMPT;
707     addtoflush(usr, d_get_extravar(o_dataspace(obj))->u.array);
708     this_user = obj->index;
709     if (i_call(f, obj, (array *) NULL, "open", 4, TRUE, 0)) {
710         i_del_value(f->sp++);
711         endthread();
712     }
713     this_user = OBJ_NONE;
714 }
715 
716 /*
717  * NAME:        comm->baccept()
718  * DESCRIPTION: accept a binary connection
719  */
720 static void comm_baccept(f, conn, port)
721 register frame *f;
722 struct _connection_ *conn;
723 int port;
724 {
725     user *usr;
726     object *obj;
727 
728     if (ec_push((ec_ftn) NULL)) {
729         conn_del(conn);         /* delete connection */
730         error((char *) NULL);   /* pass on error */
731     }
732     PUSH_INTVAL(f, port);
733     call_driver_object(f, "binary_connect", 1);
734     if (f->sp->type != T_OBJECT) {
735         fatal("driver->binary_connect() did not return persistent object");
736     }
737     obj = OBJ(f->sp->oindex);
738     f->sp++;
739     usr = comm_new(f, obj, conn, FALSE);
740     ec_pop();
741     endthread();
742 
743     this_user = obj->index;
744     if (i_call(f, obj, (array *) NULL, "open", 4, TRUE, 0)) {
745         i_del_value(f->sp++);
746         endthread();
747     }
748     this_user = OBJ_NONE;
749 }
750 
751 /*
752  * NAME:        comm->receive()
753  * DESCRIPTION: receive a message from a user
754  */
755 void comm_receive(f, timeout, mtime)
756 register frame *f;
757 Uint timeout;
758 unsigned int mtime;
759 {
760     static char intr[] =        { '\177' };
761     static char brk[] =         { '\034' };
762     static char tm[] =          { (char) IAC, (char) WONT, (char) TELOPT_TM };
763     static char will_sga[] =    { (char) IAC, (char) WILL, (char) TELOPT_SGA };
764     static char wont_sga[] =    { (char) IAC, (char) WONT, (char) TELOPT_SGA };
765     static char mode_edit[] =   { (char) IAC, (char) SB,
766                                   (char) TELOPT_LINEMODE, (char) LM_MODE,
767                                   (char) MODE_EDIT, (char) IAC, (char) SE };
768     char buffer[BINBUF_SIZE];
769     connection *conn;
770     object *obj;
771     register user *usr;
772     register int n, i, state, nls;
773     register char *p, *q;
774 
775     if (newlines != 0 || odone != 0) {
776         timeout = mtime = 0;
777     }
778     n = conn_select(timeout, mtime);
779     if (n <= 0 && newlines == 0 && odone == 0) {
780         /*
781          * call_out to do, or timeout
782          */
783         return;
784     }
785 
786     if (ec_push(errhandler)) {
787         endthread();
788         this_user = OBJ_NONE;
789         return;
790     }
791 
792     if (ntport != 0 &&nusers < maxusers) {
793         n = nexttport;
794         do {
795             /*
796              * accept new telnet connection
797              */
798             conn = conn_tnew6(n);
799             if (conn != (connection *) NULL) {
800                 comm_taccept(f, conn, n);
801                 nexttport = (n + 1) % ntport;
802             }
803             if (nusers < maxusers) {
804                 conn = conn_tnew(n);
805                 if (conn != (connection *) NULL) {
806                     comm_taccept(f, conn, n);
807                     nexttport = (n + 1) % ntport;
808                 }
809             }
810 
811             n = (n + 1) % ntport;
812         } while (n != nexttport);
813     }
814 
815     if (nbport != 0 && nusers < maxusers) {
816         n = nextbport;
817         do {
818             /*
819              * accept new binary connection
820              */
821             conn = conn_bnew6(n);
822             if (conn != (connection *) NULL) {
823                 comm_baccept(f, conn, n);
824             }
825             if (nusers < maxusers) {
826                 conn = conn_bnew(n);
827                 if (conn != (connection *) NULL) {
828                     comm_baccept(f, conn, n);
829                 }
830             }
831             n = (n + 1) % nbport;
832             if (nusers == maxusers) {
833                 nextbport = n;
834                 break;
835             }
836         } while (n != nextbport);
837     }
838 
839     for (i = nusers; i > 0; --i) {
840         usr = lastuser;
841         lastuser = usr->next;
842 
843         obj = OBJ(usr->oindex);
844         if (usr->flags & CF_OUTPUT) {
845             dataspace *data;
846 
847             data = o_dataspace(obj);
848             comm_uflush(usr, obj, data, d_get_extravar(data)->u.array);
849         }
850         if (usr->flags & CF_ODONE) {
851             /* callback */
852             usr->flags &= ~CF_ODONE;
853             --odone;
854             this_user = obj->index;
855             if (i_call(f, obj, (array *) NULL, "message_done", 12, TRUE, 0)) {
856                 i_del_value(f->sp++);
857                 endthread();
858             }
859             this_user = OBJ_NONE;
860             if (obj->count == 0) {
861                 break;  /* continue, unless the connection was closed */
862             }
863         }
864 
865         if (usr->flags & CF_BLOCKED) {
866             continue;   /* no input on this connection */
867         }
868 
869         if (usr->flags & CF_TELNET) {
870             /*
871              * telnet connection
872              */
873             if (usr->inbufsz != INBUF_SIZE) {
874                 p = usr->inbuf + usr->inbufsz;
875                 n = conn_read(usr->conn, p, INBUF_SIZE - usr->inbufsz);
876                 if (n < 0) {
877                     if (usr->inbufsz != 0) {
878                         if (p[-1] != LF) {
879                             /*
880                              * add a newline at the end
881                              */
882                             *p = LF;
883                             n = 1;
884                         }
885                     } else if (!(usr->flags & CF_OUTPUT)) {
886                         /*
887                          * empty buffer, no more input, no pending output
888                          */
889                         comm_del(f, usr, obj, FALSE);
890                         endthread();    /* this cannot be in comm_del() */
891                         break;
892                     }
893                 }
894 
895                 state = usr->state;
896                 nls = usr->newlines;
897                 q = p;
898                 while (n > 0) {
899                     switch (state) {
900                     case TS_DATA:
901                         switch (UCHAR(*p)) {
902                         case IAC:
903                             state = TS_IAC;
904                             break;
905 
906                         case BS:
907                         case 0x7f:
908                             if (q[-1] != LF) {
909                                 --q;
910                             }
911                             break;
912 
913                         case CR:
914                             nls++;
915                             newlines++;
916                             *q++ = LF;
917                             state = TS_CRDATA;
918                             break;
919 
920                         case LF:
921                             nls++;
922                             newlines++;
923                             /* fall through */
924                         default:
925                             *q++ = *p;
926                             /* fall through */
927                         case '\0':
928                             break;
929                         }
930                         break;
931 
932                     case TS_CRDATA:
933                         switch (UCHAR(*p)) {
934                         case IAC:
935                             state = TS_IAC;
936                             break;
937 
938                         case CR:
939                             nls++;
940                             newlines++;
941                             *q++ = LF;
942                             break;
943 
944                         default:
945                             *q++ = *p;
946                             /* fall through */
947                         case '\0':
948                         case LF:
949                         case BS:
950                         case 0x7f:
951                             state = TS_DATA;
952                             break;
953                         }
954                         break;
955 
956                     case TS_IAC:
957                         switch (UCHAR(*p)) {
958                         case IAC:
959                             *q++ = *p;
960                             state = TS_DATA;
961                             break;
962 
963                         case DO:
964                             state = TS_DO;
965                             break;
966 
967                         case DONT:
968                             state = TS_DONT;
969                             break;
970 
971                         case WILL:
972                             state = TS_WILL;
973                             break;
974 
975                         case WONT:
976                             state = TS_WONT;
977                             break;
978 
979                         case SB:
980                             state = TS_SB;
981                             break;
982 
983                         case IP:
984                             comm_write(usr, obj, (string *) NULL, intr,
985                                        sizeof(intr));
986                             state = TS_DATA;
987                             break;
988 
989                         case BREAK:
990                             comm_write(usr, obj, (string *) NULL, brk,
991                                        sizeof(brk));
992                             state = TS_DATA;
993                             break;
994 
995                         case AYT:
996                             comm_write(usr, obj, (string *) NULL, ayt,
997                                        strlen(ayt));
998                             state = TS_DATA;
999                             break;
1000 
1001                         default:
1002                             /* let's hope it wasn't important */
1003                             state = TS_DATA;
1004                             break;
1005                         }
1006                         break;
1007 
1008                     case TS_DO:
1009                         if (UCHAR(*p) == TELOPT_TM) {
1010                             comm_write(usr, obj, (string *) NULL, tm,
1011                                        sizeof(tm));
1012                         } else if (UCHAR(*p) == TELOPT_SGA) {
1013                             usr->flags &= ~CF_GA;
1014                             comm_write(usr, obj, (string *) NULL, will_sga,
1015                                        sizeof(will_sga));
1016                         }
1017                         state = TS_DATA;
1018                         break;
1019 
1020                     case TS_DONT:
1021                         if (UCHAR(*p) == TELOPT_SGA) {
1022                             usr->flags |= CF_GA;
1023                             comm_write(usr, obj, (string *) NULL, wont_sga,
1024                                        sizeof(wont_sga));
1025                         }
1026                         state = TS_DATA;
1027                         break;
1028 
1029                     case TS_WILL:
1030                         if (UCHAR(*p) == TELOPT_LINEMODE) {
1031                             /* linemode confirmed; now request editing */
1032                             comm_write(usr, obj, (string *) NULL, mode_edit,
1033                                        sizeof(mode_edit));
1034                         }
1035                         /* fall through */
1036                     case TS_WONT:
1037                         state = TS_DATA;
1038                         break;
1039 
1040                     case TS_SB:
1041                         /* skip to the end */
1042                         if (UCHAR(*p) == IAC) {
1043                             state = TS_SE;
1044                         }
1045                         break;
1046 
1047                     case TS_SE:
1048                         if (UCHAR(*p) == SE) {
1049                             /* end of subnegotiation */
1050                             state = TS_DATA;
1051                         } else {
1052                             state = TS_SB;
1053                         }
1054                         break;
1055                     }
1056                     p++;
1057                     --n;
1058                 }
1059                 usr->state = state;
1060                 usr->newlines = nls;
1061                 usr->inbufsz = q - usr->inbuf;
1062                 if (nls == 0) {
1063                     continue;
1064                 }
1065 
1066                 /*
1067                  * input terminated by \n
1068                  */
1069                 p = (char *) memchr(q = usr->inbuf, LF, usr->inbufsz);
1070                 usr->newlines--;
1071                 --newlines;
1072                 n = p - usr->inbuf;
1073                 p++;                    /* skip \n */
1074                 usr->inbufsz -= n + 1;
1075 
1076                 PUSH_STRVAL(f, str_new(usr->inbuf, (long) n));
1077                 for (n = usr->inbufsz; n != 0; --n) {
1078                     *q++ = *p++;
1079                 }
1080             } else {
1081                 /*
1082                  * input buffer full
1083                  */
1084                 n = usr->inbufsz;
1085                 usr->inbufsz = 0;
1086                 PUSH_STRVAL(f, str_new(usr->inbuf, (long) n));
1087             }
1088             usr->flags |= CF_PROMPT;
1089             if (!(usr->flags & CF_FLUSH)) {
1090                 addtoflush(usr, d_get_extravar(o_dataspace(obj))->u.array);
1091             }
1092         } else {
1093             /*
1094              * binary connection
1095              */
1096             if (usr->flags & CF_UDP) {
1097                 if (usr->flags & CF_UDPDATA) {
1098                     n = conn_udpread(usr->conn, buffer, BINBUF_SIZE);
1099                     if (n >= 0) {
1100                         /*
1101                          * received datagram
1102                          */
1103                         PUSH_STRVAL(f, str_new(buffer, (long) n));
1104                         this_user = obj->index;
1105                         if (i_call(f, obj, (array *) NULL, "receive_datagram",
1106                                    16, TRUE, 1)) {
1107                             i_del_value(f->sp++);
1108                             endthread();
1109                         }
1110                         this_user = OBJ_NONE;
1111                     }
1112                 } else if (conn_udpcheck(usr->conn)) {
1113                     usr->flags |= CF_UDPDATA;
1114                     this_user = obj->index;
1115                     if (i_call(f, obj, (array *) NULL, "open_datagram", 13,
1116                                TRUE, 0)) {
1117                         i_del_value(f->sp++);
1118                         endthread();
1119                     }
1120                     this_user = OBJ_NONE;
1121                 }
1122             }
1123 
1124             n = conn_read(usr->conn, p = buffer, BINBUF_SIZE);
1125             if (n <= 0) {
1126                 if (n < 0 && !(usr->flags & CF_OUTPUT)) {
1127                     /*
1128                      * no more input and no pending output
1129                      */
1130                     comm_del(f, usr, obj, FALSE);
1131                     endthread();        /* this cannot be in comm_del() */
1132                     break;
1133                 }
1134                 continue;
1135             }
1136 
1137             PUSH_STRVAL(f, str_new(buffer, (long) n));
1138         }
1139 
1140         this_user = obj->index;
1141         if (i_call(f, obj, (array *) NULL, "receive_message", 15, TRUE, 1)) {
1142             i_del_value(f->sp++);
1143             endthread();
1144         }
1145         this_user = OBJ_NONE;
1146         break;
1147     }
1148 
1149     ec_pop();
1150     comm_flush();
1151 }
1152 
1153 /*
1154  * NAME:        comm->ip_number()
1155  * DESCRIPTION: return the ip number of a user (as a string)
1156  */
1157 string *comm_ip_number(obj)
1158 object *obj;
1159 {
1160     char ipnum[40];
1161 
1162     conn_ipnum(users[EINDEX(obj->etabi)].conn, ipnum);
1163     return str_new(ipnum, (long) strlen(ipnum));
1164 }
1165 
1166 /*
1167  * NAME:        comm->ip_name()
1168  * DESCRIPTION: return the ip name of a user
1169  */
1170 string *comm_ip_name(obj)
1171 object *obj;
1172 {
1173     char ipname[1024];
1174 
1175     conn_ipname(users[EINDEX(obj->etabi)].conn, ipname);
1176     return str_new(ipname, (long) strlen(ipname));
1177 }
1178 
1179 /*
1180  * NAME:        comm->close()
1181  * DESCRIPTION: remove a user
1182  */
1183 void comm_close(f, obj)
1184 frame *f;
1185 object *obj;
1186 {
1187     comm_del(f, &users[EINDEX(obj->etabi)], obj, TRUE);
1188 }
1189 
1190 /*
1191  * NAME:        comm->user()
1192  * DESCRIPTION: return the current user
1193  */
1194 object *comm_user()
1195 {
1196     object *obj;
1197 
1198     return (this_user != OBJ_NONE && (obj=OBJR(this_user))->count != 0) ?
1199             obj : (object *) NULL;
1200 }
1201 
1202 /*
1203  * NAME:        comm->users()
1204  * DESCRIPTION: return an array with all user objects
1205  */
1206 array *comm_users(data)
1207 dataspace *data;
1208 {
1209     array *a;
1210     register int i, n;
1211     register user *usr;
1212     register value *v;
1213     register object *obj;
1214 
1215     n = 0;
1216     for (i = nusers, usr = users; i > 0; usr++) {
1217         if (usr->oindex != OBJ_NONE) {
1218             --i;
1219             if (OBJR(usr->oindex)->count != 0) {
1220                 n++;
1221             }
1222         }
1223     }
1224 
1225     a = arr_new(data, (long) n);
1226     v = a->elts;
1227     for (usr = users; n > 0; usr++) {
1228         if (usr->oindex != OBJ_NONE && (obj=OBJR(usr->oindex))->count != 0) {
1229             PUT_OBJVAL(v, obj);
1230             v++;
1231             --n;
1232         }
1233     }
1234     return a;
1235 }
1236 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.