OSSP CVS Repository

ossp - Check-in [1197]
Not logged in
[Honeypot]  [Browse]  [Home]  [Login]  [Reports
[Search]  [Ticket]  [Timeline
  [Patchset]  [Tagging/Branching

Check-in Number: 1197
Date: 2001-Oct-19 15:06:35 (local)
2001-Oct-19 13:06:35 (UTC)
User:rse
Branch:
Comment: First cut for an IRC output channel. This beast is able to send the message to the IRC channel, but the whole client/server communication is not quite correct because I don't know how to correctly deal with the server responses due to the fact that the IRC protocol (according to the RFC) is asynchronous and there can be replies but there have no to be replies. The effect is that currently we see:

| *** l2_test (~rse@dev10.dev.de.cw.net) has joined channel #l2 | <l2_test> A program of user rse on host dev10.dev.de.cw.net logged at Fri, 19 | Oct 2001 15:01:27 CEST: | <l2_test> 0Checking localhost foo [12345/myparm] | <foo\x01bar><66:6f:6f:01:62:61:72><Zm9vAWJhcg==> | *** Signoff: l2_test (EOF From client)

As you can see, the "EOF from client" is the problem. Currently it is caused by a sa_shutdown(), but I don't know how to program it. So, feel free to jump in and fix the communication of this channel.

Tickets:
Inspections:
Files:
ossp-pkg/l2/l2_ch_irc.c      1.1 -> 1.2     233 inserted, 3 deleted

ossp-pkg/l2/l2_ch_irc.c 1.1 -> 1.2

--- l2_ch_irc.c  2001/10/04 14:58:29     1.1
+++ l2_ch_irc.c  2001/10/19 13:06:35     1.2
@@ -24,47 +24,277 @@
 **  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 **  SUCH DAMAGE.
 **
-**  l2_ch_irc.c: internet relay chat channel implementation
+**  l2_ch_irc.c: Internet Relay Chat (IRC) channel implementation
 */
 
 #include "l2.h"
+#include "l2_p.h"
 
+#include <unistd.h>
+#include <sys/utsname.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <time.h>
+
+/* declare private channel configuration */
+typedef struct {
+    char *cpLocalProg;
+    char *cpLocalHost;
+    char *cpLocalUser;
+    char *cpPassword;
+    char *cpNickname;
+    char *cpUsername;
+    char *cpRealname;
+    char *cpChannel;
+    int   bJoin;
+    char *cpHost;
+    char *cpPort;
+    long nTimeout; 
+    sa_addr_t *saaServer;
+    sa_t *saServer;
+} l2_ch_irc_t;
+
+/* create channel */
 static l2_result_t hook_create(l2_context_t *ctx, l2_channel_t *ch)
 {
+    l2_ch_irc_t *cfg;
+    struct utsname uts;
+    struct passwd *pw;
+
+    /* allocate private channel configuration */
+    if ((cfg = (l2_ch_irc_t *)malloc(sizeof(l2_ch_irc_t))) == NULL)
+        return L2_ERR_ARG;
+
+    /* initialize configuration with reasonable defaults */
+    cfg->cpLocalProg = NULL;
+    if ((pw = getpwuid(getuid())) != NULL)
+        cfg->cpLocalUser = strdup(pw->pw_name);
+    else
+        cfg->cpLocalUser = l2_util_asprintf("uid#%d", getuid());
+    if (uname(&uts) == 0)
+        cfg->cpLocalHost = strdup(uts.nodename);
+    else
+        cfg->cpLocalHost = strdup("localhost");
+    cfg->cpPassword = strdup("*");
+    cfg->cpNickname = strdup(cfg->cpLocalUser);
+    cfg->cpUsername = l2_util_asprintf("%s@%s", cfg->cpLocalUser, cfg->cpLocalHost);
+    cfg->cpRealname = strdup(cfg->cpUsername);
+    cfg->cpChannel  = strdup("#l2");
+    cfg->bJoin      = 1;
+    cfg->cpHost     = NULL;
+    cfg->cpPort     = strdup("6667");
+    cfg->nTimeout   = 30;
+    cfg->saaServer  = NULL;
+    cfg->saServer   = NULL;
+
+    /* link private channel configuration into channel context */
+    ctx->vp = cfg;
+
     return L2_OK;
 }
 
+/* configure channel */
 static l2_result_t hook_configure(l2_context_t *ctx, l2_channel_t *ch, const char *fmt, va_list ap)
 {
-    return L2_OK;
+    l2_ch_irc_t *cfg = (l2_ch_irc_t *)ctx->vp;
+    l2_param_t pa[12]; 
+    l2_result_t rv;
+
+    /* feed and call generic parameter parsing engine */
+    L2_PARAM_SET(pa[0],  progname,  STRING, &cfg->cpLocalProg);
+    L2_PARAM_SET(pa[1],  localhost, STRING, &cfg->cpLocalHost);
+    L2_PARAM_SET(pa[2],  localuser, STRING, &cfg->cpLocalUser);
+    L2_PARAM_SET(pa[3],  nickname,  STRING, &cfg->cpNickname);
+    L2_PARAM_SET(pa[4],  username,  STRING, &cfg->cpUsername);
+    L2_PARAM_SET(pa[5],  realname,  STRING, &cfg->cpRealname);
+    L2_PARAM_SET(pa[6],  channel,   STRING, &cfg->cpChannel);
+    L2_PARAM_SET(pa[7],  join,      INT,    &cfg->bJoin);
+    L2_PARAM_SET(pa[8],  host,      STRING, &cfg->cpHost);
+    L2_PARAM_SET(pa[9],  port,      STRING, &cfg->cpPort);
+    L2_PARAM_SET(pa[10], timeout,   INT,    &cfg->nTimeout);
+    L2_PARAM_END(pa[11]);
+    rv = l2_util_setparams(pa, fmt, ap);
+
+    return rv;
 }
 
+/* open channel */
 static l2_result_t hook_open(l2_context_t *ctx, l2_channel_t *ch)
 {
+    l2_ch_irc_t *cfg = (l2_ch_irc_t *)ctx->vp;
+    sa_rc_t rc;
+
+    /* make sure a path was set */
+    if (cfg->cpHost == NULL)
+        return L2_ERR_USE;
+
+    /* create socket address */
+    if ((rc = sa_addr_create(&cfg->saaServer)) != SA_OK)
+        return (rc == SA_ERR_SYS ? L2_ERR_SYS : L2_ERR_INT);
+    if ((rc = sa_addr_u2a(cfg->saaServer, "inet://%s:%s", 
+                          cfg->cpHost, cfg->cpPort)) != SA_OK)
+        return (rc == SA_ERR_SYS ? L2_ERR_SYS : L2_ERR_INT);
+
+    /* create socket */
+    if ((rc = sa_create(&cfg->saServer)) != SA_OK)
+        return (rc == SA_ERR_SYS ? L2_ERR_SYS : L2_ERR_INT);
+
+    /* configure socket parameters */
+    sa_timeout(cfg->saServer, SA_TIMEOUT_ALL, cfg->nTimeout, 0);
+    sa_timeout(cfg->saServer, SA_TIMEOUT_READ, 2, 0);
+    sa_buffer(cfg->saServer, SA_BUFFER_READ, 4096);
+    sa_buffer(cfg->saServer, SA_BUFFER_WRITE, 4096);
+
     return L2_OK;
 }
 
-static l2_result_t hook_write(l2_context_t *ctx, l2_channel_t *ch, l2_level_t level, const char *buf, size_t buf_size)
+/* write to channel */
+static l2_result_t hook_write(l2_context_t *ctx, l2_channel_t *ch,
+                              l2_level_t level, const char *buf, size_t buf_size)
 {
+    l2_ch_irc_t *cfg = (l2_ch_irc_t *)ctx->vp;
+    char caLine[1024];
+    sa_t *sa;
+    sa_addr_t *saa;
+    sa_rc_t sa_rv;
+    size_t n;
+    struct tm *tm;
+    time_t t;
+    char caDate[80];
+    
+    /* 
+     * Sample IRC client transaction for reference:
+     * | PASS secret
+     * | NICK rse
+     * | USER rse@engelschall.com 0 * :Ralf S. Engelschall
+     * | :irc.engelschall.com 001 rse :Welcome to the Internet Relay Network rse!~rse@dev10.dev.de.cw.net
+     * | :irc.engelschall.com 002 rse :Your host is irc.engelschall.com, running version 2.10.3p2
+     * | :irc.engelschall.com 003 rse :This server was created Wed Oct 17 2001 at 18:06:57 CEST
+     * | :irc.engelschall.com 004 rse irc.engelschall.com 2.10.3p2 aoOirwabeiIklmnoOpqrstv
+     * | :irc.engelschall.com 251 rse :There are 1 users and 0 services on 1 servers
+     * | :irc.engelschall.com 254 rse 11 :channels formed
+     * | :irc.engelschall.com 255 rse :I have 1 users, 0 services and 0 servers
+     * | :irc.engelschall.com 375 rse :- irc.engelschall.com Message of the Day - 
+     * | :irc.engelschall.com 372 rse :- 17/10/2001 19:32
+     * | :irc.engelschall.com 372 rse :- Welcome to the Engelschall VISP IRC Service.
+     * | :irc.engelschall.com 376 rse :End of MOTD command.
+     * | :rse MODE rse :+i
+     * | JOIN #dev
+     * | :rse!~rse@dev10.dev.de.cw.net JOIN :#dev
+     * | :irc.engelschall.com 353 rse = #dev :@rse 
+     * | :irc.engelschall.com 366 rse #dev :End of NAMES list.
+     * | PRIVMSG #dev :Sample log message line 1
+     * | PRIVMSG #dev :Sample log message line 2 
+     * | PRIVMSG #dev :Sample log message line 3
+     * | QUIT
+     * | ERROR :Closing Link: rse[~rse@dev10.dev.de.cw.net] (I Quit)
+     *
+     * For more details read:
+     * RFC 2812: Internet Relay Chat: Client Protocol; C. Kalt; April 2000.
+     */
+
+    /* establish connection to server */
+    saa = cfg->saaServer;
+    sa  = cfg->saServer;
+    if ((sa_rv = sa_connect(sa, saa)) != SA_OK)
+        return (sa_rv == SA_ERR_SYS ? L2_ERR_SYS : L2_ERR_INT);
+
+    /* determine current time */
+    t = time(NULL);
+    tm = localtime(&t);
+    strftime(caDate, sizeof(caDate), "%a, %d %b %Y %H:%M:%S %Z", tm);
+
+    /* write transaction to IRC server */
+    sa_writef(sa, "PASS %s\r\n", cfg->cpPassword);
+    sa_writef(sa, "NICK %s\r\n", cfg->cpNickname);
+    sa_writef(sa, "USER %s 0 * :%s\r\n", cfg->cpUsername, cfg->cpRealname);
+    if (cfg->bJoin)
+        sa_writef(sa, "JOIN %s\r\n", cfg->cpChannel);
+    sa_writef(sa, "PRIVMSG %s :", cfg->cpChannel);
+    if (cfg->cpLocalProg != NULL)
+        sa_writef(sa, "Program %s of user %s on host %s logged at %s:\r\n", 
+                   cfg->cpLocalProg, cfg->cpLocalUser, cfg->cpLocalHost, caDate);
+    else
+        sa_writef(sa, "A program of user %s on host %s logged at %s:\r\n", 
+                   cfg->cpLocalUser, cfg->cpLocalHost, caDate);
+    sa_writef(sa, "PRIVMSG %s :", cfg->cpChannel);
+    sa_write(sa, buf, buf_size-1, NULL);
+    sa_writef(sa, "\r\n");
+    if (cfg->bJoin)
+        sa_writef(sa, "PART %s\r\n", cfg->cpChannel);
+    sa_writef(sa, "QUIT\r\n");
+    sa_flush(sa);
+
+    /* shutdown write side of connection to server */
+    sa_shutdown(sa, "w");
+
+    /* still read server responses */
+    while (sa_readln(sa, caLine, sizeof(caLine), &n) == SA_OK)
+        ;
+
+    /* shutdown read side of connection to server */
+    sa_shutdown(sa, "r");
+
     return L2_OK;
 }
 
+/* close channel */
 static l2_result_t hook_close(l2_context_t *ctx, l2_channel_t *ch)
 {
+    l2_ch_irc_t *cfg = (l2_ch_irc_t *)ctx->vp;
+
+    /* destroy remote address */
+    if (cfg->saServer != NULL) {
+        sa_destroy(cfg->saServer);
+        cfg->saServer = NULL;
+    }
+    if (cfg->saaServer != NULL) {
+        sa_addr_destroy(cfg->saaServer);
+        cfg->saaServer = NULL;
+    }
+
     return L2_OK;
 }
 
+/* destroy channel */
 static l2_result_t hook_destroy(l2_context_t *ctx, l2_channel_t *ch)
 {
+    l2_ch_irc_t *cfg = (l2_ch_irc_t *)ctx->vp;
+
+    /* destroy channel configuration */
+    if (cfg->cpLocalProg != NULL)
+        free(cfg->cpLocalProg);
+    if (cfg->cpLocalHost != NULL)
+        free(cfg->cpLocalHost);
+    if (cfg->cpLocalUser != NULL)
+        free(cfg->cpLocalUser);
+    if (cfg->cpPassword != NULL)
+        free(cfg->cpPassword);
+    if (cfg->cpNickname != NULL)
+        free(cfg->cpNickname);
+    if (cfg->cpUsername != NULL)
+        free(cfg->cpUsername);
+    if (cfg->cpRealname != NULL)
+        free(cfg->cpRealname);
+    if (cfg->cpChannel != NULL)
+        free(cfg->cpChannel);
+    if (cfg->cpHost != NULL)
+        free(cfg->cpHost);
+    if (cfg->cpPort != NULL)
+        free(cfg->cpPort);
+    free(cfg);
+
     return L2_OK;
 }
 
+/* exported channel handler structure */
 l2_handler_t l2_handler_irc = {
     L2_CHANNEL_OUTPUT,
     hook_create,
     hook_configure,
     hook_open,
     hook_write,
+    NULL,
     hook_close,
     hook_destroy
 };

CVSTrac 2.0.1