Intial commit
This commit is contained in:
204
tcl-dp/unix/Makefile.in
Executable file
204
tcl-dp/unix/Makefile.in
Executable 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
56
tcl-dp/unix/compat/in.h
Normal 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
|
||||
|
||||
|
||||
43
tcl-dp/unix/compat/malloc.h
Normal file
43
tcl-dp/unix/compat/malloc.h
Normal 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 */
|
||||
|
||||
|
||||
60
tcl-dp/unix/compat/stdlib.h
Normal file
60
tcl-dp/unix/compat/stdlib.h
Normal 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 */
|
||||
|
||||
|
||||
80
tcl-dp/unix/compat/string.h
Normal file
80
tcl-dp/unix/compat/string.h
Normal 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 */
|
||||
|
||||
|
||||
85
tcl-dp/unix/compat/unistd.h
Normal file
85
tcl-dp/unix/compat/unistd.h
Normal 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
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
196
tcl-dp/unix/configure.in
Executable 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
100
tcl-dp/unix/dpAppInit.c
Normal 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
326
tcl-dp/unix/dpEFilter.c
Normal 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
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
51
tcl-dp/unix/dpInit.c
Normal 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
99
tcl-dp/unix/dpLocks.c
Normal 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
79
tcl-dp/unix/dpPort.h
Normal 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
735
tcl-dp/unix/dpSerial.c
Normal 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
280
tcl-dp/unix/dpSock.c
Normal 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
810
tcl-dp/unix/dpUnixIpm.c
Normal 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
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
669
tcl-dp/unix/dpUnixUdp.c
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user