#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* #include */ /* #include */ #include #include #include #define RETRIES 2 /* now that we have included everything under the Sun... */ /* and I won't mention Sun TLI problems here */ void nodelay(); /* hack routine to improve performance.. maybe */ void setnonblocking(); /* sets the given socket non-blocking */ void setblocking(); /* sets the given socket blocking again */ int setsendrecvbufs(); /* Sets send/recv buffer sizes */ int setportconn (s, port, range) /* returns final port value or error */ int *s; /* socket server uses.. this is created here */ int port; /* initial port we make service on. */ int range; /* range of ports */ { struct sockaddr_in sa; int ts; int i; int j; int rc; int p; p = port; ts = socket (AF_INET, SOCK_STREAM, 0); /* yuck */ #ifdef VERBOSE printf("Socket [%d]\n", ts); #endif /* VERBOSE */ sa.sin_family = AF_INET; sa.sin_addr.s_addr = INADDR_ANY; for(i=0; i<=range; i++) { sa.sin_port = htons (p); /* convert just to be safe */ #ifdef VERBOSE printf ("Port [%d] NB [0x%x]\n", p, sa.sin_port); #endif /* VERBOSE */ rc = ( bind(ts, (struct sockaddr *)&sa, sizeof (sa))); #ifdef VERBOSE printf ("Bind on socket [%d] port [%d] = [%d]\n", ts, p, rc); #endif /* VERBOSE */ if (rc) perror("Bind()"); if (!rc) /* i.e. a valid port was found */ { #ifdef VERBOSE printf("Attempting listen after bind on socket [%d]\n", ts); #endif /* VERBOSE */ rc = listen (ts, 25); /* handle 5 possible connection at once */ #ifdef VERBOSE printf("Listen on socket [%d] = [%d]\n", rc); #endif /* VERBOSE */ if (rc) perror ("Listen()"); if (rc) break; /* i.e. error */ /* else */ *s = ts; /* return socket value as well */ return (p); } /* if ((rc!=EADDRINUSE)&&(rc!=EADDRNOTAVAIL)&&(rc!=EACCES)) { */ /* for now we ignore this... yes we do */ /* } */ /* port was unavailable so */ p++; /* look at the next one */ } /* ok.. we didnot find one */ close (ts); *s = 0; /* return no socket */ return (rc); /* which is negative and the last bind return code */ } int allowconn (s, fe, spid) int s; /* socket we listen on */ int fe; /* Fork Enabled? 0=no 1=yes */ /* If enabled then forks new process on accept */ int *spid; /* new process id handling the returned socked */ /* used by multitasking servers */ { int s2; /* new socket */ int i; /* struct sockaddr *new_s_addr_ptr; */ struct sockaddr new_s_addr; int new_s_addr_len; new_s_addr_len = sizeof (new_s_addr); #ifdef VERBOSE printf("Allowing connections on socket [%d]\n", s); #endif /* VERBOSE */ /* s2 = accept (s, new_s_addr_ptr, &new_s_addr_len); */ /* make sure the socket is a blocking socket i.e. hasn't been probe'd */ setblocking (s); s2 = accept (s, &new_s_addr, &new_s_addr_len); if (s2<0) { printf("Accept on socket [%d] failed as [%d]\n", s, s2); perror ("Accept()"); close (s2); /* not that it was open in the first place */ return (s2); } #ifdef VERBOSE printf("Accepted connection on socket [%d] as new socket [%d]\n", s, s2); #endif /* VERBOSE */ nodelay(s2); return (s2); } /* Probe conn is a non blocking version of allowconn() */ int probeconn (s, fe, spid) int s; /* socket we listen on */ int fe; /* Fork Enabled? 0=no 1=yes */ /* If enabled then forks new process on accept */ int *spid; /* new process id handling the returned socked */ /* used by multitasking servers */ { int s2; /* new socket */ int i; /* struct sockaddr *new_s_addr_ptr; */ struct sockaddr new_s_addr; int new_s_addr_len; new_s_addr_len = sizeof (new_s_addr); #ifdef VERBOSE printf("Allowing connections on socket [%d]\n", s); #endif /* VERBOSE */ /* s2 = accept (s, new_s_addr_ptr, &new_s_addr_len); */ /* make the socket non blocking for the probe to work */ setnonblocking (s); s2 = accept (s, &new_s_addr, &new_s_addr_len); #ifdef VERBOSE printf("Accept returned [%d][0x%x]\n", s2, s2); #endif /* VERBOSE */ if (s2<0) { /* printf("Accept on socket [%d] failed as [%d]\n", s, s2); */ /* printf("Errno is %d\n", errno); */ /* printf("EWOULDBLOCK = %d\n", (int) EWOULDBLOCK); */ /* as this is non-blocking printing the below is wrong as its not an */ /* error, but an unavilable connection */ /* perror ("Accept()"); */ /* close (s2); */ /* not that it was open in the first place */ /* be nice and make the return value 0 ? */ /* s2 = 0; */ /* return (s2); */ return (0); } #ifdef VERBOSE printf("Accepted connection on socket [%d] as new socket [%d]\n", s, s2); #endif /* VERBOSE */ /* make the new socket blocking by default as it is currently non */ setblocking (s2); /* set tcpnodelay as well */ nodelay(s2); return (s2); } int getconn (host, port, search) char *host; /* full name of host running service */ int *port; /* port where service is running */ /* note this is also a return value */ int search; /* range allowed for port search */ { struct sockaddr_in sa_in; char target_addr[MAXHOSTNAMELEN+20]; int target_port; int init_comm_port; struct hostent *hp; u_long target_s_addr; int ts; int rc; int i; target_port = *port; /* get start point */ hp = gethostbyname (host); bcopy(hp->h_addr, (char *)&target_s_addr, hp->h_length); sa_in.sin_family = AF_INET; sa_in.sin_addr.s_addr = target_s_addr; while (search>=0) { ts = socket (AF_INET, SOCK_STREAM, 0); /* yuck */ /* try a new socket each time? */ sa_in.sin_port = htons (target_port); /* convert just to be safe */ /* hope I can keep reusing this struct */ rc = connect (ts, (struct sockaddr *) &sa_in, sizeof(sa_in)); if (!rc) { /* success */ *port = target_port; /* tell them the port used */ i = fcntl (ts, F_GETFL, 0); #ifdef VERBOSE printf("FL on [%d] = %d\n", ts, i); #endif /* VERBOSE */ nodelay(ts); return (ts); /* give them the socket */ } else { /* failure */ perror ("Connect()"); target_port++; /* look at the next port */ search--; /* one less attempt left */ /* I belive ts is now defunted.. so I close it?? */ close (ts); } } /* while */ /* well we are here so fidles.. */ return (rc); } int getconn_addr (addr, port, search) unsigned long addr; /* sa_addr of host running service */ int *port; /* port where service is running */ /* note this is also a return value */ int search; /* range allowed for port search */ { struct sockaddr_in sa_in; char target_addr[MAXHOSTNAMELEN+20]; int target_port; int init_comm_port; struct hostent *hp; u_long target_s_addr; int ts; int rc; int i; target_port = *port; /* get start point */ /* hp = gethostbyname (host); */ /* bcopy(hp->h_addr, (char *)&target_s_addr, hp->h_length); */ sa_in.sin_family = AF_INET; /* sa_in.sin_addr.s_addr = target_s_addr; */ sa_in.sin_addr.s_addr = addr; while (search>=0) { ts = socket (AF_INET, SOCK_STREAM, 0); /* yuck */ /* try a new socket each time? */ sa_in.sin_port = htons (target_port); /* convert just to be safe */ /* hope I can keep reusing this struct */ rc = connect (ts, (struct sockaddr *) &sa_in, sizeof(sa_in)); if (!rc) { /* success */ *port = target_port; /* tell them the port used */ i = fcntl (ts, F_GETFL, 0); #ifdef VERBOSE printf("FL on [%d] = %d\n", ts, i); #endif /* VERBOSE */ nodelay(ts); return (ts); /* give them the socket */ } else { /* failure */ perror ("Connect()"); target_port++; /* look at the next port */ search--; /* one less attempt left */ /* I belive ts is now defunted.. so I close it?? */ close (ts); } } /* while */ /* well we are here so fidles.. */ return (rc); } int closeconn (s) int s; /* socket to close, also notifies the other party */ { /* too tired */ close (s); } int pollconn (s) /* checks for incomming events on a socket */ int s; { short ine, oute; struct pollfd pfd; int tout; int rc; ine=0; oute=0; tout=0000; /* 0 seconds */ /* either ready now or never :) */ /* tout=2000; */ /* 2 seconds */ /* OK, pack the poll data struct */ pfd.fd = s; pfd.events = ine | POLLIN; pfd.revents = oute; /* ok, kick it in the arse and let it go */ rc = poll (&pfd, 1, tout); /* results */ #ifdef VERBOSE printf ("Poll on [%d] returned [%d] with events [%d][0x%x]\n", s, rc, pfd.revents, pfd.revents); if (pfd.revents & POLLIN) printf("POLLIN\n"); if (pfd.revents & POLLPRI) printf("POLLPRI\n"); if (pfd.revents & POLLOUT) printf("POLLOUT\n"); if (pfd.revents & POLLERR) printf("POLLERR\n"); if (pfd.revents & POLLHUP) printf("POLLHUP\n"); if (pfd.revents & POLLNVAL) printf("POLLNVAL\n"); #ifdef FULL_POLL_LIST if (pfd.revents & POLLRDNORM) printf("POLLRDNORM\n"); if (pfd.revents & POLLRDBAND) printf("POLLRDBAND\n"); if (pfd.revents & POLLWRNORM) printf("POLLWRNORM\n"); if (pfd.revents & POLLWRBAND) printf("POLLWRBAND\n"); #endif /* FULL_POLL_LIST */ #endif /* VERBOSE */ if (pfd.revents == POLLIN) return (1); else return (0); /* default is nothing incomming */ } int writeconn (s, data, len)/* sends stream data. I.e. no header/seq stuff */ /* return value = len or error */ int s; /* socket conn is on */ char *data; /* raw data to send */ int len; /* length of data to send */ { int i,j,k; int n; unsigned long nblen; /* networkbyte message length */ int tosend, gone, fluffed; /* loop variables */ tosend = len; gone = 0; /* just in case */ fluffed = 0; /* just in case */ for (i=0;tosend>0;) { #ifdef DB9 printf("Write loop for socket [%d]. Sent [%d] / [%d] or [%d] left.\n", s, i, len, tosend); #endif /* DB9 */ gone = write (s, &data[i], tosend); #ifdef DB9 printf("wrote [%d] byte on socket [%d].\n", gone, s); #endif /* DB9 */ if (gone<=0) { fluffed++; if (gone<0) perror ("Write()"); if (fluffed==RETRIES) { fprintf(stderr,"Problem, connection on socket [%d] has failed.\nThis connect has been closed.\n", s); fflush(stderr); close (s); return (i); /* how much we sent in the end... */ /* upto the user app to realise the error. */ } /* if fluffed */ } else { /* i.e. we sent some */ i+= gone; /* total sent and index ptr update */ tosend -= gone; fluffed = 0; /* fluffed reset counter */ } /* if gone */ } /* for look on tosend */ /* ok all done... now return amount wrote */ return (i); } int readconn (s, data, len)/* reads stream data. I.e. no header/seq stuff */ /* return is read length or error */ int s; /* socket conn is on */ char *data; /* raw data buffer */ int len; /* length of data tobe read */ { int i,j,k; int n; char bb; /* Bit Bucket character */ unsigned int toget; /* note type */ int got, fluffed; /* loop variables */ toget = (unsigned) len; fluffed = 0; #ifdef DB9 printf("read on [%d] to get msg length [%d]\n", s, toget); #endif for (i=0;toget>0;) { #ifdef DB9 printf("Reading on [%d] amount [%d]\n", s, toget); #endif /* DB9 */ got = read (s, &data[i], toget); #ifdef DB9 printf("reading on [%d] got [%d] bytes.\n", s, got); #endif /* DB9 */ if (got<=0) { fluffed++; if (fluffed==RETRIES) { fprintf(stderr,"Problem, connection on socket [%d] has failed.\nThis connect has been closed.\n", s); fflush(stderr); close (s); return (i); /* how much we got in the end... */ /* upto the user app to realise the error. */ } /* if fluffed */ } else { /* i.e. we got */ i+= got; /* total got and index ptr update */ toget -= got; fluffed = 0; /* fluffed reset counter */ } /* if got */ } /* for look on toget */ /* ok all done... now return amount read */ return (i); } int writemsgconn (s, data, len)/* sends message data. I.e. header & seq */ /* return value = len or error */ int s; /* socket conn is on */ char *data; /* raw data to send */ int len; /* length of data to send */ { int i,j,k; int n; unsigned long nblen; /* networkbyte message length */ int tosend, gone, fluffed; /* loop variables */ nblen = htonl ((unsigned long) len); /* message length for the header */ #ifdef DB9 printf("Attempting message write on [%d] for msg of len [%d]\n", s, len); #endif /* write outgoing message length */ n = write (s, &nblen, sizeof(long)); /* ek */ if(n!=4) { exit (-100); } /* ok thats a bad way to do it! */ #ifdef DB9 printf("wrote on socket [%d] message hdr.\n", s); #endif tosend = len; gone = 0; /* just in case */ fluffed = 0; /* just in case */ for (i=0;tosend>0;) { #ifdef DB9 printf("Write loop for socket [%d]. Sent [%d] / [%d] or [%d] left.\n", s, i, len, tosend); #endif /* DB9 */ gone = write (s, &data[i], tosend); #ifdef DB9 printf("wrote [%d] byte on socket [%d].\n", gone, s); #endif /* DB9 */ if (gone<=0) { fluffed++; if (gone<0) perror ("Write()"); if (fluffed==RETRIES) { fprintf(stderr,"Problem, connection on socket [%d] has failed.\nThis connect has been closed.\n", s); fflush(stderr); close (s); return (i); /* how much we sent in the end... */ /* upto the user app to realise the error. */ } /* if fluffed */ } else { /* i.e. we sent some */ i+= gone; /* total sent and index ptr update */ tosend -= gone; fluffed = 0; /* fluffed reset counter */ } /* if gone */ } /* for look on tosend */ /* ok all done... now return amount wrote */ return (i); } int readmsgconn (s, data, mlen)/* reads message data. I.e. header & seq */ /* return value = len or error */ int s; /* socket conn is on */ char *data; /* raw data buffer */ int mlen; /* max length of data buffer */ { int i,j,k; int n; char bb; /* Bit Bucket character */ unsigned long ilen, nbilen; /* incomming message length */ unsigned long elen; /* expected message length */ unsigned int tojunk, toget; /* note type */ int got, fluffed; /* loop variables */ elen = (unsigned long) mlen; /* how much buffer we have to play with */ fluffed = 0; #ifdef DB9 printf("Attempting message read on [%d] for msg of max len [%u]\n", s, elen); #endif /* read incomming message length */ n = read (s, &nbilen, sizeof(long)); /* ek */ if(n!=4) { exit (-100); } /* ok thats a bad way to do it! */ ilen = ntohl (nbilen); /* convert from network byte format */ #ifdef DB9 printf("read on socket [%d] returns message hdr indicating msg size of [%u]\n", s, ilen); #endif if (ilen > mlen) /* buffer too small.. will have to truncate. */ /* Note we don't read ahead or anything fancy */ { tojunk = ilen - mlen; toget = mlen; } else { tojunk = 0; toget = ilen; } #ifdef DB9 printf("read on [%d] total msg length [%d] overrun [%d]\n", s, toget, tojunk); #endif for (i=0;toget>0;) { #ifdef DB9 printf("Reading on [%d] amount [%d]\n", s, toget); #endif /* DB9 */ got = read (s, &data[i], toget); #ifdef DB9 printf("reading on [%d] got [%d] bytes.\n", s, got); #endif /* DB9 */ if (got<=0) { fluffed++; if (fluffed==RETRIES) { fprintf(stderr,"Problem, connection on socket [%d] has failed.\nThis connect has been closed.\n", s); fflush(stderr); close (s); return (i); /* how much we got in the end... */ /* upto the user app to realise the error. */ } /* if fluffed */ } else { /* i.e. we got */ i+= got; /* total got and index ptr update */ toget -= got; fluffed = 0; /* fluffed reset counter */ } /* if got */ } /* for look on toget */ /* now for the truncate bit. */ if (tojunk) for (j=0;jp_proto, TCP_NODELAY, &one, sizeof(one)) < 0) */ if( p && setsockopt(s, p->p_proto, TCP_NODELAY, (char*)&one, sizeof(one)) < 0) perror("setsockopt: nodelay"); #else printf("TCPNODELAY ignored\n"); #endif /* NODELAYALLOWED */ } void setnonblocking( s ) /* sets the given socket non-blocking */ int s; { int i, j; i = fcntl (s, F_GETFL, 0); #ifdef VERBOSE printf("FL on [%d] = %d\n", s, i); #endif /* VERBOSE */ i = i | O_NONBLOCK; /* mark it as non blocking */ #ifdef VERBOSE printf ("O_NONBLOCK = %d\n", O_NONBLOCK); #endif /* VERBOSE */ j = fcntl (s, F_SETFL, i); #ifdef VERBOSE printf("New FL [%d] on [%d] returns [%d]\n", i, s, j); #endif /* VERBOSE */ } void setblocking( s ) /* sets the given socket blocking again */ int s; { int i, j; i = fcntl (s, F_GETFL, 0); #ifdef VERBOSE printf("FL on [%d] = %d\n", s, i); #endif /* VERBOSE */ i = i & (!O_NONBLOCK); /* mark it as non non-blocking, i.e. blocking */ j = fcntl (s, F_SETFL, i); #ifdef VERBOSE printf("New FL [%d] on [%d] returns [%d]\n", i, s, j); #endif /* VERBOSE */ } int setsendrecvbufs ( s, bufsize ) /* Sets send/recv buffer sizes */ /* returns 0 for ok and 1 for unix not accepting and -1 for error */ /* if a problem occurs, it sets buffers back to what they were */ /* Note: Bufsize is in kilobytes */ { unsigned int sb_org, rb_org; unsigned int sb_new, rb_new; unsigned int sb_chk, rb_chk; unsigned int optsize; int rc; optsize = sizeof (int); /* I hope... */ sb_new = bufsize * 1024; /* into bytes */ rb_new = bufsize * 1024; /* into bytes */ if (sb_new<=0) { fprintf(stderr, "SNIPE_LITE:Conn:attempt to set send/recv bufs to %d ignored\n", sb_new); return (-1); } /* get original values first */ rc = getsockopt(s, SOL_SOCKET, SO_SNDBUF, (char*)&sb_org, &optsize); rc = getsockopt(s, SOL_SOCKET, SO_RCVBUF, (char*)&rb_org, &optsize); /* Now to attempt to set the new ones */ rc = setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char*)&sb_new, optsize); rc = setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char*)&rb_new, optsize); /* Now to verify the socket options */ rc = getsockopt(s, SOL_SOCKET, SO_SNDBUF, (char*)&sb_chk, &optsize); rc = getsockopt(s, SOL_SOCKET, SO_RCVBUF, (char*)&rb_chk, &optsize); /* ok junk debugging */ #ifdef VERBOSE printf("[sockopt] socket %d send org %d new %d vrfy %d\t\trecv org %d, new %d vrfy %d\n", s, sb_org, sb_new, sb_chk, rb_org, rb_new, rb_chk); #endif /* Now to do what we do */ /* if both are ok... worked */ if ((sb_chk==sb_new)&&(rb_chk==rb_new)) return (0); /* if **either** match the older values */ if ((sb_chk==sb_org)||(rb_chk==rb_org)) return (1); /* else we have to attempt a reset */ rc = setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char*)&sb_org, optsize); rc = setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char*)&rb_org, optsize); /* At this point we could check again, but there is little point as */ /* if this hasn't changed it back we are in trouble anyway */ return (1); } double sec_time() /* returns the time in seconds as a double */ { struct timeval tp; struct timezone tzp; double sec=0.0; double psec=0.0; gettimeofday (&tp, &tzp); sec = (double)tp.tv_sec; psec = ((double)tp.tv_usec)/1000000.0; return (sec+psec); }