001: /*
002: * SocketCmd.java --
003: *
004: * Copyright (c) 1997 Sun Microsystems, Inc.
005: *
006: * See the file "license.terms" for information on usage and
007: * redistribution of this file, and for a DISCLAIMER OF ALL
008: * WARRANTIES.
009: *
010: * RCS: @(#) $Id: SocketCmd.java,v 1.7 2002/01/21 01:59:35 mdejong Exp $
011: *
012: */
013:
014: package tcl.lang;
015:
016: import java.util.*;
017: import java.io.IOException;
018:
019: /**
020: * This class implements the built-in "socket" command in Tcl.
021: */
022:
023: class SocketCmd implements Command {
024:
025: static final private String validCmds[] = { "-async", "-myaddr",
026: "-myport", "-server", };
027:
028: static final int OPT_ASYNC = 0;
029: static final int OPT_MYADDR = 1;
030: static final int OPT_MYPORT = 2;
031: static final int OPT_SERVER = 3;
032:
033: /**
034: * This procedure is invoked to process the "socket" Tcl command.
035: * See the user documentation for details on what it does.
036: *
037: * @param interp the current interpreter.
038: * @param argv command arguments.
039: */
040:
041: public void cmdProc(Interp interp, TclObject argv[])
042: throws TclException {
043:
044: boolean server = false; // True if this is a server socket
045: boolean async = false; // True if this is asynchronous
046: String channelId = ""; // Key into chanTable
047: String myaddr = ""; // DNS or IP address of the server
048: String script = ""; // Script for server to run
049: String host = ""; // The server fot the client
050: int myport = 0; // The port to connect from
051: int port = 0; // The port to connect to
052: int index; // Index to the correct cmd
053: int i; // Index to the current arg from argv
054:
055: for (i = 1; (i < argv.length); i++) {
056: if ((argv[i].toString().length() > 0)
057: && (argv[i].toString().charAt(0) == '-')) {
058: index = TclIndex.get(interp, argv[i], validCmds,
059: "option", 0);
060: } else {
061: break;
062: }
063:
064: switch (index) {
065: case OPT_ASYNC: {
066: if (server) {
067: throw new TclException(interp,
068: "cannot set -async option for server sockets");
069: }
070: async = true;
071: break;
072: }
073: case OPT_MYADDR: {
074: i++;
075: if (i >= argv.length) {
076: throw new TclException(interp,
077: "no argument given for -myaddr option");
078: }
079: myaddr = argv[i].toString();
080: break;
081: }
082: case OPT_MYPORT: {
083: i++;
084: if (i >= argv.length) {
085: throw new TclException(interp,
086: "no argument given for -myport option");
087: }
088: myport = getPort(interp, argv[i]);
089: break;
090: }
091: case OPT_SERVER: {
092: if (async) {
093: throw new TclException(interp,
094: "cannot set -async option for server sockets");
095: }
096: server = true;
097: i++;
098: if (i >= argv.length) {
099: throw new TclException(interp,
100: "no argument given for -server option");
101: }
102: script = argv[i].toString();
103: break;
104: }
105: default: {
106: throw new TclException(interp, "bad option \""
107: + argv[i]
108: + "\", must be -async, -myaddr, -myport,"
109: + " or -server");
110: }
111: }
112: }
113:
114: if (server) {
115: host = myaddr;
116: if (myport != 0) {
117: throw new TclException(interp,
118: "Option -myport is not valid for servers");
119: }
120: } else if ((i + 1) < argv.length) {
121: host = argv[i].toString();
122: i++;
123: } else {
124: errorWrongNumArgs(interp, argv[0].toString());
125: }
126:
127: if (i == argv.length - 1) {
128: port = getPort(interp, argv[i]);
129: } else {
130: errorWrongNumArgs(interp, argv[0].toString());
131: }
132:
133: if (server) {
134: TclObject scr = TclString.newInstance(script);
135: ServerSocketChannel sock = new ServerSocketChannel(interp,
136: myaddr, port, scr);
137:
138: TclIO.registerChannel(interp, sock);
139: interp.setResult(sock.getChanName());
140:
141: // FIXME: Comments from the C implementation below ...
142:
143: // Register with the interpreter to let us know when the
144: // interpreter is deleted (by having the callback set the
145: // acceptCallbackPtr->interp field to NULL). This is to
146: // avoid trying to eval the script in a deleted interpreter.
147:
148: // Register a close callback. This callback will inform the
149: // interpreter (if it still exists) that this channel does not
150: // need to be informed when the interpreter is deleted.
151:
152: } else {
153: try {
154: SocketChannel sock = new SocketChannel(interp,
155: TclIO.RDWR, myaddr, myport, async, host, port);
156:
157: TclIO.registerChannel(interp, sock);
158: interp.setResult(sock.getChanName());
159: } catch (IOException e) {
160: throw new TclException(interp, "cannot open socket: "
161: + e.getMessage());
162: }
163: }
164: }
165:
166: /**
167: * A unique error msg is printed for socket. Call this methods
168: * instead of the standard TclException.wrongNumArgs().
169: *
170: * @param interp the current interpreter.
171: * @param cmd the name of the command (extracted form argv[0] of cmdProc)
172: */
173:
174: private static void errorWrongNumArgs(Interp interp, String cmdName)
175: throws TclException {
176: throw new TclException(
177: interp,
178: "wrong # args: should be either:\n"
179: + cmdName
180: + " ?-myaddr addr? ?-myport myport? ?-async? host port\n"
181: + cmdName
182: + " -server command ?-myaddr addr? port");
183: }
184:
185: /**
186: * TclSockGetPort -> getPort
187: *
188: * Maps from a string, which could be a service name, to a port.
189: * Unfortunately, Java does not provide any way to access the
190: * getservbyname functionality so we are limited to port numbers.
191: *
192: */
193:
194: private static int getPort(Interp interp, TclObject tobj)
195: throws TclException {
196: int num = Util.getInt(interp, tobj.toString());
197: if (num > 0xFFFF)
198: throw new TclException(interp,
199: "couldn't open socket: port number too high");
200: return num;
201: }
202:
203: }
|