home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 35 Internet
/
35-Internet.zip
/
identd.zip
/
identd.cpp
next >
Wrap
C/C++ Source or Header
|
1997-10-31
|
9KB
|
347 lines
//
// Roddy's wee identd/2 - 31 October 1997
//
// questions, comments, etc to collinsr@cs.rpi.edu
//
// accepts rfc1413 (identd) requests, and says either "ERROR: INVALID-PORT"
// if it couldn't understand the request, or "OS/2: FOOBAR" where
// 'foobar' is whatever your USER environment variable is set to (or 'os2-user'
// if it's not set.)
//
// Use this code freely, but at your own risk. It works for me,
// but I admit I did not check all the return codes, any one of which
// might cause the computer to crash, melt, or morph into an avatar of
// Bill Gates who will proceed to format your disk and install unholy
// lumps of software on it.
//
// If find it useful, it'd be nice if you sent me an email saying so
// (but I'd understand if you didn't...)
//
#define INCL_DOS
#define INCL_ERRORS
#include <os2.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <types.h>
#include <time.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/ioctl.h>
#include <net/route.h>
#include <net/if.h>
#include <net/if_arp.h>
struct THREAD_PARAMS {
int sock;
int timeout;
HEV hevActivity;
};
struct OPTIONS {
int port; // port to listen on
int timeout; // # of seconds to wait for query after open
int verbosity; // how verbose?
char *pszMsg; // what to say?
};
struct globals {
int verbosity;
char *pszMsg;
int serverSock;
} G;
enum {V_NONE = 0, V_LOW, V_HI};
const int DEFAULT_PORT = 113;
const int DEFAULT_TIMEOUT = 30;
const int DEFAULT_VERBOSITY = V_LOW;
const char DEFAULT_RESPONSE_VARIABLE[] = "USER";
const char DEFAULT_RESPONSE_STRING[] = "os2-user";
const char *VERSION = "identd version 1.1 " __DATE__ "@" __TIME__ "\n";
int get_options(OPTIONS& o, int argc, char *argv[]);
void usage(char *pszArgv0);
void die(char *pszMsg);
void notify(int v_level, const char *pszFormat, ... );
void cleanup(void);
int setup_server(int port);
int accept_connection(int sock);
void handle_connection(int sock, int timeout);
void _Optlink transact_ident(void *arg);
int readbytes(int sock, char *buffer, int buflen);
// ----------------------------------------
int main(int argc, char *argv[])
{
OPTIONS o;
int serverSock, clientSock;
if (get_options(o, argc, argv)) usage(argv[0]);
G.verbosity = o.verbosity;
G.pszMsg = o.pszMsg;
notify(V_HI, VERSION);
notify(V_HI, "questions, comments, etc to collinsr@cs.rpi.edu\n");
notify(V_HI, "options: -p %d -t %d -v %d; response is \"%s\"\n",
o.port, o.timeout, o.verbosity, o.pszMsg);
serverSock = setup_server(o.port);
G.serverSock = serverSock;
DosExitList(EXLST_ADD | 0x00000000, (PFNEXITLIST) cleanup);
while (1) {
clientSock = accept_connection(serverSock);
handle_connection(clientSock, o.timeout);
soclose(clientSock);
}
}
// ----------------------------------------
void notify(int v_level, const char *pszFormat, ...)
{
va_list varList;
time_t t;
char sztime[27];
if (v_level <= G.verbosity ) {
time(&t);
strcpy(sztime, ctime(&t));
sztime[strlen(sztime)-1] = (char) 0;
fprintf(stderr, "%s: ", sztime);
va_start(varList, pszFormat);
vfprintf(stderr, pszFormat, varList);
va_end(varList);
}
}
void die(char *pszMsg) {
psock_errno(pszMsg);
exit(1);
}
void cleanup(void) {
notify(V_LOW, "exiting\n");
soclose(G.serverSock);
}
void usage(char *pszArgv0)
{
fprintf(stderr, "usage: %s [-p port] [-t timeout] [-v verbosity]\n",
pszArgv0);
fprintf(stderr, " -p port: port accepting identd requests\n");
fprintf(stderr, " -t timeout: seconds to wait for query after open\n");
fprintf(stderr, " -v verbosity: message density (%d=quiet ... %d=noisy)\n",
V_NONE, V_HI);
fprintf(stderr, " sends %s variable, or \"%s\" if not set\n",
DEFAULT_RESPONSE_VARIABLE, DEFAULT_RESPONSE_STRING);
fprintf(stderr, " defaults: -p %d, -t %d, -v %d\n", DEFAULT_PORT,
DEFAULT_TIMEOUT, DEFAULT_VERBOSITY);
exit(1);
}
int get_options(OPTIONS& o, int argc, char *argv[])
{
int c = 1;
char *arg;
o.port = DEFAULT_PORT;
o.timeout = DEFAULT_TIMEOUT;
o.verbosity = DEFAULT_VERBOSITY;
if (getenv(DEFAULT_RESPONSE_VARIABLE) == 0) {
o.pszMsg = strdup(DEFAULT_RESPONSE_STRING);
} else {
o.pszMsg = strdup(getenv(DEFAULT_RESPONSE_VARIABLE));
}
while (c < argc) {
arg = argv[c++];
if (arg[0] == '-') {
switch (arg[1]) {
case 'p':
if (sscanf(argv[c], "%d", &o.port) != 1) {
fprintf(stderr, "couldn't parse integer from -p %s\n", argv[c]);
return(1);
}
break;
case 't':
if (sscanf(argv[c], "%d", &o.timeout) != 1) {
fprintf(stderr, "couldn't parse integer from -t %s\n", argv[c]);
return(1);
}
break;
case 'v':
if (sscanf(argv[c], "%d", &o.verbosity) != 1) {
fprintf(stderr, "couldn't parse integer from -v %s\n", argv[c]);
return(1);
}
break;
default:
fprintf(stderr, "unknown option %s\n", arg);
return(1);
}
c++;
} else {
fprintf(stderr, "unknown option %s\n", arg);
return(1);
}
}
return(0);
}
// ----------------------------------------
int setup_server(int port)
{
struct sockaddr_in serv_addr;
int sock, rc;
rc = sock_init();
if (rc) die("sock_init");
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == -1) die("setting up server socket");
memset(&serv_addr, (char) 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(port);
rc = bind(sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
if (rc) die("bind");
rc = listen(sock, 5);
if (rc) die("listen");
return(sock);
}
int accept_connection(int sock)
{
int newSock, addrSize;
struct sockaddr_in clientAddr;
addrSize = sizeof(clientAddr);
newSock = accept(sock, (struct sockaddr *)&clientAddr, &addrSize);
if (newSock == -1) die("accept");
if (G.verbosity >= V_LOW) {
struct hostent *h = gethostbyaddr((char *) &clientAddr.sin_addr,
sizeof(clientAddr.sin_addr),
AF_INET);
char *hname = (h == 0) ? (char *) inet_ntoa(clientAddr.sin_addr) :
h->h_name;
notify(V_LOW, "connect from %s [%s]\n",
(char *) inet_ntoa(clientAddr.sin_addr), hname);
}
return(newSock);
}
void handle_connection(int sock, int timeout)
{
THREAD_PARAMS *tp;
int tid;
int rc;
tp = new THREAD_PARAMS;
tp->sock = sock;
tp->timeout = timeout;
rc = DosCreateEventSem((char *) 0, &tp->hevActivity, 0L, 0);
if (rc) {
notify(V_NONE, "Oops: couldn't create a semaphore; rc %d\n", rc);
} else {
tid = _beginthread(transact_ident, 0, 16*1024, tp);
if (tid == -1) {
notify(V_NONE, "Oops: couldn't create a thread\n");
} else {
notify(V_HI, "%d:%d waiting %d seconds for query\n", tid, sock, timeout);
rc = DosWaitEventSem(tp->hevActivity, timeout * 1000);
switch (rc) {
case NO_ERROR:
break;
case ERROR_TIMEOUT:
DosKillThread(tid);
notify(V_NONE, "thread %d socket %d timeout!\n", tid, sock);
break;
default:
DosKillThread(tid);
notify(V_NONE, "Oops: unexpected %d waiting for %d:%d\n",
rc, tid, sock);
break;
}
}
DosCloseEventSem(tp->hevActivity);
}
notify(V_HI, "%d:%d done\n", tid, sock);
delete tp;
}
void _Optlink transact_ident(void *arg)
{
THREAD_PARAMS *tp = (THREAD_PARAMS *) arg;
const int buflen = 1024;
int done, rc, port_server, port_client;
char buf[buflen], buf_index, buf_remaining;
rc = readbytes(tp->sock, buf, buflen);
if (rc < 0) {
notify(V_NONE, "Oops: recv was %d\n", sock_errno());
} else {
buf[rc] = 0;
notify(V_LOW, "request was %s\n", buf);
if (sscanf(buf, "%d , %d", &port_server, &port_client) != 2) {
sprintf(buf, "0 , 0 : ERROR : INVALID-PORT");
} else {
sprintf(buf, "%d, %d : OS/2 : %s", port_server, port_client, G.pszMsg);
}
notify(V_LOW, "response was %s\n", buf);
rc = send(tp->sock, buf, strlen(buf), 0);
sprintf(buf, "\r\n");
rc = send(tp->sock, buf, strlen(buf), 0);
}
rc = DosPostEventSem(tp->hevActivity);
}
int readbytes(int sock, char *buffer, int buflen)
{
int index, remaining, rc, done;
index = 0;
remaining = buflen;
done = 0;
do {
rc = recv(sock, &(buffer[index]), remaining, 0);
if (rc < 0) return (-1);
if (rc > 0) {
index += rc;
remaining -= rc;
}
if (remaining < 0) return (-1);
if ((rc > 0) && (index >= 2)) {
done = ((buffer[index-1] == '\n') || (buffer[index-1] == '\r'));
}
} while (!done);
return(index);
}