Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Asynch name lookups

  • Loading branch information...
commit b7319a8d93372b399c9555e95819e1e1b6ff78dc 1 parent 4bf3b6d
ec429 authored
Showing with 126 additions and 16 deletions.
  1. +10 −8 Makefile
  2. +6 −0 input.c
  3. +51 −2 irc.c
  4. +9 −2 irc.h
  5. +11 −0 osconf.h
  6. +3 −3 plans
  7. +36 −1 quirc.c
18 Makefile
View
@@ -1,13 +1,15 @@
# Makefile for quIRC
-CC ?= gcc
-OPTFLAGS = -g
-CFLAGS ?= -Wall -Wextra -Werror -pedantic -std=gnu99 $(OPTFLAGS)
-AWK ?= gawk
+CC := gcc
+OPTFLAGS := -g
+CFLAGS := -Wall -Wextra -Werror -pedantic -std=gnu99 $(OPTFLAGS)
+AWK := gawk
VERSION := `git describe --tags`
-PREFIX ?= /usr/local
-LIBS := ttyraw.o ttyesc.o irc.o bits.o colour.o buffer.o names.o config.o input.o
-INCLUDE := ttyraw.h ttyesc.h irc.h bits.h colour.h buffer.h names.h config.h input.h quirc.h version.h
+PREFIX := /usr/local
+# -lanl is for ASYNCH_NL
+OPTLIBS := -lanl
+LIBS := ttyraw.o ttyesc.o irc.o bits.o colour.o buffer.o names.o config.o input.o $(OPTLIBS)
+INCLUDE := ttyraw.h ttyesc.h irc.h bits.h colour.h buffer.h names.h config.h input.h quirc.h version.h osconf.h
all: quirc doc
@@ -41,7 +43,7 @@ README: readme.htm
ttyesc.o: ttyesc.c ttyesc.h bits.h
-irc.o: irc.c irc.h bits.h buffer.h colour.h names.h numeric.h
+irc.o: irc.c irc.h bits.h buffer.h colour.h names.h numeric.h osconf.h
irc.h: config.h
touch irc.h
6 input.c
View
@@ -703,6 +703,11 @@ int cmd_handle(char *inp, char **qmsg, fd_set *master, int *fdmax) // old state=
{
char dstr[30+strlen(server)+strlen(newport)];
sprintf(dstr, "Connecting to %s on port %s...", server, newport);
+ #if ASYNCH_NL
+ irc_connect(server, newport, master, fdmax);
+ if(!quiet) add_to_buffer(0, c_status, dstr, "/server: ");
+ if(force_redraw<3) redraw_buffer();
+ #else
int serverhandle=irc_connect(server, newport, master, fdmax);
if(serverhandle)
{
@@ -716,6 +721,7 @@ int cmd_handle(char *inp, char **qmsg, fd_set *master, int *fdmax) // old state=
if(!quiet) add_to_buffer(cbuf, c_status, dstr, "/server: ");
if(force_redraw<3) redraw_buffer();
}
+ #endif
}
}
else
53 irc.c
View
@@ -8,14 +8,55 @@
#include "irc.h"
-void handle_sigpipe(int sig)
+void handle_signals(int sig)
{
if(sig==SIGPIPE)
sigpipe=1;
else if(sig==SIGWINCH)
sigwinch=1;
+ else if(sig==SIGUSR1)
+ sigusr1=1;
}
+#if ASYNCH_NL
+int irc_connect(char *server, char *portno, __attribute__((unused)) fd_set *master, __attribute__((unused)) int *fdmax)
+{
+ if(nl_details)
+ {
+ add_to_buffer(0, c_err, "DNS lookup already in progress (/nlcancel to cancel)", "/connect: ");
+ return(-1);
+ }
+ // Look up server
+ struct addrinfo *hints=malloc(sizeof(struct addrinfo));
+ if(!hints)
+ {
+ add_to_buffer(0, c_err, strerror(errno), "malloc: ");
+ return(-1);
+ }
+ memset(hints, 0, sizeof(*hints));
+ hints->ai_family=AF_INET;
+ hints->ai_socktype = SOCK_STREAM; // TCP stream sockets
+ nl_details=malloc(sizeof(struct gaicb));
+ if(!nl_details)
+ {
+ add_to_buffer(0, c_err, strerror(errno), "malloc: ");
+ return(-1);
+ }
+ *nl_details=(struct gaicb){.ar_name=strdup(server), .ar_service=strdup(portno), .ar_request=hints};
+ getaddrinfo_a( // function call split into lines because it's complicated
+ GAI_NOWAIT,
+ &nl_details,
+ 1,
+ &(struct sigevent){.sigev_notify=SIGEV_SIGNAL, .sigev_signo=SIGUSR1, .sigev_value.sival_ptr=strdup(portno)}
+ );
+ return(0);
+}
+
+int irc_conn_found(fd_set *master, int *fdmax)
+{
+ int serverhandle=0;
+ struct addrinfo *servinfo=nl_details->ar_result;
+#else /* ASYNCH_NL */
int irc_connect(char *server, char *portno, fd_set *master, int *fdmax)
{
int serverhandle=0;
@@ -30,6 +71,7 @@ int irc_connect(char *server, char *portno, fd_set *master, int *fdmax)
add_to_buffer(0, c_err, (char *)gai_strerror(rv), "getaddrinfo: ");
return(0); // 0 indicates failure as rv is new serverhandle value
}
+#endif /* ASYNCH_NL */
char sip[INET_ADDRSTRLEN];
struct addrinfo *p;
// loop through all the results and connect to the first we can
@@ -70,7 +112,14 @@ int irc_connect(char *server, char *portno, fd_set *master, int *fdmax)
return(0); // 0 indicates failure as rv is new serverhandle value
}
freeaddrinfo(servinfo);
-
+ servinfo=NULL;
+#if ASYNCH_NL
+ free((char *)nl_details->ar_name);
+ free((char *)nl_details->ar_service);
+ free((void *)nl_details->ar_request);
+ free(nl_details);
+ nl_details=NULL;
+#endif
FD_SET(serverhandle, master);
*fdmax=max(*fdmax, serverhandle);
return(serverhandle);
11 irc.h
View
@@ -8,6 +8,8 @@
irc: networking functions
*/
+#define _GNU_SOURCE // feature test macro
+
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
@@ -46,14 +48,19 @@ message;
#include "config.h"
#include "numeric.h"
#include "names.h"
+#include "osconf.h"
#define MQUOTE '\020'
-volatile sig_atomic_t sigpipe, sigwinch;
+volatile sig_atomic_t sigpipe, sigwinch, sigusr1;
-void handle_sigpipe(int); // handles both sigpipe and sigwinch
+void handle_signals(int); // handles sigpipe, sigwinch and sigusr1
int irc_connect(char *server, char *portno, fd_set *master, int *fdmax); // non-blocking
+#if ASYNCH_NL
+struct gaicb *nl_details;
+int irc_conn_found(fd_set *master, int *fdmax); // non-blocking; call this when the getaddrinfo_a() has finished
+#endif
int irc_conn_rest(int b, char *nick, char *username, char *passwd, char *fullname); // call this when the non-blocking connect() has finished
int autoconnect(fd_set *master, int *fdmax, servlist *serv);
int irc_tx(int fd, char * packet);
11 osconf.h
View
@@ -0,0 +1,11 @@
+#pragma once
+
+/*
+ quIRC - simple terminal-based IRC client
+ Copyright (C) 2010-11 Edward Cree
+
+ See quirc.c for license information
+ osconf.h: platform-specific configuration settings
+*/
+
+#define ASYNCH_NL 1 // set to 0 if platform does not provide getaddrinfo_a() (and remove -lanl from Makefile OPTLIBS)
6 plans
View
@@ -2,7 +2,7 @@
Scripting language. Under development in branch 'script'.
-curses. The current hardwired ANSI-escapes code for painting the screen is clumsy. However, it's tailored to my needs, and now that it's neatly packaged away, it should be easier to cope with. So, I may just stick with it.
+termcap (or terminfo) awareness. The current hardwired ANSI-escapes code for painting the screen is clumsy. However, it's tailored to my needs, and now that it's neatly packaged away, it should be easier to cope with. So, I may just stick with it. (This entry used to say "curses.", but I tried that and found curses' input semantics were insufficiently rich; in particular it didn't like Ctrl-cursor keys)
Need to fix the problem of the conn_rest not getting called for eg worldofspectrum (why is this happening?)
@@ -16,8 +16,6 @@ Make hidden lines (quiet mode, conference mode, etc.) be stored in scrollback.
Optionally fold runs of the same type of message. Eg.: =foo=bar=baz= have joined #whatever.
-Make getaddrinfo() calls use getaddrinfo_a(). They currently block everything on connect, which means that /server can cause existing connections to ping off. (However, getaddrinfo_a() is not portable and some 64-bit libc have bugs, so we need a switch to disable its use.)
-
Handle \ in tab-completion. It should be expanded to \\.
Make /close on server tabs close the associated channel tabs. /disconnect the same, presumably.
@@ -34,6 +32,8 @@ Option for no hanging indent (wordline() tabx=0).
Const-correctness. There are a lot of functions taking a char * that should take a const char *.
+Check the return value of malloc (and realloc) everywhere. At the moment we're lax, which is fine on overcommitting Linux but not elsewhere.
+
Remember channel keys for /rejoin. An argument to /rejoin overrides (but doesn't overwrite unless the /rejoin succeeds).
Proper handling of Unicode in character-based things like cursor-movement, backspace.
37 quirc.c
View
@@ -29,8 +29,10 @@ int main(int argc, char *argv[])
init_start_buffer();
sigpipe=0;
+ sigwinch=0;
+ sigusr1=0;
struct sigaction sa;
- sa.sa_handler=handle_sigpipe;
+ sa.sa_handler=handle_signals;
sa.sa_flags=0;
sigemptyset(&sa.sa_mask);
@@ -48,6 +50,13 @@ int main(int argc, char *argv[])
push_buffer();
return(1);
}
+ if(sigaction(SIGUSR1, &sa, NULL)==-1)
+ {
+ fprintf(stderr, "Failed to set SIGUSR1 handler\n");
+ perror("sigaction");
+ push_buffer();
+ return(1);
+ }
int infc=fcntl(STDIN_FILENO, F_GETFD);
if(infc>=0)
@@ -203,6 +212,32 @@ int main(int argc, char *argv[])
}
sigwinch=0;
}
+ #if ASYNCH_NL
+ if(sigusr1)
+ {
+ char *server=strdup(nl_details->ar_name);
+ if(!server) server="server";
+ const char *port=nl_details->ar_service;
+ if(!port) port="port";
+ char dstr[32+strlen(server)+strlen(port)];
+ sprintf(dstr, "Found %s, connecting on %s...", server, port);
+ if(!quiet) add_to_buffer(cbuf, c_status, dstr, "/connect: ");
+ if(force_redraw<3) redraw_buffer();
+ int serverhandle=irc_conn_found(&master, &fdmax);
+ if(serverhandle)
+ {
+ bufs=(buffer *)realloc(bufs, ++nbufs*sizeof(buffer));
+ init_buffer(nbufs-1, SERVER, server, buflines);
+ cbuf=nbufs-1;
+ bufs[cbuf].handle=serverhandle;
+ bufs[cbuf].nick=strdup(nick);
+ bufs[cbuf].server=cbuf;
+ bufs[cbuf].conninpr=true;
+ }
+ free(server);
+ sigusr1=0; // there would be a race condition here, but we don't allow concurrent name lookups anyway so it's safe
+ }
+ #endif
// propagate liveness values into dependent tabs, and ping idle connections
{
time_t now=time(NULL);
Please sign in to comment.
Something went wrong with that request. Please try again.