/* * io.c * * Copyright (C) 1994-1997, John Kilburg * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "port_before.h" #include #include #include #ifdef __QNX__ #include #include /* for O_NDELAY/O_NONBLOCK, gethostname() */ #define FNDELAY O_NDELAY #else #ifdef __EMX__ #define FNDELAY O_NDELAY #endif #include #endif #if (defined(SYSV) || defined(SVR4)) && (defined(sun) || defined(hpux) || defined(_nec_ews_svr4)) #include #endif #include #include #include #include #include #include #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #include #include "port_after.h" #include "ChimeraP.h" #include "ChimeraStream.h" union sockaddr_union { struct sockaddr sa; struct sockaddr_in sin; struct sockaddr_in6 sin6; } ; struct ChimeraStreamP { bool destroyed; MemPool mp; ChimeraResources cres; int s; int as; struct in6_addr addr; int port; bool bound; bool accepted; /* read callback */ ChimeraStreamCallback rdfunc; void *rdclosure; byte *rdb; size_t rdlen; XtInputId rdid; /* write callback */ ChimeraStreamCallback wrfunc; void *wrclosure; byte *wrb; size_t wrmax; size_t wri; XtInputId wrid; }; static void WriteStreamHandler _ArgProto((XtPointer, int *, XtInputId *)); static void ReadStreamHandler _ArgProto((XtPointer, int *, XtInputId *)); /* * WriteStreamHandler */ static void WriteStreamHandler(cldata, netfd, xid) XtPointer cldata; int *netfd; XtInputId *xid; { ChimeraStream ps = (ChimeraStream)cldata; ssize_t wlen; int s; if (ps->bound) s = ps->as; else s = ps->s; wlen = write(s, ps->wrb + ps->wri, ps->wrmax - ps->wri); if (wlen < 0) { if (errno != EWOULDBLOCK) { XtRemoveInput(ps->wrid); ps->wrid = 0; CMethod(ps->wrfunc)(ps, -1, ps->wrclosure); } } else { ps->wri += wlen; if (ps->wri == ps->wrmax) { XtRemoveInput(ps->wrid); ps->wrid = 0; CMethod(ps->wrfunc)(ps, 0, ps->wrclosure); } } return; } /* * ReadStreamHandler */ static void ReadStreamHandler(cldata, netfd, xid) XtPointer cldata; int *netfd; XtInputId *xid; { ChimeraStream ps = (ChimeraStream)cldata; ssize_t rlen; union sockaddr_union addr; int s; int namlen; if (ps->bound) { if (!ps->accepted) { namlen = sizeof(addr); if ((ps->as = accept(ps->s, &addr.sa, &namlen)) < 0) { XtRemoveInput(ps->rdid); ps->rdid = 0; CMethod(ps->rdfunc)(ps, -1, ps->rdclosure); } ps->accepted = true; } s = ps->as; } else s = ps->s; rlen = read(s, ps->rdb, ps->rdlen); if (rlen < 0) { if (errno != EWOULDBLOCK) { XtRemoveInput(ps->rdid); ps->rdid = 0; CMethod(ps->rdfunc)(ps, rlen, ps->rdclosure); } } else { XtRemoveInput(ps->rdid); ps->rdid = 0; CMethod(ps->rdfunc)(ps, rlen, ps->rdclosure); } return; } /* * StreamRead */ void StreamRead(ps, b, blen, func, closure) ChimeraStream ps; byte *b; size_t blen; ChimeraStreamCallback func; void *closure; { int s; myassert(!ps->destroyed, "ChimeraStream destroyed"); if (ps->bound && ps->accepted) s = ps->as; else s = ps->s; ps->rdb = b; ps->rdlen = blen; ps->rdfunc = func; ps->rdclosure = closure; ps->rdid = XtAppAddInput(ps->cres->appcon, s, (XtPointer)XtInputReadMask, ReadStreamHandler, (XtPointer)ps); return; } /* * StreamWrite */ void StreamWrite(ps, b, blen, func, closure) ChimeraStream ps; byte *b; size_t blen; ChimeraStreamCallback func; void *closure; { myassert(!ps->destroyed, "ChimeraStream destroyed."); ps->wrb = b; ps->wri = 0; ps->wrmax = blen; ps->wrfunc = func; ps->wrclosure = closure; ps->wrid = XtAppAddInput(ps->cres->appcon, ps->s, (XtPointer)XtInputWriteMask, WriteStreamHandler, (XtPointer)ps); return; } /* * StreamCreateINet */ ChimeraStream StreamCreateINet(cres, host, port) ChimeraResources cres; char *host; int port; { ChimeraStream ps; int s; int rval; union sockaddr_union addr; struct hostent *hp; MemPool mp; if (host == NULL) return(NULL); memset(&addr, 0, sizeof(addr)); if( inet_pton( AF_INET, host, &addr.sin.sin_addr ) ) { addr.sin.sin_family = AF_INET ; addr.sin.sin_port = htons( (unsigned short)port ) ; s = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ) ; if (s < 0) return(NULL); rval = connect(s, (struct sockaddr *)&addr, sizeof(addr) ) ; if( rval >= 0 || errno == EINPROGRESS ) goto Connected ; /* Eeurgh, a goto :) */ } // // IPv6 literal support commented out as it doesn't work because of : in URLs // // else if( inet_pton( AF_INET6, host, &addr.sin6.sin6_addr ) ) // { // addr.sin6.sin6_family = AF_INET6 ; // addr.sin6.sin6_port = htons( (unsigned short)port ) ; // s = socket( AF_INET6, SOCK_STREAM, IPPROTO_TCP ) ; // if (s < 0) return(NULL); // // rval = connect(s, (struct sockaddr *)&addr, sizeof(addr) ) ; // if( rval >= 0 || errno == EINPROGRESS ) // goto Connected ; /* Eeurgh, a goto :) */ // } else { if( ( hp = gethostbyname2( host, AF_INET6 ) ) != NULL ) { if( hp->h_addrtype == AF_INET6 ) { addr.sin6.sin6_family = AF_INET6 ; if( hp->h_length > (int) sizeof( addr.sin6.sin6_addr ) ) hp->h_length = sizeof( addr.sin6.sin6_addr ) ; addr.sin6.sin6_port = htons( (unsigned short)port ) ; s = socket( AF_INET6, SOCK_STREAM, IPPROTO_TCP ) ; if (s < 0) return(NULL); do { memcpy( &addr.sin6.sin6_addr, *(hp->h_addr_list++), hp->h_length ) ; rval = connect(s, (struct sockaddr *)&addr, sizeof(addr) ) ; if( rval >= 0 || errno == EINPROGRESS ) goto Connected ; /* Eeurgh, a goto :) */ } while( *(hp->h_addr_list) ) ; } } if( ( hp = gethostbyname2( host, AF_INET ) ) != NULL ) { if( hp->h_addrtype == AF_INET ) { addr.sin.sin_family = AF_INET ; if( hp->h_length > (int) sizeof( addr.sin.sin_addr ) ) hp->h_length = sizeof( addr.sin.sin_addr ) ; addr.sin.sin_port = htons( (unsigned short)port ) ; s = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ) ; if (s < 0) return(NULL); do { memcpy( &addr.sin.sin_addr, *(hp->h_addr_list++), hp->h_length ) ; rval = connect(s, (struct sockaddr *)&addr, sizeof(addr) ) ; if( rval >= 0 || errno == EINPROGRESS ) goto Connected ; /* Eeurgh, a goto :) */ } while( *(hp->h_addr_list) ) ; } } } /* Couldn't connect */ return NULL ; Connected: mp = MPCreate(); ps = (ChimeraStream)MPCGet(mp, sizeof(struct ChimeraStreamP)); ps->mp = mp; ps->cres = cres; ps->s = s; return((ChimeraStream)ps); } /* * StreamCreateINet2 */ ChimeraStream StreamCreateINet2(cres) ChimeraResources cres; { MemPool mp; ChimeraStream ps; int s; struct sockaddr_in6 addr; struct hostent *hp; int namlen; char host[BUFSIZ]; s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (s < 0) return(NULL); memcpy( (char *)&addr.sin6_addr, (char *)&in6addr_any, 16 ) ; addr.sin6_family = AF_INET6; addr.sin6_port = 0; if (bind(s, (struct sockaddr *) &addr, sizeof (addr)) < 0) { close(s); return(NULL); } if (listen(s, 1) < 0) { close(s); return(NULL); } namlen = sizeof(addr); if (getsockname(s, (struct sockaddr *)&addr, &namlen) < 0) { close(s); return(NULL); } #ifdef __QNX__ ioctl(s, FNDELAY, 0); #else fcntl(s, F_SETFL, FNDELAY); #endif mp = MPCreate(); ps = (ChimeraStream)MPCGet(mp, sizeof(struct ChimeraStreamP)); ps->mp = mp; ps->cres = cres; ps->s = s; ps->port = (int)addr.sin6_port; ps->addr = addr.sin6_addr; ps->bound = true; return((ChimeraStream)ps); } /* * StreamDestroy */ void StreamDestroy(ps) ChimeraStream ps; { myassert(!ps->destroyed, "ChimeraStream destroyed"); ps->destroyed = true; if (ps->rdid != 0) XtRemoveInput(ps->rdid); if (ps->wrid != 0) XtRemoveInput(ps->wrid); close(ps->s); MPDestroy(ps->mp); return; } /* * StreamGetINetPort */ int StreamGetINetPort(ps) ChimeraStream ps; { return(ps->port); } /* * StreamGetINetAddr */ struct in6_addr StreamGetINetAddr(ps) ChimeraStream ps; { return(ps->addr); } /* * StreamCreate */ ChimeraStream StreamCreate(cres, fd) ChimeraResources cres; int fd; { MemPool mp; ChimeraStream ps; fcntl(fd, F_SETFL, FNDELAY); mp = MPCreate(); ps = (ChimeraStream)MPCGet(mp, sizeof(struct ChimeraStreamP)); ps->mp = mp; ps->cres = cres; ps->s = fd; return((ChimeraStream)ps); }