diff -cr dgd/src/comm.c dgd-patched/src/comm.c *** dgd/src/comm.c Sat Aug 12 19:00:38 1995 --- dgd-patched/src/comm.c Sun Sep 3 15:55:45 1995 *************** *** 20,31 **** } u; int inbufsz; /* bytes in input buffer */ int outbufsz; /* bytes in output buffer */ char flags; /* connection flags */ char state; /* telnet state */ - short newlines; /* # of newlines in input buffer */ connection *conn; /* connection */ ! char inbuf[INBUF_SIZE]; /* input buffer */ ! char outbuf[OUTBUF_SIZE]; /* output buffer */ } user; /* flags */ --- 20,31 ---- } u; int inbufsz; /* bytes in input buffer */ int outbufsz; /* bytes in output buffer */ + int newlines; /* # of newlines in input buffer */ char flags; /* connection flags */ char state; /* telnet state */ connection *conn; /* connection */ ! char *inbuf; /* input buffer */ ! char *outbuf; /* output buffer */ } user; /* flags */ *************** *** 33,38 **** --- 33,41 ---- # define CF_TELNET 0x02 /* telnet connection */ # define CF_GA 0x04 /* send GA after prompt */ # define CF_SEENCR 0x08 /* just seen a CR */ + # define CF_PORT 0x10 /* port connection */ + # define CF_DATAGRAM 0x20 /* datagram connection */ + # define CF_CONNECTING 0x40 /* connection being initiated */ /* state */ # define TS_DATA 0 *************** *** 48,69 **** static int maxusers; /* max # of users */ static int nusers; /* # of users */ static int newlines; /* # of newlines in all input buffers */ - static long binchars; /* # characters in binary buffers */ static object *this_user; /* current user */ /* * NAME: comm->init() * DESCRIPTION: initialize communications */ ! void comm_init(nusers, telnet_port, binary_port) ! int nusers, telnet_port, binary_port; { register int i; register user **usr; ! conn_init(nusers, telnet_port, binary_port); ! users = ALLOC(user*, maxusers = nusers); ! for (i = nusers, usr = users; i > 0; --i, usr++) { *usr = (user *) NULL; } } --- 51,71 ---- static int maxusers; /* max # of users */ static int nusers; /* # of users */ static int newlines; /* # of newlines in all input buffers */ static object *this_user; /* current user */ /* * NAME: comm->init() * DESCRIPTION: initialize communications */ ! void comm_init(cf_users) ! int cf_users; { register int i; register user **usr; ! conn_init(cf_users); ! users = ALLOC(user*, maxusers = cf_users); ! for (i = cf_users, usr = users; i > 0; --i, usr++) { *usr = (user *) NULL; } } *************** *** 80,119 **** /* * NAME: comm->new() ! * DESCRIPTION: accept a new connection */ ! static void comm_new(obj, conn, telnet) object *obj; connection *conn; ! bool telnet; { ! static char init[] = { IAC, WONT, TELOPT_ECHO, IAC, DO, TELOPT_LINEMODE }; register user **usr; if (obj->flags & (O_USER | O_EDITOR)) { ! error("user object is already used for user or editor"); } for (usr = users; *usr != (user *) NULL; usr++) ; mstatic(); ! *usr = ALLOC(user, 1); mdynamic(); (*usr)->u.obj = obj; obj->flags |= O_USER; obj->etabi = usr - users; (*usr)->inbufsz = 0; (*usr)->outbufsz = 0; (*usr)->conn = conn; ! if (telnet) { ! /* initialize connection */ ! conn_write(conn, init, sizeof(init)); ! (*usr)->flags = CF_TELNET | CF_ECHO; (*usr)->state = TS_DATA; ! (*usr)->newlines = 0; } else { ! (*usr)->flags = 0; } nusers++; - this_user = obj; } /* --- 82,142 ---- /* * NAME: comm->new() ! * DESCRIPTION: allocate and init a new user struct (assumes nusers < maxusers) */ ! static void comm_new(obj, conn, flags) object *obj; connection *conn; ! int flags; { ! static char give_lm[] = { IAC, DO, TELOPT_LINEMODE }; ! static char echo_on[] = { IAC, WONT, TELOPT_ECHO }; ! register user **usr; + register int size; if (obj->flags & (O_USER | O_EDITOR)) { ! error("User object is already used for user or editor"); ! } ! ! if (flags & CF_PORT) { ! size = sizeof(user); ! } else if (flags & CF_TELNET) { ! size = sizeof(user) + INBUF_SIZE + OUTBUF_SIZE; ! } else { ! size = sizeof(user) + OUTBUF_SIZE; } + for (usr = users; *usr != (user *) NULL; usr++) ; mstatic(); ! *usr = (user *)ALLOC(char, size); mdynamic(); (*usr)->u.obj = obj; obj->flags |= O_USER; obj->etabi = usr - users; (*usr)->inbufsz = 0; (*usr)->outbufsz = 0; + (*usr)->newlines = 0; (*usr)->conn = conn; ! (*usr)->flags = flags; ! if (flags & CF_PORT) { ! (*usr)->inbuf = (char *) NULL; ! (*usr)->outbuf = (char *) NULL; ! } else if (flags & CF_TELNET) { ! (*usr)->inbuf = (char *) *usr + sizeof(user); ! (*usr)->outbuf = (*usr)->inbuf + INBUF_SIZE; (*usr)->state = TS_DATA; ! if (!(flags & CF_CONNECTING)) { ! if (flags & CF_ECHO) { ! conn_write(conn, echo_on, 3); ! } ! conn_write(conn, give_lm, 3); ! } } else { ! (*usr)->inbuf = (char *) NULL; ! (*usr)->outbuf = (char *) *usr + sizeof(user); } nusers++; } /* *************** *** 128,135 **** conn_del((*usr)->conn); if ((*usr)->flags & CF_TELNET) { newlines -= (*usr)->newlines; - } else { - binchars -= (*usr)->inbufsz; } obj = (*usr)->u.obj; obj->flags &= ~O_USER; --- 151,156 ---- *************** *** 150,155 **** --- 171,238 ---- } /* + * NAME: comm->listen() + * DESCRIPTION: have an object listen to a port + */ + void comm_listen(obj, port, protocol) + object *obj; + int port, protocol; + { + register connection *conn; + int flags; + + if (nusers >= maxusers) + error("Max number of connection/port objects exceeded"); + + if (protocol == PRC_TELNET) { + flags = CF_TELNET | CF_ECHO | CF_PORT; + protocol = PRC_TCP; + } else if (protocol == PRC_UDP) { + flags = CF_DATAGRAM | CF_PORT; + } else { + flags = CF_PORT; + } + conn = conn_listen(port, protocol); + if (conn != (connection *) NULL) { + comm_new(obj, conn, flags); + } else { + error("Could not open port"); + } + if (i_call(obj, "open", TRUE, 0)) { + i_del_value(sp++); + } + } + + /* + * NAME: comm->connect() + * DESCRIPTION: initiate a telnet or tcp connection + */ + void comm_connect(obj, host, port, protocol) + object *obj; + char *host; + int port, protocol; + { + register connection *conn; + int flags; + + if (nusers >= maxusers) + error("Max number of connection/port objects exceeded"); + + if (protocol == PRC_TELNET) { + flags = CF_TELNET | CF_CONNECTING; + protocol = PRC_TCP; + } else if (protocol == PRC_TCP) { + flags = CF_CONNECTING; + } + conn = conn_connect(host, port, protocol); + if (conn != (connection *) NULL) { + comm_new(obj, conn, flags); + } else { + error("Could not initiate connection"); + } + } + + /* * NAME: comm->send() * DESCRIPTION: send a message to a user */ *************** *** 162,173 **** register unsigned short len, size; usr = users[UCHAR(obj->etabi)]; p = str->text; len = str->len; if (usr->flags & CF_TELNET) { - /* - * telnet connection - */ size = usr->outbufsz; q = usr->outbuf + size; while (len != 0) { --- 245,259 ---- register unsigned short len, size; usr = users[UCHAR(obj->etabi)]; + if (usr->flags & (CF_DATAGRAM | CF_PORT)) { + error("Object is not a stream connection"); + } + if (usr->flags & CF_CONNECTING) { + error("Connection is not yet ready"); + } p = str->text; len = str->len; if (usr->flags & CF_TELNET) { size = usr->outbufsz; q = usr->outbuf + size; while (len != 0) { *************** *** 218,223 **** --- 304,329 ---- } /* + * NAME: comm->sendto() + * DESCRIPTION: send a datagram + */ + void comm_sendto(obj, data, host, port) + object *obj; + string *data; + char *host; + int port; + { + register user *usr; + + usr = users[UCHAR(obj->etabi)]; + if (usr->flags & CF_DATAGRAM == 0) { + error("Object is not a datagram object"); + } + conn_sendto(usr->conn, data->text, data->len, host, port); + } + + + /* * NAME: comm->echo() * DESCRIPTION: turn on/off input echoing for a user */ *************** *** 229,234 **** --- 335,342 ---- char buf[3]; usr = users[UCHAR(obj->etabi)]; + if (usr->flags & CF_CONNECTING) + error("Connection is not yet ready"); if ((usr->flags & CF_TELNET) && echo != (usr->flags & CF_ECHO)) { buf[0] = IAC; buf[1] = (echo) ? WONT : WILL; *************** *** 276,356 **** * NAME: comm->receive() * DESCRIPTION: receive a message from a user */ ! object *comm_receive(buf, size) ! char *buf; ! int *size; { static int lastuser; connection *conn; object *o; ! register int n, i, state, flags, nls; register char *p, *q; - if (nusers < maxusers) { - /* - * accept new telnet connection - */ - conn = conn_tnew(); - if (conn != (connection *) NULL) { - if (ec_push()) { - conn_del(conn); /* delete connection */ - error((char *) NULL); /* pass on error */ - } - call_driver_object("telnet_connect", 0); - ec_pop(); - if (sp->type != T_OBJECT) { - fatal("driver->telnet_connect() did not return an object"); - } - d_export(); - comm_new(o = o_object(sp->oindex, sp->u.objcnt), conn, TRUE); - sp++; - if (i_call(o, "open", TRUE, 0)) { - i_del_value(sp++); - d_export(); - } - comm_flush(TRUE); - } - } - - if (nusers < maxusers) { - /* - * accept new binary connection - */ - conn = conn_bnew(); - if (conn != (connection *) NULL) { - if (ec_push()) { - conn_del(conn); /* delete connection */ - error((char *) NULL); /* pass on error */ - } - call_driver_object("binary_connect", 0); - ec_pop(); - if (sp->type != T_OBJECT) { - fatal("driver->binary_connect() did not return an object"); - } - d_export(); - comm_new(o = o_object(sp->oindex, sp->u.objcnt), conn, FALSE); - sp++; - if (i_call(o, "open", TRUE, 0)) { - i_del_value(sp++); - d_export(); - } - comm_flush(TRUE); - } - } - - /* - * read input from users - */ this_user = (object *) NULL; ! n = conn_select(newlines == 0 && binchars == 0); ! if (n <= 0) { ! /* ! * call_out to do, or timeout ! */ ! if (newlines == 0 && binchars == 0) { ! return (object *) NULL; ! } ! } else { static char intr[] = { '\177' }; static char brk[] = { '\034' }; static char tm[] = { (char) IAC, (char) WILL, (char) TELOPT_TM }; --- 384,400 ---- * NAME: comm->receive() * DESCRIPTION: receive a message from a user */ ! void comm_receive() { static int lastuser; connection *conn; object *o; ! register int n; register char *p, *q; this_user = (object *) NULL; ! n = conn_select(newlines == 0); ! if (n > 0 || newlines > 0) { static char intr[] = { '\177' }; static char brk[] = { '\034' }; static char tm[] = { (char) IAC, (char) WILL, (char) TELOPT_TM }; *************** *** 359,590 **** static char mode_edit[]= { (char) IAC, (char) SB, (char) TELOPT_LINEMODE, (char) LM_MODE, (char) MODE_EDIT, (char) IAC, (char) SE }; ! register user **usr; ! ! for (i = maxusers, usr = users; i > 0; --i, usr++) { ! if (*usr != (user *) NULL && (*usr)->inbufsz != INBUF_SIZE) { ! p = (*usr)->inbuf + (*usr)->inbufsz; ! n = conn_read((*usr)->conn, p, INBUF_SIZE - (*usr)->inbufsz); ! if (n < 0) { ! /* ! * bad connection ! */ ! comm_del(usr); ! d_export(); /* this cannot be in comm_del() */ ! } else if ((*usr)->flags & CF_TELNET) { ! /* ! * telnet mode ! */ ! flags = (*usr)->flags; ! state = (*usr)->state; ! nls = (*usr)->newlines; ! q = p; ! while (n > 0) { ! switch (state) { ! case TS_DATA: ! switch (UCHAR(*p)) { ! case '\0': ! flags &= ~CF_SEENCR; ! break; ! case IAC: ! state = TS_IAC; ! break; ! case BS: ! case 0x7f: ! if (q != (*usr)->inbuf && q[-1] != LF) { ! --q; ! } ! flags &= ~CF_SEENCR; ! break; ! case CR: ! nls++; ! newlines++; ! *q++ = LF; ! flags |= CF_SEENCR; ! break; ! case LF: ! if ((flags & CF_SEENCR) != 0) { flags &= ~CF_SEENCR; break; } - nls++; - newlines++; - /* fall through */ - default: - *q++ = *p; - flags &= ~CF_SEENCR; break; - } - break; ! case TS_IAC: ! switch (UCHAR(*p)) { ! case IAC: ! *q++ = *p; ! state = TS_DATA; ! break; ! case DO: ! state = TS_DO; ! break; ! case DONT: ! state = TS_DONT; ! break; ! case WILL: ! state = TS_WILL; ! break; ! case WONT: ! state = TS_WONT; ! break; ! case SB: ! state = TS_SB; break; ! case IP: ! conn_write((*usr)->conn, intr, 1); state = TS_DATA; break; ! case BREAK: ! conn_write((*usr)->conn, brk, 1); state = TS_DATA; break; ! default: ! /* let's hope it wasn't important */ state = TS_DATA; break; - } - break; - - case TS_DO: - if (UCHAR(*p) == TELOPT_TM) { - conn_write((*usr)->conn, tm, 3); - } else if (UCHAR(*p) == TELOPT_SGA) { - flags &= ~CF_GA; - conn_write((*usr)->conn, will_sga, 3); - } - state = TS_DATA; - break; - - case TS_DONT: - if (UCHAR(*p) == TELOPT_SGA) { - flags |= CF_GA; - conn_write((*usr)->conn, wont_sga, 3); - } - state = TS_DATA; - break; ! case TS_WILL: ! if (UCHAR(*p) == TELOPT_LINEMODE) { ! /* linemode confirmed; now request editing */ ! conn_write((*usr)->conn, mode_edit, 7); ! } ! /* fall through */ ! case TS_WONT: ! state = TS_DATA; ! break; ! ! case TS_SB: ! /* skip to the end */ ! if (UCHAR(*p) == IAC) { ! state = TS_SE; ! } ! break; ! case TS_SE: ! if (UCHAR(*p) == SE) { ! /* end of subnegotiation */ ! state = TS_DATA; ! } else { ! state = TS_SB; } ! break; } ! p++; ! --n; } ! (*usr)->flags = flags; ! (*usr)->state = state; ! (*usr)->newlines = nls; ! (*usr)->inbufsz = q - (*usr)->inbuf; ! } else { ! /* ! * binary mode ! */ ! (*usr)->inbufsz += n; ! binchars += n; ! } ! } ! } ! } ! ! if (newlines != 0 || binchars != 0) { ! register user *usr; ! ! n = lastuser; ! for (;;) { ! n = (n + 1) % maxusers; ! usr = users[n]; ! if (usr != (user *) NULL && usr->inbufsz != 0) { ! if (usr->flags & CF_TELNET) { ! /* ! * telnet connection ! */ ! if (usr->newlines != 0) { ! /* ! * input terminated by \n ! */ p = (char *) memchr(usr->inbuf, LF, usr->inbufsz); - usr->newlines--; --newlines; lastuser = n; ! *size = n = p - usr->inbuf; ! if (n != 0) { ! memcpy(buf, usr->inbuf, n); } p++; /* skip \n */ n++; ! usr->inbufsz -= n; if (usr->inbufsz != 0) { /* can't rely on memcpy */ for (q = usr->inbuf, n = usr->inbufsz; n > 0; --n) { *q++ = *p++; } } ! return this_user = usr->u.obj; } else if (usr->inbufsz == INBUF_SIZE) { /* * input buffer full */ lastuser = n; ! memcpy(buf, usr->inbuf, *size = INBUF_SIZE); usr->inbufsz = 0; ! return this_user = usr->u.obj; } } else { /* ! * binary connection */ ! lastuser = n; ! binchars -= usr->inbufsz; ! memcpy(buf, usr->inbuf, *size = usr->inbufsz); ! usr->inbufsz = 0; ! return this_user = usr->u.obj; } } } } - - return (object *) NULL; } /* --- 403,698 ---- static char mode_edit[]= { (char) IAC, (char) SB, (char) TELOPT_LINEMODE, (char) LM_MODE, (char) MODE_EDIT, (char) IAC, (char) SE }; ! register user *usr; ! char buf[INBUF_SIZE]; ! Int size; ! n = lastuser; ! for (;;) { ! n = (n + 1) % maxusers; ! usr = users[n]; ! if (usr != (user *) NULL) { ! if (usr->flags & CF_CONNECTING) { ! int r; ! ! r = conn_connected(usr->conn); ! if (r == 1) { ! usr->flags &= ~CF_CONNECTING; ! this_user = usr->u.obj; ! if (i_call(this_user, "open", TRUE, 0)) { ! i_del_value(sp++); ! d_export(); ! } ! comm_flush(TRUE); ! } else if (r == -1) { ! comm_del(&users[n]); ! d_export(); ! } ! } else if (usr->flags & CF_DATAGRAM) { ! size = conn_recvfrom(usr->conn, buf, INBUF_SIZE); ! if (size > 0) { ! lastuser = n; ! (--sp)->type = T_STRING; ! str_ref(sp->u.string = str_new(buf, (long) size)); ! (--sp)->type = T_STRING; ! str_ref(sp->u.string = conn_ipnum(usr->conn)); ! (--sp)->type = T_INT; ! sp->u.number = conn_port(usr->conn); ! this_user = usr->u.obj; ! if (i_call(this_user, "receive_datagram", TRUE, 3)) { ! i_del_value(sp++); ! d_export(); ! } ! return; ! } ! } else if (usr->flags & CF_PORT) { ! if (nusers < maxusers) { ! conn = conn_accept(usr->conn); ! if (conn != (connection *) NULL) { ! (--sp)->type = T_STRING; ! str_ref(sp->u.string = conn_ipnum(conn)); ! (--sp)->type = T_INT; ! sp->u.number = conn_port(conn); ! if (ec_push()) { ! conn_del(conn); ! error((char *) NULL); /* pass on error */ ! } ! this_user = usr->u.obj; ! if (!i_call(this_user, "connection", TRUE, 2) || ! sp->type != T_OBJECT) { ! error("connection() did not return an object"); ! } ! ec_pop(); ! d_export(); ! comm_new(o = o_object(sp->oindex, sp->u.objcnt), ! conn, usr->flags & ~CF_PORT); ! sp++; ! this_user = o; ! if (i_call(this_user, "open", TRUE, 0)) { ! i_del_value(sp++); ! d_export(); ! } ! comm_flush(TRUE); ! } ! } ! } else if (usr->flags & CF_TELNET) { ! p = usr->inbuf + usr->inbufsz; ! size = conn_read(usr->conn, p, INBUF_SIZE - usr->inbufsz); ! if (size < 0) { ! /* ! * bad connection ! */ ! comm_del(&users[n]); ! d_export(); ! continue; ! } else if (size > 0) { ! register int state, flags, nls; ! ! flags = usr->flags; ! state = usr->state; ! nls = usr->newlines; ! q = p; ! while (size > 0) { ! switch (state) { ! case TS_DATA: ! switch (UCHAR(*p)) { ! case IAC: ! state = TS_IAC; ! break; ! case BS: ! case 0x7f: ! if (q != usr->inbuf && q[-1] != LF) { ! --q; ! } ! flags &= ~CF_SEENCR; ! break; ! case CR: ! nls++; ! newlines++; ! *q++ = LF; ! flags |= CF_SEENCR; ! break; ! case LF: ! if ((flags & CF_SEENCR) != 0) { ! flags &= ~CF_SEENCR; ! break; ! } ! nls++; ! newlines++; ! /* fall through */ ! default: ! *q++ = *p; flags &= ~CF_SEENCR; break; } break; ! case TS_IAC: ! switch (UCHAR(*p)) { ! case IAC: ! *q++ = *p; ! state = TS_DATA; ! break; ! case DO: ! state = TS_DO; ! break; ! case DONT: ! state = TS_DONT; ! break; ! case WILL: ! state = TS_WILL; ! break; ! case WONT: ! state = TS_WONT; ! break; ! ! case SB: ! state = TS_SB; ! break; ! ! case IP: ! conn_write(usr->conn, intr, 1); ! state = TS_DATA; ! break; ! ! case BREAK: ! conn_write(usr->conn, brk, 1); ! state = TS_DATA; ! break; ! default: ! state = TS_DATA; ! break; ! } break; ! case TS_DO: ! if (UCHAR(*p) == TELOPT_TM) { ! conn_write(usr->conn, tm, 3); ! } else if (UCHAR(*p) == TELOPT_SGA) { ! flags &= ~CF_GA; ! conn_write(usr->conn, will_sga, 3); ! } state = TS_DATA; break; ! case TS_DONT: ! if (UCHAR(*p) == TELOPT_SGA) { ! flags |= CF_GA; ! conn_write(usr->conn, wont_sga, 3); ! } state = TS_DATA; break; ! case TS_WILL: ! if (UCHAR(*p) == TELOPT_LINEMODE) { ! conn_write(usr->conn, mode_edit, 7); ! } ! /* fall through */ ! case TS_WONT: state = TS_DATA; break; ! case TS_SB: ! /* skip to the end */ ! if (UCHAR(*p) == IAC) { ! state = TS_SE; ! } ! break; ! case TS_SE: ! if (UCHAR(*p) == SE) { ! /* end of subnegotiation */ ! state = TS_DATA; ! } else if (UCHAR(*p) == IAC) { ! /* doubled IAC counts as data */ ! state = TS_SB; ! } ! break; } ! p++; ! --size; } ! usr->flags = flags; ! usr->state = state; ! usr->newlines = nls; ! usr->inbufsz = q - usr->inbuf; } ! if (usr->newlines > 0) { p = (char *) memchr(usr->inbuf, LF, usr->inbufsz); --newlines; + --(usr->newlines); lastuser = n; ! size = n = p - usr->inbuf; ! if (size != 0) { ! memcpy(buf, usr->inbuf, size); } p++; /* skip \n */ n++; ! usr->inbufsz -= size + 1; if (usr->inbufsz != 0) { /* can't rely on memcpy */ for (q = usr->inbuf, n = usr->inbufsz; n > 0; --n) { *q++ = *p++; } } ! this_user = usr->u.obj; ! (--sp)->type = T_STRING; ! str_ref(sp->u.string = str_new(buf, (long) size)); ! if (i_call(this_user, "receive_message", TRUE, 1)) { ! i_del_value(sp++); ! d_export(); ! } ! return; } else if (usr->inbufsz == INBUF_SIZE) { /* * input buffer full */ lastuser = n; ! (--sp)->type = T_STRING; ! str_ref(sp->u.string = ! str_new(usr->inbuf, (long) INBUF_SIZE)); usr->inbufsz = 0; ! this_user = usr->u.obj; ! if (i_call(this_user, "receive_message", TRUE, 1)) { ! i_del_value(sp++); ! d_export(); ! } ! return; } } else { /* ! * binary mode */ ! size = conn_read(usr->conn, buf, INBUF_SIZE); ! if (size < 0) { ! comm_del(&users[n]); ! d_export(); ! } else if (size > 0) { ! lastuser = n; ! (--sp)->type = T_STRING; ! str_ref(sp->u.string = str_new(buf, (long) size)); ! this_user = usr->u.obj; ! if (i_call(this_user, "receive_message", TRUE, 1)) { ! i_del_value(sp++); ! d_export(); ! } ! return; ! } } } + if (n == lastuser) { + return; + } } } } /* *************** *** 594,603 **** string *comm_ip_number(obj) object *obj; { ! char *ipnum; ! ! ipnum = conn_ipnum(users[UCHAR(obj->etabi)]->conn); ! return str_new(ipnum, (long) strlen(ipnum)); } /* --- 702,708 ---- string *comm_ip_number(obj) object *obj; { ! return conn_ipnum(users[UCHAR(obj->etabi)]->conn); } /* diff -cr dgd/src/comm.h dgd-patched/src/comm.h *** dgd/src/comm.h Tue Jun 6 18:12:12 1995 --- dgd-patched/src/comm.h Sun Sep 3 15:51:33 1995 *************** *** 1,24 **** # define INBUF_SIZE 2048 # define OUTBUF_SIZE 1024 typedef struct _connection_ connection; ! extern void conn_init P((int, unsigned int, unsigned int)); extern void conn_finish P((void)); ! extern connection *conn_tnew P((void)); ! extern connection *conn_bnew P((void)); extern void conn_del P((connection*)); extern int conn_select P((int)); extern int conn_read P((connection*, char*, int)); extern int conn_write P((connection*, char*, int)); ! extern char *conn_ipnum P((connection*)); ! extern void comm_init P((int, int, int)); extern void comm_finish P((void)); extern int comm_send P((object*, string*)); extern void comm_echo P((object*, int)); extern void comm_flush P((int)); ! extern object *comm_receive P((char*, int*)); extern string *comm_ip_number P((object*)); extern void comm_close P((object*)); extern object *comm_user P((void)); --- 1,36 ---- # define INBUF_SIZE 2048 # define OUTBUF_SIZE 1024 + # define PRC_TCP 1 + # define PRC_UDP 2 + # define PRC_TELNET 3 + typedef struct _connection_ connection; ! extern void conn_init P((int)); extern void conn_finish P((void)); ! extern connection *conn_listen P((int, int)); ! extern connection *conn_accept P((connection*)); ! extern connection *conn_connect P((char*, int, int)); ! extern int conn_connected P((connection*)); extern void conn_del P((connection*)); extern int conn_select P((int)); + extern int conn_recvfrom P((connection*, char*, int)); extern int conn_read P((connection*, char*, int)); + extern void conn_sendto P((connection*, char*, int, char*, int)); extern int conn_write P((connection*, char*, int)); ! extern string *conn_ipnum P((connection*)); ! extern int conn_port P((connection*)); ! extern void comm_init P((int)); extern void comm_finish P((void)); + extern void comm_listen P((object*, int, int)); + extern void comm_connect P((object*, char*, int, int)); extern int comm_send P((object*, string*)); + extern void comm_sendto P((object*, string*, char*, int)); extern void comm_echo P((object*, int)); extern void comm_flush P((int)); ! extern void comm_receive P((void)); extern string *comm_ip_number P((object*)); extern void comm_close P((object*)); extern object *comm_user P((void)); diff -cr dgd/src/comp/comp.c dgd-patched/src/comp/comp.c *** dgd/src/comp/comp.c Mon Jul 31 15:15:44 1995 --- dgd-patched/src/comp/comp.c Sun Sep 3 15:51:33 1995 *************** *** 529,536 **** * NAME: comm->init() * DESCRIPTION: pretend to initialize communications */ ! void comm_init(nusers, telnet_port, binary_port) ! int nusers, telnet_port, binary_port; { } --- 529,536 ---- * NAME: comm->init() * DESCRIPTION: pretend to initialize communications */ ! void comm_init(nusers) ! int nusers; { } *************** *** 569,574 **** --- 569,607 ---- */ void comm_flush(flag) int flag; + { + } + + /* + * NAME: comm->listen() + * DESCRIPTION: pretend to open a port for listening + */ + void comm_listen(obj, port, protocol) + object *obj; + int port, protocol; + { + } + + /* + * NAME: comm->connect() + * DESCRIPTION: pretend to initiate a telnet or tcp connection + */ + void comm_connect(obj, host, port, protocol) + object *obj; + char *host; + int port, protocol; + { + } + + /* + * NAME: comm->sendto() + * DESCRIPTION: pretend to send a datagram + */ + void comm_sendto(obj, data, host, port) + object *obj; + string *data; + char *host; + int port; { } diff -cr dgd/src/config.c dgd-patched/src/config.c *** dgd/src/config.c Sat Aug 12 19:00:38 1995 --- dgd-patched/src/config.c Sun Sep 3 15:51:33 1995 *************** *** 582,587 **** --- 582,592 ---- header[16] = (char *) &pdummy.p - (char *) &pdummy.fill; /* pointer align */ header[17] = sizeof(align); /* struct align */ + /* initialize communications */ + mstatic(); + comm_init((int) conf[USERS].u.num); + mdynamic(); + starttime = boottime = P_time(); i_set_cost((Int) conf[MAX_COST].u.num); if (dumpfile == (char *) NULL) { *************** *** 598,610 **** call_driver_object("restored", 0); } i_del_value(sp++); - - /* initialize communications */ - mstatic(); - comm_init((int) conf[USERS].u.num, - (int) conf[TELNET_PORT].u.num, - (int) conf[BINARY_PORT].u.num); - mdynamic(); } /* --- 603,608 ---- diff -cr dgd/src/dgd.c dgd-patched/src/dgd.c *** dgd/src/dgd.c Sun Aug 13 15:25:58 1995 --- dgd-patched/src/dgd.c Sun Sep 3 15:51:33 1995 *************** *** 88,97 **** int argc; char **argv; { - char buf[INBUF_SIZE]; - int size; - object *usr; - if (argc < 2 || argc > 3) { P_message("Usage: dgd config_file [dump_file]\012"); /* LF */ return 2; --- 88,93 ---- *************** *** 164,179 **** } /* user input */ ! usr = comm_receive(buf, &size); ! if (usr != (object *) NULL) { ! (--sp)->type = T_STRING; ! str_ref(sp->u.string = str_new(buf, (long) size)); ! if (i_call(usr, "receive_message", TRUE, 1)) { ! i_del_value(sp++); comm_flush(TRUE); - d_export(); - } - } /* callouts */ co_call(); --- 160,167 ---- } /* user input */ ! comm_receive(); comm_flush(TRUE); /* callouts */ co_call(); diff -cr dgd/src/host/unix/connect.c dgd-patched/src/host/unix/connect.c *** dgd/src/host/unix/connect.c Tue Jun 6 18:12:13 1995 --- dgd-patched/src/host/unix/connect.c Sun Sep 3 15:51:33 1995 *************** *** 13,97 **** struct _connection_ { int fd; /* file descriptor */ ! struct sockaddr_in addr; /* internet address of connection */ struct _connection_ *next; /* next in list */ }; static int nusers; /* # of users */ static connection *connections; /* connections array */ static connection *flist; /* list of free connections */ - static int telnet; /* telnet port socket descriptor */ - static int binary; /* binary port socket descriptor */ static fd_set fds; /* file descriptor bitmap */ static fd_set readfds; /* file descriptor read bitmap */ static int maxfd; /* largest fd opened yet */ /* * NAME: conn->init() * DESCRIPTION: initialize connections */ ! void conn_init(maxusers, telnet_port, binary_port) int maxusers; - unsigned int telnet_port, binary_port; { - struct sockaddr_in sin; - struct hostent *host; register int n; register connection *conn; - char buffer[256]; - int on; - - gethostname(buffer, sizeof(buffer)); - host = gethostbyname(buffer); - if (host == (struct hostent *) NULL) { - perror("gethostbyname"); - exit(2); - } - - telnet = socket(host->h_addrtype, SOCK_STREAM, 0); - binary = socket(host->h_addrtype, SOCK_STREAM, 0); - if (telnet < 0 || binary < 0) { - perror("socket"); - exit(2); - } - on = 1; - if (setsockopt(telnet, SOL_SOCKET, SO_REUSEADDR, (char *) &on, - sizeof(on)) < 0) { - perror("setsockopt"); - exit(2); - } - on = 1; - if (setsockopt(binary, SOL_SOCKET, SO_REUSEADDR, (char *) &on, - sizeof(on)) < 0) { - perror("setsockopt"); - exit(2); - } - - memset(&sin, '\0', sizeof(sin)); - memcpy(&sin.sin_addr, host->h_addr, host->h_length); - sin.sin_port = htons(telnet_port); - sin.sin_family = host->h_addrtype; - sin.sin_addr.s_addr = INADDR_ANY; - if (bind(telnet, (struct sockaddr *) &sin, sizeof(sin)) < 0) { - perror("bind"); - exit(2); - } - sin.sin_port = htons(binary_port); - if (bind(binary, (struct sockaddr *) &sin, sizeof(sin)) < 0) { - perror("bind"); - exit(2); - } - - if (listen(telnet, 5) < 0 || listen(binary, 5) < 0) { - perror("listen"); - exit(2); - } - - if (fcntl(telnet, F_SETFL, FNDELAY) < 0 || - fcntl(binary, F_SETFL, FNDELAY) < 0) { - perror("fcntl"); - exit(2); - } connections = ALLOC(connection, nusers = maxusers); for (n = nusers, conn = connections; n > 0; --n, conn++) { --- 13,43 ---- struct _connection_ { int fd; /* file descriptor */ ! struct sockaddr_in sin; /* peer's address */ struct _connection_ *next; /* next in list */ + char host[16]; /* ascii ip number of peer */ + char hostlen; /* length of host string */ }; static int nusers; /* # of users */ static connection *connections; /* connections array */ static connection *flist; /* list of free connections */ static fd_set fds; /* file descriptor bitmap */ + static fd_set connectfds; /* file descriptor bitmap */ static fd_set readfds; /* file descriptor read bitmap */ + static fd_set writefds; /* file descriptor write bitmap */ + static fd_set failfds; /* file descriptor exception bitmap */ static int maxfd; /* largest fd opened yet */ /* * NAME: conn->init() * DESCRIPTION: initialize connections */ ! void conn_init(maxusers) int maxusers; { register int n; register connection *conn; connections = ALLOC(connection, nusers = maxusers); for (n = nusers, conn = connections; n > 0; --n, conn++) { *************** *** 101,106 **** --- 47,53 ---- } FD_ZERO(&fds); + FD_ZERO(&connectfds); } /* *************** *** 109,139 **** */ void conn_finish() { - close(telnet); - close(binary); } /* ! * NAME: conn->tnew() ! * DESCRIPTION: accept a new telnet connection */ ! connection *conn_tnew() { - int fd, len; - struct sockaddr_in sin; register connection *conn; - - len = sizeof(sin); - fd = accept(telnet, (struct sockaddr *) &sin, &len); - if (fd < 0) { - return (connection *) NULL; - } - conn = flist; flist = conn->next; conn->fd = fd; ! memcpy(&conn->addr, (char *) &sin, len); ! FD_SET(fd, &fds); if (fd > maxfd) { maxfd = fd; } --- 56,78 ---- */ void conn_finish() { } /* ! * NAME: conn->new() ! * DESCRIPTION: initialize a new connection struct */ ! static connection *conn_new(fd, sin) ! int fd; ! struct sockaddr_in *sin; { register connection *conn; conn = flist; flist = conn->next; conn->fd = fd; ! memcpy(&conn->sin, sin, sizeof(conn->sin)); ! strcpy(conn->host, inet_ntoa(sin->sin_addr)); ! conn->hostlen = strlen(conn->host); if (fd > maxfd) { maxfd = fd; } *************** *** 142,173 **** } /* ! * NAME: conn->bnew() ! * DESCRIPTION: accept a new binary connection */ ! connection *conn_bnew() { ! int fd, len; struct sockaddr_in sin; ! register connection *conn; ! len = sizeof(sin); ! fd = accept(binary, (struct sockaddr *) &sin, &len); if (fd < 0) { return (connection *) NULL; } - conn = flist; - flist = conn->next; - conn->fd = fd; - memcpy(&conn->addr, (char *) &sin, len); FD_SET(fd, &fds); ! if (fd > maxfd) { ! maxfd = fd; } ! return conn; } /* * NAME: conn->del() --- 81,206 ---- } /* ! * NAME: conn->listen() ! * DESCRIPTION: bind a connection to a local port ! */ ! connection *conn_listen(port, protocol) ! int port, protocol; ! { ! int fd; ! static struct sockaddr_in sin; ! int on = 1; ! ! fd = socket(PF_INET, (protocol == PRC_UDP) ? SOCK_DGRAM : SOCK_STREAM, 0); ! if (fd < 0) { ! return (connection *) NULL; ! } ! if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, ! sizeof(on)) < 0) { ! close(fd); ! return (connection *) NULL; ! } ! ! sin.sin_family = AF_INET; ! sin.sin_port = htons(port); ! sin.sin_addr.s_addr = INADDR_ANY; /* htonl? */ ! if (bind(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { ! close(fd); ! return (connection *) NULL; ! } ! ! if (protocol != PRC_UDP && listen(fd, 5) < 0) { ! close(fd); ! return (connection *) NULL; ! } ! ! if (fcntl(fd, F_SETFL, FNDELAY) < 0) { ! close(fd); ! return (connection *) NULL; ! } ! ! FD_SET(fd, &fds); ! return conn_new(fd, &sin); ! } ! ! /* ! * NAME: conn->accept() ! * DESCRIPTION: accept a connection */ ! connection *conn_accept(conn) ! connection *conn; { ! int fd; struct sockaddr_in sin; ! int len = sizeof(sin); ! fd = accept(conn->fd, (struct sockaddr *) &sin, &len); if (fd < 0) { return (connection *) NULL; } FD_SET(fd, &fds); ! return conn_new(fd, &sin); ! } ! ! /* ! * NAME: conn->connect() ! * DESCRIPTION: initiate a tcp connection ! */ ! connection *conn_connect(host, port, protocol) ! char *host; ! int port, protocol; ! { ! int fd; ! static struct sockaddr_in sin; ! ! if (protocol != PRC_TCP) { ! return (connection *) NULL; } ! fd = socket(PF_INET, SOCK_STREAM, 0); ! if (fd < 0) { ! return (connection *) NULL; ! } ! ! if (fcntl(fd, F_SETFL, FNDELAY) < 0) { ! close(fd); ! return (connection *) NULL; ! } ! ! sin.sin_family = AF_INET; ! sin.sin_port = htons(port); ! sin.sin_addr.s_addr = inet_addr(host); ! if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0 && ! errno != EINPROGRESS) { ! close(fd); ! return (connection *) NULL; ! } ! ! FD_SET(fd, &connectfds); ! return conn_new(fd, &sin); ! } ! ! /* ! * NAME: conn->connected() ! * DESCRIPTION: mark a connecting socket as active ! */ ! int conn_connected(conn) ! register connection *conn; ! { ! if (conn->fd == -1) ! return -1; ! if (FD_ISSET(conn->fd, &failfds)) { ! FD_CLR(conn->fd, &connectfds); ! return -1; ! } else if (FD_ISSET(conn->fd, &writefds)) { ! FD_CLR(conn->fd, &connectfds); ! FD_SET(conn->fd, &fds); ! return 1; ! } ! return 0; } + /* * NAME: conn->del() *************** *** 179,184 **** --- 212,218 ---- if (conn->fd >= 0) { close(conn->fd); FD_CLR(conn->fd, &fds); + FD_CLR(conn->fd, &connectfds); conn->fd = -1; } conn->next = flist; *************** *** 195,204 **** struct timeval timeout; memcpy(&readfds, &fds, sizeof(fd_set)); timeout.tv_sec = (int) wait; timeout.tv_usec = 0; ! return select(maxfd + 1, &readfds, (fd_set *) NULL, (fd_set *) NULL, ! &timeout); } /* --- 229,264 ---- struct timeval timeout; memcpy(&readfds, &fds, sizeof(fd_set)); + memcpy(&writefds, &connectfds, sizeof(fd_set)); + memcpy(&failfds, &connectfds, sizeof(fd_set)); timeout.tv_sec = (int) wait; timeout.tv_usec = 0; ! return select(maxfd + 1, &readfds, &writefds, &failfds, &timeout); ! } ! ! /* ! * NAME: conn->recvfrom() ! * DESCRIPTION: read a datagram ! */ ! int conn_recvfrom(conn, buf, size) ! connection *conn; ! char *buf; ! int size; ! { ! struct sockaddr_in sin; ! int len = sizeof(sin); ! ! if (conn->fd < 0) { ! return -1; ! } ! if (!FD_ISSET(conn->fd, &readfds)) { ! return 0; ! } ! size = recvfrom(conn->fd, buf, size, 0, (struct sockaddr *)&sin, &len); ! memcpy(&(conn->sin), &sin, len); ! strcpy(conn->host, inet_ntoa(sin.sin_addr)); ! conn->hostlen = strlen(conn->host); ! return size; /* Size may legitimately be 0 */ } /* *************** *** 213,219 **** if (conn->fd < 0) { return -1; } ! if (!FD_ISSET(conn->fd, &readfds)) { return 0; } size = read(conn->fd, buf, size); --- 273,279 ---- if (conn->fd < 0) { return -1; } ! if (!FD_ISSET(conn->fd, &readfds) || size == 0) { return 0; } size = read(conn->fd, buf, size); *************** *** 221,226 **** --- 281,304 ---- } /* + * NAME: conn->sendto() + * DESCRIPTION: send a datagram + */ + void conn_sendto(conn, data, size, host, port) + connection *conn; + char *data, *host; + int size, port; + { + static struct sockaddr_in sin; + if (conn->fd >= 0) { + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = inet_addr(host); + sin.sin_port = htons(port); + sendto(conn->fd, data, size, 0, (struct sockaddr *)&sin, sizeof(sin)); + } + } + + /* * NAME: conn->write() * DESCRIPTION: write to a connection; return the amount of bytes written */ *************** *** 233,238 **** --- 311,317 ---- if ((size=write(conn->fd, buf, size)) < 0 && errno != EWOULDBLOCK) { close(conn->fd); FD_CLR(conn->fd, &fds); + FD_CLR(conn->fd, &connectfds); conn->fd = -1; } return size; *************** *** 244,251 **** * NAME: conn->ipnum() * DESCRIPTION: return the ip number of a connection */ ! char *conn_ipnum(conn) connection *conn; { ! return inet_ntoa(conn->addr.sin_addr); } --- 323,341 ---- * NAME: conn->ipnum() * DESCRIPTION: return the ip number of a connection */ ! string *conn_ipnum(conn) ! connection *conn; ! { ! return str_new(conn->host, conn->hostlen); ! } ! ! /* ! * NAME: conn->port() ! * DESCRIPTION: return the port number of a connection ! */ ! int conn_port(conn) connection *conn; { ! return ntohs(conn->sin.sin_port); } + diff -cr dgd/src/kfun/std.c dgd-patched/src/kfun/std.c *** dgd/src/kfun/std.c Sat Aug 12 19:00:40 1995 --- dgd-patched/src/kfun/std.c Sun Sep 3 15:51:33 1995 *************** *** 602,615 **** obj = i_this_object(); if (obj->count != 0) { ! if (obj->flags & O_USER) { if (sp->type == T_INT) { comm_echo(obj, sp->u.number != 0); } else { num = comm_send(obj, sp->u.string); } - } else if ((obj->flags & O_DRIVER) && sp->type == T_STRING) { - P_message(sp->u.string->text); } } if (sp->type == T_STRING) { --- 602,615 ---- obj = i_this_object(); if (obj->count != 0) { ! if ((obj->flags & O_DRIVER) && sp->type == T_STRING) { ! P_message(sp->u.string->text); ! } else if (obj->flags & O_USER) { if (sp->type == T_INT) { comm_echo(obj, sp->u.number != 0); } else { num = comm_send(obj, sp->u.string); } } } if (sp->type == T_STRING) { *************** *** 621,626 **** --- 621,747 ---- } # endif + # ifdef FUNCDEF + FUNCDEF("open_port", kf_open_port, p_open_port) + # else + char p_open_port[] = { C_TYPECHECKED | C_STATIC, T_VOID, + 3, T_OBJECT, T_INT, T_STRING }; + + /* + * NAME: kfun->open_port() + * DESCRIPTION: start listening on a port + */ + int kf_open_port() + { + object *obj; + char *str; + int protocol; + + obj = i_this_object(); + if (obj->count == 0) { + error("open_port() from destructed object"); + } + if (!(obj->flags & O_DRIVER)) { + error("open_port() only from driver object"); + } + + str = sp->u.string->text; + if (strcmp(str, "tcp") == 0) { + protocol = PRC_TCP; + } else if (strcmp(str, "udp") == 0) { + protocol = PRC_UDP; + } else if (strcmp(str, "telnet") == 0) { + protocol = PRC_TELNET; + } else { + return 3; + } + + obj = o_object(sp[2].oindex, sp[2].u.objcnt); + if (obj->flags & (O_USER | O_EDITOR)) { + error("object already used for socket or editor"); + } + comm_listen(o_object(sp[2].oindex, sp[2].u.objcnt), + sp[1].u.number, protocol); + str_del(sp->u.string); + sp += 2; + sp->type = T_INT; + sp->u.number = 0; + return 0; + } + # endif + + # ifdef FUNCDEF + FUNCDEF("connect", kf_connect, p_connect) + # else + char p_connect[] = { C_TYPECHECKED | C_STATIC, T_VOID, + 4, T_OBJECT, T_STRING, T_INT, T_STRING }; + + /* + * NAME: kfun->connect() + * DESCRIPTION: initiate an ip connection + */ + int kf_connect() + { + object *obj; + char *str; + int protocol; + + obj = i_this_object(); + if (obj->count == 0) { + error("connect() from destructed object"); + } + if (!(obj->flags & O_DRIVER)) { + error("connect() only from driver object"); + } + + str = sp->u.string->text; + if (strcmp(str, "tcp") == 0) { + protocol = PRC_TCP; + } else if (strcmp(str, "telnet") == 0) { + protocol = PRC_TELNET; + } else { + return 4; + } + + obj = o_object(sp[3].oindex, sp[3].u.objcnt); + if (obj->flags & (O_USER | O_EDITOR)) { + error("object already used for socket or editor"); + } + comm_connect(obj, sp[2].u.string->text, sp[1].u.number, protocol); + str_del(sp->u.string); + str_del(sp[2].u.string); + sp += 3; + sp->type = T_INT; + sp->u.number = 0; + return 0; + } + # endif + + # ifdef FUNCDEF + FUNCDEF("send_datagram", kf_send_datagram, p_send_datagram) + # else + char p_send_datagram[] = { C_TYPECHECKED | C_STATIC, T_VOID, + 3, T_STRING, T_STRING, T_INT }; + + /* + * NAME: kfun->send_datagram() + * DESCRIPTION: send a packet to a specific host and port (udp only) + */ + int kf_send_datagram() + { + object *obj; + + obj = i_this_object(); + if (obj->count != 0 && obj->flags & O_USER) { + comm_sendto(obj, sp[2].u.string, sp[1].u.string->text, sp->u.number); + } + str_del((++sp)->u.string); + str_del((++sp)->u.string); + sp->type = T_INT; + sp->u.number = 0; + return 0; + } + # endif # ifdef FUNCDEF FUNCDEF("time", kf_time, p_time)