+++ /dev/null
-/* -*-c-*-
- *
- * Nonblocking RFC931 client
- *
- * (c) 1999 Mark Wooding
- */
-
-/*----- Licensing notice --------------------------------------------------*
- *
- * This file is part of the mLib utilities library.
- *
- * mLib is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Library General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * mLib 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 Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with mLib; if not, write to the Free
- * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- * MA 02111-1307, USA.
- */
-
-/*----- Header files ------------------------------------------------------*/
-
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-
-#include "conn.h"
-#include "dstr.h"
-#include "exc.h"
-#include "ident.h"
-#include "selbuf.h"
-
-/*----- Main code ---------------------------------------------------------*/
-
-/* --- @next@ --- *
- *
- * Arguments: @char **pp@ = address of string pointer
- *
- * Returns: Address of next token.
- *
- * Use: Reads the next token from the result string. Tokens are
- * terminated by whitespace, or `:' or `,' characters. The
- * result string has had `\' escapes removed; it's stored in
- * the same memory as the input string. The actual content
- * of the delimiter doesn't seem to be interesting, so it
- * gets thrown away.
- */
-
-static char *next(char **pp)
-{
- char *p, *q, *r;
-
- /* --- Deal with reads past the end of the string --- */
-
- if (!*pp)
- return ("");
-
- /* --- Initialize various pointers into the string --- */
-
- p = q = r = *pp;
-
- /* --- Skip past any leading whitespace --- */
-
- while (isspace((unsigned char)*p))
- p++;
-
- /* --- Now start work on the string itself --- */
-
- for (;;) {
- if (*p == 0 || *p == ':' || *p == ',' || isspace((unsigned char)*p))
- break;
- else if (*p == '\\') {
- p++;
- if (!*p) {
- *q++ = '\\';
- break;
- }
- }
- *q++ = *p++;
- }
-
- /* --- Tidy up afterwards --- */
-
- while (isspace((unsigned char)*p))
- p++;
- if (*p == 0)
- *pp = 0;
- else if (*p == ':' || *p == ',')
- *pp = p + 1;
- else
- *pp = p;
- *q = 0;
-
- return (r);
-}
-
-/* --- @parse@ --- *
- *
- * Arguments: @char *p@ = pointer to input string from identd
- * @ident_reply *i@ = pointer to output block
- *
- * Returns: ---
- *
- * Use: Parses a result string from an RFC931 (identd) server.
- */
-
-static void parse(char *p, ident_reply *i)
-{
- char *q;
-
- /* --- Read the source and destination port numbers --- */
-
- i->sport = atoi(next(&p));
- i->dport = atoi(next(&p));
-
- /* --- Find out what sort of a reply this is --- */
-
- q = next(&p);
- if (strcmp(q, "USERID") == 0) {
- i->type = IDENT_USERID;
- i->u.userid.os = next(&p);
- i->u.userid.user = next(&p);
- } else if (strcmp(q, "ERROR") == 0) {
- i->type = IDENT_ERROR;
- i->u.error = next(&p);
- } else
- i->type = IDENT_BAD;
-}
-
-/* --- @line@ --- *
- *
- * Arguments: @char *s@ = pointer to string from ident server
- * @size_t len@ = length of the line
- * @void *p@ = pointer to my request block
- *
- * Returns: ---
- *
- * Use: Handles a string from an ident server.
- */
-
-static void line(char *s, size_t len, void *p)
-{
- ident_request *rq = p;
-
- rq->state = IDENT_DONE;
- close(rq->b.reader.fd);
- if (!s)
- rq->func(0, rq->p);
- else {
- ident_reply i;
- parse(s, &i);
- rq->func(&i, rq->p);
- }
- selbuf_destroy(&rq->b);
-}
-
-/* --- @connected@ --- *
- *
- * Arguments: @int fd@ = file descriptor
- * @void *p@ = pointer to request block
- *
- * Returns: ---
- *
- * Use: Handles a connection to a remote ident server.
- */
-
-static void connected(int fd, void *p)
-{
- ident_request *rq = p;
- dstr d = DSTR_INIT;
-
- /* --- Handle an error during the connect --- */
-
- if (fd < 0)
- goto fail_0;
-
- /* --- Initialize the string to send to the remote host --- */
-
- TRY {
- dstr_putf(&d, "%u, %u\r\n",
- ntohs(rq->remote.sin_port), ntohs(rq->local.sin_port));
- } CATCH switch (exc_type) {
- case EXC_NOMEM:
- EXIT_TRY;
- goto fail_1;
- default:
- RETHROW;
- } END_TRY;
-
- /* --- Do the rest of the work --- */
-
- if (write(fd, d.buf, d.len) < d.len)
- goto fail_1;
- dstr_destroy(&d);
- rq->state = IDENT_READ;
- selbuf_init(&rq->b, rq->s, fd, line, rq);
- return;
-
- /* --- Tidy up after misfortunes --- */
-
-fail_1:
- dstr_destroy(&d);
- close(fd);
-fail_0:
- rq->state = IDENT_DONE;
- rq->func(0, rq->p);
-}
-
-/* --- @ident_abort@ --- *
- *
- * Arguments: @ident_request *rq@ = pointer to request block
- *
- * Returns: ---
- *
- * Use: Cancels an ident request in progress.
- */
-
-void ident_abort(ident_request *rq)
-{
- switch (rq->state) {
- case IDENT_CONN:
- conn_kill(&rq->c);
- break;
- case IDENT_READ:
- close(rq->b.reader.fd);
- selbuf_destroy(&rq->b);
- break;
- }
-}
-
-/* --- @go@ --- *
- *
- * Arguments: @ident_request *rq@ = pointer to request block
- *
- * Returns: ---
- *
- * Use: Starts a connection to the remote ident server.
- */
-
-static void go(ident_request *rq)
-{
- int fd;
- struct sockaddr_in sin;
- int opt;
-
- /* --- Create the socket I'll use --- */
-
- if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
- goto fail_0;
- memset(&sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_port = 0;
- sin.sin_addr = rq->local.sin_addr;
- if (bind(fd, (struct sockaddr *)&sin, sizeof(sin)))
- goto fail_1;
-
- /* --- Out-of-band data would confuse us --- */
-
- opt = 1;
- setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(opt));
-
- /* --- Start a connection to the remote server --- */
-
- sin.sin_family = AF_INET;
- sin.sin_port = htons(113);
- sin.sin_addr = rq->remote.sin_addr;
- if (conn_init(&rq->c, rq->s, fd, (struct sockaddr *)&sin, sizeof(sin),
- connected, rq))
- goto fail_1;
-
- /* --- Finish off initializing the block --- */
-
- rq->state = IDENT_CONN;
- return;
-
- /* --- Tidy up after lossage --- */
-
-fail_1:
- close(fd);
-fail_0:
- rq->state = IDENT_DONE;
- rq->func(0, rq->p);
-}
-
-/* --- @ident@ --- *
- *
- * Arguments: @ident_request *rq@ = pointer to request block
- * @sel_state *s@ = I/O multiplexor
- * @const struct sockaddr_in *local, *remote@ = addresses
- * @void (*func)(ident_reply *i, void *p)@ = handler function
- * @void *p@ = argument for handler
- *
- * Returns: ---
- *
- * Use: Initializes an ident request.
- */
-
-void ident(ident_request *rq, sel_state *s,
- const struct sockaddr_in *local,
- const struct sockaddr_in *remote,
- void (*func)(ident_reply */*i*/, void */*p*/),
- void *p)
-{
- memcpy(&rq->local, local, sizeof(rq->local));
- memcpy(&rq->remote, remote, sizeof(rq->remote));
- rq->func = func;
- rq->p = p;
- rq->s = s;
- go(rq);
-}
-
-/* --- @ident_socket@ --- *
- *
- * Arguments: @ident_request *rq@ = pointer to request block
- * @sel_state *s@ = I/O multiplexor
- * @int sk@ = connected socket file descriptor
- * @void (*func)(ident_reply *i, void *p)@ = handler function
- * @void *p@ = argument for handler
- *
- * Returns: ---
- *
- * Use: An alternative interface to @ident@. Initializes an ident
- * request from a connected socket, rather than from an explicit
- * address. This will call @getsockname@ and @getpeername@ to
- * find out what the socket is actually connected to, which adds
- * convenience but wastes time.
- */
-
-void ident_socket(ident_request *rq, sel_state *s, int sk,
- void (*func)(ident_reply */*i*/, void */*p*/),
- void *p)
-{
- size_t sinsz;
- if ((sinsz = sizeof(struct sockaddr_in),
- getsockname(sk, (struct sockaddr *)&rq->local, &sinsz)) ||
- (sinsz = sizeof(struct sockaddr_in),
- getpeername(sk, (struct sockaddr *)&rq->remote, &sinsz))) {
- rq->state = IDENT_DONE;
- func(0, p);
- return;
- }
-
- rq->func = func;
- rq->p = p;
- rq->s = s;
- go(rq);
-}
-
-/*----- That's all, folks -------------------------------------------------*/