Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!ames!oliveb!sun!rishathra!page From: page%rishathra@Sun.COM (Bob Page) Newsgroups: comp.sources.amiga Subject: v89i103: dnet - networking code (unix side) v2.0, Part02/02 Message-ID: <101943@sun.Eng.Sun.COM> Date: 29 Apr 89 02:38:19 GMT Sender: news@sun.Eng.Sun.COM Lines: 2495 Approved: page@sun.com Submitted-by: dillon@postgres.berkeley.edu (Matt Dillon) Posting-number: Volume 89, Issue 103 Archive-name: comm/dnet20-us.2 # This is a shell archive. # Remove anything above and including the cut line. # Then run the rest of the file through 'sh'. # Unpacked files will be owned by you and have default permissions. #----cut here-----cut here-----cut here-----cut here----# #!/bin/sh # shar: SHell ARchive # Run the following text through 'sh' to create: # dnet/net.c # dnet/internal.c # dnet/globals.c # dnet/files.c # dnet/dnet.h # dnet/dnet.c # dnet/Makefile # dnet/MODS # dnet.servers # doc/history # doc/dnet.doc # doc/putfiles.doc # doc/dsoc.doc # doc/dnetlib.doc # doc/draw.doc # lib/dnetlib.h # lib/dnetlib.c # lib/Makefile # server/sgcopy.c # server/sshell.c # server/sloadav.c # server/scopy.c # server/Makefile # server/servers.h # This is archive 2 of a 2-part kit. # This archive created: Thu Apr 27 15:41:48 1989 if `test ! -d dnet` then mkdir dnet echo "mkdir dnet" fi echo "extracting dnet/net.c" sed 's/^X//' << \SHAR_EOF > dnet/net.c X X/* X * NET.C X * X * DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved X * X * NetWork raw device interface. Replace with whatever interface you X * want. X */ X X#include "dnet.h" X#include X XRcvInt() X{ X int n = read(0, RcvBuf + RcvData, RCVBUF - RcvData); X if (n >= 0) X RcvData += n; X if (n <= 0) /* disallow infinite fast-timeout select loops */ X RExpect = 0; X if (DDebug && n < 0) { X write(2, "RcvInt ERR\n", 11); X } X} X Xstatic struct sgttyb ttym; Xstatic struct stat Stat; X XNetOpen() X{ X int async = 1; X X fstat(0, &Stat); X fchmod(0, 0600); X /* X signal(SIGIO, RcvInt); X */ X ioctl (0, TIOCGETP, &ttym); X ttym.sg_flags |= RAW; X ttym.sg_flags &= ~CBREAK; X ttym.sg_flags &= ~ECHO; X ioctl (0, TIOCSETP, &ttym); X /* X ioctl (0, FIOASYNC, &async); X */ X ioctl (0, FIONBIO, &async); X} X XNetClose() X{ X int async = 0; X X fchmod(0, Stat.st_mode); X ioctl (0, FIONBIO, &async); X /* X ioctl (0, FIOASYNC, &async); X */ X ioctl (0, TIOCGETP, &ttym); X ttym.sg_flags &= ~RAW; X ttym.sg_flags |= ECHO; X ioctl (0, TIOCSETP, &ttym); X} X XNetWrite(buf, bytes, expectreply) Xubyte *buf; X{ X if (expectreply) X DidWrite = 1; X if (DDebug) X fprintf(stderr, "NETWRITE %08lx %ld\n", buf, bytes); X gwrite(0, buf, bytes); X} X Xgwrite(fd, buf, bytes) Xregister char *buf; Xregister long bytes; X{ X register long n; X while (bytes) { X n = write(fd, buf, bytes); X if (n > 0) { X bytes -= n; X buf += n; X continue; X } X if (errno == EINTR) X continue; X if (errno == EWOULDBLOCK) { X fd_set fd_wr; X fd_set fd_ex; X FD_ZERO(&fd_wr); X FD_ZERO(&fd_ex); X FD_SET(fd, &fd_wr); X FD_SET(fd, &fd_ex); X select(fd+1, NULL, &fd_wr, &fd_ex, NULL); X continue; X } X if (errno == EPIPE) X return; X dneterror("gwrite"); X } X} X SHAR_EOF echo "extracting dnet/internal.c" sed 's/^X//' << \SHAR_EOF > dnet/internal.c X X/* X * INTERNAL.C X * X * DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved X * X * Usually SCMD_OPEN requests attempt to connect() to the UNIX X * domain socket of the server. However, some 'ports' are designated X * as internal to DNET. They reside here. X * X * -IALPHATERM X */ X X#include "dnet.h" X#include "../server/servers.h" X#include X#include X#include X#include X#include X Xextern char *getenv(); X Xisinternalport(port) Xuword port; X{ X if (port == PORT_IALPHATERM) X return(1); X return(0); X} X Xiconnect(ps, port) Xint *ps; Xuword port; X{ X if (port == PORT_IALPHATERM) X return(ialphaterm_connect(ps, port)); X return(-1); X} X Xialphaterm_connect(pmaster) Xint *pmaster; X{ X struct sgttyb sg; X struct tchars tc; X struct ltchars ltc; X#ifdef TIOCGSIZE X struct ttysize ts; X#else X#ifdef TIOCGWINSZ X struct winsize ws; X#endif X#endif X int lmode; X int fdmaster; X int fdslave; X int pid; X char *slavename; X X ioctl(0, TIOCGETP, (char *)&sg); X ioctl(0, TIOCGETC, (char *)&tc); X ioctl(0, TIOCGLTC, (char *)<c); X ioctl(0, TIOCLGET, (char *)&lmode); X#ifdef TIOCGSIZE X ioctl(0, TIOCGSIZE, &ts); X#else X#ifdef TIOCGWINSZ X ioctl(0, TIOCGWINSZ, &ws); X#endif X#endif X X sg.sg_flags &= ~(RAW); X sg.sg_flags |= ECHO; X#ifdef TIOCGSIZE X ts.ts_lines = 23; X ts.ts_cols = 77; X#else X#ifdef TIOCGWINSZ X ws.ws_row = 23; X ws.ws_col = 77; X#endif X#endif X X if (DDebug) X fprintf(stderr, "PTY openning internal pty\n"); X if (openpty(&fdmaster, &fdslave, &slavename) >= 0) { X if (DDebug) X fprintf(stderr, "PTY open successfull\n"); X if ((pid = fork()) == NULL) { X int i; X setenv("DNET=", "IALPHATERM"); X setuid(getuid()); X signal(SIGHUP, SIG_DFL); X signal(SIGINT, SIG_DFL); X signal(SIGQUIT, SIG_DFL); X signal(SIGTERM, SIG_DFL); X signal(SIGCHLD, SIG_DFL); X signal(SIGTSTP, SIG_IGN); X ioctl(open("/dev/tty", 2), TIOCNOTTY, NULL); X close(open(slavename, 0)); X dup2(fdslave, 0); X dup2(0, 1); X dup2(0, 2); X for (i = 3; i < 256; ++i) X close(i); X ioctl(0, TIOCSETN, &sg); X ioctl(0, TIOCSETC, &tc); X ioctl(0, TIOCSLTC, <c); X ioctl(0, TIOCLSET, &lmode); X#ifdef TIOCSSIZE X ioctl(0, TIOCSSIZE, &ts); X#else X#ifdef TIOCSWINSZ X ioctl(0, TIOCSWINSZ, &ws); X#endif X#endif X { X char *shell = getenv("SHELL"); X char *home = getenv("HOME"); X if (!shell) X shell = "/bin/sh"; X if (!home) X home = "."; X chdir(home); X execl(shell, "-fshell", NULL); X perror(shell); X } X _exit(1); X } X if (pid > 0) { X *pmaster = fdmaster; X close(fdslave); X if (DDebug) X fprintf(stderr, "PTY OPEN OK.2\n"); X return(1); X } X close(fdmaster); X close(fdslave); X if (DDebug) X fprintf(stderr, "PTY OPEN FAILURE.1\n"); X } X if (DDebug) X fprintf(stderr, "PTY OPEN FAILURE.2\n"); X return(-1); X} X Xopenpty(pfdm, pfds, pnames) Xint *pfdm; Xint *pfds; Xchar **pnames; X{ X static char ptcs[] = { "0123456789abcdef" }; X static char plate[] = { "/dev/ptyxx" }; X struct stat stat; X int i; X int j; X X for (i = 'p';; ++i) { X plate[8] = i; X plate[9] = ptcs[0]; X if (lstat(plate, &stat) < 0) X break; X for (j = 0; ptcs[j]; ++j) { X plate[9] = ptcs[j]; X plate[5] = 'p'; X if ((*pfdm = open(plate, O_RDWR)) >= 0) { X plate[5] = 't'; X if ((*pfds = open(plate, O_RDWR)) >= 0) { X *pnames = plate; X if (DDebug) X fprintf(stderr, "PTY FOUND %s\n", *pnames); X return(1); X } X close(*pfdm); X } X } X } X return(-1); X} X Xisetrows(fd, rows) X{ X#ifdef TIOCSSIZE X struct ttysize ts; X if (ioctl(fd, TIOCGSIZE, &ts) >= 0) { X ts.ts_lines = rows; X ioctl(fd, TIOCSSIZE, &ts); X } X#else X#ifdef TIOCSWINSZ X struct winsize ws; X if (ioctl(fd, TIOCGWINSZ, &ws) >= 0) { X ws.ws_row = rows; X ioctl(fd, TIOCSWINSZ, &ws); X } X#endif X#endif X} X Xisetcols(fd, cols) X{ X#ifdef TIOCSSIZE X struct ttysize ts; X if (ioctl(fd, TIOCGSIZE, &ts) >= 0) { X ts.ts_cols = cols; X ioctl(fd, TIOCSSIZE, &ts); X } X#else X#ifdef TIOCSWINSZ X struct winsize ws; X if (ioctl(fd, TIOCSWINSZ, &ws) >= 0) { X ws.ws_col = cols; X ioctl(fd, TIOCSWINSZ, &ws); X } X#endif X#endif X} X SHAR_EOF echo "extracting dnet/globals.c" sed 's/^X//' << \SHAR_EOF > dnet/globals.c X X/* X * GLOBALS.C X * X * DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved X */ X X#include "dnet.h" X Xint Enable_Abort; X Xlong USecPerByte = 1000;/* for 9600 baud.. should really set properly */ Xint DNet_fd = -1; /* Master listen socket */ XPKT Pkts[9]; /* data buffers for packets */ XPKT *Raux = Pkts+8; /* next packet in */ Xubyte WCBuf[64]; XPKT *RPak[4] = { Pkts+0,Pkts+1,Pkts+2,Pkts+3 }; XPKT *WPak[4] = { Pkts+4,Pkts+5,Pkts+6,Pkts+7 }; XCHAN Chan[MAXCHAN]; /* Channels */ XLIST TxList; /* For pending SCMD_DATA reqs. */ Xfd_set Fdread; Xfd_set Fdwrite; Xfd_set Fdexcept; Xvoid (*Fdstate[FD_SETSIZE])(); Xubyte Fdperm[FD_SETSIZE]; Xuword FdChan[FD_SETSIZE]; Xubyte RcvBuf[RCVBUF]; Xuword RcvData; Xuword RExpect; Xubyte RTimedout; Xubyte WTimedout; Xuword WChan; /* Read and Write channels */ Xuword RChan; Xuword RPStart; Xuword WPStart; Xuword WPUsed; Xuword RState; Xuword Rto_act, Wto_act; Xubyte DDebug; Xubyte DidWrite; Xubyte Restart; Xubyte DeldQuit; Xulong NumCon; X X SHAR_EOF echo "extracting dnet/files.c" sed 's/^X//' << \SHAR_EOF > dnet/files.c X X/* X * FILES.C X * X * DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved X * X * handles actions on a per file descriptor basis, including accepting X * new connections, closing old connections, and transfering data X * between connections. X */ X X#include "dnet.h" X Xextern void do_localopen(), do_connect(), do_open1(), do_openwait(), do_open(); X X/* X * new connection over master port... open request. read two byte port X * number, allocate a channel, and send off to the remote X */ X Xvoid Xdo_localopen(n, fd) X{ X struct sockaddr sa; X int addrlen = sizeof(sa); X int s; X uword chan; X X if (DDebug) X fprintf(stderr, "DO_LOCALOPEN %ld %ld\n", n, fd); X while ((s = accept(fd, &sa, &addrlen)) >= 0) { X chan = alloc_channel(); X fcntl(s, F_SETFL, FNDELAY); X if (DDebug) X fprintf(stderr, " ACCEPT: %ld on channel %ld ", s, chan); X if (chan == 0xFFFF) { X ubyte error = 1; X gwrite(s, &error, 1); X close(s); X if (DDebug) X fprintf(stderr, "(no channels)\n"); X continue; X } X Fdstate[s] = do_open1; X FdChan[s] = chan; X FD_SET(s, &Fdread); X FD_SET(s, &Fdexcept); X Chan[chan].fd = s; X Chan[chan].state = CHAN_LOPEN; X if (DDebug) X fprintf(stderr, "(State = CHAN_LOPEN)\n"); X } X} X Xvoid Xdo_open1(n, fd) X{ X uword port; X char trxpri[2]; X uword chan = FdChan[fd]; X COPEN co; X int n; X X if (DDebug) X fprintf(stderr, "DO_OPEN %ld %ld on channel %ld ", n, fd, chan); X for (;;) { X n = read(fd, &port, 2); X if (n < 0) { X if (errno == EINTR) X continue; X if (errno == EWOULDBLOCK) X return; X } X read(fd, trxpri, 2); X if (n != 2) X dneterror("do_open1: unable to read 2 bytes"); X break; X } X if (DDebug) X fprintf(stderr, "Port %ld\n", port); X co.chanh = chan >> 8; X co.chanl = chan; X co.porth = port >> 8; X co.portl = port; X co.error = 0; X co.pri = trxpri[1]; X Chan[chan].port = port; X Chan[chan].pri = 126; X WriteStream(SCMD_OPEN, &co, sizeof(co), chan); X Chan[chan].pri = trxpri[0]; X Fdstate[fd] = do_openwait; X if (DDebug) X fprintf(stderr, " Newstate = openwait\n"); X} X Xvoid Xdo_openwait(n, fd) X{ X ubyte buf[32]; X if (DDebug) X fprintf(stderr, "************ ERROR DO_OPENWAIT %ld %ld\n", n, fd); X n = read(fd, buf, 32); X if (DDebug) { X fprintf(stderr, " OPENWAIT, READ %ld bytes\n", n); X if (n < 0) X perror("openwait:read"); X } X} X Xvoid Xdo_open(nn, fd) X{ X extern void nop(); X char buf[256]; X uword chan = FdChan[fd]; X int n; X X n = read(fd, buf, sizeof(buf)); X if (DDebug) { X fprintf(stderr, "DO_OPEN %ld %ld, RECEIVE DATA on chan %ld (%ld by)\n", X nn, fd, chan, n); X fprintf(stderr, " fd, chanfd %ld %ld\n", fd, Chan[chan].fd); X if (n < 0) X perror("open:read"); X } X if (n == 0 || nn == 2) { /* application closed / exception cond */ X CCLOSE cc; X X if (DDebug) X fprintf(stderr, " DO_OPEN: REMOTE EOF, channel %d\n", chan); X X cc.chanh = chan >> 8; X cc.chanl = chan; X WriteStream(SCMD_CLOSE, &cc, sizeof(CCLOSE), chan); X Chan[chan].state = CHAN_CLOSE; X Chan[chan].flags |= CHANF_LCLOSE; X if (Chan[chan].flags & CHANF_RCLOSE) { X ; X /* should never happen X int fd = Chan[chan].fd; X Chan[chan].state = CHAN_FREE; X Chan[chan].fd = -1; X Fdstate[fd] = nop; X FD_CLR(fd, &Fdread); X FD_CLR(fd, &Fdexcept); X close(fd); X */ X } else { X FD_CLR(fd, &Fdread); X FD_CLR(fd, &Fdexcept); X } X } X if (n > 0) { X WriteStream(SCMD_DATA, buf, n, chan); X } X} X SHAR_EOF echo "extracting dnet/dnet.h" sed 's/^X//' << \SHAR_EOF > dnet/dnet.h X X/* X * DNET.H X * X * DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved X */ X X#include X#include X#include X#include X#include X X/* V2.01 */ X#include X#include X X#include X#include X#include X#ifndef FD_SETSIZE X#define FD_SETSIZE (sizeof(struct fd_set) * 8) X#endif X#ifndef NFDBITS X#define NFDBITS 32 X#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) X#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) X#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) X#define FD_ZERO(p) bzero((char *)(p), sizeof(*(p))) X#endif X#ifndef sigmask X#define sigmask(m) (1 << ((m)-1)) X#endif X X#ifndef LASTTRYDNETSERVERS X#define LASTTRYDNETSERVERS "/usr/local/lib/dnet/dnet.servers" X#endif X Xstruct Node { X struct Node *ln_Succ; X struct Node *ln_Pred; X}; X Xstruct List { X struct Node *lh_Head; X struct Node *lh_Tail; X struct Node *lh_TailPred; X}; X X Xtypedef unsigned char ubyte; Xtypedef unsigned short uword; Xtypedef unsigned long ulong; X Xtypedef struct List LIST; Xtypedef struct Node NODE; X X#include "channel.h" X X#define PKT struct _PKT X#define XIOR struct _XIOR X X#define EMPTY 0 /* empty (sent) */ X#define READY 1 /* data ready (not sent yet) */ X#define RCVBUF 4096 X X#define MAXCHAN 128 /* Max # of channels supported */ X#define SYNC 0xFF /* SYNC character */ X#define WTIME 2000000 /* in micro seconds (expect ack) */ X#define RTIME 1000000 /* in micro seconds (read to) */ X#define MAXPKT 200 /* maximum packet size (data area) */ X#define MINPKT 32 /* minimum packet size (data area) for purposes */ X /* of determining the dynamic maximum packet size*/ X /* only. Actual minimum is, of course, 1 byte */ X X#define OVERHEAD 7 /* for packets with data */ X XXIOR { X NODE io_Node; X ubyte *io_Data; X ulong io_Length; X ulong io_Actual; X uword io_Channel; X ubyte io_Command; X ubyte io_Error; X char io_Pri; X}; X XPKT { X uword iolength; /* send: length of packet, recv: length of data */ X ubyte state; /* EMPTY, READY */ X X ubyte sync; /* THE PACKET */ X ubyte ctl; X ubyte cchk; X ubyte lenh; X ubyte lenl; X ubyte data[MAXPKT+2]; X}; X X /* X * In receiving a packet the receiver can be in one of these X * states. X */ X X#define RS_SYNC 0 /* Waiting for sync */ X#define RS_CTL 1 /* Waiting for command */ X#define RS_CCHK 2 /* Waiting for check byte */ X#define RS_LEN1 3 /* Waiting for MSB length byte */ X#define RS_LEN2 4 /* Waiting for LSB length byte */ X#define RS_DATA 5 /* Waiting for data & checksum */ X X /* X * The low level protocol generates packets. This is used X * for error checking, data sequencing, retries, restart, etc... X * The packet format is: X * X * SYNC sss0xccc CHK X * SYNC sss1xccc CHK nnnnnnnn nnnnnnnn [DATA] CHK2 X * msb lsb X * X * sss = sequence # X * B4 = packet contains data X * B3 = reserved (may be used to extend the command set) X * ccc = PKF_????? X * X * NOTE that the data length nnn..nn is not checked with either X * CHK or CHK2 . The protocol will determine if the length X * is reasonable (< MAXPKT) and then try to read that many X * bytes. The CHK will obviously fail if the length was X * incorrect. X */ X X#define PKF_SEQUENCE 0xE0 /* Sequence # */ X#define PKF_DATA 0x10 /* 1-65535 bytes */ X#define PKF_RESERVED 0x08 /* reserved bit */ X#define PKF_MASK 0x07 /* command mask */ X X#define PKCMD_WRITE 1 /* A DATA packet */ X#define PKCMD_CHECK 2 /* Request ACK or NAK for win */ X#define PKCMD_ACK 3 /* ACK a window */ X#define PKCMD_NAK 4 /* NAK a window */ X#define PKCMD_RESTART 5 /* RESTART dnet. (new) */ X#define PKCMD_ACKRSTART 6 /* ACK a restart (new) */ X#define PKCMD_RESERVE3 7 X X /* X * All channel multiplexing, channel commands, etc... is encoded X * within a PKCMD_WRITE packet. X * X * Channel commands are characterized by a one byte control X * field and up to 7 bytes of data. The control field format X * is: 10cccnnn [DATA] ccc = SCMD_?? X * nnn = # additional data bytes X */ X X#define SCMD_SWITCH 0x00 /* switch active channel # */ X#define SCMD_OPEN 0x01 /* open a channel */ X#define SCMD_CLOSE 0x02 /* close a channel */ X#define SCMD_ACKCMD 0x03 /* ack an open/close request */ X#define SCMD_EOFCMD 0x04 /* Reof or Weof */ X#define SCMD_QUIT 0x05 /* QUIT dnet */ X#define SCMD_IOCTL 0x06 /* channel ioctl (new),PTY sup */ X#define SCMD_RESERVE1 0x07 X X /* X * Stream data is characterized by the following format: X * X * msb lsb X * 11nnnnnn nnnnnnnn [128-16383 bytes DATA] X * 0nnnnnnn [0-127 bytes DATA] X * X * NOTE: 11000000 0ccccccc nnnnnnnn reserved for furture ext. of X * SCMD commands. X */ X X#define SCMD_DATA 0x08 /* stream command, DATA (dummy ID) */ X X /* X * Each channel can be in one of several states. X */ X X#define CHAN_FREE 0x01 /* free channel */ X#define CHAN_ROPEN 0x02 /* remote open, wait port msg */ X#define CHAN_LOPEN 0x03 /* local open, wait reply */ X#define CHAN_OPEN 0x04 /* channel open */ X#define CHAN_CLOSE 0x05 /* one side of channel closed */ X X#define CHANF_ROK 0x01 /* remote hasn't EOF'd us yet */ X#define CHANF_WOK 0x02 /* remote will accept data */ X#define CHANF_LCLOSE 0x04 /* channel closed on our side */ X#define CHANF_RCLOSE 0x08 /* channel closed on rem side */ X Xextern ubyte *RemHead(); Xextern ubyte *malloc(); Xextern char *getenv(); X X#ifndef NOEXT Xextern long USecPerByte; Xextern int DNet_fd; Xextern PKT Pkts[9]; Xextern ubyte WCBuf[64]; Xextern PKT *RPak[4]; Xextern PKT *WPak[4]; Xextern CHAN Chan[MAXCHAN]; Xextern LIST TxList; /* For pending DNCMD_WRITE reqs. */ Xextern fd_set Fdread; Xextern fd_set Fdwrite; Xextern fd_set Fdexcept; Xextern void (*Fdstate[FD_SETSIZE])(); Xextern ubyte Fdperm[FD_SETSIZE]; Xextern uword FdChan[FD_SETSIZE]; Xextern ubyte RcvBuf[RCVBUF]; Xextern ubyte RTimedout, WTimedout; Xextern uword Rto_act, Wto_act; Xextern uword RcvData; Xextern uword RExpect; Xextern uword RChan; Xextern uword WChan; Xextern uword RPStart; Xextern uword WPStart; Xextern uword WPUsed; Xextern uword RState; Xextern ubyte DDebug; Xextern ubyte DidWrite; Xextern ubyte Restart; Xextern ubyte DeldQuit; Xextern ulong NumCon; X Xextern int errno; X X#endif X SHAR_EOF echo "extracting dnet/dnet.c" sed 's/^X//' << \SHAR_EOF > dnet/dnet.c X X/* X * DNET.C X * X * DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved X * X * Handles action on all active file descriptors and dispatches X * to the proper function in FILES.C X * X */ X X#include "dnet.h" X#include X#include X Xhandle_child() X{ X union wait stat; X struct rusage rus; X while (wait3(&stat, WNOHANG, &rus) > 0); X} X Xchar * Xshowselect(ptr) Xfd_set *ptr; X{ X static char buf[FD_SETSIZE+32]; X short i; X X for (i = 0; i < FD_SETSIZE; ++i) { X buf[i] = (FD_ISSET(i, ptr)) ? '1' : '0'; X } X buf[i] = 0; X return(buf); X} X X Xloganddie() X{ X fflush(stderr); X fprintf(stderr, "\nHUPSIGNAL\n"); X perror("HUP, last error:"); X fprintf(stderr, "Last select return:\n"); X fprintf(stderr, " %s\n", showselect(&Fdread)); X fprintf(stderr, " %s\n", showselect(&Fdwrite)); X fprintf(stderr, " %s\n", showselect(&Fdexcept)); X fprintf(stderr, "RcvData = %ld\n", RcvData); X fprintf(stderr, "RChan/WChan = %ld/%ld\n", RChan, WChan); X fprintf(stderr, "RPStart = %ld\n", RPStart); X fprintf(stderr, "WPStart = %ld\n", WPStart); X fprintf(stderr, "WPUsed = %ld\n", WPUsed); X fprintf(stderr, "RState = %ld\n", RState); X fflush(stderr); X kill(0, SIGILL); X exit(1); X} X X#define SASIZE(sa) (sizeof(sa)-sizeof((sa).sa_data)+strlen((sa).sa_data)) X Xmain(ac,av) Xchar *av[]; X{ X long sink_mask, dnet_mask; X long mark = 0; X ubyte notdone; X char local_dir[MAXPATHLEN]; X struct passwd pw_info; X extern void RcvInt(); X X if (getenv("DNETDIR")) { X strcpy(local_dir, getenv("DNETDIR")); X if (chdir(local_dir)) { X fprintf(stderr, "Unable to chdir to DNETDIR: %s\n", local_dir); X exit(1); X } X freopen("DNET.LOG", "w", stderr); X } else { X pw_info = *getpwuid(getuid()); X strcpy(local_dir, pw_info.pw_dir); X strcat(local_dir, "/.dnet"); X if (chdir(local_dir)) { X mkdir(local_dir, 0700); X if (chdir(local_dir)) { X fprintf(stderr, "Unable to create dir %s\n", local_dir); X exit(1); X } X } X freopen("DNET.LOG", "w", stderr); X } X fprintf(stderr, "DNet startup\n"); X fprintf(stderr, "Log file placed in %s\n", local_dir); X fflush(stderr); X X signal(SIGINT, SIG_IGN); X signal(SIGPIPE, SIG_IGN); X signal(SIGQUIT, SIG_IGN); X signal(SIGCHLD, handle_child); X signal(SIGHUP, loganddie); X X bzero(Pkts,sizeof(Pkts)); X setlistenport(""); X X { X register short i; X for (i = 1; i < ac; ++i) { X register char *ptr = av[i]; X if (*ptr != '-') { X DDebug = 1; X fprintf(stderr, "Debug mode on\n"); X continue; X } X switch(*ptr) { X case 'B': X USecPerByte = atoi(ptr+1) / 10; /* bytes per second */ X USecPerByte = 1000000 / USecPerByte; X fprintf(stderr, "Assuming about %ld uS/byte for timeout calc\n", X USecPerByte X ); X break; X default: X fprintf(stderr, "Unknown option: %c\n", *ptr); X printf("Unknown option: %c\n", *ptr); X exit(1); X } X } X } X X NewList(&TxList); X X Fdperm[0] = 1; X Fdstate[0] = RcvInt; X FD_SET(0, &Fdread); X FD_SET(0, &Fdexcept); X X fprintf(stderr, "DNET RUNNING, Listenfd=%ld\n", DNet_fd); X NetOpen(); /* initialize network and interrupt driven read */ X TimerOpen(); /* initialize timers */ X X do_netreset(); X do_restart(); X X notdone = 1; X while (notdone) { X /* X * MAIN LOOP. select() on all the file descriptors. Set the X * timeout to infinity (NULL) normally. However, if there is X * a pending read or write timeout, set the select timeout X * to 2 seconds in case they timeout before we call select(). X * (i.e. a timing window). OR, if we are in the middle of a X * read, don't use descriptor 0 and timeout according to X * the expected read length, then set the descriptor as ready. X */ X X fd_set fd_rd; X fd_set fd_wr; X fd_set fd_ex; X struct timeval tv, *ptv; X int err; X X fd_rd = Fdread; X fd_wr = Fdwrite; X fd_ex = Fdexcept; X X tv.tv_sec = 0; /* normally wait forever for an event */ X tv.tv_usec= 0; X ptv = NULL; X if ((Rto_act || Wto_act)) { /* unless timeout pending */ X ptv = &tv; X tv.tv_sec = 2; X } X X /* ... or expecting data (don't just wait for one byte). X * X * This is an attempt to reduce the CPU usage for the process. X * If we are expecting data over the serial line, then don't X * return from the select() even if data is available, but X * wait for the timeout period indicated before reading the X * data. Don't wait more than 64 byte times or we may loose X * some data (the silo's are only so big.. like 128 bytes). X * X * Currently, USecPerByte is not set properly (set for 9600 baud) X */ X X if (RExpect) { X ptv = &tv; X tv.tv_usec= USecPerByte * ((RExpect < 64) ? RExpect : 64); X tv.tv_sec = 0; X FD_CLR(0, &fd_rd); X } X err = select(FD_SETSIZE, &fd_rd, &fd_wr, &fd_ex, ptv); X if (RExpect) { X FD_SET(0, &fd_rd); /* pretend data ready */ X } X if (DDebug) X fprintf(stderr, "SERR %ld %ld %08lx %08lx\n", X err, errno, RExpect, ptv X ); X X if (RTimedout) { X RTimedout = 0; X do_rto(); X mark = 0; X } X if (WTimedout) { X WTimedout = 0; X do_wto(); X } X if (err < 0) { X if (errno == EBADF) { X perror("select"); X dneterror(NULL); X } X } else { X register short i; X register short j; X register long mask; X X for (i = 0; i < FD_SETSIZE/NFDBITS; ++i) { X if (mask = fd_ex.fds_bits[i]) { X for (j = i * NFDBITS; mask; (mask >>= 1),(++j)) { X if (mask & 1) X (*Fdstate[j])(2,j); X } X } X if (mask = fd_wr.fds_bits[i]) { X for (j = i * NFDBITS; mask; (mask >>= 1),(++j)) { X if (mask & 1) X (*Fdstate[j])(1,j); X } X } X if (mask = fd_rd.fds_bits[i]) { X for (j = i * NFDBITS; mask; (mask >>= 1),(++j)) { X if (mask & 1) X (*Fdstate[j])(0,j); X } X } X } X } X if (RcvData != mark) X mark = do_rnet(); X do_wupdate(); X do_wnet(); X } X dneterror(NULL); X} X Xvoid Xnop() X{ X} X Xdo_netreset() X{ X register short i; X register CHAN *ch; X for (i = 0; i < FD_SETSIZE; ++i) { X if (!Fdperm[i]) X Fdstate[i] = nop; X } X for (i = 0, ch = Chan; i < MAXCHAN; ++i, ++ch) { X switch(ch->state) { X case CHAN_OPEN: X case CHAN_LOPEN: /* pending on network */ X case CHAN_CLOSE: X if (ch->fd >= 0) { X FD_CLR(ch->fd, &Fdread); X FD_CLR(ch->fd, &Fdexcept); X Fdstate[ch->fd] = nop; X close(ch->fd); X ch->fd = -1; X ch->state = CHAN_FREE; X ch->flags = 0; X --NumCon; X } X ClearChan(&TxList, i, 1); X break; X } X } X RPStart = 0; X WPStart = 0; X WPUsed = 0; X RState = 0; X RChan = 0; X WChan = 0; X} X Xdo_restart() X{ X static ubyte buf[3] = { SYNC, PKCMD_RESTART, (SYNC<<1)^PKCMD_RESTART }; X Restart = 1; X NetWrite(buf, sizeof(buf), 1); X WTimeout(WTIME); X} X Xsetlistenport(remotehost) Xchar *remotehost; X{ X static struct sockaddr sa[2]; X int s; X extern void do_localopen(); X X if (DNet_fd >= 0) { X unlink(sa[0].sa_data); X Fdstate[DNet_fd] = nop; X Fdperm[DNet_fd] = 0; X FD_CLR(DNet_fd, &Fdread); X FD_CLR(DNet_fd, &Fdexcept); X close(DNet_fd); X } X setenv("DNETHOST=", remotehost); X sprintf(sa[0].sa_data, "DNET.%s", remotehost); X unlink(sa[0].sa_data); X sa[0].sa_family = AF_UNIX; X X s = socket(PF_UNIX, SOCK_STREAM, 0); X fcntl(s, F_SETOWN, getpid()); X fcntl(s, F_SETFL, FNDELAY); X if (bind(s, &sa[0], SASIZE(sa[0])) < 0) { X perror("bind"); X exit(1); X } X if (listen(s, 5) < 0) { X unlink(sa[0].sa_data); X perror("listen"); X exit(1); X } X DNet_fd = s; X Fdstate[DNet_fd] = do_localopen; X Fdperm[DNet_fd] = 1; X FD_SET(DNet_fd, &Fdread); X FD_SET(DNet_fd, &Fdexcept); X} X SHAR_EOF echo "extracting dnet/Makefile" sed 's/^X//' << \SHAR_EOF > dnet/Makefile X X# THE DNET DRIVER, UNIX END X# X# DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved X# X# the BIN should be placed in your path for ease of use. DNET uses X# UNIX level sockets allowing multiple users on a system to run it X# independantly. You should make a special directory (Example: .DNET) X# and then setenv DNETDIR ~/.DNET/ ... all clients and servers will X# use the enviroment variable to find/create the UNIX level sockets. X XBIN = ../bin XOBJS = dnet.o control.o files.o globals.o net.o subs.o internal.o X X X$(BIN)/dnet: $(OBJS) X cc $(OBJS) -o $(BIN)/dnet X Xclean: X rm -f *.o make.out X SHAR_EOF echo "extracting dnet/MODS" sed 's/^X//' << \SHAR_EOF > dnet/MODS X Xnet.c: notion of reply expected added to NetWrite() Xdnet.c: select modified. On error still attempt write ops X SHAR_EOF echo "extracting dnet.servers" sed 's/^X//' << \SHAR_EOF > dnet.servers X X8192 ~/src/dnet.unix/bin/scopy ~ X8193 ~/src/dnet.unix/bin/sshell ~ X8197 ~/src/dnet.unix/bin/sloadav ~ X8201 ~/src/dnet.unix/bin/sgcopy ~ X SHAR_EOF if `test ! -d doc` then mkdir doc echo "mkdir doc" fi echo "extracting doc/history" sed 's/^X//' << \SHAR_EOF > doc/history X X V1.00 sometime in 1987 X First release X X V1.20 sometime in 1988 X Fixes to the first release X X V2.00 1 March 1989 X X Major fixes, additions, and other items. X X X SHAR_EOF echo "extracting doc/dnet.doc" sed 's/^X//' << \SHAR_EOF > doc/dnet.doc X XUNIX/DNET X X DNET [debug] X X Run the DNET protocol on descriptor 0. If the enviroment variable X DNETDIR exists, DNET will create the rendezvous sockets in the X specified directory (DNETDIR must have a hanging slash on it), X otherwise the current directory is used. X X DNET also opens a log file (DNET.LOG) in the directory. If the debug X option is given, DNET writes gobs of debugging information to the log. X X Descriptor 0 may be a tty or socket. X X To allow DNET to startup servers on demand, the file "dnet.servers" X must exist in the rendezvous directory. X X -Matt X SHAR_EOF echo "extracting doc/putfiles.doc" sed 's/^X//' << \SHAR_EOF > doc/putfiles.doc XUNIX/PUTFILES XAMIGA/PUTFILES X X PUTFILES [-dDESTDIR] file/dir file/dir file/dir .. X X File transfer client. Transfer the specified files and or directories X to the destination directory on the remote machine. For instance: X X unix: putfiles -dram: charlie.txt /usr/include X X *places the file charlie.txt as ram:charlie.txt, and places the X directory structure /usr/include as ram:include/(whatever). X X The default destination directory depends on the remote host. If the X destination is an Amiga, the default is DF0: (so you probably always X want to specify a -d switch). On the UNIX end, the default is whatever X is set in the file dnet.servers X X Currently, no file compression is done. I also hope to add X semi-automatic crash recovery (continue download where you left off X after a crash), though it should be noted that it is very difficult X to crash DNET with random modem noise. X SHAR_EOF echo "extracting doc/dsoc.doc" sed 's/^X//' << \SHAR_EOF > doc/dsoc.doc X X XUNIX/DSOC X X XDSOC [port#] X X (default: 8196 = AMIGSHELL (CLI window)) X X Connect to the remote port but keep the TTY in COOKED mode (normal). X The connection will be terminated by killing the process on the UNIX X end or typing ^C. NOTE THAT ^C KILLS DSOC AND IS NOT SENT THROUGH TO X THE REMOTE CLI. X X The default port accesses the SCLI server on the Amiga end, which X starts up a CLI. Things work properly only if *MY* PIPE: device is X installed on the Amiga. Things close down properly only if you X have a CLI prompt when you exit DSOC. X X The SCLI server currently handles only one connection at a time. X SHAR_EOF echo "extracting doc/dnetlib.doc" sed 's/^X//' << \SHAR_EOF > doc/dnetlib.doc X XUNIX/DNETLIB X X UNIX END DNET LIBRARY INTERFACE X X See the server source for good examples of usage. X Xlong private; Xuword port Xchar *buf; Xint fd; Xint res1..5, bytes Xchar pri; Xlong val68, valvax; X Xprivate = DListen(port) listen on a port (server) X fd = DAccept(private) accept a connection (server) X DNAAccept(private) don't accept a conn.(server) X fd = DOpen(host, port, txpri, rxpri) open a remote connection (client) X res1 = read(fd, buf, bytes) standard unix read() X res2 = gread(fd, buf, bytes) (see below) X res3 = ggread(fd, buf, bytes) (see below) X res4 = write(fd, buf, bytes) standard unix write() X res5 = gwrite(fd, buf, bytes) (see below) X close(fd); X X val68 = ntohl68(valvax) convert to and from MC68000 longword format. X valvax= htonl68(val68) X X XDListen() sets up a UNIX domain socket in the current directory unless X another is specified by the DNETDIR enviroment variable. X Returns a private structure pointer or NULL on error. X X This call will override any existing server for the port in X the directory permanently. It does not cause an existing X server to exit, however, and you should be careful to kill X old servers before starting new ones. See the source for a X template of correct server code. X XDAccept() Accepts a new connection on the port. Returns a file X descriptor or a negative value. This call will block. X XDOpen() Attempt to connect to a port on the remote machine. Returns X a file descriptor or a negative value. The error is either X due to not finding DNET's master port (DNET must be running), X or the remote server not running. X X This call looks in the current directory for the master X socket unless another is specified by the DNETDIR enviroment X variable. X X Two priorities are specified. One for sending, and one for X receiving data. A priority is a value -127 to 126 inclusive, X with 126 the highest priority. Normally, priorities range X from -80 (file transfers) to +20 (terminal window). X XDEof() Send an EOF without closing the connection. Currently doesn't X work worth shit, so don't use it. X Xwrite() Standard UNIX write call. But we are dealing with a socket X here, so one must be careful of the return value. (1) WRITE() X may not return the # bytes requested to write, but less, X (2) WRITE() may return a negative value indicating an error or X that it was interrupted or that it would have blocked (if you X have got non-blocking IO setup). (3) WRITE() returns 0 on X socket EOF. X Xgwrite() This call will write all the bytes specified, whether the X socket is non-blocking or not. It handles restarting the X WRITE() call on EINTR and properly handles EWOULDBLOCK. X X It returns the number bytes requested or fewer on error. If X fewer bytes are returned you should close the socket and exit. X Xread() Standard UNIX read call. But we are still dealing with a X socket here and anything might happen. READ() can return fewer X than the number of bytes requested, 0 on EOF, or a negative X number indicating various errors. X Xgread() GREAD() handles retrying if the EINTR error occurs. GREAD() X blocks until at least one character is received (or EOF), and X does this even if the socket is marked non-blocking. GREAD() X returns 0 on EOF/ERROR. X Xggread() GGREAD() not only retries on EINTR, but will block until ALL X the requested bytes are read in, even if the socket is marked X non-blocking. GGREAD() returns -1 on EOF/ERROR. You can also X tell if an EOF/ERROR occured if fewer than the requested X number of bytes are read. X SHAR_EOF echo "extracting doc/draw.doc" sed 's/^X//' << \SHAR_EOF > doc/draw.doc X XUNIX/DRAW X X XDRAW [port#] X X (default: 8195 = AMIGTERM (talk window)) X X Connect to the remote port and place the TTY in RAW mode. The X connection can only be terminated by the remote end, or by killing X the process on the UNIX end. X X The default port brings up a 'talk' window on the Amiga. AMIGATERM X will recognize a ^C sent from DRAW and close the connection. X SHAR_EOF if `test ! -d lib` then mkdir lib echo "mkdir lib" fi echo "extracting lib/dnetlib.h" sed 's/^X//' << \SHAR_EOF > lib/dnetlib.h X X#define EFATAL 0 X#define EWARN 1 X#define EDEBUG 2 X SHAR_EOF echo "extracting lib/dnetlib.c" sed 's/^X//' << \SHAR_EOF > lib/dnetlib.c X X/* X * DNETLIB.C X * X * DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved X * X * Library Interface for DNET. X */ X X#include X#include X#include X#include X#include X#include X#ifdef O_CREAT X#include X#endif X#include "../lib/dnetlib.h" X Xextern char *getenv(); X Xtypedef unsigned short uword; Xtypedef unsigned long ulong; Xtypedef unsigned char ubyte; Xtypedef struct sockaddr SOCKADDR; X Xtypedef struct { X int s; X uword port; X} CHANN; X X#define NAMELEN sizeof(".PORT.XXXXX") X#define NAMEPAT "%s.PORT.%ld" X Xchar *getdirpart(); X XCHANN * XDListen(port) Xuword port; X{ X CHANN *chan; X int s; X SOCKADDR *sa = (SOCKADDR *)malloc(sizeof(SOCKADDR)+256); X char *dirstr = getenv("DNETDIR") ? getenv("DNETDIR") : ""; X X sprintf(sa->sa_data, NAMEPAT, dirstr, port); X sa->sa_family = AF_UNIX; X unlink(sa->sa_data); X X s = socket(PF_UNIX, SOCK_STREAM, 0); X fcntl(s, F_SETOWN, getpid()); X if (bind(s, sa, sizeof(*sa)-sizeof(sa->sa_data)+strlen(sa->sa_data)) < 0) { X close(s); X free(sa); X return(NULL); X } X if (listen(s, 5) < 0) { X close(s); X unlink(sa->sa_data); X free(sa); X return(NULL); X } X chan = (CHANN *)malloc(sizeof(CHANN)); X chan->s = s; X chan->port = port; X free(sa); X return(chan); X} X X XDUnListen(chan) XCHANN *chan; X{ X char *dirstr = getenv("DNETDIR") ? getenv("DNETDIR") : ""; X char buf[32]; X X close(chan->s); X sprintf(buf, NAMEPAT, dirstr, chan->port); X unlink(buf); X free(chan); X} X XDAccept(chan) XCHANN *chan; X{ X SOCKADDR sa; X int addrlen = sizeof(sa); X int fd; X X fd = accept(chan->s, &sa, &addrlen); X return(fd); X} X XDOpen(host, port, txpri, rxpri) Xchar *host; Xuword port; Xchar txpri, rxpri; X{ X int s; X char rc; X short xb[3]; X SOCKADDR *sa = (SOCKADDR *)malloc(sizeof(SOCKADDR)+256); X char *dirstr = getenv("DNETDIR") ? getenv("DNETDIR") : ""; X X if (rxpri < -127) X rxpri = -127; X if (rxpri > 126) X rxpri = 126; X if (txpri < -127) X txpri = -127; X if (txpri > 126) X txpri = 126; X X if (host == NULL) X host = (getenv("DNETHOST")) ? getenv("DNETHOST"):""; X X sa->sa_family = AF_INET; X sprintf(sa->sa_data, "%s%s%s", dirstr, "DNET.", host); X X s = socket(PF_UNIX, SOCK_STREAM, 0); X fcntl(s, F_SETOWN, getpid()); X if (connect(s, sa, sizeof(*sa)-sizeof(sa->sa_data)+ X strlen(sa->sa_data))<0) { X close(s); X free(sa); X return(-1); X } X free(sa); X xb[0] = port; X ((char *)&xb[1])[0] = txpri; X ((char *)&xb[1])[1] = rxpri; X write(s, xb, 4); X if (read(s, &rc, 1) == 1 && rc == 0) X return(s); X close(s); X return(-1); X} X XDEof(fd) X{ X char dummy; X X shutdown(fd, 1); X write(fd, &dummy, 0); X} X Xgwrite(fd, buf, bytes) Xchar *buf; X{ X int n; X int orig = bytes; X extern int errno; X while (bytes) { X n = write(fd, buf, bytes); X if (n > 0) { X bytes -= n; X buf += n; X continue; X } X if (n < 0) { X if (errno == EINTR) X continue; X if (errno == EWOULDBLOCK) { X int wm = 1 << fd; X int em = 1 << fd; X if (select(fd+1, NULL, &wm, &em, NULL) < 0) X continue; X if (wm) X continue; X } X return(orig - bytes); X } X } X return(orig); X} X Xgread(fd, buf, bytes) Xchar *buf; X{ X int n; X int orig = bytes; X extern int errno; X while (bytes) { X n = read(fd, buf, bytes); X if (n > 0) { X bytes -= n; X buf += n; X break; X } X if (n < 0) { X if (errno == EINTR) X continue; X if (errno == EWOULDBLOCK) { X int rm = 1 << fd; X int em = 1 << fd; X if (select(fd+1, &rm, NULL, &em, NULL) < 0) X continue; X if (rm) X continue; X } X return(orig - bytes); X } X if (n == 0) X break; X } X return(orig - bytes); X} X Xggread(fd, buf, bytes) Xchar *buf; X{ X int n; X int ttl = 0; X while (bytes) { X n = gread(fd, buf, bytes); X if (n > 0) { X bytes -= n; X buf += n; X ttl += n; X continue; X } X return(-1); X } X return(ttl); X} X X/* X * Convert to and from 68000 longword format. Of course, it really X * doesn't matter what format you use, just as long as it is defined. X */ X Xntohl68(n) Xulong n; X{ X return( X (((ubyte *)&n)[0] << 24)| X (((ubyte *)&n)[1] << 16)| X (((ubyte *)&n)[2] << 8)| X (((ubyte *)&n)[3]) X ); X} X Xhtonl68(n) Xulong n; X{ X ulong v; X ((ubyte *)&v)[0] = n >> 24; X ((ubyte *)&v)[1] = n >> 16; X ((ubyte *)&v)[2] = n >> 8; X ((ubyte *)&v)[3] = n; X return(v); X} X X XDoOption(ac, av, ops, args) Xshort ac; Xchar *av[]; Xchar *ops; Xlong args; X{ X register short i; X short j; X X for (i = j = 1; i < ac; ++i) { X register char *ptr = av[i]; X if (*ptr != '-') { X av[j++] = av[i]; X continue; X } X while (*++ptr) { X register char *op; X long **ap = (long **)&args; X short isshort; X X for (op = ops; *op && *op != *ptr;) { X if (*op == *ptr) X break; X if (*++op == '%') { X while (*op && *op != 's' && *op != 'd') X ++op; X if (*op) X ++op; X } X if (*op == ',') /* optional , */ X ++op; X ++ap; X } X if (*op == 0) X return(-1); X if (op[1] != '%') { X *(short *)*ap = 1; X ++ap; X continue; X } X op += 2; X isshort = 1; X while (*op && *op != 's' && *op != 'd') { X switch(*op) { X case 'h': X isshort = 1; X break; X case 'l': X isshort = 0; X break; X default: X return(-1); X } X ++op; X } X switch(*op) { X case 's': X if (ptr[1]) { X *(char **)*ap = ptr + 1; X ptr = "\0"; X } else { X *(char **)*ap = av[++i]; X } X break; X case 'd': X if (isshort) X *(short *)*ap = atoi(++ptr); X else X *(long *)*ap = atoi(++ptr); X while (*ptr >= '0' && *ptr <= '9') X ++ptr; X break; X default: X return(-1); X } X } X } X return(j); X} X Xelog(how, ctl, arg) Xchar *ctl; Xlong arg; X{ X char *dir = getenv("DNETDIR"); X FILE *fi; X char buf[256]; X long dtime; X X time(&dtime); X X if (!dir) X dir = ""; X sprintf(buf, "%s%s", dir, "DNET.LOG"); X if (fi = fopen(buf, "a")) { X strcpy(buf, ctime(&dtime)); X buf[strlen(buf)-1] = 0; X fprintf(fi, "%s ", buf); X fprintf(fi, ctl, arg); X putc('\n', fi); X fclose(fi); X } X if (how == EFATAL) X exit(1); X} X SHAR_EOF echo "extracting lib/Makefile" sed 's/^X//' << \SHAR_EOF > lib/Makefile X X Xdnetlib.o : dnetlib.c X cc -c dnetlib.c X SHAR_EOF if `test ! -d server` then mkdir server echo "mkdir server" fi echo "extracting server/sgcopy.c" sed 's/^X//' << \SHAR_EOF > server/sgcopy.c X X/* X * SGCOPY.C V1.1 X * X * DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved. X * X * GET-COPY SERVER (NEW COPY SERVER) X * X * The current version only accepts one connection at a time. This server X * will send requested files to the remote machine. X * X * length in 68000 longword format. X */ X X#include X#include X#include X#include X#include X#include X#include X#include X#include X#include X X#include "servers.h" X Xtypedef struct { X char Cmd; X char Str[64]; X long Val; X} HDR; X Xtypedef unsigned char ubyte; Xchar *getnamepart(); Xchar *getdirpart(); X Xchar Buf[4096]; Xint Chan; X Xchandler() X{ X union wait stat; X struct rusage rus; X while (wait3(&stat, WNOHANG, &rus) > 0); X} X Xmain(ac,av) Xchar *av[]; X{ X long chann = DListen(PORT_GFILECOPY); X int fd; X int n; X char buf[256]; X extern int errno; X X if (av[1]) X chdir(av[1]); X signal(SIGCHLD, chandler); X signal(SIGPIPE, SIG_IGN); X for (;;) { X fd = DAccept(chann); X if (fd < 0) { X if (errno == EINTR) X continue; X break; X } X if (fork() == NULL) { X SGCopy(fd); X _exit(1); X } X close(fd); X } X perror("SCOPY"); X} X XSGCopy(fd) Xint fd; X{ X short error = 0; X static HDR Hdr; X X Chan = fd; X error = WriteHeader('H', "Hello, GCopy server V1.30", 0); X if (error) X return(error); X switch(ReadHeader(&Hdr)) { X default: X case -1: X error = 1; X return(error); X case 'H': X break; X } X while (!error) { X switch(ReadHeader(&Hdr)) { X case 'G': X { X char svdir[1024]; X getwd(svdir); X if (chdir(getdirpart(Hdr.Str)) < 0) { X error = WriteHeader('N', "Unable to cd to dir", 0); X } else { X error = PutObject(getnamepart(Hdr.Str)); X } X chdir(svdir); X } X break; X case 'E': X goto done; X case 'P': /* put-files, not implemented */ X default: X error = 1; X break; X } X } Xdone: X ; X} X XPutObject(str) Xchar *str; X{ X struct stat stat; X short error = 0; X X if (lstat(str, &stat) < 0) { X error = WriteHeader('N', "Unable to find object", 0); X return(0); X } X if (stat.st_mode & S_IFDIR) { X error = PutDir(str); X } else { X error = PutFile(str); X } X return(0); X} X XPutDir(name) Xchar *name; X{ X struct stat stat; X char svdir[1024]; X static HDR Hdr; X short error = 0; X char *fn = getnamepart(name); X DIR *dir; X struct direct *de; X X if (lstat(name, &stat) < 0 || !(dir = opendir(name))) { X WriteHeader('N', "Possible Disk Error", 0); X error = 1; X goto done; X } X if (error = WriteHeader('D', fn, 0)) X goto done; X switch(ReadHeader(&Hdr)) { X case 'Y': X break; X case 'S': X goto done; X case 'N': X error = 1; X break; X default: X error = 1; X break; X } X if (error) X goto done; X X getwd(svdir); X if (chdir(name) < 0) { X error = 1; X WriteHeader('N', "unable to chdir", 0); X } X if (error) X goto done; X X while (de = readdir(dir)) { X if (strcmp(de->d_name, ".") == 0) X continue; X if (strcmp(de->d_name, "..") == 0) X continue; X if (lstat(de->d_name, &stat) < 0) { X continue; X } X if (stat.st_mode & S_IFDIR) { X error = PutDir(de->d_name); X } else { X error = PutFile(de->d_name); X } X if (error) X break; X } X WriteHeader('E', NULL, 0); X chdir(svdir); Xdone: X return(error); X} X XPutFile(name) Xchar *name; X{ X int fd = -1; X static HDR Hdr; X long len; X short error = 0; X char *fn = getnamepart(name); X X fd = open(fn, O_RDONLY, 0); X if (fd < 0) { /* don't do anything if unable to open it */ X WriteHeader('N', "file not readable", 0); X goto done; X } X len = lseek(fd, 0L, 2); X if (error = WriteHeader('F', fn, len)) X goto done; X switch(ReadHeader(&Hdr)) { X case 'Y': X lseek(fd, Hdr.Val, 0); /* start pos. */ X len -= Hdr.Val; X if (len < 0) X len = 0; X break; X case 'S': X goto done; X case 'N': X error = 1; X break; X default: X error = 1; X break; X } X if (error) X goto done; X while (len) { X register long n = (len > sizeof(Buf)) ? sizeof(Buf) : len; X X if (read(fd, Buf, n) != n) { /* read failed! */ X error = 10; X goto done; X } X if (gwrite(Chan, Buf, n) != n) { X error = 10; X goto done; X } X len -= n; X } Xdone: X if (fd >= 0) X close(fd); X return(error); X} X X XWriteHeader(c, str, len) Xchar c; Xchar *str; Xlong len; X{ X ubyte sl; X X if (str == NULL) X str = ""; X sl = strlen(str); X X if (gwrite(Chan, &c, 1) < 0) X return(1); X if (gwrite(Chan, &sl,1) < 0) X return(1); X if (gwrite(Chan, str, sl) != sl) X return(1); X len = htonl68(len); X if (gwrite(Chan, &len, 4) != 4) X return(1); X return(0); X} X XReadHeader(hdr) XHDR *hdr; X{ X ubyte sl; X ubyte cmd; X X hdr->Cmd = -1; X if (ggread(Chan, &cmd, 1) != 1) X return(-1); X if (ggread(Chan, &sl, 1) != 1) X return(-1); X if (sl >= sizeof(hdr->Str)) { X return(-1); X } X if (ggread(Chan, hdr->Str, sl) != sl) X return(-1); X hdr->Str[sl] = 0; X if (ggread(Chan, &hdr->Val, 4) != 4) X return(-1); X hdr->Val = ntohl68(hdr->Val); X hdr->Cmd = cmd; X return(hdr->Cmd); X} X Xchar * Xgetnamepart(str) Xchar *str; X{ X register char *ptr = str + strlen(str); X X while (ptr >= str) { X if (*ptr == '/') X break; X --ptr; X } X return(ptr+1); X} X Xchar * Xgetdirpart(str) Xchar *str; X{ X static char buf[1024]; X X strcpy(buf, str); X getnamepart(buf)[0] = 0; X if (buf[0] == 0) X return("."); X return(buf); X} SHAR_EOF echo "extracting server/sshell.c" sed 's/^X//' << \SHAR_EOF > server/sshell.c X X/* X * S_SHELL.C OBSOLETE OBSOLETE OBSOLETE X * X * DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved X * X * Connect a csh to a pseudo terminal pair... PORT_ALPHATERM X * NOTE!! PORT_IALPHATERM (a pseudo-terminal csh) is also available X * through the FTERM client program on the Amiga side, and much faster X * since the server for PORT_IALPHATERM is DNET itself (one less process X * to go through). X * X * -doesn't handle SIGWINCH X * -doesn't handle flow control ... don't cat any long files! X */ X X#include X#include X#include X#include X#include X#include X X#include "servers.h" X Xchandler() X{ X union wait stat; X struct rusage rus; X while (wait3(&stat, WNOHANG, &rus) > 0); X} X Xmain(ac,av) Xchar *av[]; X{ X long chann = DListen(PORT_ALPHATERM); X int fd; X int n; X char buf[256]; X extern int errno; X X if (av[1]) X chdir(av[1]); X signal(SIGCHLD, chandler); X signal(SIGPIPE, SIG_IGN); X for (;;) { X fd = DAccept(chann); X if (fd < 0) { X if (errno == EINTR) X continue; X break; X } X if (fork() == NULL) { X dup2(fd, 0); X dup2(fd, 1); X dup2(fd, 2); X close(fd); X execl("/usr/ucb/rlogin", "rlogin", "localhost", NULL); X exit(1); X } X close(fd); X } X perror("SSHELL"); X} X SHAR_EOF echo "extracting server/sloadav.c" sed 's/^X//' << \SHAR_EOF > server/sloadav.c X X/* X * SLOADAV.C X * X * DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved X * X * Reports the load average every 5 minutes or until the connection X * is closed. X */ X X#include X#include X#include X#include X#include X#include X X#include "servers.h" X Xchandler() X{ X union wait stat; X struct rusage rus; X while (wait3(&stat, WNOHANG, &rus) > 0); X} X Xmain(ac,av) Xchar *av[]; X{ X long chann = DListen(PORT_LOADAV); X int fd; X int n; X char buf[256]; X extern int errno; X X if (av[1]) X chdir(av[1]); X signal(SIGCHLD, chandler); X signal(SIGPIPE, SIG_IGN); X for (;;) { X fd = DAccept(chann); X if (fd < 0) { X if (errno == EINTR) X continue; X break; X } X if (fork() == NULL) { X do_loadav(fd); X close(fd); X _exit(1); X } X close(fd); X } X perror("SLOADAV"); X} X Xdo_loadav(fd) X{ X char dummy; X char buf[256]; X FILE *fi; X X while (ggread(fd, &dummy, 1) == 1) { X fi = popen("uptime", "r"); X if (fi == NULL) X break; X if (fgets(buf, 256, fi)) { X dummy = strlen(buf); X buf[dummy-1] = 0; X gwrite(fd, &dummy, 1); X gwrite(fd, buf, dummy); X } X if (ferror(fi)) X break; X pclose(fi); X } X} X SHAR_EOF echo "extracting server/scopy.c" sed 's/^X//' << \SHAR_EOF > server/scopy.c X X/* X * SCOPY.C X * X * DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved X * X * Remote file copy server (putfiles is the client program) X */ X X#include X#include X#include X#include X#include X#include X#include X#include X#include X X#include "servers.h" X#include "../lib/dnetlib.h" X Xchar Buf[4096]; X Xchandler() X{ X union wait stat; X struct rusage rus; X while (wait3(&stat, WNOHANG, &rus) > 0); X} X Xmain(ac,av) Xchar *av[]; X{ X long chann = DListen(PORT_FILECOPY); X int fd; X int n; X char buf[256]; X extern int errno; X X elog(EDEBUG, "SCOPY START", 0); X if (av[1]) X chdir(av[1]); X signal(SIGCHLD, chandler); X signal(SIGPIPE, SIG_IGN); X for (;;) { X fd = DAccept(chann); X if (fd < 0) { X if (errno == EINTR) X continue; X break; X } X elog(EDEBUG, "SCOPY CONNECT", 0); X if (fork() == NULL) { X putdir(fd, "."); X _exit(1); X } X close(fd); X } X perror("SCOPY"); X} X Xputdir(chan, dirname) Xchar *dirname; X{ X struct stat stat; X char olddir[256]; X char co, nl, name[128]; X long len; X int ret = -1; X X getwd(olddir); X if (lstat(dirname, &stat) >= 0 && !(stat.st_mode & S_IFDIR)) { X char rc = 'N'; X gwrite(chan, &rc, 1); X elog(EWARN, "SCOPY: Unable to cd to dir '%s'", dirname); X return(1); X } X if (chdir(dirname) < 0) { X if (mkdir(dirname, 0777) < 0 || chdir(dirname) < 0) { X char rc = 'N'; X elog(EWARN, "SCOPY: Unable to create directory '%s'", dirname); X gwrite(chan, &rc, 1); X return(1); X } X } X co = 'Y'; X gwrite(chan, &co, 1); X while (ggread(chan, &co, 1) == 1) { X if (ggread(chan, &nl, 1) != 1 || ggread(chan, name, nl) != nl) X break; X if (ggread(chan, &len, 4) != 4) X break; X len = ntohl68(len); X switch(co) { X case 'C': X co = 'Y'; X if (chdir(name) < 0) { X if (mkdir(name, 0777) < 0 || chdir(name) < 0) { X co = 'N'; X elog(EWARN, "SCOPY: Unable to create directory '%s'", X dirname); X } X } X gwrite(chan, &co, 1); X break; X case 'W': X if (putfile(chan, name, len) < 0) { X ret = -1; X elog(EWARN, "SCOPY: Failure on file %.*s", len, name); X goto fail; X } X break; X case 'X': X if (putdir(chan, name) < 0) { X ret = -1; X goto fail; X } X break; X case 'Y': X ret = 1; X co = 'Y'; X gwrite(chan, &co, 1); X goto fail; X default: X co = 'N'; X gwrite(chan, &co, 1); X break; X } X } Xfail: X chdir(olddir); X return(ret); X} X Xputfile(chan, name, len) Xchar *name; X{ X long fd = open(name, O_WRONLY|O_CREAT|O_TRUNC, 0666); X long n, r; X char rc; X X if (fd < 0) { X rc = 'N'; X gwrite(chan, &rc, 1); X return(0); X } X rc = 'Y'; X gwrite(chan, &rc, 1); X while (len) { X r = (len > sizeof(Buf)) ? sizeof(Buf) : len; X n = ggread(chan, Buf, r); X if (n != r) X break; X if (write(fd, Buf, n) != n) X break; X len -= n; X } X close(fd); X if (len) { X unlink(name); X return(-1); X } X rc = 'Y'; X gwrite(chan, &rc, 1); X return(0); X} X SHAR_EOF echo "extracting server/Makefile" sed 's/^X//' << \SHAR_EOF > server/Makefile X X# DNET SERVERS X# X# X# DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved X XNETLIB = ../lib/dnetlib.o XBIN = ../bin X X Xall: $(NETLIB) $(BIN)/scopy $(BIN)/sshell \ X $(BIN)/sloadav $(BIN)/sgcopy X X$(BIN)/scopy: scopy.o X cc scopy.o $(NETLIB) -o $(BIN)/scopy X X$(BIN)/sgcopy: sgcopy.o X cc sgcopy.o $(NETLIB) -o $(BIN)/sgcopy X X$(BIN)/sshell: sshell.o X cc sshell.o $(NETLIB) -o $(BIN)/sshell X X$(BIN)/sloadav: sloadav.o X cc sloadav.o $(NETLIB) -o $(BIN)/sloadav X Xclean: X rm -f *.o make.out X SHAR_EOF echo "extracting server/servers.h" sed 's/^X//' << \SHAR_EOF > server/servers.h X X/* X * SERVERS.H X * X * DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved X */ X X#define PORT_FILECOPY 8192 X#define PORT_ALPHATERM 8193 X#define PORT_ECHO 8194 X#define PORT_IALPHATERM 8195 X#define PORT_AMIGATERM 8195 X#define PORT_AMIGASHELL 8196 X#define PORT_LOADAV 8197 X#define PORT_PRINTER 8198 X#define PORT_PASSWD 8199 X#define PORT_BBS 8200 X#define PORT_GFILECOPY 8201 X X SHAR_EOF echo "End of archive 2 (of 2)" # if you want to concatenate archives, remove anything after this line exit