Intial commit

This commit is contained in:
Mario Fetka
2024-05-27 16:13:40 +02:00
parent f8dc12b10a
commit d71d446104
2495 changed files with 539746 additions and 0 deletions

204
tcl-dp/unix/Makefile.in Executable file
View File

@@ -0,0 +1,204 @@
#
# This file is a Makefile for DP. If it has the name "Makefile.in"
# then it is a template for a Makefile; to generate the actual
# Makefile, run "./configure", which is a configuration script
# generated by the "autoconf" program (constructs like "@foo@" will
# get replaced in the actual Makefile.
#
#
@SET_MAKE@
# Current DP version; used in various names.
TCLVERSION = @TCL_VERSION@
VERSION = @DP_VERSION@
# Set the CFLAGS variable to -g if you want debug option. You can also
# specify it in the command line. E.g., type
# make CFLAGS=-g all
#
# CFLAGS = -g @TCL_VER_DEF@
CFLAGS = -O @TCL_VER_DEF@
# The directory containing the Tcl sources and headers appropriate for
# this version of your shared library ("srcdir" will be replaced or
# has already been replaced by the configure script):
TCL_GENERIC_DIR = @TCL_SRC_DIR@/generic
# The directory containing the Tcl library archive file appropriate
# for this version of Tk:
TCL_BIN_DIR = @TCL_BIN_DIR@
# Libraries to use when linking:
LIBS = @TCL_BUILD_LIB_SPEC@ @TCL_LIBS@ -lc
#----------------------------------------------------------------
# The information below is modified by the configure script when
# Makefile is generated from Makefile.in. You shouldn't normally
# modify any of this stuff by hand.
#----------------------------------------------------------------
CC = @CC@
SHLIB_CFLAGS = @SHLIB_CFLAGS@
SHLIB_LD = @SHLIB_LD@
SHLIB_SUFFIX = @SHLIB_SUFFIX@
SHLIB_VERSION = @SHLIB_VERSION@
SRC_DIR = @SRC_DIR@
GENERIC_DIR = @SRC_DIR@/generic
UNIX_DIR = @SRC_DIR@/unix
OBJ_DIR = @SRC_DIR@/unix/objs
LLIB = @SRC_DIR@/library
AC_FLAGS = @DEFS@
CC_SWITCHES = $(CFLAGS) -I${TCL_GENERIC_DIR} -I${SRC_DIR} ${SHLIB_CFLAGS} \
@OS_DEF@ $(AC_FLAGS)
DP_LIB_FILE = @DP_LIB_FILE@
OBJS = \
$(OBJ_DIR)/dpChan.o \
$(OBJ_DIR)/dpCmds.o \
$(OBJ_DIR)/dpInit.o \
$(OBJ_DIR)/dpRPC.o \
$(OBJ_DIR)/dpTcp.o \
$(OBJ_DIR)/dpSock.o \
$(OBJ_DIR)/dpUdp.o \
$(OBJ_DIR)/dpSerial.o \
$(OBJ_DIR)/dpUnixSock.o \
$(OBJ_DIR)/dpUnixSerial.o \
$(OBJ_DIR)/dpUnixInit.o \
$(OBJ_DIR)/dpUnixEmail.o \
$(OBJ_DIR)/dpLocks.o \
$(OBJ_DIR)/dpPlugF.o \
$(OBJ_DIR)/dpFilters.o \
$(OBJ_DIR)/dpIdentity.o \
$(OBJ_DIR)/dpPackOff.o \
$(OBJ_DIR)/dpIPM.o
all: $(DP_LIB_FILE) movefilter
$(DP_LIB_FILE): $(OBJ_DIR) $(OBJS)
rm -f $(DP_LIB_FILE)
@DP_MAKE_LIB@
dpsh: $(DP_LIB_FILE) $(OBJ_DIR)/dpAppInit.o movefilter
$(CC) -o dpsh $(OBJ_DIR)/dpAppInit.o $(OBJS) $(LIBS)
puredpsh: $(DP_LIB_FILE) $(OBJ_DIR)/dpAppInit.o movefilter
purify $(CC) -o dpsh $(OBJ_DIR)/dpAppInit.o $(OBJS) $(LIBS)
#----------------------------------------------------------------------
$(OBJ_DIR)/dpAppInit.o: $(UNIX_DIR)/dpAppInit.c
$(CC) $(CC_SWITCHES) -c $(UNIX_DIR)/dpAppInit.c -o \
$(OBJ_DIR)/dpAppInit.o
$(OBJ_DIR)/dpChan.o: $(GENERIC_DIR)/dpChan.c
$(CC) $(CC_SWITCHES) -c $(GENERIC_DIR)/dpChan.c -o \
$(OBJ_DIR)/dpChan.o
$(OBJ_DIR)/dpCmds.o: $(GENERIC_DIR)/dpCmds.c
$(CC) $(CC_SWITCHES) -c $(GENERIC_DIR)/dpCmds.c -o \
$(OBJ_DIR)/dpCmds.o
$(OBJ_DIR)/dpSock.o: $(GENERIC_DIR)/dpSock.c
$(CC) $(CC_SWITCHES) -c $(GENERIC_DIR)/dpSock.c -o \
$(OBJ_DIR)/dpSock.o
$(OBJ_DIR)/dpSerial.o: $(GENERIC_DIR)/dpSerial.c
$(CC) $(CC_SWITCHES) -c $(GENERIC_DIR)/dpSerial.c -o \
$(OBJ_DIR)/dpSerial.o
$(OBJ_DIR)/dpIPM.o: @IPM@
$(CC) $(CC_SWITCHES) -c @IPM@ -o \
$(OBJ_DIR)/dpIPM.o
$(OBJ_DIR)/dpTcp.o: @TCP@
$(CC) $(CC_SWITCHES) -c @TCP@ -o \
$(OBJ_DIR)/dpTcp.o
$(OBJ_DIR)/dpUdp.o: @UDP@
$(CC) $(CC_SWITCHES) -c @UDP@ -o \
$(OBJ_DIR)/dpUdp.o
$(OBJ_DIR)/dpRPC.o: $(GENERIC_DIR)/dpRPC.c
$(CC) $(CC_SWITCHES) -c $(GENERIC_DIR)/dpRPC.c -o \
$(OBJ_DIR)/dpRPC.o
$(OBJ_DIR)/dpInit.o: $(GENERIC_DIR)/dpInit.c
$(CC) $(CC_SWITCHES) -c $(GENERIC_DIR)/dpInit.c -o \
$(OBJ_DIR)/dpInit.o
$(OBJ_DIR)/dpUnixInit.o: $(UNIX_DIR)/dpInit.c
$(CC) $(CC_SWITCHES) -c $(UNIX_DIR)/dpInit.c -o \
$(OBJ_DIR)/dpUnixInit.o
$(OBJ_DIR)/dpUnixSerial.o: $(UNIX_DIR)/dpSerial.c
$(CC) $(CC_SWITCHES) -c $(UNIX_DIR)/dpSerial.c -o \
$(OBJ_DIR)/dpUnixSerial.o
$(OBJ_DIR)/dpUnixSock.o: $(UNIX_DIR)/dpSock.c
$(CC) $(CC_SWITCHES) -c $(UNIX_DIR)/dpSock.c -o \
$(OBJ_DIR)/dpUnixSock.o
$(OBJ_DIR)/dpUnixEmail.o: $(UNIX_DIR)/dpEmail.c
$(CC) $(CC_SWITCHES) -c -DLLIB=\"$(LLIB)\" $(UNIX_DIR)/dpEmail.c -o \
$(OBJ_DIR)/dpUnixEmail.o
$(OBJ_DIR)/dpLocks.o: $(UNIX_DIR)/dpLocks.c
$(CC) $(CC_SWITCHES) -DSOURCE=\"dp\" -c $(UNIX_DIR)/dpLocks.c -o \
$(OBJ_DIR)/dpLocks.o
$(OBJ_DIR)/dpIdentity.o: $(GENERIC_DIR)/dpIdentity.c
$(CC) $(CC_SWITCHES) -c $(GENERIC_DIR)/dpIdentity.c -o \
$(OBJ_DIR)/dpIdentity.o
$(OBJ_DIR)/dpPlugF.o: $(GENERIC_DIR)/dpPlugF.c
$(CC) $(CC_SWITCHES) -c $(GENERIC_DIR)/dpPlugF.c -o \
$(OBJ_DIR)/dpPlugF.o
$(OBJ_DIR)/dpFilters.o: $(GENERIC_DIR)/dpFilters.c
$(CC) $(CC_SWITCHES) -c $(GENERIC_DIR)/dpFilters.c -o \
$(OBJ_DIR)/dpFilters.o
dpfilter: $(OBJ_DIR)/dpEFilter.o $(OBJ_DIR)/dpLocks.o
$(CC) $(CC_SWITCHES) $(OBJ_DIR)/dpEFilter.o \
$(OBJ_DIR)/dpLocks.o -o dpfilter
$(OBJ_DIR)/dpPackOff.o: $(GENERIC_DIR)/dpPackOff.c
$(CC) $(CC_SWITCHES) -c $(GENERIC_DIR)/dpPackOff.c -o \
$(OBJ_DIR)/dpPackOff.o
$(OBJ_DIR)/dpEFilter.o: $(UNIX_DIR)/dpEFilter.c
$(CC) $(CC_SWITCHES) -c $(UNIX_DIR)/dpEFilter.c -o \
$(OBJ_DIR)/dpEFilter.o
#----------------------------------------------------------------------
$(OBJ_DIR):
if [ ! -d objs ]; then \
mkdir objs; \
fi
# This is necessary for the email channel
movefilter: dpfilter
cp ./dpfilter $(LLIB)
clean:
rm -f dpsh $(OBJ_DIR)/*.o *${SHLIB_SUFFIX} $(LLIB)/dpfilter dpfilter \
pkgIndex.tcl confdefs.h
tests: $(DP_LIB_FILE)
cd ../tests; @TCL_SRC_DIR@/unix/tclsh all
install:
@echo You didn't read the README, did you?
Makefile: Makefile.in
./config.status
distclean: clean
rm -rf objs config.cache config.log config.status lib.exp \
$(LLIB)/dpfilter Makefile

56
tcl-dp/unix/compat/in.h Normal file
View File

@@ -0,0 +1,56 @@
/*These definitions are required by the IPmulticast code. Some systems do not*/
/* have these definitions in their netinet/in.h file.*/
#ifndef IN_CLASSD_NET
#define IN_CLASSD_NET 0xf0000000 /* These ones aren't really */
#endif
#ifndef IN_CLASSD_NSHIFT
#define IN_CLASSD_NSHIFT 28 /* net and host fields, but */
#endif
#ifndef IN_CLASSD_HOST
#define IN_CLASSD_HOST 0x0fffffff /* routing needn't know. */
#endif
#ifndef INADDR_UNSPEC_GROUP
#define INADDR_UNSPEC_GROUP (u_long)0xe0000000 /* 224.0.0.0 */
#endif
#ifndef INADDR_ALLHOSTS_GROUP
#define INADDR_ALLHOSTS_GROUP (u_long)0xe0000001 /* 224.0.0.1 */
#endif
#ifndef INADDR_MAX_LOCAL_GROUP
#define INADDR_MAX_LOCAL_GROUP (u_long)0xe00000ff /* 224.0.0.255 */
#endif
/*
* Options for use with [gs]etsockopt at the IP level.
*/
#ifndef IP_OPTIONS
#define IP_OPTIONS 1 /* set/get IP per-packet options */
#endif
#ifndef IP_MULTICAST_IF
#define IP_MULTICAST_IF 2 /* set/get IP multicast interface */
#define IP_MULTICAST_TTL 3 /* set/get IP multicast timetolive */
#define IP_MULTICAST_LOOP 4 /* set/get IP multicast loopback */
#define IP_ADD_MEMBERSHIP 5 /* add an IP group membership */
#define IP_DROP_MEMBERSHIP 6 /* drop an IP group membership */
#define IP_DEFAULT_MULTICAST_TTL 1 /* normally limit m'casts to 1 hop */
#define IP_DEFAULT_MULTICAST_LOOP 1 /* normally hear sends if a member */
#define IP_MAX_MEMBERSHIPS 20 /* per socket; must fit in one mbuf */
/*
* Argument structure for IP_ADD_MEMBERSHIP and IP_DROP_MEMBERSHIP.
*/
struct ip_mreq {
struct in_addr imr_multiaddr; /* IP multicast address of group */
struct in_addr imr_interface; /* local IP address of interface */
};
#endif

View File

@@ -0,0 +1,43 @@
/*
* malloc.h --
*
* Declares facilities exported by the "malloc" portion of
* the C library. This file isn't complete in the ANSI-C
* sense; it only declares things that are needed by Tcl-DP.
*
* Copyright (c) 1991 The Regents of the University of California.
* All rights reserved.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
* CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* /usr/u/multimed/cmt/CVSROOT/tcl-dp/compat/malloc.h,v 1.2 1995/04/01 20:37:36 grafton Exp SPRITE (Berkeley)
*/
#ifndef _MALLOC
#define _MALLOC
#include <tcl.h>
extern void free _ANSI_ARGS_((void *));
extern void *malloc _ANSI_ARGS_((int));
extern void *calloc _ANSI_ARGS_((int, int));
extern void *realloc _ANSI_ARGS_((void *, int));
#endif /* _MALLOC */

View File

@@ -0,0 +1,60 @@
/*
* stdlib.h --
*
* Declares facilities exported by the "stdlib" portion of
* the C library. This file isn't complete in the ANSI-C
* sense; it only declares things that are needed by Tcl.
* This file is needed even on many systems with their own
* stdlib.h (e.g. SunOS) because not all stdlib.h files
* declare all the procedures needed here (such as strtod).
*
* Copyright (c) 1991 The Regents of the University of California.
* All rights reserved.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
* CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* /usr/u/multimed/cmt/CVSROOT/tcl-dp/compat/stdlib.h,v 1.3 1995/05/24 18:00:00 bsmith Exp SPRITE (Berkeley)
*/
#ifndef _STDLIB
#define _STDLIB
#include <tcl.h>
extern void abort _ANSI_ARGS_((void));
extern double atof _ANSI_ARGS_((CONST char *string));
extern int atoi _ANSI_ARGS_((CONST char *string));
extern long atol _ANSI_ARGS_((CONST char *string));
extern void exit _ANSI_ARGS_((int status));
extern char * getenv _ANSI_ARGS_((CONST char *name));
extern void qsort _ANSI_ARGS_((VOID *base, int n, int size,
int (*compar)(CONST VOID *element1, CONST VOID
*element2)));
extern double strtod _ANSI_ARGS_((CONST char *string, char **endPtr));
extern long strtol _ANSI_ARGS_((CONST char *string, char **endPtr,
int base));
extern unsigned long strtoul _ANSI_ARGS_((CONST char *string,
char **endPtr, int base));
extern char * calloc _ANSI_ARGS_((int n, int size));
extern char * malloc _ANSI_ARGS_((int size));
extern char * realloc _ANSI_ARGS_((void *ptr, int size));
#endif /* _STDLIB */

View File

@@ -0,0 +1,80 @@
/*
* string.h --
*
* Declarations of ANSI C library procedures for string handling.
*
* Copyright (c) 1991-1993 The Regents of the University of California.
* All rights reserved.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
* CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* /usr/u/multimed/cmt/CVSROOT/tcl-dp/compat/string.h,v 1.2 1995/04/01 20:37:39 grafton Exp SPRITE (Berkeley)
*/
#ifndef _STRING
#define _STRING
#include <tcl.h>
/*
* The following #include is needed to define size_t. (This used to
* include sys/stdtypes.h but that doesn't exist on older versions
* of SunOS, e.g. 4.0.2, so I'm trying sys/types.h now.... hopefully
* it exists everywhere)
*/
#include <sys/types.h>
extern char * memchr _ANSI_ARGS_((CONST VOID *s, int c, size_t n));
extern int memcmp _ANSI_ARGS_((CONST VOID *s1, CONST VOID *s2,
size_t n));
extern char * memcpy _ANSI_ARGS_((VOID *t, CONST VOID *f, size_t n));
extern char * memmove _ANSI_ARGS_((VOID *t, CONST VOID *f,
size_t n));
extern char * memset _ANSI_ARGS_((VOID *s, int c, size_t n));
extern int strcasecmp _ANSI_ARGS_((CONST char *s1,
CONST char *s2));
extern char * strcat _ANSI_ARGS_((char *dst, CONST char *src));
extern char * strchr _ANSI_ARGS_((CONST char *string, int c));
extern int strcmp _ANSI_ARGS_((CONST char *s1, CONST char *s2));
extern char * strcpy _ANSI_ARGS_((char *dst, CONST char *src));
extern size_t strcspn _ANSI_ARGS_((CONST char *string,
CONST char *chars));
extern char * strdup _ANSI_ARGS_((CONST char *string));
extern char * strerror _ANSI_ARGS_((int error));
extern size_t strlen _ANSI_ARGS_((CONST char *string));
extern int strncasecmp _ANSI_ARGS_((CONST char *s1,
CONST char *s2, size_t n));
extern char * strncat _ANSI_ARGS_((char *dst, CONST char *src,
size_t numChars));
extern int strncmp _ANSI_ARGS_((CONST char *s1, CONST char *s2,
size_t nChars));
extern char * strncpy _ANSI_ARGS_((char *dst, CONST char *src,
size_t numChars));
extern char * strpbrk _ANSI_ARGS_((CONST char *string, char *chars));
extern char * strrchr _ANSI_ARGS_((CONST char *string, int c));
extern size_t strspn _ANSI_ARGS_((CONST char *string,
CONST char *chars));
extern char * strstr _ANSI_ARGS_((CONST char *string,
CONST char *substring));
extern char * strtok _ANSI_ARGS_((CONST char *s, CONST char *delim));
#endif /* _STRING */

View File

@@ -0,0 +1,85 @@
/*
* unistd.h --
*
* Macros, CONSTants and prototypes for Posix conformance.
*
* Copyright 1989 Regents of the University of California
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies. The University of California
* makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without
* express or implied warranty.
*
* /usr/u/multimed/cmt/CVSROOT/tcl-dp/compat/unistd.h,v 1.2 1995/04/01 20:37:41 grafton Exp
*/
#ifndef _UNISTD
#define _UNISTD
#include <sys/types.h>
#ifndef _TCL
# include "tcl.h"
#endif
#ifndef NULL
#define NULL 0
#endif
/*
* Strict POSIX stuff goes here. Extensions go down below, in the
* ifndef _POSIX_SOURCE section.
*/
extern void _exit _ANSI_ARGS_((int status));
extern int access _ANSI_ARGS_((CONST char *path, int mode));
extern int chdir _ANSI_ARGS_((CONST char *path));
extern int chown _ANSI_ARGS_((CONST char *path, uid_t owner, gid_t group));
extern int close _ANSI_ARGS_((int fd));
extern int dup _ANSI_ARGS_((int oldfd));
extern int dup2 _ANSI_ARGS_((int oldfd, int newfd));
extern int execl _ANSI_ARGS_((CONST char *path, ...));
extern int execle _ANSI_ARGS_((CONST char *path, ...));
extern int execlp _ANSI_ARGS_((CONST char *file, ...));
extern int execv _ANSI_ARGS_((CONST char *path, char **argv));
extern int execve _ANSI_ARGS_((CONST char *path, char **argv, char **envp));
extern int execvp _ANSI_ARGS_((CONST char *file, char **argv));
extern pid_t fork _ANSI_ARGS_((void));
extern char *getcwd _ANSI_ARGS_((char *buf, size_t size));
extern gid_t getegid _ANSI_ARGS_((void));
extern uid_t geteuid _ANSI_ARGS_((void));
extern gid_t getgid _ANSI_ARGS_((void));
extern int getgroups _ANSI_ARGS_((int bufSize, int *buffer));
extern pid_t getpid _ANSI_ARGS_((void));
extern uid_t getuid _ANSI_ARGS_((void));
extern int isatty _ANSI_ARGS_((int fd));
extern long lseek _ANSI_ARGS_((int fd, long offset, int whence));
extern int pipe _ANSI_ARGS_((int *fildes));
extern int read _ANSI_ARGS_((int fd, char *buf, size_t size));
extern int setgid _ANSI_ARGS_((gid_t group));
extern int setuid _ANSI_ARGS_((uid_t user));
extern unsigned sleep _ANSI_ARGS_ ((unsigned seconds));
extern char *ttyname _ANSI_ARGS_((int fd));
extern int unlink _ANSI_ARGS_((CONST char *path));
extern int write _ANSI_ARGS_((int fd, CONST char *buf, size_t size));
#ifndef _POSIX_SOURCE
extern char *crypt _ANSI_ARGS_((CONST char *, CONST char *));
extern int fchown _ANSI_ARGS_((int fd, uid_t owner, gid_t group));
extern int flock _ANSI_ARGS_((int fd, int operation));
extern int ftruncate _ANSI_ARGS_((int fd, unsigned long length));
extern int readlink _ANSI_ARGS_((CONST char *path, char *buf, int bufsize));
extern int setegid _ANSI_ARGS_((gid_t group));
extern int seteuid _ANSI_ARGS_((uid_t user));
extern int setreuid _ANSI_ARGS_((int ruid, int euid));
extern int symlink _ANSI_ARGS_((CONST char *, CONST char *));
extern int ttyslot _ANSI_ARGS_((void));
extern int truncate _ANSI_ARGS_((CONST char *path, unsigned long length));
extern int vfork _ANSI_ARGS_((void));
#endif /* _POSIX_SOURCE */
#endif /* _UNISTD */

1196
tcl-dp/unix/configure vendored Executable file

File diff suppressed because it is too large Load Diff

196
tcl-dp/unix/configure.in Executable file
View File

@@ -0,0 +1,196 @@
dnl This file is an input file used by the GNU "autoconf" program to
dnl generate the file "configure", which is run to configure the
dnl Makefile in this directory.
AC_INIT(../generic/dpInit.c)
#--------------------------------------------------------------------
# Version information about this DP release.
#--------------------------------------------------------------------
DP_VERSION=4.0
DP_MAJOR_VERSION=4
DP_MINOR_VERSION=0
VERSION=${DP_VERSION}
AC_PROG_RANLIB
AC_HAVE_HEADERS(unistd.h limits.h)
AC_PROG_MAKE_SET
#--------------------------------------------------------------------
# See if there was a command-line option for where Tcl is; if
# not, assume that its top-level directory is a sibling of ours.
#--------------------------------------------------------------------
AC_ARG_WITH(tcl, [ --with-tcl=DIR Tcl source is in DIR],
TCL_BIN_DIR=$withval, TCL_BIN_DIR=UNDEF)
#-------------------------------------------------------------------
# If the Tcl dir was not specified, assume it is a sibling to the top
# Tcl-DP directory and search for the versions we support.
#-------------------------------------------------------------------
if test $TCL_BIN_DIR = "UNDEF" ; then
if test -d ../../tcl8.0/unix ; then
REQ_TCL_VER=8.0
TCL_VER_DEF=-D_TCL80
elif test -d ../../tcl7.6/unix ; then
REQ_TCL_VER=7.6
TCL_VER_DEF=-D_TCL76
else
echo "Could not find Tcl source directory. Please install"
echo "the Tcl source code or specify the directory with the"
echo " --with-tcl=<path_to_unix_dir> switch."
exit 1
fi
TCL_BIN_DIR=`cd ../../tcl${REQ_TCL_VER}/unix; pwd`
echo "Found Tcl $REQ_TCL_VER in $TCL_BIN_DIR"
else
# Check for Tcl 8 by grepping the directory string for an 8
if test `echo $TCL_BIN_DIR | grep 8` ; then
REQ_TCL_VER=8.0
TCL_VER_DEF=-D_TCL80
echo "Found Tcl 8.0 in $TCL_BIN_DIR"
else
# Assume the directory string is for Tcl 7.6
REQ_TCL_VER=7.6
TCL_VER_DEF=-D_TCL76
echo "Defaulting to Tcl 7.6 in $TCL_BIN_DIR"
fi
fi
if test ! -d $TCL_BIN_DIR; then
echo "Tcl source directory $TCL_BIN_DIR doesn't exist"
echo "Please install the Tcl source code."
exit 1
fi
TCL_SRC_DIR=`cd $TCL_BIN_DIR; make topDirName`
#--------------------------------------------------------------------
# Find out the top level source directory of this package.
#--------------------------------------------------------------------
SRC_DIR=`cd ..; pwd`
AC_SUBST(SRC_DIR)
#--------------------------------------------------------------------
# Read in configuration information generated by Tcl for shared
# libraries, and arrange for it to be substituted into our
# Makefile.
#--------------------------------------------------------------------
file=$TCL_BIN_DIR/tclConfig.sh
. $file
CC=$TCL_CC
SHLIB_CFLAGS=$TCL_SHLIB_CFLAGS
SHLIB_LD=$TCL_SHLIB_LD
SHLIB_LD_LIBS=$TCL_SHLIB_LD_LIBS
SHLIB_SUFFIX=$TCL_SHLIB_SUFFIX
SHLIB_VERSION=$TCL_SHLIB_VERSION
TCL_LIBS=$TCL_LIBS
TCL_VERSION=$TCL_VERSION
####################################################
# This code is necessary because Tcl 7.6 uses
# DP's generic socket code while Tcl 8.x uses
# the socket code in the OS dir
#
if test $TCL_VERSION -eq 7 ; then
IPM=\$\(GENERIC_DIR\)/dpIPM.c
TCP=\$\(GENERIC_DIR\)/dpTcp.c
UDP=\$\(GENERIC_DIR\)/dpUdp.c
else
IPM=\$\(UNIX_DIR\)/dpUnixIpm.c
TCP=\$\(UNIX_DIR\)/dpUnixTcp.c
UDP=\$\(UNIX_DIR\)/dpUnixUdp.c
fi
AC_SUBST(IPM)
AC_SUBST(TCP)
AC_SUBST(UDP)
####################################################
AC_SUBST(CC)
AC_SUBST(SHLIB_CFLAGS)
AC_SUBST(SHLIB_LD)
AC_SUBST(SHLIB_LD_LIBS)
AC_SUBST(SHLIB_SUFFIX)
AC_SUBST(SHLIB_VERSION)
AC_SUBST(TCL_BUILD_LIB_SPEC)
AC_SUBST(TCL_LIBS)
AC_SUBST(TCL_VERSION)
AC_SUBST(TCL_SRC_DIR)
AC_SUBST(TCL_BIN_DIR)
#-------------------------------------------
# Export OS name in a define
#-------------------------------------------
OS_DEF=""
AC_PROGRAM_CHECK(uname_found, uname, 1, 0)
[ if test $uname_found -eq 1 ; then
system=`uname -s`-`uname -r`
case $system in
SunOS-4*)
OS_DEF="-D__SUNOS__"
;;
SunOS-5*)
OS_DEF="-D__SOLARIS__"
;;
Linux*)
OS_DEF="-D__LINUX__"
;;
HP-UX*)
OS_DEF="-D__HPUX__"
;;
FreeBSD*)
OS_DEF="-D__FREEBSD__"
;;
esac
fi ]
eval "DP_LIB_FILE=libdp40${TCL_SHLIB_SUFFIX}"
DP_MAKE_LIB="\${SHLIB_LD} -o ${DP_LIB_FILE} \${OBJS} ${SHLIB_LD_LIBS}"
DP_PKG_FILE="[[file join [file dirname \$dir] ${DP_LIB_FILE}]]"
#----------------------------------------------------------------------
# Substitution strings exported by DP
#----------------------------------------------------------------------
AC_SUBST(DP_MAJOR_VERSION)
AC_SUBST(DP_MINOR_VERSION)
AC_SUBST(DP_VERSION)
AC_SUBST(DP_MAKE_LIB)
AC_SUBST(DP_LIB_FILE)
AC_SUBST(DP_PKG_FILE)
AC_SUBST(OS_DEF)
AC_SUBST(TCL_VER_DEF)
#----------------------------------------------------------------------
# Do all checking AFTER this line because most checkings depend
# of the value of CC, which is defined only after we read in
# the Tcl config info.
#----------------------------------------------------------------------
AC_MSG_CHECKING(checking for ip multicast)
AC_TRY_COMPILE([#include "sys/types.h"
#include "netinet/in.h"],
[int f1=IP_ADD_MEMBERSHIP;
int f2=IP_MULTICAST_TTL;
int f3=IP_MULTICAST_LOOP;], ip_ok=1, ip_ok=0)
if test $ip_ok = 1; then
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
AC_DEFINE(NO_MULTICAST_DEF)
fi
AC_OUTPUT(Makefile)

100
tcl-dp/unix/dpAppInit.c Normal file
View File

@@ -0,0 +1,100 @@
/*
* dpAppInit.c --
*
* Main program for the dpsh application.
*
* Copyright (c) 1993 The Regents of the University of California.
* Copyright (c) 1994-1995 Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
* SCCS: @(#) tclAppInit.c 1.17 96/03/26 12:45:29
*/
#include "generic/dp.h"
/*
* The following variable is a special hack that is needed in order for
* Sun shared libraries to be used for Tcl.
*/
extern int matherr();
int *tclDummyMathPtr = (int *) matherr;
#ifdef TCL_TEST
EXTERN int Tcltest_Init _ANSI_ARGS_((Tcl_Interp *interp));
#endif /* TCL_TEST */
/*
*----------------------------------------------------------------------
*
* main --
*
* This is the main program for the application.
*
* Results:
* None: Tcl_Main never returns here, so this procedure never
* returns either.
*
* Side effects:
* Whatever the application does.
*
*----------------------------------------------------------------------
*/
int
main(argc, argv)
int argc; /* Number of command-line arguments. */
char **argv; /* Values of command-line arguments. */
{
Tcl_Main(argc, argv, Tcl_AppInit);
return 0; /* Needed only to prevent compiler warning. */
}
/*
*----------------------------------------------------------------------
*
* Tcl_AppInit --
*
* This procedure performs application-specific initialization.
* Most applications, especially those that incorporate additional
* packages, will have their own version of this procedure.
*
* Results:
* Returns a standard Tcl completion code, and leaves an error
* message in interp->result if an error occurs.
*
* Side effects:
* Depends on the startup script.
*
*----------------------------------------------------------------------
*/
int
Tcl_AppInit(interp)
Tcl_Interp *interp; /* Interpreter for application. */
{
if (Tcl_Init(interp) == TCL_ERROR) {
return TCL_ERROR;
}
if (Dp_Init(interp) == TCL_ERROR) {
return TCL_ERROR;
}
/*
* Specify a user-specific startup file to invoke if the application
* is run interactively. Typically the startup file is "~/.apprc"
* where "app" is the name of the application. If this line is deleted
* then no user-specific startup file will be run under any conditions.
*/
Tcl_SetVar(interp, "tcl_rcFileName", "~/.tclshrc", TCL_GLOBAL_ONLY);
return TCL_OK;
}

326
tcl-dp/unix/dpEFilter.c Normal file
View File

@@ -0,0 +1,326 @@
/*
* dpEFilter.c --
*
* This auxilliary program will be used to filter the incoming
* email messages. It uses a list of email sources in $HOME/argv[1]
* to filter incoming mail. If a message has a From entry matching
* one given source, the message (with the header removed will be appended
* to the corresponding file.
*
* The exit codes returned by the program are given below:
*
* 0 - everything went OK
* 1 - number of command line parameters incorrect
* 2 - lock could not be created or the lock created by somebody else
* could not be removed
* 3 - read/open error in channel file
* 4 - read/open error in spool file
* 5 - read/open error in seek file
* 6 - empty lock file name
*/
/*
* Major problems
*
* Make sure that the lines in the seek file are shorter than ARBITRARY_LIMIT.
* This is not a problem at this point, because the subject is always
* "email channel".
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/time.h>
#include "generic/dpInt.h"
/*
* This auxilliary program will be used to filter the incoming
* email messages. It uses a list of email sources in $HOME/argv[1]
* to filter incoming mail. If a message has a From entry matching
* one given source, the message (with the header removed will be appended
* to the corresponding file.
*
* The exit codes returned by the program are given below:
*
* 0 - everything went OK
* 1 - number of command line parameters incorrect
* 2 - lock could not be created or the lock created by somebody else
* could not be removed
* 3 - read/open error in channel file
* 4 - read/open error in spool file
* 5 - read/open error in seek file
*/
#define ARBITRARY_LIMIT 500
#define LOCK_TIMEOUT 10
/* Prototypes of local functions */
static void Demultiplex _ANSI_ARGS_((char *channelFile, char *spoolFile,
char *seekFile));
static void Match _ANSI_ARGS_((char *pattern));
static void Exit _ANSI_ARGS_((int));
/*
* Call: filter home-directory lockFile channelFile seekFile spoolFile
*/
char lockFilePath [ARBITRARY_LIMIT];
int main (argc, argv)
int argc; /* Number of arguments, including the program's name. */
char *argv[]; /* argv[0] = program's path */
/* argv[1] = root directory */
/* argv[2] = lock file name */
/* argv[3] = channel file name */
/* argv[4] = seek file name */
/* argv[5] = spool file name */
{
char spoolFilePath [ARBITRARY_LIMIT];
char channelFilePath [ARBITRARY_LIMIT];
char seekFilePath [ARBITRARY_LIMIT];
int returnValue;
if(argc != 6)
Exit(1);
strcpy(lockFilePath, argv[1]);
strcat(lockFilePath, argv[2]);
strcpy(spoolFilePath, argv[1]);
strcat(spoolFilePath, argv[5]);
strcpy(channelFilePath, argv[1]);
strcat(channelFilePath, argv[3]);
strcpy(seekFilePath, argv[1]);
strcat(seekFilePath, argv[4]);
if((returnValue = PutLock(lockFilePath)) != 0) {
exit(0);
/* Exit(returnValue); */
}
Demultiplex(spoolFilePath, channelFilePath, seekFilePath);
if((returnValue = RemoveLock(lockFilePath)) != 0) {
exit(0);
/* Exit(returnValue); */
}
return 0;
}
/*
* Demultiplex --
*
* This function scans the incoming message. First, it looks for the
* sender; if the sender is one of those authorized, it retrieves the
* subject and the body of the message (the body starts after the
* first empty line of the message, the empty line is not included).
* For each message that is accepted, one line is added to the seek file,
* while the body is appended to the spool file.
*
* Results:
*
* None.
*
* Side effects:
*
* If the message is accepted, one line is added to the seek file, and
* the body of the message is appended to the spool file.
*/
static void
Demultiplex (spoolFile, channelFile, seekFile)
char *channelFile; /* Name of channel file. */
char *spoolFile; /* Name of spool file. */
char *seekFile; /* Name of seek file. */
{
char stdinBuffer [ARBITRARY_LIMIT];
char buffer2 [ARBITRARY_LIMIT];
char chanBuffer [ARBITRARY_LIMIT];
FILE *fpChan, *fpSpool, *fpSeek;
int i, found;
long count;
char ctemp, first;
/*
* It is likely that these two definitions will have to be changed for
* different systems. One should put here the strings that immediately
* preceed the sender and the subject in the message. These string
* comparisons are done ignoring character case.
*/
char *p1 = "from ";
char *p2 = "subject: ";
/* Check for the sender in the incoming message. */
Match(p1);
/* Isolate the sender's name from other data on the same line. */
fgets(stdinBuffer, ARBITRARY_LIMIT, stdin);
strtok(stdinBuffer, " ");
/* Check if the sender appears in the channel file. */
if((fpChan = fopen(channelFile, "r")) == NULL) {
fclose(fpChan);
Exit(3);
}
fgets(chanBuffer, ARBITRARY_LIMIT, fpChan);
chanBuffer[strlen(chanBuffer) - 1] = '\0';
while(!feof(fpChan)) {
if(!strcasecmp(chanBuffer, stdinBuffer)) {
break;
}
fgets(chanBuffer, ARBITRARY_LIMIT, fpChan);
chanBuffer[strlen(chanBuffer) - 1] = '\0';
}
if(feof(fpChan)) {
/* Sender not on list. */
fclose(fpChan);
Exit(0);
}
fclose(fpChan);
/* OK, authorized sender. Look for the subject now. */
Match(p2);
fgets(buffer2, ARBITRARY_LIMIT, stdin);
buffer2[strlen(buffer2) - 1] = '\0';
/*
* Look for the first empty line (two succesive '\n' characters)
* in the message.
*/
found = 0;
if((ctemp = getchar()) != '\n') {
for(ctemp = getchar(); !feof(stdin); ctemp = getchar()) {
if(ctemp == '\n') {
if(found == 1) {
break;
}
else {
found = 1;
}
}
else {
found = 0;
}
}
}
/* Transfer the rest of the message to the spool file. */
if((fpSpool = fopen(spoolFile, "a")) == NULL) {
Exit(4);
}
count = 0;
first = getchar();
if(!feof(stdin)) {
for(ctemp = getchar(); !feof(stdin); first = ctemp, ctemp = getchar(), count++) {
if(fputc(first, fpSpool) == EOF) {
fclose(fpSpool);
Exit(4);
}
}
};
fclose(fpSpool);
/* Add one entry to the seek file. */
if((fpSeek = fopen(seekFile, "a")) == NULL) {
Exit(5);
}
if(fprintf(fpSeek, "%s %.8ld 00000000 %s\n", chanBuffer, count, buffer2) == EOF) {
fclose(fpSeek);
Exit(5);
}
fclose(fpSeek);
return;
}
/*
* Match --
*
* Returns only if the pattern is found in the standard input.
* We expect the pattern to appear at the beginning of a line.
* the comparison is case insensitive. After the pattern is found,
* no more characters are read.
*
* Results:
*
* None.
*
* Side effects:
*
* Reads stdin until the pattern or EOF is found.
*/
static void
Match (pattern)
char *pattern; /* Pattern to match against. */
{
int i;
while(1) {
for(i = 0; (pattern[i] != '\0') && (!feof(stdin)); i++) {
if(pattern[i] != tolower(getchar()))
break;
}
if(pattern[i] == '\0')
/* the pattern was found in the standard input */
return;
while(!feof(stdin)) {
if(getchar() == '\n')
break;
}
if(feof(stdin))
/* premature end of file */
Exit(4);
}
}
static void Exit (i)
int i;
{
RemoveLock(lockFilePath);
exit(i);
}

2051
tcl-dp/unix/dpEmail.c Normal file

File diff suppressed because it is too large Load Diff

51
tcl-dp/unix/dpInit.c Normal file
View File

@@ -0,0 +1,51 @@
/*
* dpInit.c --
*
* Perform UNIX-specific initialization of DP.
*
* Copyright (c) 1995-1996 The Regents of Cornell University.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
*/
#include "generic/dpPort.h"
#include "generic/dpInt.h"
/*
*----------------------------------------------------------------------
*
* DppInit --
*
* Performs Unix-specific interpreter initialization related to the
* dp_library variable.
*
* Results:
* Returns a standard Tcl result. Leaves an error message or result
* in interp->result.
*
* Side effects:
* Sets "dp_library" Tcl variable, runs "tk.tcl" script.
*
*----------------------------------------------------------------------
*/
int
DppInit(interp)
Tcl_Interp *interp;
{
/*
* (ToDo) Load in the TCL library
*/
return TCL_OK;
}

99
tcl-dp/unix/dpLocks.c Normal file
View File

@@ -0,0 +1,99 @@
#include <stdio.h>
#include <errno.h>
/*
* If the lock is set by another process, PutLock will make an attempt to remove
* it every SLEEP_TIME seconds.
*/
#define SLEEP_TIME 1
#define ERROR(x) { \
FILE *fp; \
char buffer [1000]; \
sprintf(buffer, "%s place %d error = %d", SOURCE, x, errno);\
perror(buffer); \
fp = fopen("ERROR", "a"); \
fprintf(fp, buffer); \
fclose(fp); \
};
/*
* PutLock --
*
* Creates a symbolic link on the file given in lockFilePath. The name of
* the file the link points is a string representing the process number of
* the filter process. If the link already exists, the program checks if
* the process whose number is given in the symbolic link still exists. If
* yes, the program waits for one second and then checks again for the
* status of the lock. If no, the existing lock is removed and the new one
* is put in its place.
*
* Results:
*
* The return value is 2 if the operation failed, otherwise it is 0.
*
* Side effects:
*
* Puts a lock (symbolic link) on the given file.
*
*/
int
PutLock (lockFilePath)
char *lockFilePath; /* File to put lock on. */
{
char pid [15];
sprintf(pid, "%ld", (long)getpid());
/*
* Waiting for lock to be removed or for timeout.
* If other error than "already existing link" occurs, exit.
*/
while(symlink(pid, lockFilePath) == -1) {
sleep(1);
}
return 0;
}
/*
* RemoveLock --
*
* Remove the symbolic link from the file given in lockFilePath. The link
* is removed only if it was put by this process (this is checked by
* comparing the value of the symbolink link with the ptrocess id).
*
* Results:
*
* The return value is 2 if the operation failed, otherwise it is 0.
*
* Side effects:
*
* None.
*/
int
RemoveLock (lockFilePath)
char *lockFilePath; /* File to remove lock from. */
{
if(unlink(lockFilePath) != 0) {
FILE *fp = fopen("/usr/u/mperham/FILTER", "a");
ERROR(8);
return 2;
}
return 0;
}

79
tcl-dp/unix/dpPort.h Normal file
View File

@@ -0,0 +1,79 @@
/*
* unix/dpPort.h --
*
* This file is included by all of the Dp C files. It contains
* information that may be configuration-dependent, such as
* #includes for system include files and a few other things.
*
* Copyright (c) 1995-1996 The Regents of Cornell University.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
*/
#ifndef _DPUNIXPORT
#define _DPUNIXPORT
#include <stdlib.h>
#include <errno.h>
#ifndef DP_HAS_MULTICAST
# include "unix/compat/in.h"
#endif
#define NONBLOCKING(flags) (flags & O_NONBLOCK)
#define DP_SOCKET TCL_UNIX_FD
#define SERIAL_HANDLE TCL_UNIX_FD
#define DP_SOCKET_ERROR (-1)
#define DP_INADDR_NONE (-1)
#define ASYNC_CONNECT_ERROR EINPROGRESS
/*
* The following are abstract data types for sockets and internet addresses
*/
typedef int DpSocket;
typedef struct sockaddr DpSocketAddress;
typedef struct sockaddr_in DpSocketAddressIP;
typedef int SerialHandle;
#ifndef _TCL76
typedef ClientData FileHandle;
int SockGetFile _ANSI_ARGS_((ClientData instanceData, int direction,
FileHandle *handlePtr));
int SockClose _ANSI_ARGS_((ClientData instanceData,
Tcl_Interp *interp));
int SockBlockMode _ANSI_ARGS_((ClientData instanceData, int mode));
void SockWatch _ANSI_ARGS_((ClientData instanceData, int mask));
int UdpIpmOutput _ANSI_ARGS_((ClientData instanceData, char *buf,
int toWrite, int *errorCodePtr));
#endif
/*
* The flag for setting non-blocking I/O varies a bit from Unix to Unix
*/
#ifdef HPUX
# define NBIO_FLAG O_NONBLOCK
#else
# define NBIO_FLAG O_NDELAY
#endif
#define DP_INADDR_ANY INADDR_ANY
/*
* Serial Port stuff
*/
#if !defined(PARITY_NONE)
# define PARITY_NONE 0
# define PARITY_ODD 1
# define PARITY_EVEN 2
#endif
#endif /* _DPUNIXPORT */

735
tcl-dp/unix/dpSerial.c Normal file
View File

@@ -0,0 +1,735 @@
/* Tcl_Channel implementation for serial ports */
#include "generic/dpInt.h"
#include "generic/dpPort.h"
#include <termios.h>
/*
* These names cannot be longer than MAX_LENGTH - 1
*
* Note that a given machine may only HAVE 2 serial ports
* so serial3 and serial4 may not work even if they are
* listed here.
*
* A note on naming: because there is no standard UNIX
* naming scheme, we must do it by OS. You can add more
* ports by upping NUM_PORTS and adding the names.
*
*/
#define NUM_PORTS 4
static char *portNames[NUM_PORTS] = {
#if defined(__LINUX__)
"/dev/ttyS0",
"/dev/ttyS1",
"/dev/ttyS2",
"/dev/ttyS3"
#elif defined(__HPUX__)
"/dev/plt_rs232_a",
"/dev/plt_rs232_b",
NULL,
NULL
#elif defined(__SUNOS__) || defined(__SOLARIS__)
"/dev/ttya",
"/dev/ttyb",
"/dev/ttyc",
"/dev/ttyd"
#elif defined(__sgi)
"/dev/ttyd1",
"/dev/ttyd2",
"/dev/ttyd3",
"/dev/ttyd4"
#elif defined(__FREEBSD__)
/*
* Why is it so difficult to find out
* the names of the damn serial ports in
* FreeBSD?
*/
NULL,
NULL,
NULL,
NULL
#else
/*
* We could assume the worst and just not let
* DP be compiled. But most people won't
* even use the serial interface (<sniff>) so we'll
* just let DP catch it at runtime.
*/
NULL,
NULL,
NULL,
NULL
#endif
};
int DppOpenSerialChannel _ANSI_ARGS_((Tcl_Interp *interp,
ClientData instanceData, char *devStr,
int flags));
int DppSerialBlock _ANSI_ARGS_((ClientData instanceData,
int mode));
int DppSerialClose _ANSI_ARGS_((ClientData instanceData));
int DppSerialInput _ANSI_ARGS_((ClientData instanceData,
char *bufPtr, int bufSize,
int *errorCodePtr));
int DppSerialOutput _ANSI_ARGS_((ClientData instanceData,
char *bufPtr, int toWrite,
int *errorCodePtr));
int DppSerialSetOption _ANSI_ARGS_((ClientData instanceData,
int optionName, int val));
int DppSerialGetOption _ANSI_ARGS_((ClientData instanceData,
int opt, char *optionName,
Tcl_DString *dsPtr));
int DppSerialFileReady _ANSI_ARGS_((ClientData instanceData,
int mask));
void DppSerialWatchFile _ANSI_ARGS_((ClientData instanceData,
int mask));
static char * DppBaudRateConsToStr _ANSI_ARGS_((int rate));
static int DppBaudRateNumToCons _ANSI_ARGS_((int rate));
static char * DppCheckDevice _ANSI_ARGS_((char *devStr));
/* ------------------------------------------------
*
* DppOpenSerialChannel -
*
* Creates a DP channel using the serial port specified
* in dev (i.e. "serial1")
*
* Returns
*
* Tcl_Channel used for I/O.
*
* Side Effects
*
* None.
*
* ------------------------------------------------
*/
int
DppOpenSerialChannel(interp, instanceData, devStr, flags)
Tcl_Interp *interp;
ClientData instanceData;
char *devStr; /* /dev to use */
int flags; /* T/F to block */
/* Only block is implemented
right now */
{
SerialState *ssPtr = (SerialState *) instanceData;
char *openStr;
int fd, mode = O_RDWR;
int blockFlag = 0;
blockFlag |= 0x1;
if (flags & 0x2) {
mode = O_RDONLY;
}
if ((openStr = DppCheckDevice(devStr)) == NULL) {
Tcl_AppendResult(interp, "Unknown device \"", devStr, "\"", NULL);
return TCL_ERROR;
}
fd = open(openStr, mode);
if (fd == -1) {
Tcl_AppendResult(interp, "Error opening ", openStr,
": ", Tcl_PosixError(interp), NULL);
return TCL_ERROR;
}
ssPtr->fd = fd;
strcpy(ssPtr->deviceName, devStr);
/*
* Setup the port to a default of 19200, 8N1
*/
if (DppSerialSetOption(ssPtr, DP_BAUDRATE, 19200) == TCL_ERROR) {
goto error;
}
if (DppSerialSetOption(ssPtr, DP_CHARSIZE, 8) == TCL_ERROR) {
goto error;
}
if (DppSerialSetOption(ssPtr, DP_PARITY, PARITY_NONE) == TCL_ERROR) {
goto error;
}
if (DppSerialSetOption(ssPtr, DP_STOPBITS, 1) == TCL_ERROR) {
goto error;
}
if (DppSerialSetOption(ssPtr, DP_BLOCK, blockFlag) == TCL_ERROR) {
goto error;
}
return TCL_OK;
error:
Tcl_AppendResult(interp, "Error configuring serial device", NULL);
return TCL_ERROR;
}
/* --------------------------------------------------
*
* SerialBlock --
*
* Sets blocking mode of serial port based on
* mode.
*
* Returns
*
* TCL_OK or TCL_ERROR
*
* Side Effects
*
* None.
*
* ---------------------------------------------------
*/
int
DppSerialBlock(instanceData, mode)
ClientData instanceData;
int mode;
{
if (mode == TCL_MODE_BLOCKING) {
return DppSerialSetOption(instanceData, DP_BLOCK, 1);
} else {
return DppSerialSetOption(instanceData, DP_BLOCK, 0);
}
}
/* --------------------------------------------------
*
* SerialClose --
*
* Closes the serial port and frees memory
* associated with the port.
*
* Returns
*
* TCL_OK or TCL_ERROR
*
* Side Effects
*
* Channel is no longer available.
*
* ---------------------------------------------------
*/
int
DppSerialClose(instanceData)
ClientData instanceData;
{
SerialState *ssPtr = (SerialState *) instanceData;
return close(ssPtr->fd);
}
/* --------------------------------------------------
*
* SerialInput --
*
* Reads upto bufSize bytes from serial port
* into buf.
*
* Returns
*
* Number of bytes read or -1 with POSIX error code
* in errorCodePtr.
*
* Side Effects
*
* buf is modified.
*
* ---------------------------------------------------
*/
int
DppSerialInput(instanceData, bufPtr, bufSize, errorCodePtr)
ClientData instanceData;
char *bufPtr;
int bufSize;
int *errorCodePtr;
{
SerialState *ssPtr = (SerialState *) instanceData;
int amount;
amount = read(ssPtr->fd, bufPtr, bufSize);
if (amount > 0) {
/* We are fine. Return amount read */
return amount;
} else if (amount == 0) {
/* There is no data to be read */
int flags;
fcntl(ssPtr->fd, F_GETFL, &flags);
if (NONBLOCKING(flags)) {
*errorCodePtr = EAGAIN;
return -1;
} else {
return amount;
}
}
/* Bummer! Set the error code and return */
*errorCodePtr = errno;
return -1;
}
/* --------------------------------------------------
*
* SerialOutput --
*
* Sends toWrite bytes out through the serial
* port.
*
* Returns
*
* Number of bytes written or -1 and a POSIX
* error in errorCodePtr.
*
* Side Effects
*
* None.
*
* ---------------------------------------------------
*/
int
DppSerialOutput(instanceData, bufPtr, toWrite, errorCodePtr)
ClientData instanceData;
char *bufPtr;
int toWrite;
int *errorCodePtr;
{
int amount;
SerialState *ssPtr = (SerialState *) instanceData;
amount = write(ssPtr->fd, bufPtr, toWrite);
if (amount > 0) {
return amount;
} else if (amount == 0) {
int flags;
fcntl(ssPtr->fd, F_GETFL, &flags);
if (NONBLOCKING(flags)) {
*errorCodePtr = EAGAIN;
return -1;
} else {
return amount;
}
}
*errorCodePtr = errno;
return -1;
}
/* --------------------------------------------------
*
* DppSetSerialState --
*
* Platform-specific serial option changer.
*
* Returns
*
* TCL_OK or TCL_ERROR
*
* Side Effects
*
* None.
*
* ---------------------------------------------------
*/
int
DppSerialSetOption(instanceData, optionName, optionVal)
ClientData instanceData;
int optionName;
int optionVal;
{
SerialState *ssPtr = (SerialState *) instanceData;
struct termios term;
int rate;
int flags = 0;
if (tcgetattr(ssPtr->fd, &term) == -1) {
return TCL_ERROR;
}
switch (optionName) {
case DP_PARITY:
if (optionVal == PARITY_NONE) {
term.c_cflag &= ~PARENB;
} else {
term.c_cflag |= PARENB;
if (optionVal == PARITY_EVEN) {
term.c_cflag &= ~PARODD;
} else {
term.c_cflag |= PARODD;
}
}
break;
case DP_CHARSIZE:
term.c_cflag &= ~(CSIZE);
if (optionVal == 7) {
term.c_cflag |= CS7;
} else {
term.c_cflag |= CS8;
}
break;
case DP_STOPBITS:
if (optionVal == 1) {
term.c_cflag &= (~CSTOPB);
} else {
term.c_cflag |= CSTOPB;
}
break;
case DP_BAUDRATE:
rate = DppBaudRateNumToCons(optionVal);
if (rate == -1) {
char baud[7];
sprintf(baud, "%ld", optionVal);
Tcl_SetErrno(EINVAL);
return TCL_ERROR;
}
cfsetispeed(&term, rate);
cfsetospeed(&term, rate);
break;
case DP_BLOCK:
fcntl(ssPtr->fd, F_GETFL, &flags);
if (optionVal == 1) {
if (NONBLOCKING(flags)) {
flags &= ~NBIO_FLAG;
fcntl(ssPtr->fd, F_SETFL, flags);
}
} else {
if (!NONBLOCKING(flags)) {
flags |= NBIO_FLAG;
fcntl(ssPtr->fd, F_SETFL, flags);
}
}
break;
default:
Tcl_SetErrno(EINVAL);
return TCL_ERROR;
}
if (tcsetattr(ssPtr->fd, TCSADRAIN, &term) == -1) {
return TCL_ERROR;
}
return TCL_OK;
}
/* ----------------------------------------------------
*
* Dpp_BaudRateNumToCons --
*
* Translates an integer baudrate into a constant
* understood by the system.
*
* Returns
*
* Constant representing the baudrate or 0xFFFFFFFF on error.
*
* Side Effects
*
* None.
*
* -----------------------------------------------------
*/
static int
DppBaudRateNumToCons(rate)
int rate;
{
switch (rate) {
case 1200:
return B1200;
case 2400:
return B2400;
case 4800:
return B4800;
case 9600:
return B9600;
case 19200:
return B19200;
case 38400:
return B38400;
#ifdef B57600
case 57600:
return B57600;
#endif
#ifdef B115200
case 115200:
return B115200;
#endif
default:
return -1;
}
}
/* ----------------------------------------------------
*
* DppSerialGetOption --
*
* Returns the value of the given option or the
* value of ALL options if optionName is set to
* DP_ALL_OPTIONS.
*
* Returns
*
* TCL_OK or TCL_ERROR.
*
* Side Effects
*
* None.
*
* -----------------------------------------------------
*/
int
DppSerialGetOption(instanceData, opt, optionName, dsPtr)
ClientData instanceData;
int opt;
char *optionName;
Tcl_DString *dsPtr;
{
SerialState *ssPtr = (SerialState *) instanceData;
struct termios term;
char *rate;
unsigned long ospeed;
tcgetattr(ssPtr->fd, &term);
switch (opt) {
case DP_PARITY:
if (term.c_cflag & PARENB) {
if (term.c_cflag & PARODD) {
Tcl_DStringAppend(dsPtr, "odd", -1);
} else {
Tcl_DStringAppend(dsPtr, "even", -1);
}
} else {
Tcl_DStringAppend(dsPtr, "none", -1);
}
return TCL_OK;
case DP_STOPBITS:
if (term.c_cflag & CSTOPB) {
Tcl_DStringAppend(dsPtr, "2", -1);
} else {
Tcl_DStringAppend(dsPtr, "1", -1);
}
return TCL_OK;
case DP_CHARSIZE:
if ((term.c_cflag & CS8) == CS8) {
Tcl_DStringAppend(dsPtr, "8", -1);
} else {
Tcl_DStringAppend(dsPtr, "7", -1);
}
return TCL_OK;
case DP_BAUDRATE:
#if defined(__SOLARIS__) && defined(CBAUDEXT)
if (term.c_cflag & CBAUDEXT) {
ospeed = (term.c_cflag & CBAUD) + CBAUD + 1;
} else {
ospeed = term.c_cflag & CBAUD;
}
#elif defined(__FREEBSD__)
ospeed = term.c_ospeed;
#else
ospeed = term.c_cflag & CBAUD;
#endif
rate = DppBaudRateConsToStr(ospeed);
if (rate == NULL) {
Tcl_SetErrno(EINVAL);
return TCL_ERROR;
}
Tcl_DStringAppend(dsPtr, rate, -1);
return TCL_OK;
case DP_DEVICENAME:
Tcl_DStringAppend(dsPtr, ssPtr->deviceName, -1);
return TCL_OK;
default:
{
char bufStr[128];
sprintf(bufStr, "bad option \"%s\": must be -blocking, -buffering, -buffersize, -eofchar, -translation, or a channel type specific option", optionName);
Tcl_DStringAppend(dsPtr, bufStr, -1);
Tcl_SetErrno (EINVAL);
return TCL_ERROR;
}
}
}
/* ----------------------------------------------------
*
* Dpp_BaudRateConsToStr --
*
* Translates the native UNIX baudrate constants
* to a human-readable string.
*
* Returns
*
* Pointer to the string representing the baudrate
*
* Side Effects
*
* None.
*
* -----------------------------------------------------
*/
static char *
DppBaudRateConsToStr(rate)
int rate;
{
switch (rate) {
case B1200:
return "1200";
case B2400:
return "2400";
case B4800:
return "4800";
case B9600:
return "9600";
case B19200:
return "19200";
case B38400:
return "38400";
#ifdef B57600
case B57600:
return "57600";
#endif
#ifdef B115200
case B115200:
return "115200";
#endif
default:
return NULL;
}
}
/* ----------------------------------------------------
*
* DppCheckDevice --
*
* This function checks to make sure a string
* matches the name of a valid serial port on
* this OS. In UNIX, there is no standard for
* RS-232 ports, so we must #define them based
* on the OS. We also allow the DP naming
* method of "serialx" which we translate into
* an OS-specific name.
*
* Returns
*
* TCL_OK if the string is ok with devStr updated
* or TCL_ERROR if the string is invalid.
*
* Side Effects
*
* None.
*
* -----------------------------------------------------
*/
static char *
DppCheckDevice(devStr)
char *devStr;
{
int num;
if (strlen(devStr) == 7) {
if (strncmp(devStr, "serial", 6) == 0) {
num = devStr[6] - '1';
if ((num < 0) || (num > 3)) {
return NULL;
}
return portNames[num];
}
}
return NULL;
}
/* ----------------------------------------------------
*
* DppSerialWatchFile --
*
* Sets up event handling on a serial port.
* We can use Tcl_WatchFile since serial
* ports are file descriptors in UNIX.
*
* Returns
*
* Nothing.
*
* Side Effects
*
* None.
*
* -----------------------------------------------------
*/
void
DppSerialWatchFile(instanceData, mask)
ClientData instanceData;
int mask;
{
SerialState *ssPtr = (SerialState *) instanceData;
#ifdef _TCL76
Tcl_WatchFile((ClientData)ssPtr->fd, mask);
#else
if (mask) {
Tcl_CreateFileHandler(ssPtr->fd, mask,
(Tcl_FileProc *) Tcl_NotifyChannel,
(ClientData) ssPtr->channel);
} else {
Tcl_DeleteFileHandler(ssPtr->fd);
}
#endif
}
/* ----------------------------------------------------
*
* DppSerialFileReady --
*
* Returns events of interest on the serial port
* based on mask.
*
* Returns
*
* See above.
*
* Side Effects
*
* None.
*
* -----------------------------------------------------
*/
#ifdef _TCL76
int
DppSerialFileReady(instanceData, mask)
ClientData instanceData;
int mask;
{
SerialState *ssPtr = (SerialState *) instanceData;
return Tcl_FileReady(ssPtr->theFile, mask);
}
#endif

280
tcl-dp/unix/dpSock.c Normal file
View File

@@ -0,0 +1,280 @@
/*
* unix/dpSock.c --
*
* This file implements generic Unix-specific routines for the
* socket code.
*
* Copyright (c) 1995-1996 Cornell University.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
*/
#include "generic/dpInt.h"
#include "generic/dpPort.h"
/*
*--------------------------------------------------------------
*
* DppCloseSocket --
*
* Close the socket passed in.
*
* Results:
* None
*
* Side effects:
* None
*
*--------------------------------------------------------------
*/
int
DppCloseSocket (sock)
DpSocket sock;
{
return close(sock);
}
/*
*--------------------------------------------------------------
*
* DppSetBlock --
*
* Put the socket into a blocking or non-blocking state.
*
* Results:
* None
*
* Side effects:
* None
*
*--------------------------------------------------------------
*/
int
DppSetBlock (sock, block)
DpSocket sock;
int block;
{
int flags;
flags = fcntl(sock, F_GETFL, 0);
if (block) {
/* Set blocking mode */
fcntl(sock, F_SETFL, flags & ~NBIO_FLAG);
} else {
/* Set non-blocking mode */
fcntl(sock, F_SETFL, flags | NBIO_FLAG);
}
return 0;
}
/*
* -------------------------------------------------------------
*
* DppGetErrno --
*
* Returns the POSIX error code.
*
* Results:
* The POSIX errorcode.
*
* Side Effects:
* None.
*
* -------------------------------------------------------------
*/
int
DppGetErrno()
{
return Tcl_GetErrno();
}
#ifndef _TCL76
/*
*--------------------------------------------------------------
*
* SockBlockMode --
*
* Sets the tcp socket to blocking or non-blocking. Just
* a wrapper around the platform specific function.
*
* Results:
* Zero if the operation was successful, or a nonzero POSIX
* error code if the operation failed.
*
* Side effects:
* None
*
*--------------------------------------------------------------
*/
int
SockBlockMode (instanceData, mode)
ClientData instanceData; /* Pointer to tcpState struct */
int mode; /* TCL_MODE_BLOCKING or TCL_MODE_NONBLOCKING */
{
SocketState *statePtr = (SocketState *)instanceData;
if (mode == TCL_MODE_BLOCKING) {
return DppSetBlock(statePtr->sock, 1);
} else {
return DppSetBlock(statePtr->sock, 0);
}
}
/*
*--------------------------------------------------------------
*
* SockClose --
*
* This function is called by the Tcl channel driver when the
* caller want to close the socket. It releases the instanceData
* and closes the scoket. All queued output will have been flushed
* to the device before this function is called.
*
* Results:
* Zero for success, otherwise a nonzero POSIX error code and,
* if interp is not NULL, an error message in interp->result
*
* Side effects:
* None
*
*--------------------------------------------------------------
*/
int
SockClose (instanceData, interp)
ClientData instanceData; /* (in) Pointer to tcpState struct */
Tcl_Interp *interp; /* (in) For error reporting */
{
SocketState *statePtr = (SocketState *)instanceData;
int result;
SDBG(("Closing socket %d\n", statePtr->sock));
result = DppCloseSocket(statePtr->sock);
if ((result != 0) && (interp != NULL)) {
DppGetErrno();
Tcl_SetResult(interp, Tcl_PosixError(interp), TCL_STATIC);
}
/*
* IPM only
*/
if (statePtr->flags & SOCKET_IPM) {
Tcl_DStringFree(&statePtr->groupList);
}
ckfree((char *)statePtr);
return result;
}
/*
*--------------------------------------------------------------
*
* SockWatch --
*
* Creates an event callback for this socket or deletes
* the current callback.
*
* Results:
* None.
*
* Side effects:
* The callback can do anything.
*
*--------------------------------------------------------------
*/
void
SockWatch (instanceData, mask)
ClientData instanceData;
int mask;
{
SocketState *infoPtr = (SocketState *) instanceData;
if (mask) {
Tcl_CreateFileHandler(infoPtr->sock, mask,
(Tcl_FileProc *) Tcl_NotifyChannel,
(ClientData) infoPtr->channel);
SDBG(("Creating callback for socket %d\n", infoPtr->sock));
} else {
Tcl_DeleteFileHandler(infoPtr->sock);
SDBG(("Deleting callback for socket %d\n", infoPtr->sock));
}
}
/*
*--------------------------------------------------------------
*
* SockGetFile --
*
* Called from Tcl_GetChannelFile to retrieve the handle
* from inside a socket based channel.
*
* Results:
* TCL_OK
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
int
SockGetFile(instanceData, direction, handlePtr)
ClientData instanceData;
int direction;
FileHandle *handlePtr;
{
SocketState *statePtr = (SocketState *)instanceData;
*handlePtr = statePtr->sockFile;
return TCL_OK;
}
/*
*--------------------------------------------------------------
*
* UdpIpmOutput --
*
* This function is called by the Tcl channel driver whenever
* the user wants to send output to the UDP socket.
* The function writes toWrite bytes from buf to the socket.
*
* Results:
* A nonnegative integer indicating how many bytes were written
* to the socket. The return value is normally the same as toWrite,
* but may be less in some cases such as if the output operation
* is interrupted by a signal.
*
* Side effects:
* None
*
*--------------------------------------------------------------
*/
int
UdpIpmOutput (instanceData, buf, toWrite, errorCodePtr)
ClientData instanceData; /* (in) Pointer to udpState struct */
char *buf; /* (in) Buffer to write */
int toWrite; /* (in) Number of bytes to write */
int *errorCodePtr; /* (out) POSIX error code (if any) */
{
SocketState *statePtr = (SocketState *) instanceData;
int result;
result = sendto(statePtr->sock, buf, toWrite, 0,
(struct sockaddr *) &statePtr->sockaddr,
sizeof(statePtr->sockaddr));
if (result == DP_SOCKET_ERROR) {
*errorCodePtr = DppGetErrno();
}
return result;
}
#endif

810
tcl-dp/unix/dpUnixIpm.c Normal file
View File

@@ -0,0 +1,810 @@
/*
* dpIPM.c --
*
* This file implements the generic code for an IP multicasting
* channel driver. These are channels that are created by
* evaluating "dp_connect ipm".
*
* Copyright (c) 1995-1996 Cornell University.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
*/
#include "generic/dpInt.h"
#ifndef IN_MULTICAST
/*
* This just checks to make sure the IP address is a valid
* IP multicast address: 224.0.0.0 < addr < 239.255.255.255
*/
#define IN_MULTICAST(i) (((i) & 0xf0000000) == 0xe0000000)
#endif
/*
* The default send and receive buffer size.
*/
#define DP_IPM_SENDBUFSIZE 8192
#define DP_IPM_RECVBUFSIZE 8192
typedef SocketState IpmState;
#define PEEK_MODE (1<<1) /* Read without consuming? */
#define ASYNC_CONNECT (1<<2) /* Asynchronous connection? */
#define IS_SERVER (1<<3) /* Is this a server Ipm socket? */
/*
* Procedures that are used in this file only.
*/
static IpmState * CreateIPMSocket _ANSI_ARGS_((Tcl_Interp *interp,
int ipAddr, int port, int ttl));
static int IpmInput _ANSI_ARGS_((ClientData instanceData,
char *buf, int bufSize, int *errorCodePtr));
static int IpmSetOption _ANSI_ARGS_((ClientData instanceData,
Tcl_Interp *interp, char *optionName,
char *optionValue));
static int IpmGetOption _ANSI_ARGS_((ClientData instanceData,
Tcl_Interp *interp, char *optionName,
Tcl_DString *dsPtr));
static Tcl_ChannelType ipmChannelType = {
"ipm", /* Name of channel */
SockBlockMode, /* Proc to set blocking mode on socket */
SockClose, /* Proc to close a socket */
IpmInput, /* Proc to get input from a socket */
UdpIpmOutput, /* Proc to send output to a socket */
NULL, /* Can't seek on a socket! */
IpmSetOption, /* Proc to set a socket option */
IpmGetOption, /* Proc to set a socket option */
SockWatch, /* Proc called to set event loop wait params */
SockGetFile /* Proc to return a handle assoc with socket */
};
static int ipmCount = 0; /* Number of ipm files opened -- used to
* generate unique ids for channels */
/*
*--------------------------------------------------------------
*
* DpOpenIpmChannel --
*
* Opens a new channel that uses the IPM protocol.
*
* Results:
* Returns a pointer to the newly created Tcl_Channel. This
* is the structure with all the function pointers Tcl needs
* to communicate with (read, write, close, etc) the channel.
*
* Side effects:
* A socket is created with the specified port. No other
* socket can use that port until this channel is closed.
*
*--------------------------------------------------------------
*/
Tcl_Channel
DpOpenIpmChannel(interp, argc, argv)
Tcl_Interp *interp; /* For error reporting; can be NULL. */
int argc; /* Number of arguments. */
char **argv; /* Argument strings. */
{
#ifdef NO_MULTICAST_DEF
Tcl_AppendResult(interp, "IP multicast is not available on this system",
NULL);
return NULL;
#else
Tcl_Channel chan;
IpmState *statePtr = NULL;
char channelName[20];
char *groupName, *str;
char **av;
int i, ac;
/*
* The default values for the value-option pairs
*/
int ipAddr = 0;
int port = 0;
int ttl = 1;
/*
* Flags to indicate that a certain option has been set by the
* command line
*/
int setGroup = 0;
int setPort = 0;
for (i=0; i<argc; i+=2) {
int v = i+1;
size_t len = strlen(argv[i]);
if (strncmp(argv[i], "-group", len)==0) {
if (v==argc) {goto arg_missing;}
if (!DpHostToIpAddr(argv[v], &ipAddr)) {
Tcl_AppendResult (interp, "Illegal value for -group \"",
argv[v], "\"", NULL);
return NULL;
}
groupName = argv[v];
setGroup = 1;
} else if (strncmp(argv[i], "-myport", len)==0) {
if (v==argc) {goto arg_missing;}
if (Tcl_GetInt(interp, argv[v], &port) != TCL_OK) {
return NULL;
}
if (port < 0) {
Tcl_AppendResult(interp, "expected non-negative integer ",
"but got \"", argv[v], "\"", NULL);
return NULL;
}
setPort = 1;
} else if (strncmp(argv[i], "-ttl", len)==0) {
if (v==argc) {goto arg_missing;}
if (Tcl_GetInt(interp, argv[v], &ttl) != TCL_OK) {
return NULL;
}
} else {
Tcl_AppendResult(interp, "unknown option \"",
argv[i], "\", must be -group, ",
"-myport or -ttl", NULL);
return NULL;
}
}
/*
* Check the options that must or must not be specified, depending on
* the -server option.
*/
if (!setGroup) {
Tcl_AppendResult(interp, "option -group must be specified",
NULL);
return NULL;
}
if (!setPort) {
Tcl_AppendResult(interp, "option -myport must be specified",
NULL);
return NULL;
}
/*
* Create a new socket and wrap it in a channel.
*/
statePtr = CreateIPMSocket(interp, ipAddr, port, ttl);
if (statePtr == NULL) {
return NULL;
}
sprintf(channelName, "ipm%d", ipmCount++);
chan = Tcl_CreateChannel(&ipmChannelType, channelName,
(ClientData)statePtr, TCL_READABLE|TCL_WRITABLE);
Tcl_RegisterChannel(interp, chan);
ac = 1;
av = &groupName;
str = Tcl_Merge(ac, av);
Tcl_DStringAppendElement(&statePtr->groupList, str);
ckfree(str);
if (Tcl_SetChannelOption(interp, chan, "-translation", "binary") !=
TCL_OK) {
DpClose(interp, chan);
ckfree((char *)statePtr);
return NULL;
}
if (Tcl_SetChannelOption(interp, chan, "-blocking", "1") !=
TCL_OK) {
DpClose(interp, chan);
ckfree((char *)statePtr);
return NULL;
}
if (Tcl_SetChannelOption(interp, chan, "-buffering", "none") !=
TCL_OK) {
DpClose(interp, chan);
ckfree((char *)statePtr);
return NULL;
}
return chan;
arg_missing:
Tcl_AppendResult(interp, "value for \"", argv[argc-1], "\" missing", NULL);
return NULL;
#endif
}
/*
*--------------------------------------------------------------
*
* IpmInput --
*
* This function is called by the Tcl channel driver whenever the
* user wants to get input from the IPM socket. If the socket
* has some data available but less than requested by the bufSize
* argument, we only read as much data as is available and return
* without blocking. If the socket has no data available
* whatsoever and is blocking, we block until at least one byte
* of data can be read from the socket.
*
* Results:
* A nonnegative integer indicating how many bytes were read, or
* DP_SOCKET_ERROR in case of error (with errorCodePtr set to the
* POSIX error code).
*
* Side effects:
* None
*
*--------------------------------------------------------------
*/
static int
IpmInput(instanceData, buf, bufSize, errorCodePtr)
ClientData instanceData; /* (in) Pointer to ipmState struct */
char *buf; /* (in/out) Buffer to fill */
int bufSize; /* (in) Size of buffer */
int *errorCodePtr; /* (out) POSIX error code (if any) */
{
IpmState *statePtr = (IpmState *)instanceData;
DpSocketAddressIP fromAddr;
int bytesRead, fromLen;
unsigned int fromHost, fromPort;
char str[64];
fromLen = sizeof(fromAddr);
bytesRead = recvfrom(statePtr->sock, buf, bufSize, 0,
(struct sockaddr *)&fromAddr, &fromLen);
if (bytesRead == DP_SOCKET_ERROR) {
*errorCodePtr = DppGetErrno();
return -1;
}
if (statePtr->interp != NULL) {
fromHost = ntohl(fromAddr.sin_addr.s_addr);
fromPort = ntohs(fromAddr.sin_port);
sprintf (str, "{%d.%d.%d.%d %d}", (fromHost>>24),
(fromHost>>16) & 0xFF, (fromHost>>8) & 0xFF, fromHost & 0xFF,
fromPort);
Tcl_SetVar(statePtr->interp, "dp_from", str, TCL_GLOBAL_ONLY);
}
return bytesRead;
}
/*
*--------------------------------------------------------------
*
* IpmSetOption --
*
* This function is called by the Tcl channel driver
* whenever Tcl evaluates and fconfigure call to set
* some property of the ipm socket (e.g., the buffer
* size). The valid options are "sendBuffer" and
* "recvBuffer"
*
* Results:
* Standard Tcl return value.
*
* Side effects:
* Depends on the option. Generally changes the maximum
* message size that can be sent/received.
*
*--------------------------------------------------------------
*/
static int
IpmSetOption (instanceData, interp, optionName, optionValue)
ClientData instanceData;
Tcl_Interp *interp;
char *optionName;
char *optionValue;
{
int option;
int value;
char c;
int rc;
IpmState *statePtr = (IpmState *)instanceData;
/*
* Set the option specified by optionName
*/
if (optionName[0] == '-') {
option = DpTranslateOption(optionName+1);
} else {
option = -1;
}
switch (option) {
case DP_REUSEADDR:
if (Tcl_GetBoolean(interp, optionValue, &value) != TCL_OK) {
return TCL_ERROR;
}
return DpIpmSetSocketOption(statePtr, option, value);
case DP_RECV_BUFFER_SIZE:
case DP_SEND_BUFFER_SIZE:
if (Tcl_GetInt(interp, optionValue, &value) != TCL_OK) {
return TCL_ERROR;
}
if (value <=0) {
Tcl_AppendResult(interp, "Buffer size must be > 0", NULL);
return TCL_ERROR;
}
return DpIpmSetSocketOption(statePtr, option, value);
case DP_GROUP:
c = optionValue[0];
if (c != '+' && c != '-') {
Tcl_AppendResult (interp, "Expected an add/drop token. ",
"Please see docs on how to add/drop a group.", NULL);
return TCL_ERROR;
}
if (DpHostToIpAddr (&optionValue[1], &value) == 0) {
Tcl_AppendResult (interp,
"Expected IP address or hostname but got \"",
optionValue, "\"", NULL);
return TCL_ERROR;
}
if (c == '+') {
option = DP_ADD_MEMBERSHIP;
} else {
option = DP_DROP_MEMBERSHIP;
}
rc = DpIpmSetSocketOption(statePtr, option, value);
if (rc == 0) {
/*
* Update the group list
*/
if (option == DP_ADD_MEMBERSHIP) {
Tcl_DStringAppendElement(&statePtr->groupList,
&optionValue[1]);
} else {
int argc, i, j = 0;
char **argv;
Tcl_SplitList(interp,
Tcl_DStringValue(&statePtr->groupList),
&argc, &argv);
for (i=0;i<argc;i++) {
if (!strcmp(argv[i], &optionValue[1])) {
while (i<argc) {
argv[i] = argv[i+1];
i++;
}
j = 1;
break;
}
}
if (!j) {
Tcl_AppendResult(interp, "Group address not found",
"in list", NULL);
return TCL_ERROR;
} else {
Tcl_DStringFree(&statePtr->groupList);
Tcl_DStringInit(&statePtr->groupList);
Tcl_DStringAppend(&statePtr->groupList,
Tcl_Merge(argc-1, argv), -1);
}
}
}
return rc;
case DP_MULTICAST_LOOP:
if (Tcl_GetInt(interp, optionValue, &value) != TCL_OK) {
return TCL_ERROR;
}
return DpIpmSetSocketOption(statePtr, DP_MULTICAST_LOOP, value);
case DP_MYPORT:
Tcl_AppendResult(interp, "Port may not be changed",
" after creation.", NULL);
return TCL_ERROR;
default:
Tcl_AppendResult (interp, "bad option \"", optionName,
"\": must be -recvBuffer, -reuseAddr, -group, ",
"-sendBuffer or a standard fconfigure option", NULL);
return TCL_ERROR;
}
}
/*
*--------------------------------------------------------------
*
* IpmGetOption --
*
* This function is called by the Tcl channel code to
* retrieve a parameter of the socket (e.g., a buffer size).
* The valid options are "sendBuffer" and "recvBuffer"
*
* Results:
* A standard Tcl result
*
* Side effects:
* None
*
*--------------------------------------------------------------
*/
static int
IpmGetOption (instanceData,
interp,
optionName, dsPtr)
ClientData instanceData;
Tcl_Interp *interp;
char *optionName;
Tcl_DString *dsPtr;
{
int option;
unsigned int value = 0xFFFFFFFF;
char str[256];
IpmState *statePtr = (IpmState *)instanceData;
/*
* If optionName is NULL, then return all options in option-value
* pairs.
*/
if (optionName == NULL) {
Tcl_DStringAppend (dsPtr, " -recvBuffer ", -1);
IpmGetOption(instanceData, interp, "-recvBuffer", dsPtr);
Tcl_DStringAppend (dsPtr, " -reuseAddr ", -1);
IpmGetOption(instanceData, interp, "-reuseAddr", dsPtr);
Tcl_DStringAppend (dsPtr, " -sendBuffer ", -1);
IpmGetOption(instanceData, interp, "-sendBuffer", dsPtr);
Tcl_DStringAppend (dsPtr, " -loopback ", -1);
IpmGetOption(instanceData, interp, "-loopback", dsPtr);
Tcl_DStringAppend (dsPtr, " -group ", -1);
IpmGetOption(instanceData, interp, "-group", dsPtr);
Tcl_DStringAppend (dsPtr, " -myport ", -1);
IpmGetOption(instanceData, interp, "-myport", dsPtr);
return TCL_OK;
}
/*
* Retrive the value of the option specified by optionName
*/
if (optionName[0] == '-') {
option = DpTranslateOption(&optionName[1]);
} else {
option = -1;
}
switch (option) {
case DP_RECV_BUFFER_SIZE:
case DP_SEND_BUFFER_SIZE:
if (DpIpmGetSocketOption(statePtr, option, &value) != 0) {
return TCL_ERROR;
}
sprintf (str, "%d", value);
Tcl_DStringAppend(dsPtr, str, -1);
break;
case DP_REUSEADDR:
if (DpIpmGetSocketOption(statePtr, option, &value) != 0) {
return TCL_ERROR;
}
if (value) {
/*
* Some systems returns a non-zero value (not necessarily 1)
* to indicate "true".
*/
value = 1;
}
sprintf (str, "%d", value);
Tcl_DStringAppend(dsPtr, str, -1);
break;
case DP_GROUP:
Tcl_DStringAppend(dsPtr, Tcl_DStringValue(&statePtr->groupList),
Tcl_DStringLength(&statePtr->groupList));
break;
case DP_MYPORT:
sprintf(str, "%d", statePtr->groupPort);
Tcl_DStringAppend(dsPtr, str, -1);
break;
case DP_MULTICAST_LOOP:
if (DpIpmGetSocketOption(statePtr, option, &value) != 0) {
return TCL_ERROR;
}
sprintf(str, "%d", value);
Tcl_DStringAppend(dsPtr, str, -1);
break;
default:
Tcl_AppendResult(interp,
"bad option \"", optionName,"\": must be -blocking,",
" -buffering, -buffersize, -eofchar, -translation,",
" or a channel type specific option", NULL);
Tcl_SetErrno (EINVAL);
return TCL_ERROR;
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* CreateIPMSocket --
*
* This function opens a new socket in client mode
* and initializes the IpmState structure.
*
* Results:
* Returns a new IpmState, or NULL with an error in interp->result,
* if interp is not NULL.
*
* Side effects:
* Opens a socket.
*
*----------------------------------------------------------------------
*/
static IpmState *
CreateIPMSocket(interp, group, port, ttl)
Tcl_Interp *interp; /* For error reporting; can be NULL. */
int group; /* IP address of the multicast group. */
int port; /* Port number. */
int ttl; /* Time to live value. */
{
IpmState * statePtr = NULL;
DpSocket sock;
if (!IN_MULTICAST(group)) {
Tcl_AppendResult(interp, "No such IP multicast group", NULL);
return NULL;
}
/*
* Create the socket
*/
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock == DP_SOCKET_ERROR) {
goto error;
}
statePtr = (IpmState *)ckalloc(sizeof(IpmState));
statePtr->interp = interp;
statePtr->groupPort = port;
statePtr->groupAddr = group;
statePtr->sock = sock;
statePtr->sockFile = (ClientData)sock;
Tcl_DStringInit(&statePtr->groupList);
/*
* Bind the socket
*/
memset(&statePtr->sockaddr, 0, sizeof(statePtr->sockaddr));
statePtr->sockaddr.sin_family = AF_INET;
statePtr->sockaddr.sin_port = htons((unsigned short) port);
statePtr->sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
if (DpIpmSetSocketOption(statePtr, DP_REUSEADDR, 1) != 0) {
goto error;
}
if (bind(sock, (struct sockaddr *) &statePtr->sockaddr,
sizeof(statePtr->sockaddr)) != 0) {
goto error;
}
statePtr->sockaddr.sin_addr.s_addr = htonl(group);
statePtr->groupPort = (int) ntohs(statePtr->sockaddr.sin_port);
statePtr->flags |= SOCKET_IPM;
/*
* On some older machines, we need to ask for multicast
* permission.
*/
if (DpIpmSetSocketOption(statePtr, DP_BROADCAST, 1) != 0) {
goto error;
}
/*
* Make this an IPM socket by setting the socket options. Also, set
* other default options of this socket, such as buffer size.
*/
if (DpIpmSetSocketOption(statePtr, DP_ADD_MEMBERSHIP, group) != 0) {
goto error;
}
if (DpIpmSetSocketOption(statePtr, DP_MULTICAST_TTL, ttl) != 0) {
goto error;
}
if (DpIpmSetSocketOption(statePtr, DP_MULTICAST_LOOP, 1) != 0) {
goto error;
}
if (DpIpmSetSocketOption(statePtr, DP_RECV_BUFFER_SIZE,
DP_IPM_RECVBUFSIZE) != 0) {
goto error;
}
if (DpIpmSetSocketOption(statePtr, DP_SEND_BUFFER_SIZE,
DP_IPM_SENDBUFSIZE) != 0) {
goto error;
}
return statePtr;
error:
/*
* Translate Windows Socket error to POSIX errorcode
*/
DppGetErrno();
Tcl_AppendResult(interp, "Error creating IPM socket: ",
Tcl_PosixError(interp), NULL);
if (statePtr) {
if (statePtr->sock != DP_SOCKET_ERROR) {
DppCloseSocket(statePtr->sock);
}
ckfree((char*)statePtr);
}
return NULL;
}
/*
*--------------------------------------------------------------
*
* DpIpmSetSocketOption --
*
* Sets a socket option. The allowable options for Ipm
* sockets are
* DP_SEND_BUFFER_SIZE (int)
* DP_RECV_BUFFER_SIZE (int)
* DP_BLOCK (T/F)
*
* Results:
* Zero if the operation was successful, or a nonzero POSIX
* error code if the operation failed.
*
* Side effects:
* None
*
*--------------------------------------------------------------
*/
int
DpIpmSetSocketOption(statePtr, option, value)
IpmState *statePtr; /* (in) IpmState structure */
int option; /* (in) Option to set */
int value; /* (in) new value for option */
{
int sock, result = -2;
struct ip_mreq mreq;
struct linger l;
/*
* NT 3.5 seems to have a bug when passing a size of char down.
* It comes back with an error indicating a segfault. When
* increased to the size of an int, everything seems to be OK.
* Pad on both sides of the value so NT doesn't segfault.
*/
unsigned char buf[8], *p;
p = buf+sizeof(int);
*p = (unsigned char)value;
sock = statePtr->sock;
switch (option) {
case DP_ADD_MEMBERSHIP:
if (!IN_MULTICAST(value)) {
Tcl_SetErrno(EINVAL);
return -1;
}
mreq.imr_multiaddr.s_addr = htonl(value);
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
result = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq,
sizeof(mreq));
break;
case DP_DROP_MEMBERSHIP:
mreq.imr_multiaddr.s_addr = htonl(value);
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
result = setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char *)&mreq,
sizeof(mreq));
break;
case DP_BROADCAST:
result = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&value,
sizeof(value));
break;
case DP_MULTICAST_TTL:
result = setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, (char *)p,
sizeof(unsigned char));
break;
case DP_MULTICAST_LOOP:
result = setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP,(char*)p,
sizeof(unsigned char));
break;
case DP_RECV_BUFFER_SIZE:
result = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&value,
sizeof(value));
break;
case DP_REUSEADDR:
result = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&value,
sizeof(value));
break;
case DP_SEND_BUFFER_SIZE:
result = setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&value,
sizeof(value));
break;
default:
return EINVAL;
}
if (result != 0) {
return DppGetErrno();
}
return 0;
}
/*
*--------------------------------------------------------------
*
* DpIpmGetSocketOption --
*
* Sets a socket option. The allowable options for Ipm
* sockets are
* DP_SEND_BUFFER_SIZE (int)
* DP_RECV_BUFFER_SIZE (int)
* Note that we can't determine whether a socket is blocking,
* so DP_BLOCK is not allowed.
*
* Results:
* Zero if the operation was successful, or a nonzero POSIX
* error code if the operation failed.
*
* Side effects:
* None
*
*--------------------------------------------------------------
*/
int
DpIpmGetSocketOption (statePtr, option, valuePtr)
IpmState *statePtr; /* (in) IpmState structure */
int option; /* (in) Option to set */
int *valuePtr; /* (out) current value of option */
{
int sock, result, len;
struct linger l;
char p;
sock = statePtr->sock;
len = sizeof(int);
switch (option) {
case DP_RECV_BUFFER_SIZE:
result = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)valuePtr,
&len);
break;
case DP_REUSEADDR:
result = getsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)valuePtr,
&len);
break;
case DP_SEND_BUFFER_SIZE:
result = getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)valuePtr,
&len);
break;
case DP_MULTICAST_LOOP:
/*
* This call should only happen in Unix since it is invalid
* under Windows. IpmGetOption should have caught it.
*/
len = sizeof(unsigned char);
result = getsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP,(char*)&p,
&len);
*valuePtr = p;
break;
default:
return EINVAL;
}
if (result != 0) {
return DppGetErrno();
}
return 0;
}

1196
tcl-dp/unix/dpUnixTcp.c Normal file

File diff suppressed because it is too large Load Diff

669
tcl-dp/unix/dpUnixUdp.c Normal file
View File

@@ -0,0 +1,669 @@
/*
* generic/dpUdp.c --
*
* This file implements the generic code for a udp channel driver. These
* are channels that are created by evaluating "dp_connect udp".
*
* The architecture consists of a generic layer and a platform specific
* layer. The rational is that platform specific code goes in its layer,
* while platform independent code goes in its layer. However, most
* socket implementations use the Berkeley sockets interface, which is
* similar across platforms with a few annoying differences. These are
* separated into two files, dpSockUdp.c contains the generic socket code,
* which makes calls on routines in win/dpSock.c, which contains the
* platform specific code. We retain the two level architecture, though,
* so non-Berkeley socket interfaces can be built (if any still exist).
*
* Copyright (c) 1995-1996 Cornell University.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
*/
#include "generic/dpInt.h"
#include "generic/dpPort.h"
/*
* Below are all the channel driver procedures that must be supplied for
* a channel. Replace Udp with the name of this channel type.
* In many cases, the DpGeneric driver procedures can be used (e.g.,
* "DpGenericBlockMode)"
*/
static int UdpInput _ANSI_ARGS_((ClientData instanceData,
char *buf, int bufSize,
int *errorCodePtr));
static int UdpOutput _ANSI_ARGS_((ClientData instanceData,
char *buf, int toWrite,
int *errorCodePtr));
static int UdpSetOption _ANSI_ARGS_((ClientData instanceData,
Tcl_Interp *interp, char *optionName,
char *optionValue));
static int UdpGetOption _ANSI_ARGS_((ClientData instanceData,
Tcl_Interp *interp, char *optionName,
Tcl_DString *dsPtr));
typedef SocketState UdpState;
static Tcl_ChannelType udpChannelType = {
"udp", /* Name of channel */
SockBlockMode, /* Proc to set blocking mode on socket */
SockClose, /* Proc to close a socket */
UdpInput, /* Proc to get input from a socket */
UdpIpmOutput, /* Proc to send output to a socket */
NULL, /* Can't seek on a socket! */
UdpSetOption, /* Proc to set a socket option */
UdpGetOption, /* Proc to set a socket option */
SockWatch, /* Proc called to set event loop wait params */
SockGetFile /* Proc to return a handle assoc with socket */
};
#define PEEK_MODE (1<<1) /* Read without consuming? */
static int udpCount = 0; /* Number of udp files opened -- used to
* generate unique ids for channels */
/*
*--------------------------------------------------------------
*
* UdpInput --
*
* This function is called by the Tcl channel driver whenever
* the user wants to get input from the UDP socket.
* If the socket has some data available but
* less than requested by the bufSize argument, we only read
* as much data as is available and return without blocking.
* If the socket has no data available whatsoever and is
* blocking, we block until at least one byte of data can be
* read from the socket.
*
* Results:
* A nonnegative integer indicating how many bytes were read,
* or -1 in case of error (with errorCodePtr set to the POSIX
* error code).
*
* Side effects:
* None
*
*--------------------------------------------------------------
*/
static int
UdpInput (instanceData, buf, bufSize, errorCodePtr)
ClientData instanceData; /* (in) Pointer to udpState struct */
char *buf; /* (in/out) Buffer to fill */
int bufSize; /* (in) Size of buffer */
int *errorCodePtr; /* (out) POSIX error code (if any) */
{
UdpState *statePtr = (UdpState *)instanceData;
int result, peek;
int fromHost, fromPort;
char str[256];
DpSocketAddressIP fromAddr;
int bytesRead, flags = 0, fromLen;
peek = (statePtr->flags & PEEK_MODE);
if (peek) {
flags = MSG_PEEK;
} else {
flags = 0;
}
fromLen = sizeof(fromAddr);
bytesRead = recvfrom(statePtr->sock, buf, bufSize, flags,
(DpSocketAddress *)&fromAddr, &fromLen);
if (bytesRead == DP_SOCKET_ERROR) {
*errorCodePtr = DppGetErrno();
return -1;
}
if (statePtr->interp != NULL) {
fromHost = ntohl(fromAddr.sin_addr.s_addr);
fromPort = ntohs(fromAddr.sin_port);
sprintf (str, "{%d.%d.%d.%d %d}", (fromHost>>24),
(fromHost>>16) & 0xFF, (fromHost>>8) & 0xFF, fromHost & 0xFF,
fromPort);
Tcl_SetVar(statePtr->interp, "dp_from", str, TCL_GLOBAL_ONLY);
}
return bytesRead;
}
/*
*--------------------------------------------------------------
*
* UdpSetOption --
*
* This function is called by the Tcl channel driver
* whenever Tcl evaluates and fconfigure call to set
* some property of the udp socket (e.g., the buffer
* size). The valid options are "sendBuffer" and
* "recvBuffer"
*
* Results:
* Standard Tcl return value.
*
* Side effects:
* Depends on the option. Generally changes the maximum
* message size that can be sent/received.
*
*--------------------------------------------------------------
*/
static int
UdpSetOption (instanceData, interp, optionName, optionValue)
ClientData instanceData;
Tcl_Interp *interp;
char *optionName;
char *optionValue;
{
int option;
int value;
UdpState *statePtr = (UdpState *)instanceData;
/*
* Set the option specified by optionName
*/
if (optionName[0] == '-') {
option = DpTranslateOption(optionName+1);
} else {
option = -1;
}
switch (option) {
case DP_SEND_BUFFER_SIZE:
case DP_RECV_BUFFER_SIZE:
if (Tcl_GetInt(interp, optionValue, &value) != TCL_OK) {
return TCL_ERROR;
}
if (value <=0) {
Tcl_AppendResult (interp, "Buffer size must be > 0", NULL);
return TCL_ERROR;
}
return DpUdpSetSocketOption (statePtr, option, value);
case DP_PEEK:
if (Tcl_GetBoolean(interp, optionValue, &value) != TCL_OK) {
return TCL_ERROR;
}
if (value == 0) {
statePtr->flags &= ~PEEK_MODE;
} else {
statePtr->flags |= PEEK_MODE;
}
break;
case DP_HOST:
if (DpHostToIpAddr (optionValue, &value) == 0) {
Tcl_AppendResult (interp,
"Expected IP address or hostname but got \"",
optionValue, "\"", NULL);
return TCL_ERROR;
}
statePtr->sockaddr.sin_addr.s_addr = htonl(value);
break;
case DP_PORT:
if (Tcl_GetInt(interp, optionValue, &value) != TCL_OK) {
return TCL_ERROR;
}
if (value <= 0) {
Tcl_AppendResult (interp, "Port number must be > 0", NULL);
return TCL_ERROR;
}
statePtr->sockaddr.sin_port = htons((unsigned short) value);
break;
case DP_MYPORT:
Tcl_AppendResult (interp, "Can't set port after socket is opened",
NULL);
return TCL_ERROR;
default:
Tcl_AppendResult (interp, "Illegal option \"", optionName,
"\" -- must be sendBuffer, recvBuffer, peek, ",
"host, port, or a standard fconfigure option", NULL);
return TCL_ERROR;
}
return TCL_OK;
}
/*
*--------------------------------------------------------------
*
* UdpGetOption --
*
* This function is called by the Tcl channel code to
* retrieve a parameter of the socket (e.g., a buffer size).
* The valid options are "sendBuffer" and "recvBuffer"
*
* Results:
* A standard Tcl result
*
* Side effects:
* None
*
*--------------------------------------------------------------
*/
static int
UdpGetOption (instanceData,
interp,
optionName, dsPtr)
ClientData instanceData;
Tcl_Interp *interp;
char *optionName;
Tcl_DString *dsPtr;
{
int option;
int size;
unsigned int addr;
char str[256];
UdpState *statePtr = (UdpState *)instanceData;
/*
* If optionName is NULL, then store an alternating list of
* all supported options and their current values in dsPtr
*/
if (optionName == NULL) {
Tcl_DStringAppend (dsPtr, " -sendBuffer ", -1);
UdpGetOption(instanceData, interp, "-sendBuffer", dsPtr);
Tcl_DStringAppend (dsPtr, " -recvBuffer ", -1);
UdpGetOption(instanceData, interp, "-recvBuffer", dsPtr);
Tcl_DStringAppend (dsPtr, " -peek ", -1);
UdpGetOption(instanceData, interp, "-peek", dsPtr);
Tcl_DStringAppend (dsPtr, " -host ", -1);
UdpGetOption(instanceData, interp, "-host", dsPtr);
Tcl_DStringAppend (dsPtr, " -port ", -1);
UdpGetOption(instanceData, interp, "-port", dsPtr);
Tcl_DStringAppend (dsPtr, " -myport ", -1);
UdpGetOption(instanceData, interp, "-myport", dsPtr);
return TCL_OK;
}
/*
* Retrive the value of the option specified by optionName
*/
if (optionName[0] == '-') {
option = DpTranslateOption(optionName+1);
} else {
option = -1;
}
switch (option) {
case DP_SEND_BUFFER_SIZE:
case DP_RECV_BUFFER_SIZE:
DpUdpGetSocketOption (statePtr, option, &size);
sprintf (str, "%d", size);
Tcl_DStringAppend (dsPtr, str, -1);
break;
case DP_PEEK:
if (statePtr->flags & PEEK_MODE) {
Tcl_DStringAppend (dsPtr, "1", -1);
} else {
Tcl_DStringAppend (dsPtr, "0", -1);
}
break;
case DP_HOST:
addr = ntohl(statePtr->sockaddr.sin_addr.s_addr);
sprintf (str, "%d.%d.%d.%d",
(addr >>24), (addr >>16) & 0xff,
(addr >> 8) & 0xff, (addr) & 0xff);
Tcl_DStringAppend (dsPtr, str, -1);
break;
case DP_PORT:
sprintf (str, "%d", (unsigned short)
ntohs(statePtr->sockaddr.sin_port));
Tcl_DStringAppend (dsPtr, str, -1);
break;
case DP_MYPORT:
sprintf (str, "%d", (unsigned short) statePtr->myPort);
Tcl_DStringAppend (dsPtr, str, -1);
break;
default:
Tcl_AppendResult(interp,
"bad option \"", optionName,"\": must be -blocking,",
" -buffering, -buffersize, -eofchar, -translation,",
" or a channel type specific option", NULL);
Tcl_SetErrno (EINVAL);
return TCL_ERROR;
}
return TCL_OK;
}
/*
*--------------------------------------------------------------
*
* DpOpenUdpChannel --
*
* Opens a new channel that uses the UDP protocol.
*
* Results:
* Returns a pointer to the newly created Tcl_Channel. This
* is the structure with all the function pointers Tcl needs
* to communicate with (read, write, close, etc) the channel.
*
* Side effects:
* A socket is created with the specified port. No other
* socket can use that port until this channel is closed.
*
*--------------------------------------------------------------
*/
Tcl_Channel
DpOpenUdpChannel(interp, argc, argv)
Tcl_Interp *interp; /* For error reporting; can be NULL. */
int argc; /* Number of arguments. */
char **argv; /* Argument strings. */
{
Tcl_Channel chan;
UdpState *statePtr;
char channelName[20];
int i, result;
/*
* The default values for the value-option pairs
*/
int hostIp = 0;
int port = 0;
int myIpAddr = DP_INADDR_ANY;
int myport = 0;
for (i=0; i<argc; i+=2) {
int v = i+1;
size_t len = strlen(argv[i]);
if (strncmp(argv[i], "-host", len)==0) {
if (v==argc) {goto arg_missing;}
if (!DpHostToIpAddr (argv[v], &hostIp)) {
Tcl_AppendResult (interp, "Unknown host \"", argv[v],
"\"", NULL);
return NULL;
}
} else if (strncmp(argv[i], "-port", len)==0) {
if (v==argc) {goto arg_missing;}
if (Tcl_GetInt(interp, argv[v], &port) != TCL_OK) {
return NULL;
}
if (port <= 0) {
Tcl_AppendResult (interp, "Port number must be > 0", NULL);
return NULL;
}
} else if (strncmp(argv[i], "-myaddr", len)==0) {
if (v==argc) {goto arg_missing;}
if (strcmp (argv[v], "any") == 0) {
myIpAddr = DP_INADDR_ANY;
} else if (!DpHostToIpAddr (argv[v], &myIpAddr)) {
Tcl_AppendResult (interp, "Illegal value for -myaddr \"",
argv[v], "\"", NULL);
return NULL;
}
} else if (strncmp(argv[i], "-myport", len)==0) {
if (v==argc) {goto arg_missing;}
if (Tcl_GetInt(interp, argv[v], &myport) != TCL_OK) {
return NULL;
}
if (myport <= 0) {
Tcl_AppendResult (interp,
"Port number for -myport must be > 0", NULL);
return NULL;
}
} else {
Tcl_AppendResult(interp, "unknown option \"",
argv[i], "\", must be -host, -myaddr, -myport ",
"or -port", NULL);
return NULL;
}
}
/*
* Create a new socket and wrap it in a channel.
*/
statePtr = (UdpState *)ckalloc(sizeof(UdpState));
statePtr->flags = 0;
statePtr->interp = interp;
statePtr->myPort = myport;
statePtr->destPort = port;
statePtr->sockaddr.sin_port = htons(port);
statePtr->sockaddr.sin_family = AF_INET;
statePtr->sockaddr.sin_addr.s_addr = htonl(hostIp);
result = DpCreateUdpSocket(interp, myIpAddr, statePtr);
if (result != TCL_OK) {
ckfree((char *)statePtr);
return NULL;
}
sprintf(channelName, "udp%d", udpCount++);
chan = Tcl_CreateChannel(&udpChannelType, channelName,
(ClientData)statePtr, TCL_READABLE|TCL_WRITABLE);
Tcl_RegisterChannel(interp, chan);
statePtr->channel = chan;
/*
* Set the initial state of the channel.
* Make sure the socket's blocking, set the default buffer sizes,
* set the destination address as specified, disable Tcl buffering
* and translation.
*/
DpUdpSetSocketOption(statePtr, DP_SEND_BUFFER_SIZE, 8192);
DpUdpSetSocketOption(statePtr, DP_RECV_BUFFER_SIZE, 8192);
DpUdpGetSocketOption(statePtr, DP_RECV_BUFFER_SIZE,
&statePtr->recvBufSize);
if (Tcl_SetChannelOption(interp, chan, "-translation", "binary") !=
TCL_OK) {
DpClose(interp, chan);
ckfree((char *)statePtr);
return NULL;
}
if (Tcl_SetChannelOption(interp, chan, "-blocking", "1") !=
TCL_OK) {
DpClose(interp, chan);
ckfree((char *)statePtr);
return NULL;
}
if (Tcl_SetChannelOption(interp, chan, "-buffering", "none") !=
TCL_OK) {
DpClose(interp, chan);
ckfree((char *)statePtr);
return NULL;
}
return chan;
arg_missing:
Tcl_AppendResult(interp, "value for \"", argv[argc-1], "\" missing", NULL);
return NULL;
}
/*
*--------------------------------------------------------------
*
* DpUdpSetSocketOption --
*
* Sets a socket option. The allowable options for UDP
* sockets are
* DP_SEND_BUFFER_SIZE (int)
* DP_RECV_BUFFER_SIZE (int)
* DP_BLOCK (T/F)
*
* Results:
* Zero if the operation was successful, or a nonzero POSIX
* error code if the operation failed.
*
* Side effects:
* None
*
*--------------------------------------------------------------
*/
int
DpUdpSetSocketOption (clientData, option, value)
ClientData clientData; /* (in) UdpState structure */
int option; /* (in) Option to set */
int value; /* (in) new value for option */
{
UdpState *statePtr = (UdpState *)clientData;
int sock, result;
sock = statePtr->sock;
switch (option) {
case DP_SEND_BUFFER_SIZE:
result = setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&value,
sizeof(value));
break;
case DP_RECV_BUFFER_SIZE:
result = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&value,
sizeof(value));
break;
default:
return EINVAL;
}
if (result != 0) {
return Tcl_GetErrno();
}
return 0;
}
/*
*--------------------------------------------------------------
*
* DpUdpGetSocketOption --
*
* Sets a socket option. The allowable options for UDP
* sockets are
* DP_SEND_BUFFER_SIZE (int)
* DP_RECV_BUFFER_SIZE (int)
* Note that we can't determine whether a socket is blocking,
* so DP_BLOCK is not allowed.
*
* Results:
* Zero if the operation was successful, or a nonzero POSIX
* error code if the operation failed.
*
* Side effects:
* None
*
*--------------------------------------------------------------
*/
int
DpUdpGetSocketOption (clientData, option, valuePtr)
ClientData clientData; /* (in) UdpState structure */
int option; /* (in) Option to set */
int *valuePtr; /* (out) current value of option */
{
UdpState *statePtr = (UdpState *)clientData;
int sock, result, len;
sock = statePtr->sock;
len = sizeof(int);
switch (option) {
case DP_SEND_BUFFER_SIZE:
result = getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)valuePtr,
&len);
break;
case DP_RECV_BUFFER_SIZE:
result = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)valuePtr,
&len);
break;
default:
return EINVAL;
}
if (result != 0) {
return Tcl_GetErrno();
}
return 0;
}
/*
*--------------------------------------------------------------
*
* DpCreateUdpSocket --
*
* Create a udp socket.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* None
*
*--------------------------------------------------------------
*/
int
DpCreateUdpSocket(interp, myIpAddr, statePtr)
Tcl_Interp *interp; /* (in) For error reporting. */
int myIpAddr; /* (in) IP addr of interface to use.
* DP_INADDR_ANY = default port */
UdpState *statePtr; /* (out) Pointer to local structure */
{
DpSocketAddressIP sockAddr;
DpSocket sock;
int len;
sock = socket(PF_INET, SOCK_DGRAM, 0);
if (sock == DP_SOCKET_ERROR) {
goto socketError;
}
statePtr->sock = sock;
/*
* Bind the socket.
* This is a bit of a mess, but it's Berkeley sockets. The sin_family
* is set to AF_INET, indicating IP addressing. The sin_addr.s_addr
* field says what interface to use. It can be INADDR_ANY to let
* the system choose a default interface. The port number can be
* zero (which tells the system to choose a port number) or > 1024,
* which is then used as the port number
*/
memset((char *)&sockAddr, 0, sizeof(sockAddr));
sockAddr.sin_family = AF_INET;
if (myIpAddr == DP_INADDR_ANY) {
sockAddr.sin_addr.s_addr = INADDR_ANY;
} else {
sockAddr.sin_addr.s_addr = htonl(myIpAddr);
}
sockAddr.sin_port = htons((unsigned short) statePtr->myPort);
if (bind(sock, (DpSocketAddress *)&sockAddr, sizeof(sockAddr)) ==
DP_SOCKET_ERROR) {
goto bindError;
}
/*
* Figure out what port number we got if we let the system chose it.
*/
if (statePtr->myPort == 0) {
len = sizeof(sockAddr);
getsockname (sock, (DpSocketAddress *)&sockAddr, &len);
statePtr->myPort = ntohs(sockAddr.sin_port);
}
statePtr->sockFile = (ClientData)statePtr->sock;
return TCL_OK;
bindError:
DppGetErrno();
Tcl_AppendResult(interp, "Error binding UDP socket to port: ",
Tcl_PosixError(interp), NULL);
DppCloseSocket (sock);
return TCL_ERROR;
socketError:
DppGetErrno();
Tcl_AppendResult(interp, "Error creating UDP socket: ",
Tcl_PosixError(interp), NULL);
return TCL_ERROR;
}