tclUnixChan.cGo to the documentation of this file.00001 /* 00002 * tclUnixChan.c 00003 * 00004 * Common channel driver for Unix channels based on files, command pipes 00005 * and TCP sockets. 00006 * 00007 * Copyright (c) 1995-1997 Sun Microsystems, Inc. 00008 * Copyright (c) 1998-1999 by Scriptics Corporation. 00009 * 00010 * See the file "license.terms" for information on usage and redistribution of 00011 * this file, and for a DISCLAIMER OF ALL WARRANTIES. 00012 * 00013 * RCS: @(#) $Id: tclUnixChan.c,v 1.89 2007/12/13 15:28:42 dgp Exp $ 00014 */ 00015 00016 #include "tclInt.h" /* Internal definitions for Tcl. */ 00017 #include "tclIO.h" /* To get Channel type declaration. */ 00018 00019 /* 00020 * sys/ioctl.h has already been included by tclPort.h. Including termios.h or 00021 * termio.h causes a bunch of warning messages because some duplicate (but not 00022 * contradictory) #defines exist in termios.h and/or termio.h 00023 */ 00024 00025 #undef NL0 00026 #undef NL1 00027 #undef CR0 00028 #undef CR1 00029 #undef CR2 00030 #undef CR3 00031 #undef TAB0 00032 #undef TAB1 00033 #undef TAB2 00034 #undef XTABS 00035 #undef BS0 00036 #undef BS1 00037 #undef FF0 00038 #undef FF1 00039 #undef ECHO 00040 #undef NOFLSH 00041 #undef TOSTOP 00042 #undef FLUSHO 00043 #undef PENDIN 00044 00045 #define SUPPORTS_TTY 00046 00047 #undef DIRECT_BAUD 00048 #ifdef B4800 00049 # if (B4800 == 4800) 00050 # define DIRECT_BAUD 00051 # endif /* B4800 == 4800 */ 00052 #endif /* B4800 */ 00053 00054 #ifdef USE_TERMIOS 00055 # include <termios.h> 00056 # ifdef HAVE_SYS_IOCTL_H 00057 # include <sys/ioctl.h> 00058 # endif /* HAVE_SYS_IOCTL_H */ 00059 # ifdef HAVE_SYS_MODEM_H 00060 # include <sys/modem.h> 00061 # endif /* HAVE_SYS_MODEM_H */ 00062 # define IOSTATE struct termios 00063 # define GETIOSTATE(fd, statePtr) tcgetattr((fd), (statePtr)) 00064 # define SETIOSTATE(fd, statePtr) tcsetattr((fd), TCSADRAIN, (statePtr)) 00065 # define GETCONTROL(fd, intPtr) ioctl((fd), TIOCMGET, (intPtr)) 00066 # define SETCONTROL(fd, intPtr) ioctl((fd), TIOCMSET, (intPtr)) 00067 00068 /* 00069 * TIP #35 introduced a different on exit flush/close behavior that does 00070 * not work correctly with standard channels on all systems. The problem 00071 * is tcflush throws away waiting channel data. This may be necessary for 00072 * true serial channels that may block, but isn't correct in the standard 00073 * case. This might be replaced with tcdrain instead, but that can block. 00074 * For now, we revert to making this do nothing, and TtyOutputProc being 00075 * the same old FileOutputProc. - hobbs [Bug #525783] 00076 */ 00077 00078 # define BAD_TIP35_FLUSH 0 00079 # if BAD_TIP35_FLUSH 00080 # define TTYFLUSH(fd) tcflush((fd), TCIOFLUSH); 00081 # else 00082 # define TTYFLUSH(fd) 00083 # endif /* BAD_TIP35_FLUSH */ 00084 # ifdef FIONREAD 00085 # define GETREADQUEUE(fd, int) ioctl((fd), FIONREAD, &(int)) 00086 # elif defined(FIORDCHK) 00087 # define GETREADQUEUE(fd, int) int = ioctl((fd), FIORDCHK, NULL) 00088 # endif /* FIONREAD */ 00089 # ifdef TIOCOUTQ 00090 # define GETWRITEQUEUE(fd, int) ioctl((fd), TIOCOUTQ, &(int)) 00091 # endif /* TIOCOUTQ */ 00092 # if defined(TIOCSBRK) && defined(TIOCCBRK) 00093 00094 /* 00095 * Can't use ?: operator below because that messes up types on either Linux or 00096 * Solaris (the two are mutually exclusive!) 00097 */ 00098 00099 # define SETBREAK(fd, flag) \ 00100 if (flag) { \ 00101 ioctl((fd), TIOCSBRK, NULL); \ 00102 } else { \ 00103 ioctl((fd), TIOCCBRK, NULL); \ 00104 } 00105 # endif /* TIOCSBRK&TIOCCBRK */ 00106 # if !defined(CRTSCTS) && defined(CNEW_RTSCTS) 00107 # define CRTSCTS CNEW_RTSCTS 00108 # endif /* !CRTSCTS&CNEW_RTSCTS */ 00109 #else /* !USE_TERMIOS */ 00110 00111 #ifdef USE_TERMIO 00112 # include <termio.h> 00113 # define IOSTATE struct termio 00114 # define GETIOSTATE(fd, statePtr) ioctl((fd), TCGETA, (statePtr)) 00115 # define SETIOSTATE(fd, statePtr) ioctl((fd), TCSETAW, (statePtr)) 00116 #else /* !USE_TERMIO */ 00117 00118 #ifdef USE_SGTTY 00119 # include <sgtty.h> 00120 # define IOSTATE struct sgttyb 00121 # define GETIOSTATE(fd, statePtr) ioctl((fd), TIOCGETP, (statePtr)) 00122 # define SETIOSTATE(fd, statePtr) ioctl((fd), TIOCSETP, (statePtr)) 00123 #else /* !USE_SGTTY */ 00124 # undef SUPPORTS_TTY 00125 #endif /* !USE_SGTTY */ 00126 00127 #endif /* !USE_TERMIO */ 00128 #endif /* !USE_TERMIOS */ 00129 00130 /* 00131 * Helper macros to make parts of this file clearer. The macros do exactly 00132 * what they say on the tin. :-) They also only ever refer to their arguments 00133 * once, and so can be used without regard to side effects. 00134 */ 00135 00136 #define SET_BITS(var, bits) ((var) |= (bits)) 00137 #define CLEAR_BITS(var, bits) ((var) &= ~(bits)) 00138 00139 /* 00140 * This structure describes per-instance state of a file based channel. 00141 */ 00142 00143 typedef struct FileState { 00144 Tcl_Channel channel; /* Channel associated with this file. */ 00145 int fd; /* File handle. */ 00146 int validMask; /* OR'ed combination of TCL_READABLE, 00147 * TCL_WRITABLE, or TCL_EXCEPTION: indicates 00148 * which operations are valid on the file. */ 00149 } FileState; 00150 00151 #ifdef SUPPORTS_TTY 00152 00153 /* 00154 * The following structure describes per-instance state of a tty-based 00155 * channel. 00156 */ 00157 00158 typedef struct TtyState { 00159 FileState fs; /* Per-instance state of the file descriptor. 00160 * Must be the first field. */ 00161 int stateUpdated; /* Flag to say if the state has been modified 00162 * and needs resetting. */ 00163 IOSTATE savedState; /* Initial state of device. Used to reset 00164 * state when device closed. */ 00165 } TtyState; 00166 00167 /* 00168 * The following structure is used to set or get the serial port attributes in 00169 * a platform-independant manner. 00170 */ 00171 00172 typedef struct TtyAttrs { 00173 int baud; 00174 int parity; 00175 int data; 00176 int stop; 00177 } TtyAttrs; 00178 00179 #endif /* !SUPPORTS_TTY */ 00180 00181 #define UNSUPPORTED_OPTION(detail) \ 00182 if (interp) { \ 00183 Tcl_AppendResult(interp, (detail), \ 00184 " not supported for this platform", NULL); \ 00185 } 00186 00187 /* 00188 * This structure describes per-instance state of a tcp based channel. 00189 */ 00190 00191 typedef struct TcpState { 00192 Tcl_Channel channel; /* Channel associated with this file. */ 00193 int fd; /* The socket itself. */ 00194 int flags; /* ORed combination of the bitfields defined 00195 * below. */ 00196 Tcl_TcpAcceptProc *acceptProc; 00197 /* Proc to call on accept. */ 00198 ClientData acceptProcData; /* The data for the accept proc. */ 00199 } TcpState; 00200 00201 /* 00202 * These bits may be ORed together into the "flags" field of a TcpState 00203 * structure. 00204 */ 00205 00206 #define TCP_ASYNC_SOCKET (1<<0) /* Asynchronous socket. */ 00207 #define TCP_ASYNC_CONNECT (1<<1) /* Async connect in progress. */ 00208 00209 /* 00210 * The following defines the maximum length of the listen queue. This is the 00211 * number of outstanding yet-to-be-serviced requests for a connection on a 00212 * server socket, more than this number of outstanding requests and the 00213 * connection request will fail. 00214 */ 00215 00216 #ifndef SOMAXCONN 00217 # define SOMAXCONN 100 00218 #endif /* SOMAXCONN */ 00219 00220 #if (SOMAXCONN < 100) 00221 # undef SOMAXCONN 00222 # define SOMAXCONN 100 00223 #endif /* SOMAXCONN < 100 */ 00224 00225 /* 00226 * The following defines how much buffer space the kernel should maintain for 00227 * a socket. 00228 */ 00229 00230 #define SOCKET_BUFSIZE 4096 00231 00232 /* 00233 * Static routines for this file: 00234 */ 00235 00236 static TcpState * CreateSocket(Tcl_Interp *interp, int port, 00237 const char *host, int server, const char *myaddr, 00238 int myport, int async); 00239 static int CreateSocketAddress(struct sockaddr_in *sockaddrPtr, 00240 const char *host, int port, int willBind, 00241 const char **errorMsgPtr); 00242 static int FileBlockModeProc(ClientData instanceData, int mode); 00243 static int FileCloseProc(ClientData instanceData, 00244 Tcl_Interp *interp); 00245 static int FileGetHandleProc(ClientData instanceData, 00246 int direction, ClientData *handlePtr); 00247 static int FileInputProc(ClientData instanceData, char *buf, 00248 int toRead, int *errorCode); 00249 static int FileOutputProc(ClientData instanceData, 00250 const char *buf, int toWrite, int *errorCode); 00251 static int FileSeekProc(ClientData instanceData, long offset, 00252 int mode, int *errorCode); 00253 static int FileTruncateProc(ClientData instanceData, 00254 Tcl_WideInt length); 00255 static Tcl_WideInt FileWideSeekProc(ClientData instanceData, 00256 Tcl_WideInt offset, int mode, int *errorCode); 00257 static void FileWatchProc(ClientData instanceData, int mask); 00258 static void TcpAccept(ClientData data, int mask); 00259 static int TcpBlockModeProc(ClientData data, int mode); 00260 static int TcpCloseProc(ClientData instanceData, 00261 Tcl_Interp *interp); 00262 static int TcpGetHandleProc(ClientData instanceData, 00263 int direction, ClientData *handlePtr); 00264 static int TcpGetOptionProc(ClientData instanceData, 00265 Tcl_Interp *interp, const char *optionName, 00266 Tcl_DString *dsPtr); 00267 static int TcpInputProc(ClientData instanceData, char *buf, 00268 int toRead, int *errorCode); 00269 static int TcpOutputProc(ClientData instanceData, 00270 const char *buf, int toWrite, int *errorCode); 00271 static void TcpWatchProc(ClientData instanceData, int mask); 00272 #ifdef SUPPORTS_TTY 00273 static int TtyCloseProc(ClientData instanceData, 00274 Tcl_Interp *interp); 00275 static void TtyGetAttributes(int fd, TtyAttrs *ttyPtr); 00276 static int TtyGetOptionProc(ClientData instanceData, 00277 Tcl_Interp *interp, const char *optionName, 00278 Tcl_DString *dsPtr); 00279 #ifndef DIRECT_BAUD 00280 static int TtyGetBaud(unsigned long speed); 00281 static unsigned long TtyGetSpeed(int baud); 00282 #endif /* DIRECT_BAUD */ 00283 static FileState * TtyInit(int fd, int initialize); 00284 static void TtyModemStatusStr(int status, Tcl_DString *dsPtr); 00285 #if BAD_TIP35_FLUSH 00286 static int TtyOutputProc(ClientData instanceData, 00287 const char *buf, int toWrite, int *errorCode); 00288 #endif /* BAD_TIP35_FLUSH */ 00289 static int TtyParseMode(Tcl_Interp *interp, const char *mode, 00290 int *speedPtr, int *parityPtr, int *dataPtr, 00291 int *stopPtr); 00292 static void TtySetAttributes(int fd, TtyAttrs *ttyPtr); 00293 static int TtySetOptionProc(ClientData instanceData, 00294 Tcl_Interp *interp, const char *optionName, 00295 const char *value); 00296 #endif /* SUPPORTS_TTY */ 00297 static int WaitForConnect(TcpState *statePtr, int *errorCodePtr); 00298 static Tcl_Channel MakeTcpClientChannelMode(ClientData tcpSocket, 00299 int mode); 00300 00301 /* 00302 * This structure describes the channel type structure for file based IO: 00303 */ 00304 00305 static Tcl_ChannelType fileChannelType = { 00306 "file", /* Type name. */ 00307 TCL_CHANNEL_VERSION_5, /* v5 channel */ 00308 FileCloseProc, /* Close proc. */ 00309 FileInputProc, /* Input proc. */ 00310 FileOutputProc, /* Output proc. */ 00311 FileSeekProc, /* Seek proc. */ 00312 NULL, /* Set option proc. */ 00313 NULL, /* Get option proc. */ 00314 FileWatchProc, /* Initialize notifier. */ 00315 FileGetHandleProc, /* Get OS handles out of channel. */ 00316 NULL, /* close2proc. */ 00317 FileBlockModeProc, /* Set blocking or non-blocking mode.*/ 00318 NULL, /* flush proc. */ 00319 NULL, /* handler proc. */ 00320 FileWideSeekProc, /* wide seek proc. */ 00321 NULL, 00322 FileTruncateProc, /* truncate proc. */ 00323 }; 00324 00325 #ifdef SUPPORTS_TTY 00326 /* 00327 * This structure describes the channel type structure for serial IO. 00328 * Note that this type is a subclass of the "file" type. 00329 */ 00330 00331 static Tcl_ChannelType ttyChannelType = { 00332 "tty", /* Type name. */ 00333 TCL_CHANNEL_VERSION_5, /* v5 channel */ 00334 TtyCloseProc, /* Close proc. */ 00335 FileInputProc, /* Input proc. */ 00336 #if BAD_TIP35_FLUSH 00337 TtyOutputProc, /* Output proc. */ 00338 #else /* !BAD_TIP35_FLUSH */ 00339 FileOutputProc, /* Output proc. */ 00340 #endif /* BAD_TIP35_FLUSH */ 00341 NULL, /* Seek proc. */ 00342 TtySetOptionProc, /* Set option proc. */ 00343 TtyGetOptionProc, /* Get option proc. */ 00344 FileWatchProc, /* Initialize notifier. */ 00345 FileGetHandleProc, /* Get OS handles out of channel. */ 00346 NULL, /* close2proc. */ 00347 FileBlockModeProc, /* Set blocking or non-blocking mode.*/ 00348 NULL, /* flush proc. */ 00349 NULL, /* handler proc. */ 00350 NULL, /* wide seek proc. */ 00351 NULL, /* thread action proc. */ 00352 NULL, /* truncate proc. */ 00353 }; 00354 #endif /* SUPPORTS_TTY */ 00355 00356 /* 00357 * This structure describes the channel type structure for TCP socket 00358 * based IO: 00359 */ 00360 00361 static Tcl_ChannelType tcpChannelType = { 00362 "tcp", /* Type name. */ 00363 TCL_CHANNEL_VERSION_5, /* v5 channel */ 00364 TcpCloseProc, /* Close proc. */ 00365 TcpInputProc, /* Input proc. */ 00366 TcpOutputProc, /* Output proc. */ 00367 NULL, /* Seek proc. */ 00368 NULL, /* Set option proc. */ 00369 TcpGetOptionProc, /* Get option proc. */ 00370 TcpWatchProc, /* Initialize notifier. */ 00371 TcpGetHandleProc, /* Get OS handles out of channel. */ 00372 NULL, /* close2proc. */ 00373 TcpBlockModeProc, /* Set blocking or non-blocking mode.*/ 00374 NULL, /* flush proc. */ 00375 NULL, /* handler proc. */ 00376 NULL, /* wide seek proc. */ 00377 NULL, /* thread action proc. */ 00378 NULL, /* truncate proc. */ 00379 }; 00380 00381 /* 00382 *---------------------------------------------------------------------- 00383 * 00384 * FileBlockModeProc -- 00385 * 00386 * Helper function to set blocking and nonblocking modes on a file based 00387 * channel. Invoked by generic IO level code. 00388 * 00389 * Results: 00390 * 0 if successful, errno when failed. 00391 * 00392 * Side effects: 00393 * Sets the device into blocking or non-blocking mode. 00394 * 00395 *---------------------------------------------------------------------- 00396 */ 00397 00398 /* ARGSUSED */ 00399 static int 00400 FileBlockModeProc( 00401 ClientData instanceData, /* File state. */ 00402 int mode) /* The mode to set. Can be one of 00403 * TCL_MODE_BLOCKING or 00404 * TCL_MODE_NONBLOCKING. */ 00405 { 00406 FileState *fsPtr = (FileState *) instanceData; 00407 int curStatus; 00408 00409 #ifndef USE_FIONBIO 00410 curStatus = fcntl(fsPtr->fd, F_GETFL); 00411 if (mode == TCL_MODE_BLOCKING) { 00412 CLEAR_BITS(curStatus, O_NONBLOCK); 00413 } else { 00414 SET_BITS(curStatus, O_NONBLOCK); 00415 } 00416 if (fcntl(fsPtr->fd, F_SETFL, curStatus) < 0) { 00417 return errno; 00418 } 00419 curStatus = fcntl(fsPtr->fd, F_GETFL); 00420 #else /* USE_FIONBIO */ 00421 if (mode == TCL_MODE_BLOCKING) { 00422 curStatus = 0; 00423 } else { 00424 curStatus = 1; 00425 } 00426 if (ioctl(fsPtr->fd, (int) FIONBIO, &curStatus) < 0) { 00427 return errno; 00428 } 00429 #endif /* !USE_FIONBIO */ 00430 return 0; 00431 } 00432 00433 /* 00434 *---------------------------------------------------------------------- 00435 * 00436 * FileInputProc -- 00437 * 00438 * This function is invoked from the generic IO level to read input from 00439 * a file based channel. 00440 * 00441 * Results: 00442 * The number of bytes read is returned or -1 on error. An output 00443 * argument contains a POSIX error code if an error occurs, or zero. 00444 * 00445 * Side effects: 00446 * Reads input from the input device of the channel. 00447 * 00448 *---------------------------------------------------------------------- 00449 */ 00450 00451 static int 00452 FileInputProc( 00453 ClientData instanceData, /* File state. */ 00454 char *buf, /* Where to store data read. */ 00455 int toRead, /* How much space is available in the 00456 * buffer? */ 00457 int *errorCodePtr) /* Where to store error code. */ 00458 { 00459 FileState *fsPtr = (FileState *) instanceData; 00460 int bytesRead; /* How many bytes were actually read from the 00461 * input device? */ 00462 00463 *errorCodePtr = 0; 00464 00465 /* 00466 * Assume there is always enough input available. This will block 00467 * appropriately, and read will unblock as soon as a short read is 00468 * possible, if the channel is in blocking mode. If the channel is 00469 * nonblocking, the read will never block. 00470 */ 00471 00472 bytesRead = read(fsPtr->fd, buf, (size_t) toRead); 00473 if (bytesRead > -1) { 00474 return bytesRead; 00475 } 00476 *errorCodePtr = errno; 00477 return -1; 00478 } 00479 00480 /* 00481 *---------------------------------------------------------------------- 00482 * 00483 * FileOutputProc-- 00484 * 00485 * This function is invoked from the generic IO level to write output to 00486 * a file channel. 00487 * 00488 * Results: 00489 * The number of bytes written is returned or -1 on error. An output 00490 * argument contains a POSIX error code if an error occurred, or zero. 00491 * 00492 * Side effects: 00493 * Writes output on the output device of the channel. 00494 * 00495 *---------------------------------------------------------------------- 00496 */ 00497 00498 static int 00499 FileOutputProc( 00500 ClientData instanceData, /* File state. */ 00501 const char *buf, /* The data buffer. */ 00502 int toWrite, /* How many bytes to write? */ 00503 int *errorCodePtr) /* Where to store error code. */ 00504 { 00505 FileState *fsPtr = (FileState *) instanceData; 00506 int written; 00507 00508 *errorCodePtr = 0; 00509 00510 if (toWrite == 0) { 00511 /* 00512 * SF Tcl Bug 465765. Do not try to write nothing into a file. STREAM 00513 * based implementations will considers this as EOF (if there is a 00514 * pipe behind the file). 00515 */ 00516 00517 return 0; 00518 } 00519 written = write(fsPtr->fd, buf, (size_t) toWrite); 00520 if (written > -1) { 00521 return written; 00522 } 00523 *errorCodePtr = errno; 00524 return -1; 00525 } 00526 00527 /* 00528 *---------------------------------------------------------------------- 00529 * 00530 * FileCloseProc -- 00531 * 00532 * This function is called from the generic IO level to perform 00533 * channel-type-specific cleanup when a file based channel is closed. 00534 * 00535 * Results: 00536 * 0 if successful, errno if failed. 00537 * 00538 * Side effects: 00539 * Closes the device of the channel. 00540 * 00541 *---------------------------------------------------------------------- 00542 */ 00543 00544 static int 00545 FileCloseProc( 00546 ClientData instanceData, /* File state. */ 00547 Tcl_Interp *interp) /* For error reporting - unused. */ 00548 { 00549 FileState *fsPtr = (FileState *) instanceData; 00550 int errorCode = 0; 00551 00552 Tcl_DeleteFileHandler(fsPtr->fd); 00553 00554 /* 00555 * Do not close standard channels while in thread-exit. 00556 */ 00557 00558 if (!TclInThreadExit() 00559 || ((fsPtr->fd != 0) && (fsPtr->fd != 1) && (fsPtr->fd != 2))) { 00560 if (close(fsPtr->fd) < 0) { 00561 errorCode = errno; 00562 } 00563 } 00564 ckfree((char *) fsPtr); 00565 return errorCode; 00566 } 00567 00568 /* 00569 *---------------------------------------------------------------------- 00570 * 00571 * FileSeekProc -- 00572 * 00573 * This function is called by the generic IO level to move the access 00574 * point in a file based channel. 00575 * 00576 * Results: 00577 * -1 if failed, the new position if successful. An output argument 00578 * contains the POSIX error code if an error occurred, or zero. 00579 * 00580 * Side effects: 00581 * Moves the location at which the channel will be accessed in future 00582 * operations. 00583 * 00584 *---------------------------------------------------------------------- 00585 */ 00586 00587 static int 00588 FileSeekProc( 00589 ClientData instanceData, /* File state. */ 00590 long offset, /* Offset to seek to. */ 00591 int mode, /* Relative to where should we seek? Can be 00592 * one of SEEK_START, SEEK_SET or SEEK_END. */ 00593 int *errorCodePtr) /* To store error code. */ 00594 { 00595 FileState *fsPtr = (FileState *) instanceData; 00596 Tcl_WideInt oldLoc, newLoc; 00597 00598 /* 00599 * Save our current place in case we need to roll-back the seek. 00600 */ 00601 00602 oldLoc = TclOSseek(fsPtr->fd, (Tcl_SeekOffset) 0, SEEK_CUR); 00603 if (oldLoc == Tcl_LongAsWide(-1)) { 00604 /* 00605 * Bad things are happening. Error out... 00606 */ 00607 00608 *errorCodePtr = errno; 00609 return -1; 00610 } 00611 00612 newLoc = TclOSseek(fsPtr->fd, (Tcl_SeekOffset) offset, mode); 00613 00614 /* 00615 * Check for expressability in our return type, and roll-back otherwise. 00616 */ 00617 00618 if (newLoc > Tcl_LongAsWide(INT_MAX)) { 00619 *errorCodePtr = EOVERFLOW; 00620 TclOSseek(fsPtr->fd, (Tcl_SeekOffset) oldLoc, SEEK_SET); 00621 return -1; 00622 } else { 00623 *errorCodePtr = (newLoc == Tcl_LongAsWide(-1)) ? errno : 0; 00624 } 00625 return (int) Tcl_WideAsLong(newLoc); 00626 } 00627 00628 /* 00629 *---------------------------------------------------------------------- 00630 * 00631 * FileWideSeekProc -- 00632 * 00633 * This function is called by the generic IO level to move the access 00634 * point in a file based channel, with offsets expressed as wide 00635 * integers. 00636 * 00637 * Results: 00638 * -1 if failed, the new position if successful. An output argument 00639 * contains the POSIX error code if an error occurred, or zero. 00640 * 00641 * Side effects: 00642 * Moves the location at which the channel will be accessed in future 00643 * operations. 00644 * 00645 *---------------------------------------------------------------------- 00646 */ 00647 00648 static Tcl_WideInt 00649 FileWideSeekProc( 00650 ClientData instanceData, /* File state. */ 00651 Tcl_WideInt offset, /* Offset to seek to. */ 00652 int mode, /* Relative to where should we seek? Can be 00653 * one of SEEK_START, SEEK_CUR or SEEK_END. */ 00654 int *errorCodePtr) /* To store error code. */ 00655 { 00656 FileState *fsPtr = (FileState *) instanceData; 00657 Tcl_WideInt newLoc; 00658 00659 newLoc = TclOSseek(fsPtr->fd, (Tcl_SeekOffset) offset, mode); 00660 00661 *errorCodePtr = (newLoc == -1) ? errno : 0; 00662 return newLoc; 00663 } 00664 00665 /* 00666 *---------------------------------------------------------------------- 00667 * 00668 * FileWatchProc -- 00669 * 00670 * Initialize the notifier to watch the fd from this channel. 00671 * 00672 * Results: 00673 * None. 00674 * 00675 * Side effects: 00676 * Sets up the notifier so that a future event on the channel will 00677 * be seen by Tcl. 00678 * 00679 *---------------------------------------------------------------------- 00680 */ 00681 00682 static void 00683 FileWatchProc( 00684 ClientData instanceData, /* The file state. */ 00685 int mask) /* Events of interest; an OR-ed combination of 00686 * TCL_READABLE, TCL_WRITABLE and 00687 * TCL_EXCEPTION. */ 00688 { 00689 FileState *fsPtr = (FileState *) instanceData; 00690 00691 /* 00692 * Make sure we only register for events that are valid on this file. Note 00693 * that we are passing Tcl_NotifyChannel directly to Tcl_CreateFileHandler 00694 * with the channel pointer as the client data. 00695 */ 00696 00697 mask &= fsPtr->validMask; 00698 if (mask) { 00699 Tcl_CreateFileHandler(fsPtr->fd, mask, 00700 (Tcl_FileProc *) Tcl_NotifyChannel, 00701 (ClientData) fsPtr->channel); 00702 } else { 00703 Tcl_DeleteFileHandler(fsPtr->fd); 00704 } 00705 } 00706 00707 /* 00708 *---------------------------------------------------------------------- 00709 * 00710 * FileGetHandleProc -- 00711 * 00712 * Called from Tcl_GetChannelHandle to retrieve OS handles from a file 00713 * based channel. 00714 * 00715 * Results: 00716 * Returns TCL_OK with the fd in handlePtr, or TCL_ERROR if there is no 00717 * handle for the specified direction. 00718 * 00719 * Side effects: 00720 * None. 00721 * 00722 *---------------------------------------------------------------------- 00723 */ 00724 00725 static int 00726 FileGetHandleProc( 00727 ClientData instanceData, /* The file state. */ 00728 int direction, /* TCL_READABLE or TCL_WRITABLE */ 00729 ClientData *handlePtr) /* Where to store the handle. */ 00730 { 00731 FileState *fsPtr = (FileState *) instanceData; 00732 00733 if (direction & fsPtr->validMask) { 00734 *handlePtr = (ClientData) INT2PTR(fsPtr->fd); 00735 return TCL_OK; 00736 } 00737 return TCL_ERROR; 00738 } 00739 00740 #ifdef SUPPORTS_TTY 00741 /* 00742 *---------------------------------------------------------------------- 00743 * 00744 * TtyCloseProc -- 00745 * 00746 * This function is called from the generic IO level to perform 00747 * channel-type-specific cleanup when a tty based channel is closed. 00748 * 00749 * Results: 00750 * 0 if successful, errno if failed. 00751 * 00752 * Side effects: 00753 * Closes the device of the channel. 00754 * 00755 *---------------------------------------------------------------------- 00756 */ 00757 00758 static int 00759 TtyCloseProc( 00760 ClientData instanceData, /* Tty state. */ 00761 Tcl_Interp *interp) /* For error reporting - unused. */ 00762 { 00763 #if BAD_TIP35_FLUSH 00764 TtyState *ttyPtr = (TtyState *) instanceData; 00765 #endif /* BAD_TIP35_FLUSH */ 00766 00767 #ifdef TTYFLUSH 00768 TTYFLUSH(ttyPtr->fs.fd); 00769 #endif /* TTYFLUSH */ 00770 00771 #if 0 00772 /* 00773 * TIP#35 agreed to remove the unsave so that TCL could be used as a 00774 * simple stty. It would be cleaner to remove all the stuff related to 00775 * TtyState.stateUpdated 00776 * TtyState.savedState 00777 * Then the structure TtyState would be the same as FileState. IMO this 00778 * cleanup could better be done for the final 8.4 release after nobody 00779 * complained about the missing unsave. - schroedter 00780 */ 00781 if (ttyPtr->stateUpdated) { 00782 SETIOSTATE(ttyPtr->fs.fd, &ttyPtr->savedState); 00783 } 00784 #endif 00785 00786 return FileCloseProc(instanceData, interp); 00787 } 00788 00789 /* 00790 *---------------------------------------------------------------------- 00791 * 00792 * TtyOutputProc-- 00793 * 00794 * This function is invoked from the generic IO level to write output to 00795 * a TTY channel. 00796 * 00797 * Results: 00798 * The number of bytes written is returned or -1 on error. An output 00799 * argument contains a POSIX error code if an error occurred, or zero. 00800 * 00801 * Side effects: 00802 * Writes output on the output device of the channel if the channel is 00803 * not designated to be closed. 00804 * 00805 *---------------------------------------------------------------------- 00806 */ 00807 00808 #if BAD_TIP35_FLUSH 00809 static int 00810 TtyOutputProc( 00811 ClientData instanceData, /* File state. */ 00812 const char *buf, /* The data buffer. */ 00813 int toWrite, /* How many bytes to write? */ 00814 int *errorCodePtr) /* Where to store error code. */ 00815 { 00816 if (TclInExit()) { 00817 /* 00818 * Do not write data during Tcl exit. Serial port may block preventing 00819 * Tcl from exit. 00820 */ 00821 00822 return toWrite; 00823 } 00824 00825 return FileOutputProc(instanceData, buf, toWrite, errorCodePtr); 00826 } 00827 #endif /* BAD_TIP35_FLUSH */ 00828 00829 #ifdef USE_TERMIOS 00830 /* 00831 *---------------------------------------------------------------------- 00832 * 00833 * TtyModemStatusStr -- 00834 * 00835 * Converts a RS232 modem status list of readable flags 00836 * 00837 *---------------------------------------------------------------------- 00838 */ 00839 00840 static void 00841 TtyModemStatusStr( 00842 int status, /* RS232 modem status */ 00843 Tcl_DString *dsPtr) /* Where to store string */ 00844 { 00845 #ifdef TIOCM_CTS 00846 Tcl_DStringAppendElement(dsPtr, "CTS"); 00847 Tcl_DStringAppendElement(dsPtr, (status & TIOCM_CTS) ? "1" : "0"); 00848 #endif /* TIOCM_CTS */ 00849 #ifdef TIOCM_DSR 00850 Tcl_DStringAppendElement(dsPtr, "DSR"); 00851 Tcl_DStringAppendElement(dsPtr, (status & TIOCM_DSR) ? "1" : "0"); 00852 #endif /* TIOCM_DSR */ 00853 #ifdef TIOCM_RNG 00854 Tcl_DStringAppendElement(dsPtr, "RING"); 00855 Tcl_DStringAppendElement(dsPtr, (status & TIOCM_RNG) ? "1" : "0"); 00856 #endif /* TIOCM_RNG */ 00857 #ifdef TIOCM_CD 00858 Tcl_DStringAppendElement(dsPtr, "DCD"); 00859 Tcl_DStringAppendElement(dsPtr, (status & TIOCM_CD) ? "1" : "0"); 00860 #endif /* TIOCM_CD */ 00861 } 00862 #endif /* USE_TERMIOS */ 00863 00864 /* 00865 *---------------------------------------------------------------------- 00866 * 00867 * TtySetOptionProc -- 00868 * 00869 * Sets an option on a channel. 00870 * 00871 * Results: 00872 * A standard Tcl result. Also sets the interp's result on error if 00873 * interp is not NULL. 00874 * 00875 * Side effects: 00876 * May modify an option on a device. Sets Error message if needed (by 00877 * calling Tcl_BadChannelOption). 00878 * 00879 *---------------------------------------------------------------------- 00880 */ 00881 00882 static int 00883 TtySetOptionProc( 00884 ClientData instanceData, /* File state. */ 00885 Tcl_Interp *interp, /* For error reporting - can be NULL. */ 00886 const char *optionName, /* Which option to set? */ 00887 const char *value) /* New value for option. */ 00888 { 00889 FileState *fsPtr = (FileState *) instanceData; 00890 unsigned int len, vlen; 00891 TtyAttrs tty; 00892 #ifdef USE_TERMIOS 00893 int flag, control, argc; 00894 const char **argv; 00895 IOSTATE iostate; 00896 #endif /* USE_TERMIOS */ 00897 00898 len = strlen(optionName); 00899 vlen = strlen(value); 00900 00901 /* 00902 * Option -mode baud,parity,databits,stopbits 00903 */ 00904 if ((len > 2) && (strncmp(optionName, "-mode", len) == 0)) { 00905 if (TtyParseMode(interp, value, &tty.baud, &tty.parity, &tty.data, 00906 &tty.stop) != TCL_OK) { 00907 return TCL_ERROR; 00908 } 00909 00910 /* 00911 * system calls results should be checked there. - dl 00912 */ 00913 00914 TtySetAttributes(fsPtr->fd, &tty); 00915 ((TtyState *) fsPtr)->stateUpdated = 1; 00916 return TCL_OK; 00917 } 00918 00919 #ifdef USE_TERMIOS 00920 00921 /* 00922 * Option -handshake none|xonxoff|rtscts|dtrdsr 00923 */ 00924 00925 if ((len > 1) && (strncmp(optionName, "-handshake", len) == 0)) { 00926 /* 00927 * Reset all handshake options. DTR and RTS are ON by default. 00928 */ 00929 00930 GETIOSTATE(fsPtr->fd, &iostate); 00931 CLEAR_BITS(iostate.c_iflag, IXON | IXOFF | IXANY); 00932 #ifdef CRTSCTS 00933 CLEAR_BITS(iostate.c_cflag, CRTSCTS); 00934 #endif /* CRTSCTS */ 00935 if (strncasecmp(value, "NONE", vlen) == 0) { 00936 /* leave all handshake options disabled */ 00937 } else if (strncasecmp(value, "XONXOFF", vlen) == 0) { 00938 SET_BITS(iostate.c_iflag, IXON | IXOFF | IXANY); 00939 } else if (strncasecmp(value, "RTSCTS", vlen) == 0) { 00940 #ifdef CRTSCTS 00941 SET_BITS(iostate.c_cflag, CRTSCTS); 00942 #else /* !CRTSTS */ 00943 UNSUPPORTED_OPTION("-handshake RTSCTS"); 00944 return TCL_ERROR; 00945 #endif /* CRTSCTS */ 00946 } else if (strncasecmp(value, "DTRDSR", vlen) == 0) { 00947 UNSUPPORTED_OPTION("-handshake DTRDSR"); 00948 return TCL_ERROR; 00949 } else { 00950 if (interp) { 00951 Tcl_AppendResult(interp, "bad value for -handshake: " 00952 "must be one of xonxoff, rtscts, dtrdsr or none", 00953 NULL); 00954 } 00955 return TCL_ERROR; 00956 } 00957 SETIOSTATE(fsPtr->fd, &iostate); 00958 return TCL_OK; 00959 } 00960 00961 /* 00962 * Option -xchar {\x11 \x13} 00963 */ 00964 00965 if ((len > 1) && (strncmp(optionName, "-xchar", len) == 0)) { 00966 GETIOSTATE(fsPtr->fd, &iostate); 00967 if (Tcl_SplitList(interp, value, &argc, &argv) == TCL_ERROR) { 00968 return TCL_ERROR; 00969 } 00970 if (argc == 2) { 00971 Tcl_DString ds; 00972 Tcl_DStringInit(&ds); 00973 00974 Tcl_UtfToExternalDString(NULL, argv[0], -1, &ds); 00975 iostate.c_cc[VSTART] = *(const cc_t *) Tcl_DStringValue(&ds); 00976 Tcl_DStringSetLength(&ds, 0); 00977 00978 Tcl_UtfToExternalDString(NULL, argv[1], -1, &ds); 00979 iostate.c_cc[VSTOP] = *(const cc_t *) Tcl_DStringValue(&ds); 00980 Tcl_DStringFree(&ds); 00981 } else { 00982 if (interp) { 00983 Tcl_AppendResult(interp, "bad value for -xchar: " 00984 "should be a list of two elements", NULL); 00985 } 00986 ckfree((char *) argv); 00987 return TCL_ERROR; 00988 } 00989 SETIOSTATE(fsPtr->fd, &iostate); 00990 ckfree((char *) argv); 00991 return TCL_OK; 00992 } 00993 00994 /* 00995 * Option -timeout msec 00996 */ 00997 00998 if ((len > 2) && (strncmp(optionName, "-timeout", len) == 0)) { 00999 int msec; 01000 01001 GETIOSTATE(fsPtr->fd, &iostate); 01002 if (Tcl_GetInt(interp, value, &msec) != TCL_OK) { 01003 return TCL_ERROR; 01004 } 01005 iostate.c_cc[VMIN] = 0; 01006 iostate.c_cc[VTIME] = (msec==0) ? 0 : (msec<100) ? 1 : (msec+50)/100; 01007 SETIOSTATE(fsPtr->fd, &iostate); 01008 return TCL_OK; 01009 } 01010 01011 /* 01012 * Option -ttycontrol {DTR 1 RTS 0 BREAK 0} 01013 */ 01014 01015 if ((len > 4) && (strncmp(optionName, "-ttycontrol", len) == 0)) { 01016 int i; 01017 01018 if (Tcl_SplitList(interp, value, &argc, &argv) == TCL_ERROR) { 01019 return TCL_ERROR; 01020 } 01021 if ((argc % 2) == 1) { 01022 if (interp) { 01023 Tcl_AppendResult(interp, "bad value for -ttycontrol: " 01024 "should be a list of signal,value pairs", NULL); 01025 } 01026 ckfree((char *) argv); 01027 return TCL_ERROR; 01028 } 01029 01030 GETCONTROL(fsPtr->fd, &control); 01031 for (i = 0; i < argc-1; i += 2) { 01032 if (Tcl_GetBoolean(interp, argv[i+1], &flag) == TCL_ERROR) { 01033 ckfree((char *) argv); 01034 return TCL_ERROR; 01035 } 01036 if (strncasecmp(argv[i], "DTR", strlen(argv[i])) == 0) { 01037 #ifdef TIOCM_DTR 01038 if (flag) { 01039 SET_BITS(control, TIOCM_DTR); 01040 } else { 01041 CLEAR_BITS(control, TIOCM_DTR); 01042 } 01043 #else /* !TIOCM_DTR */ 01044 UNSUPPORTED_OPTION("-ttycontrol DTR"); 01045 ckfree((char *) argv); 01046 return TCL_ERROR; 01047 #endif /* TIOCM_DTR */ 01048 } else if (strncasecmp(argv[i], "RTS", strlen(argv[i])) == 0) { 01049 #ifdef TIOCM_RTS 01050 if (flag) { 01051 SET_BITS(control, TIOCM_RTS); 01052 } else { 01053 CLEAR_BITS(control, TIOCM_RTS); 01054 } 01055 #else /* !TIOCM_RTS*/ 01056 UNSUPPORTED_OPTION("-ttycontrol RTS"); 01057 ckfree((char *) argv); 01058 return TCL_ERROR; 01059 #endif /* TIOCM_RTS*/ 01060 } else if (strncasecmp(argv[i], "BREAK", strlen(argv[i])) == 0) { 01061 #ifdef SETBREAK 01062 SETBREAK(fsPtr->fd, flag); 01063 #else /* !SETBREAK */ 01064 UNSUPPORTED_OPTION("-ttycontrol BREAK"); 01065 ckfree((char *) argv); 01066 return TCL_ERROR; 01067 #endif /* SETBREAK */ 01068 } else { 01069 if (interp) { 01070 Tcl_AppendResult(interp, "bad signal \"", argv[i], 01071 "\" for -ttycontrol: must be " 01072 "DTR, RTS or BREAK", NULL); 01073 } 01074 ckfree((char *) argv); 01075 return TCL_ERROR; 01076 } 01077 } /* -ttycontrol options loop */ 01078 01079 SETCONTROL(fsPtr->fd, &control); 01080 ckfree((char *) argv); 01081 return TCL_OK; 01082 } 01083 01084 return Tcl_BadChannelOption(interp, optionName, 01085 "mode handshake timeout ttycontrol xchar"); 01086 01087 #else /* !USE_TERMIOS */ 01088 return Tcl_BadChannelOption(interp, optionName, "mode"); 01089 #endif /* USE_TERMIOS */ 01090 } 01091 01092 /* 01093 *---------------------------------------------------------------------- 01094 * 01095 * TtyGetOptionProc -- 01096 * 01097 * Gets a mode associated with an IO channel. If the optionName arg is 01098 * non-NULL, retrieves the value of that option. If the optionName arg is 01099 * NULL, retrieves a list of alternating option names and values for the 01100 * given channel. 01101 * 01102 * Results: 01103 * A standard Tcl result. Also sets the supplied DString to the string 01104 * value of the option(s) returned. 01105 * 01106 * Side effects: 01107 * The string returned by this function is in static storage and may be 01108 * reused at any time subsequent to the call. Sets error message if 01109 * needed (by calling Tcl_BadChannelOption). 01110 * 01111 *---------------------------------------------------------------------- 01112 */ 01113 01114 static int 01115 TtyGetOptionProc( 01116 ClientData instanceData, /* File state. */ 01117 Tcl_Interp *interp, /* For error reporting - can be NULL. */ 01118 const char *optionName, /* Option to get. */ 01119 Tcl_DString *dsPtr) /* Where to store value(s). */ 01120 { 01121 FileState *fsPtr = (FileState *) instanceData; 01122 unsigned int len; 01123 char buf[3*TCL_INTEGER_SPACE + 16]; 01124 int valid = 0; /* Flag if valid option parsed. */ 01125 01126 if (optionName == NULL) { 01127 len = 0; 01128 } else { 01129 len = strlen(optionName); 01130 } 01131 if (len == 0) { 01132 Tcl_DStringAppendElement(dsPtr, "-mode"); 01133 } 01134 if (len==0 || (len>2 && strncmp(optionName, "-mode", len)==0)) { 01135 TtyAttrs tty; 01136 01137 valid = 1; 01138 TtyGetAttributes(fsPtr->fd, &tty); 01139 sprintf(buf, "%d,%c,%d,%d", tty.baud, tty.parity, tty.data, tty.stop); 01140 Tcl_DStringAppendElement(dsPtr, buf); 01141 } 01142 01143 #ifdef USE_TERMIOS 01144 /* 01145 * Get option -xchar 01146 */ 01147 01148 if (len == 0) { 01149 Tcl_DStringAppendElement(dsPtr, "-xchar"); 01150 Tcl_DStringStartSublist(dsPtr); 01151 } 01152 if (len==0 || (len>1 && strncmp(optionName, "-xchar", len)==0)) { 01153 IOSTATE iostate; 01154 Tcl_DString ds; 01155 valid = 1; 01156 01157 GETIOSTATE(fsPtr->fd, &iostate); 01158 Tcl_DStringInit(&ds); 01159 01160 Tcl_ExternalToUtfDString(NULL, (const char *) &iostate.c_cc[VSTART], 1, &ds); 01161 Tcl_DStringAppendElement(dsPtr, (const char *) Tcl_DStringValue(&ds)); 01162 Tcl_DStringSetLength(&ds, 0); 01163 01164 Tcl_ExternalToUtfDString(NULL, (const char *) &iostate.c_cc[VSTOP], 1, &ds); 01165 Tcl_DStringAppendElement(dsPtr, (const char *) Tcl_DStringValue(&ds)); 01166 Tcl_DStringFree(&ds); 01167 } 01168 if (len == 0) { 01169 Tcl_DStringEndSublist(dsPtr); 01170 } 01171 01172 /* 01173 * Get option -queue 01174 * Option is readonly and returned by [fconfigure chan -queue] but not 01175 * returned by unnamed [fconfigure chan]. 01176 */ 01177 01178 if ((len > 1) && (strncmp(optionName, "-queue", len) == 0)) { 01179 int inQueue=0, outQueue=0, inBuffered, outBuffered; 01180 01181 valid = 1; 01182 #ifdef GETREADQUEUE 01183 GETREADQUEUE(fsPtr->fd, inQueue); 01184 #endif /* GETREADQUEUE */ 01185 #ifdef GETWRITEQUEUE 01186 GETWRITEQUEUE(fsPtr->fd, outQueue); 01187 #endif /* GETWRITEQUEUE */ 01188 inBuffered = Tcl_InputBuffered(fsPtr->channel); 01189 outBuffered = Tcl_OutputBuffered(fsPtr->channel); 01190 01191 sprintf(buf, "%d", inBuffered+inQueue); 01192 Tcl_DStringAppendElement(dsPtr, buf); 01193 sprintf(buf, "%d", outBuffered+outQueue); 01194 Tcl_DStringAppendElement(dsPtr, buf); 01195 } 01196 01197 /* 01198 * Get option -ttystatus 01199 * Option is readonly and returned by [fconfigure chan -ttystatus] but not 01200 * returned by unnamed [fconfigure chan]. 01201 */ 01202 if ((len > 4) && (strncmp(optionName, "-ttystatus", len) == 0)) { 01203 int status; 01204 01205 valid = 1; 01206 GETCONTROL(fsPtr->fd, &status); 01207 TtyModemStatusStr(status, dsPtr); 01208 } 01209 #endif /* USE_TERMIOS */ 01210 01211 if (valid) { 01212 return TCL_OK; 01213 } 01214 return Tcl_BadChannelOption(interp, optionName, "mode" 01215 #ifdef USE_TERMIOS 01216 " queue ttystatus xchar" 01217 #endif /* USE_TERMIOS */ 01218 ); 01219 } 01220 01221 #ifdef DIRECT_BAUD 01222 # define TtyGetSpeed(baud) ((unsigned) (baud)) 01223 # define TtyGetBaud(speed) ((int) (speed)) 01224 #else /* !DIRECT_BAUD */ 01225 01226 static struct {int baud; unsigned long speed;} speeds[] = { 01227 #ifdef B0 01228 {0, B0}, 01229 #endif 01230 #ifdef B50 01231 {50, B50}, 01232 #endif 01233 #ifdef B75 01234 {75, B75}, 01235 #endif 01236 #ifdef B110 01237 {110, B110}, 01238 #endif 01239 #ifdef B134 01240 {134, B134}, 01241 #endif 01242 #ifdef B150 01243 {150, B150}, 01244 #endif 01245 #ifdef B200 01246 {200, B200}, 01247 #endif 01248 #ifdef B300 01249 {300, B300}, 01250 #endif 01251 #ifdef B600 01252 {600, B600}, 01253 #endif 01254 #ifdef B1200 01255 {1200, B1200}, 01256 #endif 01257 #ifdef B1800 01258 {1800, B1800}, 01259 #endif 01260 #ifdef B2400 01261 {2400, B2400}, 01262 #endif 01263 #ifdef B4800 01264 {4800, B4800}, 01265 #endif 01266 #ifdef B9600 01267 {9600, B9600}, 01268 #endif 01269 #ifdef B14400 01270 {14400, B14400}, 01271 #endif 01272 #ifdef B19200 01273 {19200, B19200}, 01274 #endif 01275 #ifdef EXTA 01276 {19200, EXTA}, 01277 #endif 01278 #ifdef B28800 01279 {28800, B28800}, 01280 #endif 01281 #ifdef B38400 01282 {38400, B38400}, 01283 #endif 01284 #ifdef EXTB 01285 {38400, EXTB}, 01286 #endif 01287 #ifdef B57600 01288 {57600, B57600}, 01289 #endif 01290 #ifdef _B57600 01291 {57600, _B57600}, 01292 #endif 01293 #ifdef B76800 01294 {76800, B76800}, 01295 #endif 01296 #ifdef B115200 01297 {115200, B115200}, 01298 #endif 01299 #ifdef _B115200 01300 {115200, _B115200}, 01301 #endif 01302 #ifdef B153600 01303 {153600, B153600}, 01304 #endif 01305 #ifdef B230400 01306 {230400, B230400}, 01307 #endif 01308 #ifdef B307200 01309 {307200, B307200}, 01310 #endif 01311 #ifdef B460800 01312 {460800, B460800}, 01313 #endif 01314 {-1, 0} 01315 }; 01316 01317 /* 01318 *--------------------------------------------------------------------------- 01319 * 01320 * TtyGetSpeed -- 01321 * 01322 * Given a baud rate, get the mask value that should be stored in the 01323 * termios, termio, or sgttyb structure in order to select that baud 01324 * rate. 01325 * 01326 * Results: 01327 * As above. 01328 * 01329 * Side effects: 01330 * None. 01331 * 01332 *--------------------------------------------------------------------------- 01333 */ 01334 01335 static unsigned long 01336 TtyGetSpeed( 01337 int baud) /* The baud rate to look up. */ 01338 { 01339 int bestIdx, bestDiff, i, diff; 01340 01341 bestIdx = 0; 01342 bestDiff = 1000000; 01343 01344 /* 01345 * If the baud rate does not correspond to one of the known mask values, 01346 * choose the mask value whose baud rate is closest to the specified baud 01347 * rate. 01348 */ 01349 01350 for (i = 0; speeds[i].baud >= 0; i++) { 01351 diff = speeds[i].baud - baud; 01352 if (diff < 0) { 01353 diff = -diff; 01354 } 01355 if (diff < bestDiff) { 01356 bestIdx = i; 01357 bestDiff = diff; 01358 } 01359 } 01360 return speeds[bestIdx].speed; 01361 } 01362 01363 /* 01364 *--------------------------------------------------------------------------- 01365 * 01366 * TtyGetBaud -- 01367 * 01368 * Given a speed mask value from a termios, termio, or sgttyb structure, 01369 * get the baus rate that corresponds to that mask value. 01370 * 01371 * Results: 01372 * As above. If the mask value was not recognized, 0 is returned. 01373 * 01374 * Side effects: 01375 * None. 01376 * 01377 *--------------------------------------------------------------------------- 01378 */ 01379 01380 static int 01381 TtyGetBaud( 01382 unsigned long speed) /* Speed mask value to look up. */ 01383 { 01384 int i; 01385 01386 for (i = 0; speeds[i].baud >= 0; i++) { 01387 if (speeds[i].speed == speed) { 01388 return speeds[i].baud; 01389 } 01390 } 01391 return 0; 01392 } 01393 #endif /* !DIRECT_BAUD */ 01394 01395 /* 01396 *--------------------------------------------------------------------------- 01397 * 01398 * TtyGetAttributes -- 01399 * 01400 * Get the current attributes of the specified serial device. 01401 * 01402 * Results: 01403 * None. 01404 * 01405 * Side effects: 01406 * None. 01407 * 01408 *--------------------------------------------------------------------------- 01409 */ 01410 01411 static void 01412 TtyGetAttributes( 01413 int fd, /* Open file descriptor for serial port to be 01414 * queried. */ 01415 TtyAttrs *ttyPtr) /* Buffer filled with serial port 01416 * attributes. */ 01417 { 01418 IOSTATE iostate; 01419 int baud, parity, data, stop; 01420 01421 GETIOSTATE(fd, &iostate); 01422 01423 #ifdef USE_TERMIOS 01424 baud = TtyGetBaud(cfgetospeed(&iostate)); 01425 01426 parity = 'n'; 01427 #ifdef PAREXT 01428 switch ((int) (iostate.c_cflag & (PARENB | PARODD | PAREXT))) { 01429 case PARENB : parity = 'e'; break; 01430 case PARENB | PARODD : parity = 'o'; break; 01431 case PARENB | PAREXT : parity = 's'; break; 01432 case PARENB | PARODD | PAREXT : parity = 'm'; break; 01433 } 01434 #else /* !PAREXT */ 01435 switch ((int) (iostate.c_cflag & (PARENB | PARODD))) { 01436 case PARENB : parity = 'e'; break; 01437 case PARENB | PARODD : parity = 'o'; break; 01438 } 01439 #endif /* !PAREXT */ 01440 01441 data = iostate.c_cflag & CSIZE; 01442 data = (data == CS5) ? 5 : (data == CS6) ? 6 : (data == CS7) ? 7 : 8; 01443 01444 stop = (iostate.c_cflag & CSTOPB) ? 2 : 1; 01445 #endif /* USE_TERMIOS */ 01446 01447 #ifdef USE_TERMIO 01448 baud = TtyGetBaud(iostate.c_cflag & CBAUD); 01449 01450 parity = 'n'; 01451 switch (iostate.c_cflag & (PARENB | PARODD | PAREXT)) { 01452 case PARENB : parity = 'e'; break; 01453 case PARENB | PARODD : parity = 'o'; break; 01454 case PARENB | PAREXT : parity = 's'; break; 01455 case PARENB | PARODD | PAREXT : parity = 'm'; break; 01456 } 01457 01458 data = iostate.c_cflag & CSIZE; 01459 data = (data == CS5) ? 5 : (data == CS6) ? 6 : (data == CS7) ? 7 : 8; 01460 01461 stop = (iostate.c_cflag & CSTOPB) ? 2 : 1; 01462 #endif /* USE_TERMIO */ 01463 01464 #ifdef USE_SGTTY 01465 baud = TtyGetBaud(iostate.sg_ospeed); 01466 01467 parity = 'n'; 01468 if (iostate.sg_flags & EVENP) { 01469 parity = 'e'; 01470 } else if (iostate.sg_flags & ODDP) { 01471 parity = 'o'; 01472 } 01473 01474 data = (iostate.sg_flags & (EVENP | ODDP)) ? 7 : 8; 01475 01476 stop = 1; 01477 #endif /* USE_SGTTY */ 01478 01479 ttyPtr->baud = baud; 01480 ttyPtr->parity = parity; 01481 ttyPtr->data = data; 01482 ttyPtr->stop = stop; 01483 } 01484 01485 /* 01486 *--------------------------------------------------------------------------- 01487 * 01488 * TtySetAttributes -- 01489 * 01490 * Set the current attributes of the specified serial device. 01491 * 01492 * Results: 01493 * None. 01494 * 01495 * Side effects: 01496 * None. 01497 * 01498 *--------------------------------------------------------------------------- 01499 */ 01500 01501 static void 01502 TtySetAttributes( 01503 int fd, /* Open file descriptor for serial port to be 01504 * modified. */ 01505 TtyAttrs *ttyPtr) /* Buffer containing new attributes for serial 01506 * port. */ 01507 { 01508 IOSTATE iostate; 01509 01510 #ifdef USE_TERMIOS 01511 int parity, data, flag; 01512 01513 GETIOSTATE(fd, &iostate); 01514 cfsetospeed(&iostate, TtyGetSpeed(ttyPtr->baud)); 01515 cfsetispeed(&iostate, TtyGetSpeed(ttyPtr->baud)); 01516 01517 flag = 0; 01518 parity = ttyPtr->parity; 01519 if (parity != 'n') { 01520 SET_BITS(flag, PARENB); 01521 #ifdef PAREXT 01522 CLEAR_BITS(iostate.c_cflag, PAREXT); 01523 if ((parity == 'm') || (parity == 's')) { 01524 SET_BITS(flag, PAREXT); 01525 } 01526 #endif /* PAREXT */ 01527 if ((parity == 'm') || (parity == 'o')) { 01528 SET_BITS(flag, PARODD); 01529 } 01530 } 01531 data = ttyPtr->data; 01532 SET_BITS(flag, 01533 (data == 5) ? CS5 : 01534 (data == 6) ? CS6 : 01535 (data == 7) ? CS7 : CS8); 01536 if (ttyPtr->stop == 2) { 01537 SET_BITS(flag, CSTOPB); 01538 } 01539 01540 CLEAR_BITS(iostate.c_cflag, PARENB | PARODD | CSIZE | CSTOPB); 01541 SET_BITS(iostate.c_cflag, flag); 01542 01543 #endif /* USE_TERMIOS */ 01544 01545 #ifdef USE_TERMIO 01546 int parity, data, flag; 01547 01548 GETIOSTATE(fd, &iostate); 01549 CLEAR_BITS(iostate.c_cflag, CBAUD); 01550 SET_BITS(iostate.c_cflag, TtyGetSpeed(ttyPtr->baud)); 01551 01552 flag = 0; 01553 parity = ttyPtr->parity; 01554 if (parity != 'n') { 01555 SET_BITS(flag, PARENB); 01556 if ((parity == 'm') || (parity == 's')) { 01557 SET_BITS(flag, PAREXT); 01558 } 01559 if ((parity == 'm') || (parity == 'o')) { 01560 SET_BITS(flag, PARODD); 01561 } 01562 } 01563 data = ttyPtr->data; 01564 SET_BITS(flag, 01565 (data == 5) ? CS5 : 01566 (data == 6) ? CS6 : 01567 (data == 7) ? CS7 : CS8); 01568 if (ttyPtr->stop == 2) { 01569 SET_BITS(flag, CSTOPB); 01570 } 01571 01572 CLEAR_BITS(iostate.c_cflag, PARENB | PARODD | PAREXT | CSIZE | CSTOPB); 01573 SET_BITS(iostate.c_cflag, flag); 01574 01575 #endif /* USE_TERMIO */ 01576 01577 #ifdef USE_SGTTY 01578 int parity; 01579 01580 GETIOSTATE(fd, &iostate); 01581 iostate.sg_ospeed = TtyGetSpeed(ttyPtr->baud); 01582 iostate.sg_ispeed = TtyGetSpeed(ttyPtr->baud); 01583 01584 parity = ttyPtr->parity; 01585 if (parity == 'e') { 01586 CLEAR_BITS(iostate.sg_flags, ODDP); 01587 SET_BITS(iostate.sg_flags, EVENP); 01588 } else if (parity == 'o') { 01589 CLEAR_BITS(iostate.sg_flags, EVENP); 01590 SET_BITS(iostate.sg_flags, ODDP); 01591 } 01592 #endif /* USE_SGTTY */ 01593 01594 SETIOSTATE(fd, &iostate); 01595 } 01596 01597 /* 01598 *--------------------------------------------------------------------------- 01599 * 01600 * TtyParseMode -- 01601 * 01602 * Parse the "-mode" argument to the fconfigure command. The argument is 01603 * of the form baud,parity,data,stop. 01604 * 01605 * Results: 01606 * The return value is TCL_OK if the argument was successfully parsed, 01607 * TCL_ERROR otherwise. If TCL_ERROR is returned, an error message is 01608 * left in the interp's result (if interp is non-NULL). 01609 * 01610 * Side effects: 01611 * None. 01612 * 01613 *--------------------------------------------------------------------------- 01614 */ 01615 01616 static int 01617 TtyParseMode( 01618 Tcl_Interp *interp, /* If non-NULL, interp for error return. */ 01619 const char *mode, /* Mode string to be parsed. */ 01620 int *speedPtr, /* Filled with baud rate from mode string. */ 01621 int *parityPtr, /* Filled with parity from mode string. */ 01622 int *dataPtr, /* Filled with data bits from mode string. */ 01623 int *stopPtr) /* Filled with stop bits from mode string. */ 01624 { 01625 int i, end; 01626 char parity; 01627 static const char *bad = "bad value for -mode"; 01628 01629 i = sscanf(mode, "%d,%c,%d,%d%n", speedPtr, &parity, dataPtr, 01630 stopPtr, &end); 01631 if ((i != 4) || (mode[end] != '\0')) { 01632 if (interp != NULL) { 01633 Tcl_AppendResult(interp, bad, ": should be baud,parity,data,stop", 01634 NULL); 01635 } 01636 return TCL_ERROR; 01637 } 01638 01639 /* 01640 * Only allow setting mark/space parity on platforms that support it Make 01641 * sure to allow for the case where strchr is a macro. [Bug: 5089] 01642 */ 01643 01644 #if defined(PAREXT) || defined(USE_TERMIO) 01645 if (strchr("noems", parity) == NULL) { 01646 #else 01647 if (strchr("noe", parity) == NULL) { 01648 #endif /* PAREXT|USE_TERMIO */ 01649 if (interp != NULL) { 01650 Tcl_AppendResult(interp, bad, " parity: should be ", 01651 #if defined(PAREXT) || defined(USE_TERMIO) 01652 "n, o, e, m, or s", 01653 #else 01654 "n, o, or e", 01655 #endif /* PAREXT|USE_TERMIO */ 01656 NULL); 01657 } 01658 return TCL_ERROR; 01659 } 01660 *parityPtr = parity; 01661 if ((*dataPtr < 5) || (*dataPtr > 8)) { 01662 if (interp != NULL) { 01663 Tcl_AppendResult(interp, bad, " data: should be 5, 6, 7, or 8", 01664 NULL); 01665 } 01666 return TCL_ERROR; 01667 } 01668 if ((*stopPtr < 0) || (*stopPtr > 2)) { 01669 if (interp != NULL) { 01670 Tcl_AppendResult(interp, bad, " stop: should be 1 or 2", NULL); 01671 } 01672 return TCL_ERROR; 01673 } 01674 return TCL_OK; 01675 } 01676 01677 /* 01678 *--------------------------------------------------------------------------- 01679 * 01680 * TtyInit -- 01681 * 01682 * Given file descriptor that refers to a serial port, initialize the 01683 * serial port to a set of sane values so that Tcl can talk to a device 01684 * located on the serial port. Note that no initialization happens if the 01685 * initialize flag is not set; this is necessary for the correct handling 01686 * of UNIX console TTYs at startup. 01687 * 01688 * Results: 01689 * A pointer to a FileState suitable for use with Tcl_CreateChannel and 01690 * the ttyChannelType structure. 01691 * 01692 * Side effects: 01693 * Serial device initialized to non-blocking raw mode, similar to sockets 01694 * (if initialize flag is non-zero.) All other modes can be simulated on 01695 * top of this in Tcl. 01696 * 01697 *--------------------------------------------------------------------------- 01698 */ 01699 01700 static FileState * 01701 TtyInit( 01702 int fd, /* Open file descriptor for serial port to be 01703 * initialized. */ 01704 int initialize) 01705 { 01706 TtyState *ttyPtr; 01707 01708 ttyPtr = (TtyState *) ckalloc((unsigned) sizeof(TtyState)); 01709 GETIOSTATE(fd, &ttyPtr->savedState); 01710 ttyPtr->stateUpdated = 0; 01711 if (initialize) { 01712 IOSTATE iostate = ttyPtr->savedState; 01713 01714 #if defined(USE_TERMIOS) || defined(USE_TERMIO) 01715 if (iostate.c_iflag != IGNBRK || 01716 iostate.c_oflag != 0 || 01717 iostate.c_lflag != 0 || 01718 iostate.c_cflag & CREAD || 01719 iostate.c_cc[VMIN] != 1 || 01720 iostate.c_cc[VTIME] != 0) { 01721 ttyPtr->stateUpdated = 1; 01722 } 01723 iostate.c_iflag = IGNBRK; 01724 iostate.c_oflag = 0; 01725 iostate.c_lflag = 0; 01726 SET_BITS(iostate.c_cflag, CREAD); 01727 iostate.c_cc[VMIN] = 1; 01728 iostate.c_cc[VTIME] = 0; 01729 #endif /* USE_TERMIOS|USE_TERMIO */ 01730 01731 #ifdef USE_SGTTY 01732 if ((iostate.sg_flags & (EVENP | ODDP)) || 01733 !(iostate.sg_flags & RAW)) { 01734 ttyPtr->stateUpdated = 1; 01735 } 01736 iostate.sg_flags &= EVENP | ODDP; 01737 SET_BITS(iostate.sg_flags, RAW); 01738 #endif /* USE_SGTTY */ 01739 01740 /* 01741 * Only update if we're changing anything to avoid possible blocking. 01742 */ 01743 01744 if (ttyPtr->stateUpdated) { 01745 SETIOSTATE(fd, &iostate); 01746 } 01747 } 01748 01749 return &ttyPtr->fs; 01750 } 01751 #endif /* SUPPORTS_TTY */ 01752 01753 /* 01754 *---------------------------------------------------------------------- 01755 * 01756 * TclpOpenFileChannel -- 01757 * 01758 * Open an file based channel on Unix systems. 01759 * 01760 * Results: 01761 * The new channel or NULL. If NULL, the output argument errorCodePtr is 01762 * set to a POSIX error and an error message is left in the interp's 01763 * result if interp is not NULL. 01764 * 01765 * Side effects: 01766 * May open the channel and may cause creation of a file on the file 01767 * system. 01768 * 01769 *---------------------------------------------------------------------- 01770 */ 01771 01772 Tcl_Channel 01773 TclpOpenFileChannel( 01774 Tcl_Interp *interp, /* Interpreter for error reporting; can be 01775 * NULL. */ 01776 Tcl_Obj *pathPtr, /* Name of file to open. */ 01777 int mode, /* POSIX open mode. */ 01778 int permissions) /* If the open involves creating a file, with 01779 * what modes to create it? */ 01780 { 01781 int fd, channelPermissions; 01782 FileState *fsPtr; 01783 const char *native, *translation; 01784 char channelName[16 + TCL_INTEGER_SPACE]; 01785 Tcl_ChannelType *channelTypePtr; 01786 01787 switch (mode & (O_RDONLY | O_WRONLY | O_RDWR)) { 01788 case O_RDONLY: 01789 channelPermissions = TCL_READABLE; 01790 break; 01791 case O_WRONLY: 01792 channelPermissions = TCL_WRITABLE; 01793 break; 01794 case O_RDWR: 01795 channelPermissions = (TCL_READABLE | TCL_WRITABLE); 01796 break; 01797 default: 01798 /* 01799 * This may occurr if modeString was "", for example. 01800 */ 01801 01802 Tcl_Panic("TclpOpenFileChannel: invalid mode value"); 01803 return NULL; 01804 } 01805 01806 native = Tcl_FSGetNativePath(pathPtr); 01807 if (native == NULL) { 01808 return NULL; 01809 } 01810 01811 #ifdef DJGPP 01812 SET_BITS(mode, O_BINARY); 01813 #endif 01814 01815 fd = TclOSopen(native, mode, permissions); 01816 01817 if (fd < 0) { 01818 if (interp != NULL) { 01819 Tcl_AppendResult(interp, "couldn't open \"", TclGetString(pathPtr), 01820 "\": ", Tcl_PosixError(interp), NULL); 01821 } 01822 return NULL; 01823 } 01824 01825 /* 01826 * Set close-on-exec flag on the fd so that child processes will not 01827 * inherit this fd. 01828 */ 01829 01830 fcntl(fd, F_SETFD, FD_CLOEXEC); 01831 01832 sprintf(channelName, "file%d", fd); 01833 01834 #ifdef SUPPORTS_TTY 01835 if (strcmp(native, "/dev/tty") != 0 && isatty(fd)) { 01836 /* 01837 * Initialize the serial port to a set of sane parameters. Especially 01838 * important if the remote device is set to echo and the serial port 01839 * driver was also set to echo -- as soon as a char were sent to the 01840 * serial port, the remote device would echo it, then the serial 01841 * driver would echo it back to the device, etc. 01842 * 01843 * Note that we do not do this if we're dealing with /dev/tty itself, 01844 * as that tends to cause Bad Things To Happen when you're working 01845 * interactively. Strictly a better check would be to see if the FD 01846 * being set up is a device and has the same major/minor as the 01847 * initial std FDs (beware reopening!) but that's nearly as messy. 01848 */ 01849 01850 translation = "auto crlf"; 01851 channelTypePtr = &ttyChannelType; 01852 fsPtr = TtyInit(fd, 1); 01853 } else 01854 #endif /* SUPPORTS_TTY */ 01855 { 01856 translation = NULL; 01857 channelTypePtr = &fileChannelType; 01858 fsPtr = (FileState *) ckalloc((unsigned) sizeof(FileState)); 01859 } 01860 01861 fsPtr->validMask = channelPermissions | TCL_EXCEPTION; 01862 fsPtr->fd = fd; 01863 01864 fsPtr->channel = Tcl_CreateChannel(channelTypePtr, channelName, 01865 (ClientData) fsPtr, channelPermissions); 01866 01867 if (translation != NULL) { 01868 /* 01869 * Gotcha. Most modems need a "\r" at the end of the command sequence. 01870 * If you just send "at\n", the modem will not respond with "OK" 01871 * because it never got a "\r" to actually invoke the command. So, by 01872 * default, newlines are translated to "\r\n" on output to avoid "bug" 01873 * reports that the serial port isn't working. 01874 */ 01875 01876 if (Tcl_SetChannelOption(interp, fsPtr->channel, "-translation", 01877 translation) != TCL_OK) { 01878 Tcl_Close(NULL, fsPtr->channel); 01879 return NULL; 01880 } 01881 } 01882 01883 return fsPtr->channel; 01884 } 01885 01886 /* 01887 *---------------------------------------------------------------------- 01888 * 01889 * Tcl_MakeFileChannel -- 01890 * 01891 * Makes a Tcl_Channel from an existing OS level file handle. 01892 * 01893 * Results: 01894 * The Tcl_Channel created around the preexisting OS level file handle. 01895 * 01896 * Side effects: 01897 * None. 01898 * 01899 *---------------------------------------------------------------------- 01900 */ 01901 01902 Tcl_Channel 01903 Tcl_MakeFileChannel( 01904 ClientData handle, /* OS level handle. */ 01905 int mode) /* ORed combination of TCL_READABLE and 01906 * TCL_WRITABLE to indicate file mode. */ 01907 { 01908 FileState *fsPtr; 01909 char channelName[16 + TCL_INTEGER_SPACE]; 01910 int fd = PTR2INT(handle); 01911 Tcl_ChannelType *channelTypePtr; 01912 struct sockaddr sockaddr; 01913 socklen_t sockaddrLen = sizeof(sockaddr); 01914 01915 if (mode == 0) { 01916 return NULL; 01917 } 01918 01919 sockaddr.sa_family = AF_UNSPEC; 01920 01921 #ifdef SUPPORTS_TTY 01922 if (isatty(fd)) { 01923 fsPtr = TtyInit(fd, 0); 01924 channelTypePtr = &ttyChannelType; 01925 sprintf(channelName, "serial%d", fd); 01926 } else 01927 #endif /* SUPPORTS_TTY */ 01928 if (getsockname(fd, (struct sockaddr *)&sockaddr, &sockaddrLen) == 0 01929 && sockaddrLen > 0 01930 && sockaddr.sa_family == AF_INET) { 01931 return MakeTcpClientChannelMode((ClientData) INT2PTR(fd), mode); 01932 } else { 01933 channelTypePtr = &fileChannelType; 01934 fsPtr = (FileState *) ckalloc((unsigned) sizeof(FileState)); 01935 sprintf(channelName, "file%d", fd); 01936 } 01937 01938 fsPtr->fd = fd; 01939 fsPtr->validMask = mode | TCL_EXCEPTION; 01940 fsPtr->channel = Tcl_CreateChannel(channelTypePtr, channelName, 01941 (ClientData) fsPtr, mode); 01942 01943 return fsPtr->channel; 01944 } 01945 01946 /* 01947 *---------------------------------------------------------------------- 01948 * 01949 * TcpBlockModeProc -- 01950 * 01951 * This function is invoked by the generic IO level to set blocking and 01952 * nonblocking mode on a TCP socket based channel. 01953 * 01954 * Results: 01955 * 0 if successful, errno when failed. 01956 * 01957 * Side effects: 01958 * Sets the device into blocking or nonblocking mode. 01959 * 01960 *---------------------------------------------------------------------- 01961 */ 01962 01963 /* ARGSUSED */ 01964 static int 01965 TcpBlockModeProc( 01966 ClientData instanceData, /* Socket state. */ 01967 int mode) /* The mode to set. Can be one of 01968 * TCL_MODE_BLOCKING or 01969 * TCL_MODE_NONBLOCKING. */ 01970 { 01971 TcpState *statePtr = (TcpState *) instanceData; 01972 int setting; 01973 01974 #ifndef USE_FIONBIO 01975 setting = fcntl(statePtr->fd, F_GETFL); 01976 if (mode == TCL_MODE_BLOCKING) { 01977 CLEAR_BITS(statePtr->flags, TCP_ASYNC_SOCKET); 01978 CLEAR_BITS(setting, O_NONBLOCK); 01979 } else { 01980 SET_BITS(statePtr->flags, TCP_ASYNC_SOCKET); 01981 SET_BITS(setting, O_NONBLOCK); 01982 } 01983 if (fcntl(statePtr->fd, F_SETFL, setting) < 0) { 01984 return errno; 01985 } 01986 #else /* USE_FIONBIO */ 01987 if (mode == TCL_MODE_BLOCKING) { 01988 CLEAR_BITS(statePtr->flags, TCP_ASYNC_SOCKET); 01989 setting = 0; 01990 if (ioctl(statePtr->fd, (int) FIONBIO, &setting) == -1) { 01991 return errno; 01992 } 01993 } else { 01994 SET_BITS(statePtr->flags, TCP_ASYNC_SOCKET); 01995 setting = 1; 01996 if (ioctl(statePtr->fd, (int) FIONBIO, &setting) == -1) { 01997 return errno; 01998 } 01999 } 02000 #endif /* !USE_FIONBIO */ 02001 02002 return 0; 02003 } 02004 02005 /* 02006 *---------------------------------------------------------------------- 02007 * 02008 * WaitForConnect -- 02009 * 02010 * Waits for a connection on an asynchronously opened socket to be 02011 * completed. 02012 * 02013 * Results: 02014 * None. 02015 * 02016 * Side effects: 02017 * The socket is connected after this function returns. 02018 * 02019 *---------------------------------------------------------------------- 02020 */ 02021 02022 static int 02023 WaitForConnect( 02024 TcpState *statePtr, /* State of the socket. */ 02025 int *errorCodePtr) /* Where to store errors? */ 02026 { 02027 int timeOut; /* How long to wait. */ 02028 int state; /* Of calling TclWaitForFile. */ 02029 int flags; /* fcntl flags for the socket. */ 02030 02031 /* 02032 * If an asynchronous connect is in progress, attempt to wait for it to 02033 * complete before reading. 02034 */ 02035 02036 if (statePtr->flags & TCP_ASYNC_CONNECT) { 02037 if (statePtr->flags & TCP_ASYNC_SOCKET) { 02038 timeOut = 0; 02039 } else { 02040 timeOut = -1; 02041 } 02042 errno = 0; 02043 state = TclUnixWaitForFile(statePtr->fd, 02044 TCL_WRITABLE | TCL_EXCEPTION, timeOut); 02045 if (!(statePtr->flags & TCP_ASYNC_SOCKET)) { 02046 #ifndef USE_FIONBIO 02047 flags = fcntl(statePtr->fd, F_GETFL); 02048 CLEAR_BITS(flags, O_NONBLOCK); 02049 (void) fcntl(statePtr->fd, F_SETFL, flags); 02050 #else /* USE_FIONBIO */ 02051 flags = 0; 02052 (void) ioctl(statePtr->fd, FIONBIO, &flags); 02053 #endif /* !USE_FIONBIO */ 02054 } 02055 if (state & TCL_EXCEPTION) { 02056 return -1; 02057 } 02058 if (state & TCL_WRITABLE) { 02059 CLEAR_BITS(statePtr->flags, TCP_ASYNC_CONNECT); 02060 } else if (timeOut == 0) { 02061 *errorCodePtr = errno = EWOULDBLOCK; 02062 return -1; 02063 } 02064 } 02065 return 0; 02066 } 02067 02068 /* 02069 *---------------------------------------------------------------------- 02070 * 02071 * TcpInputProc -- 02072 * 02073 * This function is invoked by the generic IO level to read input from a 02074 * TCP socket based channel. 02075 * 02076 * NOTE: We cannot share code with FilePipeInputProc because here we must 02077 * use recv to obtain the input from the channel, not read. 02078 * 02079 * Results: 02080 * The number of bytes read is returned or -1 on error. An output 02081 * argument contains the POSIX error code on error, or zero if no error 02082 * occurred. 02083 * 02084 * Side effects: 02085 * Reads input from the input device of the channel. 02086 * 02087 *---------------------------------------------------------------------- 02088 */ 02089 02090 /* ARGSUSED */ 02091 static int 02092 TcpInputProc( 02093 ClientData instanceData, /* Socket state. */ 02094 char *buf, /* Where to store data read. */ 02095 int bufSize, /* How much space is available in the 02096 * buffer? */ 02097 int *errorCodePtr) /* Where to store error code. */ 02098 { 02099 TcpState *statePtr = (TcpState *) instanceData; 02100 int bytesRead, state; 02101 02102 *errorCodePtr = 0; 02103 state = WaitForConnect(statePtr, errorCodePtr); 02104 if (state != 0) { 02105 return -1; 02106 } 02107 bytesRead = recv(statePtr->fd, buf, (size_t) bufSize, 0); 02108 if (bytesRead > -1) { 02109 return bytesRead; 02110 } 02111 if (errno == ECONNRESET) { 02112 /* 02113 * Turn ECONNRESET into a soft EOF condition. 02114 */ 02115 02116 return 0; 02117 } 02118 *errorCodePtr = errno; 02119 return -1; 02120 } 02121 02122 /* 02123 *---------------------------------------------------------------------- 02124 * 02125 * TcpOutputProc -- 02126 * 02127 * This function is invoked by the generic IO level to write output to a 02128 * TCP socket based channel. 02129 * 02130 * NOTE: We cannot share code with FilePipeOutputProc because here we 02131 * must use send, not write, to get reliable error reporting. 02132 * 02133 * Results: 02134 * The number of bytes written is returned. An output argument is set to 02135 * a POSIX error code if an error occurred, or zero. 02136 * 02137 * Side effects: 02138 * Writes output on the output device of the channel. 02139 * 02140 *---------------------------------------------------------------------- 02141 */ 02142 02143 static int 02144 TcpOutputProc( 02145 ClientData instanceData, /* Socket state. */ 02146 const char *buf, /* The data buffer. */ 02147 int toWrite, /* How many bytes to write? */ 02148 int *errorCodePtr) /* Where to store error code. */ 02149 { 02150 TcpState *statePtr = (TcpState *) instanceData; 02151 int written; 02152 int state; /* Of waiting for connection. */ 02153 02154 *errorCodePtr = 0; 02155 state = WaitForConnect(statePtr, errorCodePtr); 02156 if (state != 0) { 02157 return -1; 02158 } 02159 written = send(statePtr->fd, buf, (size_t) toWrite, 0); 02160 if (written > -1) { 02161 return written; 02162 } 02163 *errorCodePtr = errno; 02164 return -1; 02165 } 02166 02167 /* 02168 *---------------------------------------------------------------------- 02169 * 02170 * TcpCloseProc -- 02171 * 02172 * This function is invoked by the generic IO level to perform 02173 * channel-type-specific cleanup when a TCP socket based channel is 02174 * closed. 02175 * 02176 * Results: 02177 * 0 if successful, the value of errno if failed. 02178 * 02179 * Side effects: 02180 * Closes the socket of the channel. 02181 * 02182 *---------------------------------------------------------------------- 02183 */ 02184 02185 /* ARGSUSED */ 02186 static int 02187 TcpCloseProc( 02188 ClientData instanceData, /* The socket to close. */ 02189 Tcl_Interp *interp) /* For error reporting - unused. */ 02190 { 02191 TcpState *statePtr = (TcpState *) instanceData; 02192 int errorCode = 0; 02193 02194 /* 02195 * Delete a file handler that may be active for this socket if this is a 02196 * server socket - the file handler was created automatically by Tcl as 02197 * part of the mechanism to accept new client connections. Channel 02198 * handlers are already deleted in the generic IO channel closing code 02199 * that called this function, so we do not have to delete them here. 02200 */ 02201 02202 Tcl_DeleteFileHandler(statePtr->fd); 02203 02204 if (close(statePtr->fd) < 0) { 02205 errorCode = errno; 02206 } 02207 ckfree((char *) statePtr); 02208 02209 return errorCode; 02210 } 02211 02212 /* 02213 *---------------------------------------------------------------------- 02214 * 02215 * TcpGetOptionProc -- 02216 * 02217 * Computes an option value for a TCP socket based channel, or a list of 02218 * all options and their values. 02219 * 02220 * Note: This code is based on code contributed by John Haxby. 02221 * 02222 * Results: 02223 * A standard Tcl result. The value of the specified option or a list of 02224 * all options and their values is returned in the supplied DString. Sets 02225 * Error message if needed. 02226 * 02227 * Side effects: 02228 * None. 02229 * 02230 *---------------------------------------------------------------------- 02231 */ 02232 02233 static int 02234 TcpGetOptionProc( 02235 ClientData instanceData, /* Socket state. */ 02236 Tcl_Interp *interp, /* For error reporting - can be NULL. */ 02237 const char *optionName, /* Name of the option to retrieve the value 02238 * for, or NULL to get all options and their 02239 * values. */ 02240 Tcl_DString *dsPtr) /* Where to store the computed value; 02241 * initialized by caller. */ 02242 { 02243 TcpState *statePtr = (TcpState *) instanceData; 02244 struct sockaddr_in sockname; 02245 struct sockaddr_in peername; 02246 struct hostent *hostEntPtr; 02247 socklen_t size = sizeof(struct sockaddr_in); 02248 size_t len = 0; 02249 char buf[TCL_INTEGER_SPACE]; 02250 02251 if (optionName != NULL) { 02252 len = strlen(optionName); 02253 } 02254 02255 if ((len > 1) && (optionName[1] == 'e') && 02256 (strncmp(optionName, "-error", len) == 0)) { 02257 socklen_t optlen = sizeof(int); 02258 int err, ret; 02259 02260 ret = getsockopt(statePtr->fd, SOL_SOCKET, SO_ERROR, 02261 (char *)&err, &optlen); 02262 if (ret < 0) { 02263 err = errno; 02264 } 02265 if (err != 0) { 02266 Tcl_DStringAppend(dsPtr, Tcl_ErrnoMsg(err), -1); 02267 } 02268 return TCL_OK; 02269 } 02270 02271 if ((len == 0) || 02272 ((len > 1) && (optionName[1] == 'p') && 02273 (strncmp(optionName, "-peername", len) == 0))) { 02274 if (getpeername(statePtr->fd, (struct sockaddr *) &peername, 02275 &size) >= 0) { 02276 if (len == 0) { 02277 Tcl_DStringAppendElement(dsPtr, "-peername"); 02278 Tcl_DStringStartSublist(dsPtr); 02279 } 02280 Tcl_DStringAppendElement(dsPtr, inet_ntoa(peername.sin_addr)); 02281 hostEntPtr = TclpGetHostByAddr( /* INTL: Native. */ 02282 (char *) &peername.sin_addr, 02283 sizeof(peername.sin_addr), AF_INET); 02284 if (hostEntPtr != NULL) { 02285 Tcl_DString ds; 02286 02287 Tcl_ExternalToUtfDString(NULL, hostEntPtr->h_name, -1, &ds); 02288 Tcl_DStringAppendElement(dsPtr, Tcl_DStringValue(&ds)); 02289 Tcl_DStringFree(&ds); 02290 } else { 02291 Tcl_DStringAppendElement(dsPtr, inet_ntoa(peername.sin_addr)); 02292 } 02293 TclFormatInt(buf, ntohs(peername.sin_port)); 02294 Tcl_DStringAppendElement(dsPtr, buf); 02295 if (len == 0) { 02296 Tcl_DStringEndSublist(dsPtr); 02297 } else { 02298 return TCL_OK; 02299 } 02300 } else { 02301 /* 02302 * getpeername failed - but if we were asked for all the options 02303 * (len==0), don't flag an error at that point because it could be 02304 * an fconfigure request on a server socket (which have no peer). 02305 * Same must be done on win&mac. 02306 */ 02307 02308 if (len) { 02309 if (interp) { 02310 Tcl_AppendResult(interp, "can't get peername: ", 02311 Tcl_PosixError(interp), NULL); 02312 } 02313 return TCL_ERROR; 02314 } 02315 } 02316 } 02317 02318 if ((len == 0) || 02319 ((len > 1) && (optionName[1] == 's') && 02320 (strncmp(optionName, "-sockname", len) == 0))) { 02321 if (getsockname(statePtr->fd, (struct sockaddr *) &sockname, 02322 &size) >= 0) { 02323 if (len == 0) { 02324 Tcl_DStringAppendElement(dsPtr, "-sockname"); 02325 Tcl_DStringStartSublist(dsPtr); 02326 } 02327 Tcl_DStringAppendElement(dsPtr, inet_ntoa(sockname.sin_addr)); 02328 hostEntPtr = TclpGetHostByAddr( /* INTL: Native. */ 02329 (char *) &sockname.sin_addr, 02330 sizeof(sockname.sin_addr), AF_INET); 02331 if (hostEntPtr != NULL) { 02332 Tcl_DString ds; 02333 02334 Tcl_ExternalToUtfDString(NULL, hostEntPtr->h_name, -1, &ds); 02335 Tcl_DStringAppendElement(dsPtr, Tcl_DStringValue(&ds)); 02336 Tcl_DStringFree(&ds); 02337 } else { 02338 Tcl_DStringAppendElement(dsPtr, inet_ntoa(sockname.sin_addr)); 02339 } 02340 TclFormatInt(buf, ntohs(sockname.sin_port)); 02341 Tcl_DStringAppendElement(dsPtr, buf); 02342 if (len == 0) { 02343 Tcl_DStringEndSublist(dsPtr); 02344 } else { 02345 return TCL_OK; 02346 } 02347 } else { 02348 if (interp) { 02349 Tcl_AppendResult(interp, "can't get sockname: ", 02350 Tcl_PosixError(interp), NULL); 02351 } 02352 return TCL_ERROR; 02353 } 02354 } 02355 02356 if (len > 0) { 02357 return Tcl_BadChannelOption(interp, optionName, "peername sockname"); 02358 } 02359 02360 return TCL_OK; 02361 } 02362 02363 /* 02364 *---------------------------------------------------------------------- 02365 * 02366 * TcpWatchProc -- 02367 * 02368 * Initialize the notifier to watch the fd from this channel. 02369 * 02370 * Results: 02371 * None. 02372 * 02373 * Side effects: 02374 * Sets up the notifier so that a future event on the channel will be 02375 * seen by Tcl. 02376 * 02377 *---------------------------------------------------------------------- 02378 */ 02379 02380 static void 02381 TcpWatchProc( 02382 ClientData instanceData, /* The socket state. */ 02383 int mask) /* Events of interest; an OR-ed combination of 02384 * TCL_READABLE, TCL_WRITABLE and 02385 * TCL_EXCEPTION. */ 02386 { 02387 TcpState *statePtr = (TcpState *) instanceData; 02388 02389 /* 02390 * Make sure we don't mess with server sockets since they will never be 02391 * readable or writable at the Tcl level. This keeps Tcl scripts from 02392 * interfering with the -accept behavior. 02393 */ 02394 02395 if (!statePtr->acceptProc) { 02396 if (mask) { 02397 Tcl_CreateFileHandler(statePtr->fd, mask, 02398 (Tcl_FileProc *) Tcl_NotifyChannel, 02399 (ClientData) statePtr->channel); 02400 } else { 02401 Tcl_DeleteFileHandler(statePtr->fd); 02402 } 02403 } 02404 } 02405 02406 /* 02407 *---------------------------------------------------------------------- 02408 * 02409 * TcpGetHandleProc -- 02410 * 02411 * Called from Tcl_GetChannelHandle to retrieve OS handles from inside a 02412 * TCP socket based channel. 02413 * 02414 * Results: 02415 * Returns TCL_OK with the fd in handlePtr, or TCL_ERROR if there is no 02416 * handle for the specified direction. 02417 * 02418 * Side effects: 02419 * None. 02420 * 02421 *---------------------------------------------------------------------- 02422 */ 02423 02424 /* ARGSUSED */ 02425 static int 02426 TcpGetHandleProc( 02427 ClientData instanceData, /* The socket state. */ 02428 int direction, /* Not used. */ 02429 ClientData *handlePtr) /* Where to store the handle. */ 02430 { 02431 TcpState *statePtr = (TcpState *) instanceData; 02432 02433 *handlePtr = (ClientData) INT2PTR(statePtr->fd); 02434 return TCL_OK; 02435 } 02436 02437 /* 02438 *---------------------------------------------------------------------- 02439 * 02440 * CreateSocket -- 02441 * 02442 * This function opens a new socket in client or server mode and 02443 * initializes the TcpState structure. 02444 * 02445 * Results: 02446 * Returns a new TcpState, or NULL with an error in the interp's result, 02447 * if interp is not NULL. 02448 * 02449 * Side effects: 02450 * Opens a socket. 02451 * 02452 *---------------------------------------------------------------------- 02453 */ 02454 02455 static TcpState * 02456 CreateSocket( 02457 Tcl_Interp *interp, /* For error reporting; can be NULL. */ 02458 int port, /* Port number to open. */ 02459 const char *host, /* Name of host on which to open port. NULL 02460 * implies INADDR_ANY */ 02461 int server, /* 1 if socket should be a server socket, else 02462 * 0 for a client socket. */ 02463 const char *myaddr, /* Optional client-side address */ 02464 int myport, /* Optional client-side port */ 02465 int async) /* If nonzero and creating a client socket, 02466 * attempt to do an async connect. Otherwise 02467 * do a synchronous connect or bind. */ 02468 { 02469 int status, sock, asyncConnect, curState, origState; 02470 struct sockaddr_in sockaddr; /* socket address */ 02471 struct sockaddr_in mysockaddr; /* Socket address for client */ 02472 TcpState *statePtr; 02473 const char *errorMsg = NULL; 02474 02475 sock = -1; 02476 origState = 0; 02477 if (!CreateSocketAddress(&sockaddr, host, port, 0, &errorMsg)) { 02478 goto addressError; 02479 } 02480 if ((myaddr != NULL || myport != 0) && 02481 !CreateSocketAddress(&mysockaddr, myaddr, myport, 1, &errorMsg)) { 02482 goto addressError; 02483 } 02484 02485 sock = socket(AF_INET, SOCK_STREAM, 0); 02486 if (sock < 0) { 02487 goto addressError; 02488 } 02489 02490 /* 02491 * Set the close-on-exec flag so that the socket will not get inherited by 02492 * child processes. 02493 */ 02494 02495 fcntl(sock, F_SETFD, FD_CLOEXEC); 02496 02497 /* 02498 * Set kernel space buffering 02499 */ 02500 02501 TclSockMinimumBuffers(sock, SOCKET_BUFSIZE); 02502 02503 asyncConnect = 0; 02504 status = 0; 02505 if (server) { 02506 /* 02507 * Set up to reuse server addresses automatically and bind to the 02508 * specified port. 02509 */ 02510 02511 status = 1; 02512 (void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &status, 02513 sizeof(status)); 02514 status = bind(sock, (struct sockaddr *) &sockaddr, 02515 sizeof(struct sockaddr)); 02516 if (status != -1) { 02517 status = listen(sock, SOMAXCONN); 02518 } 02519 } else { 02520 if (myaddr != NULL || myport != 0) { 02521 curState = 1; 02522 (void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, 02523 (char *) &curState, sizeof(curState)); 02524 status = bind(sock, (struct sockaddr *) &mysockaddr, 02525 sizeof(struct sockaddr)); 02526 if (status < 0) { 02527 goto bindError; 02528 } 02529 } 02530 02531 /* 02532 * Attempt to connect. The connect may fail at present with an 02533 * EINPROGRESS but at a later time it will complete. The caller will 02534 * set up a file handler on the socket if she is interested in being 02535 * informed when the connect completes. 02536 */ 02537 02538 if (async) { 02539 #ifndef USE_FIONBIO 02540 curState = fcntl(sock, F_GETFL); 02541 SET_BITS(curState, O_NONBLOCK); 02542 status = fcntl(sock, F_SETFL, curState); 02543 #else /* USE_FIONBIO */ 02544 curState = 1; 02545 status = ioctl(sock, FIONBIO, &curState); 02546 #endif /* !USE_FIONBIO */ 02547 } else { 02548 status = 0; 02549 } 02550 if (status > -1) { 02551 status = connect(sock, (struct sockaddr *) &sockaddr, 02552 sizeof(sockaddr)); 02553 if (status < 0) { 02554 if (errno == EINPROGRESS) { 02555 asyncConnect = 1; 02556 status = 0; 02557 } 02558 } else { 02559 /* 02560 * Here we are if the connect succeeds. In case of an 02561 * asynchronous connect we have to reset the channel to 02562 * blocking mode. This appears to happen not very often, but 02563 * e.g. on a HP 9000/800 under HP-UX B.11.00 we enter this 02564 * stage. [Bug: 4388] 02565 */ 02566 02567 if (async) { 02568 #ifndef USE_FIONBIO 02569 curState = fcntl(sock, F_GETFL); 02570 CLEAR_BITS(curState, O_NONBLOCK); 02571 status = fcntl(sock, F_SETFL, curState); 02572 #else /* USE_FIONBIO */ 02573 curState = 0; 02574 status = ioctl(sock, FIONBIO, &curState); 02575 #endif /* !USE_FIONBIO */ 02576 } 02577 } 02578 } 02579 } 02580 02581 bindError: 02582 if (status < 0) { 02583 if (interp != NULL) { 02584 Tcl_AppendResult(interp, "couldn't open socket: ", 02585 Tcl_PosixError(interp), NULL); 02586 } 02587 if (sock != -1) { 02588 close(sock); 02589 } 02590 return NULL; 02591 } 02592 02593 /* 02594 * Allocate a new TcpState for this socket. 02595 */ 02596 02597 statePtr = (TcpState *) ckalloc((unsigned) sizeof(TcpState)); 02598 statePtr->flags = 0; 02599 if (asyncConnect) { 02600 statePtr->flags = TCP_ASYNC_CONNECT; 02601 } 02602 statePtr->fd = sock; 02603 02604 return statePtr; 02605 02606 addressError: 02607 if (sock != -1) { 02608 close(sock); 02609 } 02610 if (interp != NULL) { 02611 Tcl_AppendResult(interp, "couldn't open socket: ", 02612 Tcl_PosixError(interp), NULL); 02613 if (errorMsg != NULL) { 02614 Tcl_AppendResult(interp, " (", errorMsg, ")", NULL); 02615 } 02616 } 02617 return NULL; 02618 } 02619 02620 /* 02621 *---------------------------------------------------------------------- 02622 * 02623 * CreateSocketAddress -- 02624 * 02625 * This function initializes a sockaddr structure for a host and port. 02626 * 02627 * Results: 02628 * 1 if the host was valid, 0 if the host could not be converted to an IP 02629 * address. 02630 * 02631 * Side effects: 02632 * Fills in the *sockaddrPtr structure. 02633 * 02634 *---------------------------------------------------------------------- 02635 */ 02636 02637 static int 02638 CreateSocketAddress( 02639 struct sockaddr_in *sockaddrPtr, /* Socket address */ 02640 const char *host, /* Host. NULL implies INADDR_ANY */ 02641 int port, /* Port number */ 02642 int willBind, /* Is this an address to bind() to or 02643 * to connect() to? */ 02644 const char **errorMsgPtr) /* Place to store the error message 02645 * detail, if available. */ 02646 { 02647 #ifdef HAVE_GETADDRINFO 02648 struct addrinfo hints, *resPtr = NULL; 02649 char *native; 02650 Tcl_DString ds; 02651 int result; 02652 02653 if (host == NULL) { 02654 sockaddrPtr->sin_family = AF_INET; 02655 sockaddrPtr->sin_addr.s_addr = INADDR_ANY; 02656 addPort: 02657 sockaddrPtr->sin_port = htons((unsigned short) (port & 0xFFFF)); 02658 return 1; 02659 } 02660 02661 (void) memset(&hints, 0, sizeof(struct addrinfo)); 02662 hints.ai_family = AF_INET; 02663 hints.ai_socktype = SOCK_STREAM; 02664 if (willBind) { 02665 hints.ai_flags |= AI_PASSIVE; 02666 } 02667 02668 /* 02669 * Note that getaddrinfo() *is* thread-safe. If a platform doesn't get 02670 * that right, it shouldn't use this part of the code. 02671 */ 02672 02673 native = Tcl_UtfToExternalDString(NULL, host, -1, &ds); 02674 result = getaddrinfo(native, NULL, &hints, &resPtr); 02675 Tcl_DStringFree(&ds); 02676 if (result == 0) { 02677 memcpy(sockaddrPtr, resPtr->ai_addr, sizeof(struct sockaddr_in)); 02678 freeaddrinfo(resPtr); 02679 goto addPort; 02680 } 02681 02682 /* 02683 * Ought to use gai_strerror() here... 02684 */ 02685 02686 switch (result) { 02687 case EAI_NONAME: 02688 case EAI_SERVICE: 02689 #if defined(EAI_ADDRFAMILY) && EAI_ADDRFAMILY != EAI_NONAME 02690 case EAI_ADDRFAMILY: 02691 #endif 02692 #if defined(EAI_NODATA) && EAI_NODATA != EAI_NONAME 02693 case EAI_NODATA: 02694 #endif 02695 *errorMsgPtr = gai_strerror(result); 02696 errno = EHOSTUNREACH; 02697 return 0; 02698 case EAI_SYSTEM: 02699 return 0; 02700 default: 02701 *errorMsgPtr = gai_strerror(result); 02702 errno = ENXIO; 02703 return 0; 02704 } 02705 #else /* !HAVE_GETADDRINFO */ 02706 struct in_addr addr; /* For 64/32 bit madness */ 02707 02708 (void) memset(sockaddrPtr, '\0', sizeof(struct sockaddr_in)); 02709 sockaddrPtr->sin_family = AF_INET; 02710 sockaddrPtr->sin_port = htons((unsigned short) (port & 0xFFFF)); 02711 if (host == NULL) { 02712 addr.s_addr = INADDR_ANY; 02713 } else { 02714 struct hostent *hostent; /* Host database entry */ 02715 Tcl_DString ds; 02716 const char *native; 02717 02718 if (host == NULL) { 02719 native = NULL; 02720 } else { 02721 native = Tcl_UtfToExternalDString(NULL, host, -1, &ds); 02722 } 02723 addr.s_addr = inet_addr(native); /* INTL: Native. */ 02724 02725 /* 02726 * This is 0xFFFFFFFF to ensure that it compares as a 32bit -1 on 02727 * either 32 or 64 bits systems. 02728 */ 02729 02730 if (addr.s_addr == 0xFFFFFFFF) { 02731 hostent = TclpGetHostByName(native); /* INTL: Native. */ 02732 if (hostent != NULL) { 02733 memcpy(&addr, hostent->h_addr_list[0], 02734 (size_t) hostent->h_length); 02735 } else { 02736 #ifdef EHOSTUNREACH 02737 errno = EHOSTUNREACH; 02738 #else /* !EHOSTUNREACH */ 02739 #ifdef ENXIO 02740 errno = ENXIO; 02741 #endif /* ENXIO */ 02742 #endif /* EHOSTUNREACH */ 02743 if (native != NULL) { 02744 Tcl_DStringFree(&ds); 02745 } 02746 return 0; /* Error. */ 02747 } 02748 } 02749 if (native != NULL) { 02750 Tcl_DStringFree(&ds); 02751 } 02752 } 02753 02754 /* 02755 * NOTE: On 64 bit machines the assignment below is rumored to not do the 02756 * right thing. Please report errors related to this if you observe 02757 * incorrect behavior on 64 bit machines such as DEC Alphas. Should we 02758 * modify this code to do an explicit memcpy? 02759 */ 02760 02761 sockaddrPtr->sin_addr.s_addr = addr.s_addr; 02762 return 1; /* Success. */ 02763 #endif /* HAVE_GETADDRINFO */ 02764 } 02765 02766 /* 02767 *---------------------------------------------------------------------- 02768 * 02769 * Tcl_OpenTcpClient -- 02770 * 02771 * Opens a TCP client socket and creates a channel around it. 02772 * 02773 * Results: 02774 * The channel or NULL if failed. An error message is returned in the 02775 * interpreter on failure. 02776 * 02777 * Side effects: 02778 * Opens a client socket and creates a new channel. 02779 * 02780 *---------------------------------------------------------------------- 02781 */ 02782 02783 Tcl_Channel 02784 Tcl_OpenTcpClient( 02785 Tcl_Interp *interp, /* For error reporting; can be NULL. */ 02786 int port, /* Port number to open. */ 02787 const char *host, /* Host on which to open port. */ 02788 const char *myaddr, /* Client-side address */ 02789 int myport, /* Client-side port */ 02790 int async) /* If nonzero, attempt to do an asynchronous 02791 * connect. Otherwise we do a blocking 02792 * connect. */ 02793 { 02794 TcpState *statePtr; 02795 char channelName[16 + TCL_INTEGER_SPACE]; 02796 02797 /* 02798 * Create a new client socket and wrap it in a channel. 02799 */ 02800 02801 statePtr = CreateSocket(interp, port, host, 0, myaddr, myport, async); 02802 if (statePtr == NULL) { 02803 return NULL; 02804 } 02805 02806 statePtr->acceptProc = NULL; 02807 statePtr->acceptProcData = NULL; 02808 02809 sprintf(channelName, "sock%d", statePtr->fd); 02810 02811 statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, 02812 (ClientData) statePtr, (TCL_READABLE | TCL_WRITABLE)); 02813 if (Tcl_SetChannelOption(interp, statePtr->channel, "-translation", 02814 "auto crlf") == TCL_ERROR) { 02815 Tcl_Close(NULL, statePtr->channel); 02816 return NULL; 02817 } 02818 return statePtr->channel; 02819 } 02820 02821 /* 02822 *---------------------------------------------------------------------- 02823 * 02824 * Tcl_MakeTcpClientChannel -- 02825 * 02826 * Creates a Tcl_Channel from an existing client TCP socket. 02827 * 02828 * Results: 02829 * The Tcl_Channel wrapped around the preexisting TCP socket. 02830 * 02831 * Side effects: 02832 * None. 02833 * 02834 *---------------------------------------------------------------------- 02835 */ 02836 02837 Tcl_Channel 02838 Tcl_MakeTcpClientChannel( 02839 ClientData sock) /* The socket to wrap up into a channel. */ 02840 { 02841 return MakeTcpClientChannelMode(sock, (TCL_READABLE | TCL_WRITABLE)); 02842 } 02843 02844 /* 02845 *---------------------------------------------------------------------- 02846 * 02847 * MakeTcpClientChannelMode -- 02848 * 02849 * Creates a Tcl_Channel from an existing client TCP socket 02850 * with given mode. 02851 * 02852 * Results: 02853 * The Tcl_Channel wrapped around the preexisting TCP socket. 02854 * 02855 * Side effects: 02856 * None. 02857 * 02858 *---------------------------------------------------------------------- 02859 */ 02860 02861 static Tcl_Channel 02862 MakeTcpClientChannelMode( 02863 ClientData sock, /* The socket to wrap up into a channel. */ 02864 int mode) /* ORed combination of TCL_READABLE and 02865 * TCL_WRITABLE to indicate file mode. */ 02866 { 02867 TcpState *statePtr; 02868 char channelName[16 + TCL_INTEGER_SPACE]; 02869 02870 statePtr = (TcpState *) ckalloc((unsigned) sizeof(TcpState)); 02871 statePtr->fd = PTR2INT(sock); 02872 statePtr->flags = 0; 02873 statePtr->acceptProc = NULL; 02874 statePtr->acceptProcData = NULL; 02875 02876 sprintf(channelName, "sock%d", statePtr->fd); 02877 02878 statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, 02879 (ClientData) statePtr, mode); 02880 if (Tcl_SetChannelOption(NULL, statePtr->channel, "-translation", 02881 "auto crlf") == TCL_ERROR) { 02882 Tcl_Close(NULL, statePtr->channel); 02883 return NULL; 02884 } 02885 return statePtr->channel; 02886 } 02887 02888 /* 02889 *---------------------------------------------------------------------- 02890 * 02891 * Tcl_OpenTcpServer -- 02892 * 02893 * Opens a TCP server socket and creates a channel around it. 02894 * 02895 * Results: 02896 * The channel or NULL if failed. If an error occurred, an error message 02897 * is left in the interp's result if interp is not NULL. 02898 * 02899 * Side effects: 02900 * Opens a server socket and creates a new channel. 02901 * 02902 *---------------------------------------------------------------------- 02903 */ 02904 02905 Tcl_Channel 02906 Tcl_OpenTcpServer( 02907 Tcl_Interp *interp, /* For error reporting - may be NULL. */ 02908 int port, /* Port number to open. */ 02909 const char *myHost, /* Name of local host. */ 02910 Tcl_TcpAcceptProc *acceptProc, 02911 /* Callback for accepting connections from new 02912 * clients. */ 02913 ClientData acceptProcData) /* Data for the callback. */ 02914 { 02915 TcpState *statePtr; 02916 char channelName[16 + TCL_INTEGER_SPACE]; 02917 02918 /* 02919 * Create a new client socket and wrap it in a channel. 02920 */ 02921 02922 statePtr = CreateSocket(interp, port, myHost, 1, NULL, 0, 0); 02923 if (statePtr == NULL) { 02924 return NULL; 02925 } 02926 02927 statePtr->acceptProc = acceptProc; 02928 statePtr->acceptProcData = acceptProcData; 02929 02930 /* 02931 * Set up the callback mechanism for accepting connections from new 02932 * clients. 02933 */ 02934 02935 Tcl_CreateFileHandler(statePtr->fd, TCL_READABLE, TcpAccept, 02936 (ClientData) statePtr); 02937 sprintf(channelName, "sock%d", statePtr->fd); 02938 statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, 02939 (ClientData) statePtr, 0); 02940 return statePtr->channel; 02941 } 02942 02943 /* 02944 *---------------------------------------------------------------------- 02945 * 02946 * TcpAccept -- 02947 * Accept a TCP socket connection. This is called by the event loop. 02948 * 02949 * Results: 02950 * None. 02951 * 02952 * Side effects: 02953 * Creates a new connection socket. Calls the registered callback for the 02954 * connection acceptance mechanism. 02955 * 02956 *---------------------------------------------------------------------- 02957 */ 02958 02959 /* ARGSUSED */ 02960 static void 02961 TcpAccept( 02962 ClientData data, /* Callback token. */ 02963 int mask) /* Not used. */ 02964 { 02965 TcpState *sockState; /* Client data of server socket. */ 02966 int newsock; /* The new client socket */ 02967 TcpState *newSockState; /* State for new socket. */ 02968 struct sockaddr_in addr; /* The remote address */ 02969 socklen_t len; /* For accept interface */ 02970 char channelName[16 + TCL_INTEGER_SPACE]; 02971 02972 sockState = (TcpState *) data; 02973 02974 len = sizeof(struct sockaddr_in); 02975 newsock = accept(sockState->fd, (struct sockaddr *) &addr, &len); 02976 if (newsock < 0) { 02977 return; 02978 } 02979 02980 /* 02981 * Set close-on-exec flag to prevent the newly accepted socket from being 02982 * inherited by child processes. 02983 */ 02984 02985 (void) fcntl(newsock, F_SETFD, FD_CLOEXEC); 02986 02987 newSockState = (TcpState *) ckalloc((unsigned) sizeof(TcpState)); 02988 02989 newSockState->flags = 0; 02990 newSockState->fd = newsock; 02991 newSockState->acceptProc = NULL; 02992 newSockState->acceptProcData = NULL; 02993 02994 sprintf(channelName, "sock%d", newsock); 02995 newSockState->channel = Tcl_CreateChannel(&tcpChannelType, channelName, 02996 (ClientData) newSockState, (TCL_READABLE | TCL_WRITABLE)); 02997 02998 Tcl_SetChannelOption(NULL, newSockState->channel, "-translation", 02999 "auto crlf"); 03000 03001 if (sockState->acceptProc != NULL) { 03002 (*sockState->acceptProc)(sockState->acceptProcData, 03003 newSockState->channel, inet_ntoa(addr.sin_addr), 03004 ntohs(addr.sin_port)); 03005 } 03006 } 03007 03008 /* 03009 *---------------------------------------------------------------------- 03010 * 03011 * TclpGetDefaultStdChannel -- 03012 * 03013 * Creates channels for standard input, standard output or standard error 03014 * output if they do not already exist. 03015 * 03016 * Results: 03017 * Returns the specified default standard channel, or NULL. 03018 * 03019 * Side effects: 03020 * May cause the creation of a standard channel and the underlying file. 03021 * 03022 *---------------------------------------------------------------------- 03023 */ 03024 03025 Tcl_Channel 03026 TclpGetDefaultStdChannel( 03027 int type) /* One of TCL_STDIN, TCL_STDOUT, TCL_STDERR. */ 03028 { 03029 Tcl_Channel channel = NULL; 03030 int fd = 0; /* Initializations needed to prevent */ 03031 int mode = 0; /* compiler warning (used before set). */ 03032 char *bufMode = NULL; 03033 03034 /* 03035 * Some #def's to make the code a little clearer! 03036 */ 03037 03038 #define ZERO_OFFSET ((Tcl_SeekOffset) 0) 03039 #define ERROR_OFFSET ((Tcl_SeekOffset) -1) 03040 03041 switch (type) { 03042 case TCL_STDIN: 03043 if ((TclOSseek(0, ZERO_OFFSET, SEEK_CUR) == ERROR_OFFSET) 03044 && (errno == EBADF)) { 03045 return NULL; 03046 } 03047 fd = 0; 03048 mode = TCL_READABLE; 03049 bufMode = "line"; 03050 break; 03051 case TCL_STDOUT: 03052 if ((TclOSseek(1, ZERO_OFFSET, SEEK_CUR) == ERROR_OFFSET) 03053 && (errno == EBADF)) { 03054 return NULL; 03055 } 03056 fd = 1; 03057 mode = TCL_WRITABLE; 03058 bufMode = "line"; 03059 break; 03060 case TCL_STDERR: 03061 if ((TclOSseek(2, ZERO_OFFSET, SEEK_CUR) == ERROR_OFFSET) 03062 && (errno == EBADF)) { 03063 return NULL; 03064 } 03065 fd = 2; 03066 mode = TCL_WRITABLE; 03067 bufMode = "none"; 03068 break; 03069 default: 03070 Tcl_Panic("TclGetDefaultStdChannel: Unexpected channel type"); 03071 break; 03072 } 03073 03074 #undef ZERO_OFFSET 03075 #undef ERROR_OFFSET 03076 03077 channel = Tcl_MakeFileChannel((ClientData) INT2PTR(fd), mode); 03078 if (channel == NULL) { 03079 return NULL; 03080 } 03081 03082 /* 03083 * Set up the normal channel options for stdio handles. 03084 */ 03085 03086 if (Tcl_GetChannelType(channel) == &fileChannelType) { 03087 Tcl_SetChannelOption(NULL, channel, "-translation", "auto"); 03088 } else { 03089 Tcl_SetChannelOption(NULL, channel, "-translation", "auto crlf"); 03090 } 03091 Tcl_SetChannelOption(NULL, channel, "-buffering", bufMode); 03092 return channel; 03093 } 03094 03095 /* 03096 *---------------------------------------------------------------------- 03097 * 03098 * Tcl_GetOpenFile -- 03099 * 03100 * Given a name of a channel registered in the given interpreter, returns 03101 * a FILE * for it. 03102 * 03103 * Results: 03104 * A standard Tcl result. If the channel is registered in the given 03105 * interpreter and it is managed by the "file" channel driver, and it is 03106 * open for the requested mode, then the output parameter filePtr is set 03107 * to a FILE * for the underlying file. On error, the filePtr is not set, 03108 * TCL_ERROR is returned and an error message is left in the interp's 03109 * result. 03110 * 03111 * Side effects: 03112 * May invoke fdopen to create the FILE * for the requested file. 03113 * 03114 *---------------------------------------------------------------------- 03115 */ 03116 03117 int 03118 Tcl_GetOpenFile( 03119 Tcl_Interp *interp, /* Interpreter in which to find file. */ 03120 const char *chanID, /* String that identifies file. */ 03121 int forWriting, /* 1 means the file is going to be used for 03122 * writing, 0 means for reading. */ 03123 int checkUsage, /* 1 means verify that the file was opened in 03124 * a mode that allows the access specified by 03125 * "forWriting". Ignored, we always check that 03126 * the channel is open for the requested 03127 * mode. */ 03128 ClientData *filePtr) /* Store pointer to FILE structure here. */ 03129 { 03130 Tcl_Channel chan; 03131 int chanMode, fd; 03132 const Tcl_ChannelType *chanTypePtr; 03133 ClientData data; 03134 FILE *f; 03135 03136 chan = Tcl_GetChannel(interp, chanID, &chanMode); 03137 if (chan == (Tcl_Channel) NULL) { 03138 return TCL_ERROR; 03139 } 03140 if ((forWriting) && ((chanMode & TCL_WRITABLE) == 0)) { 03141 Tcl_AppendResult(interp, "\"", chanID, "\" wasn't opened for writing", 03142 NULL); 03143 return TCL_ERROR; 03144 } else if ((!forWriting) && ((chanMode & TCL_READABLE) == 0)) { 03145 Tcl_AppendResult(interp, "\"", chanID, "\" wasn't opened for reading", 03146 NULL); 03147 return TCL_ERROR; 03148 } 03149 03150 /* 03151 * We allow creating a FILE * out of file based, pipe based and socket 03152 * based channels. We currently do not allow any other channel types, 03153 * because it is likely that stdio will not know what to do with them. 03154 */ 03155 03156 chanTypePtr = Tcl_GetChannelType(chan); 03157 if ((chanTypePtr == &fileChannelType) 03158 #ifdef SUPPORTS_TTY 03159 || (chanTypePtr == &ttyChannelType) 03160 #endif /* SUPPORTS_TTY */ 03161 || (chanTypePtr == &tcpChannelType) 03162 || (strcmp(chanTypePtr->typeName, "pipe") == 0)) { 03163 if (Tcl_GetChannelHandle(chan, 03164 (forWriting ? TCL_WRITABLE : TCL_READABLE), 03165 (ClientData*) &data) == TCL_OK) { 03166 fd = PTR2INT(data); 03167 03168 /* 03169 * The call to fdopen below is probably dangerous, since it will 03170 * truncate an existing file if the file is being opened for 03171 * writing.... 03172 */ 03173 03174 f = fdopen(fd, (forWriting ? "w" : "r")); 03175 if (f == NULL) { 03176 Tcl_AppendResult(interp, "cannot get a FILE * for \"", chanID, 03177 "\"", NULL); 03178 return TCL_ERROR; 03179 } 03180 *filePtr = (ClientData) f; 03181 return TCL_OK; 03182 } 03183 } 03184 03185 Tcl_AppendResult(interp, "\"", chanID, 03186 "\" cannot be used to get a FILE *", NULL); 03187 return TCL_ERROR; 03188 } 03189 03190 /* 03191 *---------------------------------------------------------------------- 03192 * 03193 * TclUnixWaitForFile -- 03194 * 03195 * This function waits synchronously for a file to become readable or 03196 * writable, with an optional timeout. 03197 * 03198 * Results: 03199 * The return value is an OR'ed combination of TCL_READABLE, 03200 * TCL_WRITABLE, and TCL_EXCEPTION, indicating the conditions that are 03201 * present on file at the time of the return. This function will not 03202 * return until either "timeout" milliseconds have elapsed or at least 03203 * one of the conditions given by mask has occurred for file (a return 03204 * value of 0 means that a timeout occurred). No normal events will be 03205 * serviced during the execution of this function. 03206 * 03207 * Side effects: 03208 * Time passes. 03209 * 03210 *---------------------------------------------------------------------- 03211 */ 03212 03213 int 03214 TclUnixWaitForFile( 03215 int fd, /* Handle for file on which to wait. */ 03216 int mask, /* What to wait for: OR'ed combination of 03217 * TCL_READABLE, TCL_WRITABLE, and 03218 * TCL_EXCEPTION. */ 03219 int timeout) /* Maximum amount of time to wait for one of 03220 * the conditions in mask to occur, in 03221 * milliseconds. A value of 0 means don't wait 03222 * at all, and a value of -1 means wait 03223 * forever. */ 03224 { 03225 Tcl_Time abortTime = {0, 0}, now; /* silence gcc 4 warning */ 03226 struct timeval blockTime, *timeoutPtr; 03227 int index, numFound, result = 0; 03228 fd_mask bit; 03229 fd_mask readyMasks[3*MASK_SIZE]; 03230 fd_mask *maskp[3]; /* This array reflects the readable/writable 03231 * conditions that were found to exist by the 03232 * last call to select. */ 03233 03234 /* 03235 * If there is a non-zero finite timeout, compute the time when we give 03236 * up. 03237 */ 03238 03239 if (timeout > 0) { 03240 Tcl_GetTime(&now); 03241 abortTime.sec = now.sec + timeout/1000; 03242 abortTime.usec = now.usec + (timeout%1000)*1000; 03243 if (abortTime.usec >= 1000000) { 03244 abortTime.usec -= 1000000; 03245 abortTime.sec += 1; 03246 } 03247 timeoutPtr = &blockTime; 03248 } else if (timeout == 0) { 03249 timeoutPtr = &blockTime; 03250 blockTime.tv_sec = 0; 03251 blockTime.tv_usec = 0; 03252 } else { 03253 timeoutPtr = NULL; 03254 } 03255 03256 /* 03257 * Initialize the ready masks and compute the mask offsets. 03258 */ 03259 03260 if (fd >= FD_SETSIZE) { 03261 Tcl_Panic("TclWaitForFile can't handle file id %d", fd); 03262 /* must never get here, or readyMasks overrun will occur below */ 03263 } 03264 memset(readyMasks, 0, 3*MASK_SIZE*sizeof(fd_mask)); 03265 index = fd / (NBBY*sizeof(fd_mask)); 03266 bit = ((fd_mask)1) << (fd % (NBBY*sizeof(fd_mask))); 03267 03268 /* 03269 * Loop in a mini-event loop of our own, waiting for either the file to 03270 * become ready or a timeout to occur. 03271 */ 03272 03273 while (1) { 03274 if (timeout > 0) { 03275 blockTime.tv_sec = abortTime.sec - now.sec; 03276 blockTime.tv_usec = abortTime.usec - now.usec; 03277 if (blockTime.tv_usec < 0) { 03278 blockTime.tv_sec -= 1; 03279 blockTime.tv_usec += 1000000; 03280 } 03281 if (blockTime.tv_sec < 0) { 03282 blockTime.tv_sec = 0; 03283 blockTime.tv_usec = 0; 03284 } 03285 } 03286 03287 /* 03288 * Set the appropriate bit in the ready masks for the fd. 03289 */ 03290 03291 if (mask & TCL_READABLE) { 03292 readyMasks[index] |= bit; 03293 } 03294 if (mask & TCL_WRITABLE) { 03295 (readyMasks+MASK_SIZE)[index] |= bit; 03296 } 03297 if (mask & TCL_EXCEPTION) { 03298 (readyMasks+2*(MASK_SIZE))[index] |= bit; 03299 } 03300 03301 /* 03302 * Wait for the event or a timeout. 03303 */ 03304 03305 /* 03306 * This is needed to satisfy GCC 3.3's strict aliasing rules. 03307 */ 03308 03309 maskp[0] = &readyMasks[0]; 03310 maskp[1] = &readyMasks[MASK_SIZE]; 03311 maskp[2] = &readyMasks[2*MASK_SIZE]; 03312 numFound = select(fd+1, (SELECT_MASK *) maskp[0], 03313 (SELECT_MASK *) maskp[1], 03314 (SELECT_MASK *) maskp[2], timeoutPtr); 03315 if (numFound == 1) { 03316 if (readyMasks[index] & bit) { 03317 SET_BITS(result, TCL_READABLE); 03318 } 03319 if ((readyMasks+MASK_SIZE)[index] & bit) { 03320 SET_BITS(result, TCL_WRITABLE); 03321 } 03322 if ((readyMasks+2*(MASK_SIZE))[index] & bit) { 03323 SET_BITS(result, TCL_EXCEPTION); 03324 } 03325 result &= mask; 03326 if (result) { 03327 break; 03328 } 03329 } 03330 if (timeout == 0) { 03331 break; 03332 } 03333 if (timeout < 0) { 03334 continue; 03335 } 03336 03337 /* 03338 * The select returned early, so we need to recompute the timeout. 03339 */ 03340 03341 Tcl_GetTime(&now); 03342 if ((abortTime.sec < now.sec) 03343 || (abortTime.sec==now.sec && abortTime.usec<=now.usec)) { 03344 break; 03345 } 03346 } 03347 return result; 03348 } 03349 03350 /* 03351 *---------------------------------------------------------------------- 03352 * 03353 * FileTruncateProc -- 03354 * 03355 * Truncates a file to a given length. 03356 * 03357 * Results: 03358 * 0 if the operation succeeded, and -1 if it failed (in which case 03359 * *errorCodePtr will be set to errno). 03360 * 03361 * Side effects: 03362 * The underlying file is potentially truncated. This can have a wide 03363 * variety of side effects, including moving file pointers that point at 03364 * places later in the file than the truncate point. 03365 * 03366 *---------------------------------------------------------------------- 03367 */ 03368 03369 static int 03370 FileTruncateProc( 03371 ClientData instanceData, 03372 Tcl_WideInt length) 03373 { 03374 FileState *fsPtr = (FileState *) instanceData; 03375 int result; 03376 03377 #ifdef HAVE_TYPE_OFF64_T 03378 /* 03379 * We assume this goes with the type for now... 03380 */ 03381 03382 result = ftruncate64(fsPtr->fd, (off64_t) length); 03383 #else 03384 result = ftruncate(fsPtr->fd, (off_t) length); 03385 #endif 03386 if (result) { 03387 return errno; 03388 } 03389 return 0; 03390 } 03391 03392 /* 03393 * Local Variables: 03394 * mode: c 03395 * c-basic-offset: 4 03396 * fill-column: 78 03397 * End: 03398 */
Generated on Wed Mar 12 12:18:26 2008 by 1.5.1 |