home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / identd.zip / identd.cpp next >
C/C++ Source or Header  |  1997-10-31  |  9KB  |  347 lines

  1. //
  2. // Roddy's wee identd/2  - 31 October 1997
  3. //
  4. // questions, comments, etc to collinsr@cs.rpi.edu
  5. //
  6. // accepts rfc1413 (identd) requests, and says either "ERROR: INVALID-PORT"
  7. // if it couldn't understand the request, or "OS/2: FOOBAR" where 
  8. // 'foobar' is whatever your USER environment variable is set to (or 'os2-user'
  9. // if it's not set.)  
  10. //
  11. // Use this code freely, but at your own risk.  It works for me,
  12. // but I admit I did not check all the return codes, any one of which
  13. // might cause the computer to crash, melt, or morph into an avatar of
  14. // Bill Gates who will proceed to format your disk and install unholy
  15. // lumps of software on it.  
  16. //
  17. // If find it useful, it'd be nice if you sent me an email saying so
  18. // (but I'd understand if you didn't...)
  19. //
  20.  
  21. #define INCL_DOS
  22. #define INCL_ERRORS
  23. #include <os2.h>
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <stdarg.h>
  27. #include <types.h>
  28. #include <time.h>
  29. #include <sys/socket.h>
  30. #include <sys/stat.h>
  31. #include <sys/types.h>
  32. #include <netinet/in.h>
  33. #include <netdb.h>
  34. #include <sys/ioctl.h>
  35. #include <net/route.h>
  36. #include <net/if.h>
  37. #include <net/if_arp.h>
  38.  
  39. struct THREAD_PARAMS {
  40.   int sock;
  41.   int timeout;
  42.   HEV hevActivity;
  43. };
  44.  
  45. struct OPTIONS {
  46.   int port;       // port to listen on 
  47.   int timeout;    // # of seconds to wait for query after open
  48.   int verbosity;  // how verbose?
  49.   char *pszMsg;   // what to say?
  50. };
  51.  
  52. struct globals {
  53.   int verbosity;
  54.   char *pszMsg;
  55.   int serverSock;
  56. } G;
  57.  
  58. enum {V_NONE = 0, V_LOW, V_HI};
  59.  
  60. const int DEFAULT_PORT = 113;
  61. const int DEFAULT_TIMEOUT = 30;
  62. const int DEFAULT_VERBOSITY = V_LOW;
  63. const char DEFAULT_RESPONSE_VARIABLE[] = "USER";
  64. const char DEFAULT_RESPONSE_STRING[] = "os2-user";
  65. const char *VERSION = "identd version 1.1 " __DATE__ "@" __TIME__ "\n";
  66.  
  67. int get_options(OPTIONS& o, int argc, char *argv[]);
  68. void usage(char *pszArgv0);
  69. void die(char *pszMsg);
  70. void notify(int v_level, const char *pszFormat, ... );
  71.  
  72. void cleanup(void);
  73. int setup_server(int port);
  74. int accept_connection(int sock);
  75. void handle_connection(int sock, int timeout);
  76. void _Optlink transact_ident(void *arg);
  77. int readbytes(int sock, char *buffer, int buflen);
  78.  
  79. // ----------------------------------------
  80.  
  81. int main(int argc, char *argv[])
  82. {
  83. OPTIONS o;
  84. int serverSock, clientSock;
  85.  
  86.   if (get_options(o, argc, argv)) usage(argv[0]);
  87.   G.verbosity = o.verbosity;
  88.   G.pszMsg = o.pszMsg;
  89.   notify(V_HI, VERSION);
  90.   notify(V_HI, "questions, comments, etc to collinsr@cs.rpi.edu\n");
  91.   notify(V_HI, "options: -p %d -t %d -v %d; response is \"%s\"\n",
  92.      o.port, o.timeout, o.verbosity, o.pszMsg);
  93.  
  94.   serverSock = setup_server(o.port);
  95.   G.serverSock = serverSock;
  96.   DosExitList(EXLST_ADD | 0x00000000, (PFNEXITLIST) cleanup);
  97.  
  98.   while (1) {
  99.     clientSock = accept_connection(serverSock);
  100.     handle_connection(clientSock, o.timeout);
  101.     soclose(clientSock);
  102.   }
  103. }
  104.  
  105. // ----------------------------------------
  106.  
  107. void notify(int v_level, const char *pszFormat, ...)
  108. {
  109. va_list varList;
  110. time_t t;
  111. char sztime[27];
  112.  
  113.   if (v_level <= G.verbosity ) {
  114.     time(&t);
  115.     strcpy(sztime, ctime(&t));
  116.     sztime[strlen(sztime)-1] = (char) 0;
  117.     fprintf(stderr, "%s: ", sztime);
  118.     va_start(varList, pszFormat);
  119.     vfprintf(stderr, pszFormat, varList);
  120.     va_end(varList);
  121.   }
  122. }
  123.  
  124. void die(char *pszMsg) {
  125.   psock_errno(pszMsg);
  126.   exit(1);
  127. }
  128.  
  129. void cleanup(void) {
  130.  
  131.   notify(V_LOW, "exiting\n");
  132.   soclose(G.serverSock);
  133. }
  134.  
  135. void usage(char *pszArgv0)
  136. {
  137.   fprintf(stderr, "usage: %s [-p port] [-t timeout] [-v verbosity]\n",
  138.       pszArgv0);
  139.   fprintf(stderr, "  -p port: port accepting identd requests\n");
  140.   fprintf(stderr, "  -t timeout: seconds to wait for query after open\n");
  141.   fprintf(stderr, "  -v verbosity: message density (%d=quiet ... %d=noisy)\n",
  142.       V_NONE, V_HI);
  143.   fprintf(stderr, "  sends %s variable, or \"%s\" if not set\n",
  144.       DEFAULT_RESPONSE_VARIABLE, DEFAULT_RESPONSE_STRING);
  145.   fprintf(stderr, "  defaults: -p %d, -t %d, -v %d\n", DEFAULT_PORT,
  146.       DEFAULT_TIMEOUT, DEFAULT_VERBOSITY);
  147.   exit(1);
  148. }
  149.  
  150.  
  151. int get_options(OPTIONS& o, int argc, char *argv[])
  152. {
  153. int c = 1;
  154. char *arg;
  155.  
  156.  
  157.   o.port = DEFAULT_PORT;
  158.   o.timeout = DEFAULT_TIMEOUT;
  159.   o.verbosity = DEFAULT_VERBOSITY;
  160.   if (getenv(DEFAULT_RESPONSE_VARIABLE) == 0) {
  161.     o.pszMsg = strdup(DEFAULT_RESPONSE_STRING);
  162.   } else {
  163.     o.pszMsg = strdup(getenv(DEFAULT_RESPONSE_VARIABLE));
  164.   }
  165.  
  166.   while (c < argc) {
  167.     arg = argv[c++];
  168.     if (arg[0] == '-') {
  169.       switch (arg[1]) {
  170.       case 'p': 
  171.     if (sscanf(argv[c], "%d", &o.port) != 1) {
  172.       fprintf(stderr, "couldn't parse integer from -p %s\n", argv[c]);
  173.       return(1);
  174.     }
  175.     break;
  176.       case 't':
  177.     if (sscanf(argv[c], "%d", &o.timeout) != 1) {
  178.       fprintf(stderr, "couldn't parse integer from -t %s\n", argv[c]);
  179.       return(1);
  180.     }
  181.     break;
  182.       case 'v':
  183.     if (sscanf(argv[c], "%d", &o.verbosity) != 1) {
  184.       fprintf(stderr, "couldn't parse integer from -v %s\n", argv[c]);
  185.       return(1);
  186.     }
  187.     break;
  188.       default:
  189.     fprintf(stderr, "unknown option %s\n", arg);
  190.     return(1);
  191.       }
  192.       c++;
  193.     } else {
  194.       fprintf(stderr, "unknown option %s\n", arg);
  195.       return(1);
  196.     }
  197.   }
  198.   return(0);
  199. }
  200.  
  201.  
  202. // ----------------------------------------
  203.  
  204.  
  205. int setup_server(int port)
  206. {
  207. struct sockaddr_in serv_addr;
  208. int sock, rc;
  209.  
  210.    rc = sock_init();
  211.    if (rc) die("sock_init");
  212.  
  213.    sock = socket(AF_INET, SOCK_STREAM, 0);
  214.    if (sock == -1) die("setting up server socket");
  215.  
  216.    memset(&serv_addr, (char) 0, sizeof(serv_addr));
  217.    serv_addr.sin_family = AF_INET;
  218.    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  219.    serv_addr.sin_port = htons(port);
  220.    
  221.    rc = bind(sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
  222.    if (rc) die("bind");
  223.  
  224.    rc = listen(sock, 5);
  225.    if (rc) die("listen");
  226.  
  227.    return(sock);
  228. }
  229.  
  230. int accept_connection(int sock)
  231. {
  232. int newSock, addrSize;
  233. struct sockaddr_in clientAddr;
  234.  
  235.    addrSize = sizeof(clientAddr);
  236.    newSock = accept(sock, (struct sockaddr *)&clientAddr, &addrSize);
  237.    if (newSock == -1) die("accept");
  238.  
  239.    if (G.verbosity >= V_LOW) {
  240.      struct hostent *h = gethostbyaddr((char *) &clientAddr.sin_addr, 
  241.                        sizeof(clientAddr.sin_addr),
  242.                        AF_INET);
  243.      char *hname = (h == 0) ? (char *) inet_ntoa(clientAddr.sin_addr) :
  244.        h->h_name;
  245.  
  246.      notify(V_LOW, "connect from %s [%s]\n", 
  247.         (char *) inet_ntoa(clientAddr.sin_addr), hname);
  248.    }
  249.  
  250.    return(newSock);
  251. }
  252.  
  253.  
  254. void handle_connection(int sock, int timeout)
  255. {
  256. THREAD_PARAMS *tp;
  257. int tid;
  258. int rc;
  259.  
  260.   tp = new THREAD_PARAMS;
  261.   tp->sock = sock;
  262.   tp->timeout = timeout;
  263.   rc = DosCreateEventSem((char *) 0, &tp->hevActivity, 0L, 0);
  264.   if (rc) {
  265.     notify(V_NONE, "Oops: couldn't create a semaphore; rc %d\n", rc);
  266.   } else {
  267.     tid = _beginthread(transact_ident, 0, 16*1024, tp);
  268.     if (tid == -1) {
  269.       notify(V_NONE, "Oops: couldn't create a thread\n");
  270.     } else {
  271.       notify(V_HI, "%d:%d waiting %d seconds for query\n", tid, sock, timeout);
  272.       rc = DosWaitEventSem(tp->hevActivity, timeout * 1000);
  273.       switch (rc) {
  274.       case NO_ERROR:
  275.     break;
  276.       case ERROR_TIMEOUT:
  277.     DosKillThread(tid);
  278.     notify(V_NONE, "thread %d socket %d timeout!\n", tid, sock);
  279.     break;
  280.       default:
  281.     DosKillThread(tid);
  282.     notify(V_NONE, "Oops: unexpected %d waiting for %d:%d\n",
  283.            rc, tid, sock);
  284.     break;
  285.       }
  286.     }
  287.     DosCloseEventSem(tp->hevActivity);
  288.   }
  289.  
  290.   notify(V_HI, "%d:%d done\n", tid, sock);
  291.   delete tp;
  292. }
  293.  
  294. void _Optlink transact_ident(void *arg)
  295. {
  296. THREAD_PARAMS *tp = (THREAD_PARAMS *) arg;
  297. const int buflen = 1024;
  298. int done, rc, port_server, port_client;
  299. char buf[buflen], buf_index, buf_remaining;
  300.  
  301.   rc = readbytes(tp->sock, buf, buflen);
  302.   if (rc < 0) {
  303.     notify(V_NONE, "Oops: recv was %d\n", sock_errno());
  304.   } else {
  305.     buf[rc] = 0;
  306.     notify(V_LOW, "request was %s\n", buf);
  307.   
  308.     if (sscanf(buf, "%d , %d", &port_server, &port_client) != 2) {
  309.       sprintf(buf, "0 , 0 : ERROR : INVALID-PORT");
  310.     } else {
  311.       sprintf(buf, "%d, %d : OS/2 : %s", port_server, port_client, G.pszMsg);
  312.     }
  313.  
  314.     notify(V_LOW, "response was %s\n", buf);
  315.     rc = send(tp->sock, buf, strlen(buf), 0);
  316.     sprintf(buf, "\r\n");
  317.     rc = send(tp->sock, buf, strlen(buf), 0);
  318.   }
  319.   rc = DosPostEventSem(tp->hevActivity);
  320. }
  321.  
  322. int readbytes(int sock, char *buffer, int buflen) 
  323. {
  324. int index, remaining, rc, done;
  325.  
  326.   index = 0;
  327.   remaining = buflen;
  328.   done = 0;
  329.   do {
  330.     rc = recv(sock, &(buffer[index]), remaining, 0);
  331.     if (rc < 0) return (-1);
  332.     if (rc > 0) {
  333.       index += rc;
  334.       remaining -= rc;
  335.     }
  336.     if (remaining < 0) return (-1);
  337.     if ((rc > 0) && (index >= 2)) {
  338.       done = ((buffer[index-1] == '\n') || (buffer[index-1] == '\r'));
  339.     }
  340.   } while (!done);
  341.  
  342.   return(index);
  343. }
  344.  
  345.  
  346.       
  347.