httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Ryan Bloom <...@raleigh.ibm.com>
Subject A new apr abstraction. PortHandler directive.
Date Fri, 16 Apr 1999 17:18:46 GMT

I am attaching a patch I would like comments on.  This implements a new
PortHandler directive.  The idea is that ports can have different types in
a web server.  This directive allows a module to define what type a port
is.

The syntax is:

PortHandler ipaddr:port module_name

The module has to define an accept function, which is added to the
function list.

This accept function is defined as:

conn_type *(*accept)(int sd, struct sockaddr addr, int *len);

(The parameter list will be VERY different once apr is done.  It will
mimic apr's accept parameter list, which is (apr_accept)(apr_socket_t *))

The conn_type is defined as:

struct conn_type{
int sd,
int (*read)(int, char *, int)
int (*write)(int, const char *, int)
}

(Again, definition will change with apr, but idea remains the same.)

The read and write functions are pushed into the buff structure, and they
are used whenever this port read/writes to the network.

The default port type, is to use regular accept, and
readwithtimeout/writewithtimeout on Unix.

This patch is basically implementing and idea in the buff.h file, where it
suggests that pointers to basic I/O routines could be stored in the buff
struct.

Any thoughts/comments?

Ryan

Index: include/buff.h
===================================================================
RCS file: /home/cvs/apache-apr/pthreads/src/include/buff.h,v
retrieving revision 1.4
diff -u -r1.4 buff.h
--- buff.h	1999/04/09 04:10:35	1.4
+++ buff.h	1999/04/15 12:19:45
@@ -117,6 +117,8 @@
 /* could also put pointers to the basic I/O routines here */
     int fd;			/* the file descriptor */
     int fd_in;			/* input file descriptor, if different */
+    int (*recv) (int, char *, int, int, time_t);
+    int (*send) (int, const char *, int, int, time_t);
 #ifdef WIN32
     HANDLE hFH;			/* Windows filehandle */
 #endif
@@ -142,9 +144,13 @@
 /* Options to bset/getopt */
 #define BO_BYTECT (1)
 
+/* network I/O abstraction */
+struct conn_type *baseaccept(int, struct sockaddr *, int *);
+
 /* Stream creation and modification */
 API_EXPORT(BUFF *) ap_bcreate(pool *p, int flags);
 API_EXPORT(void) ap_bpushfd(BUFF *fb, int fd_in, int fd_out);
+API_EXPORT(void) ap_bpushnetio(BUFF *fb, struct conn_type *netio);
 
 /* XXX - unused right now - mvsk */
 API_EXPORT(BUFF *) ap_bopenf(pool *a, const char *name, int flg, int mode);
Index: include/fdqueue.h
===================================================================
RCS file: /home/cvs/apache-apr/pthreads/src/include/fdqueue.h,v
retrieving revision 1.7
diff -u -r1.7 fdqueue.h
--- fdqueue.h	1999/04/07 22:52:16	1.7
+++ fdqueue.h	1999/04/15 12:19:45
@@ -14,7 +14,7 @@
                                of queue_pop semantics */
 
 typedef struct fd_queue_elem {
-    int fd;
+    conn_type *fd;
     struct sockaddr addr;
 } FDQueueElement;
 
@@ -31,8 +31,8 @@
 
 int queue_init(FDQueue *queue, int queue_size, pool *a);
 void *queue_destroy(FDQueue *queue);
-int queue_push(FDQueue *queue, int fd, struct sockaddr *addr);
-int queue_pop(FDQueue *queue, struct sockaddr *addr, int block_if_empty);
+int queue_push(FDQueue *queue, conn_type *fd, struct sockaddr *addr);
+conn_type *queue_pop(FDQueue *queue, struct sockaddr *addr, int block_if_empty, pool *);
 int queue_size(FDQueue *queue);
 int increase_blanks(FDQueue *queue);
 int queue_full(FDQueue *queue);
Index: include/http_accept.h
===================================================================
RCS file: /home/cvs/apache-apr/pthreads/src/include/http_accept.h,v
retrieving revision 1.1
diff -u -r1.1 http_accept.h
--- http_accept.h	1999/04/07 22:52:16	1.1
+++ http_accept.h	1999/04/15 12:19:45
@@ -73,6 +73,7 @@
     int pid;
     int tid;
     int sd;
+    acceptfunc accept;
 } proc_info;
 
 #define USE_ACCEPT_QUEUE
@@ -80,7 +81,7 @@
 #if defined (USE_ACCEPT_QUEUE)
 void init_accept(pool*, int, int);
 void start_accepting_requests(int);
-int  get_request(struct sockaddr *);
+conn_type *get_request(pool *,struct sockaddr *);
 void stop_accepting_requests(pool*);
 
 #elif defined (USE_MULTI_ACCEPT)
Index: include/http_config.h
===================================================================
RCS file: /home/cvs/apache-apr/pthreads/src/include/http_config.h,v
retrieving revision 1.3
diff -u -r1.3 http_config.h
--- http_config.h	1999/03/17 17:01:09	1.3
+++ http_config.h	1999/04/15 12:19:45
@@ -273,6 +273,7 @@
     void (*child_exit) (server_rec *, pool *);
 #endif
     int (*post_read_request) (request_rec *);
+    acceptfunc accept;
 } module;
 
 /* Initializer for the first few module slots, which are only
Index: include/httpd.h
===================================================================
RCS file: /home/cvs/apache-apr/pthreads/src/include/httpd.h,v
retrieving revision 1.13
diff -u -r1.13 httpd.h
--- httpd.h	1999/03/24 18:39:46	1.13
+++ httpd.h	1999/04/15 12:19:46
@@ -647,6 +647,7 @@
 typedef struct server_rec server_rec;
 typedef struct request_rec request_rec;
 typedef struct listen_rec listen_rec;
+typedef struct conn_type conn_type;
 
 #include "util_uri.h"
 
@@ -918,12 +919,21 @@
     int limit_req_fields;    /* limit on number of request header fields  */
 };
 
+struct conn_type {
+    int sd;
+    int (*recv) (int, char *, int, int, time_t);
+    int (*send) (int, const char *, int, int, time_t);
+};
+
+typedef conn_type *(*acceptfunc)(int, struct sockaddr *, int *);
+
 /* These are more like real hosts than virtual hosts */
 struct listen_rec {
     listen_rec *next;
     struct sockaddr_in local_addr;	/* local IP address and port */
     int fd;
     int used;			/* Only used during restart */
+    acceptfunc accept;
 /* more stuff here, like which protocol is bound to the port */
 };
 
Index: main/buff.c
===================================================================
RCS file: /home/cvs/apache-apr/pthreads/src/main/buff.c,v
retrieving revision 1.7
diff -u -r1.7 buff.c
--- buff.c	1999/04/09 04:10:36	1.7
+++ buff.c	1999/04/15 12:19:46
@@ -302,6 +302,17 @@
 
 #endif /* WIN32 */
 
+/* network I/O abstraction */
+struct conn_type *baseaccept(int fd, struct sockaddr *addr, int *addrlen)
+{
+    conn_type *new = (conn_type *)malloc(sizeof(conn_type)); 
+
+    new->recv = recvwithtimeout;
+    new->send = sendwithtimeout;
+   
+    new->sd = accept(fd, addr, addrlen);
+    return new;
+}
 
 /* the lowest level reading primitive */
 static int ap_read(BUFF *fb, void *buf, int nbyte)
@@ -326,7 +337,7 @@
 
 #if defined (WIN32)
     if (fb->flags & B_SOCKET) {
-	rv = recvwithtimeout(fb->fd_in, buf, nbyte, 0, sec);
+	rv = fb->recv(fb->fd_in, buf, nbyte, 0, sec);
 	if (rv == SOCKET_ERROR)
 	    errno = WSAGetLastError();
     }
@@ -351,7 +362,7 @@
     }
     rv = ap_read(fb, buf, nbyte);
 #else
-    rv = recvwithtimeout(fb->fd_in, buf, nbyte, 0, sec);
+    rv = fb->recv(fb->fd_in, buf, nbyte, 0, sec);
 #endif /* WIN32 */
     return rv;
 }
@@ -383,14 +394,14 @@
 
 #if defined(WIN32)
     if (fb->flags & B_SOCKET) {
-	rv = sendwithtimeout(fb->fd, buf, nbyte, 0, sec);
+	rv = fb->send(fb->fd, buf, nbyte, 0, sec);
 	if (rv == SOCKET_ERROR)
 	    errno = WSAGetLastError();
     }
     else
 	rv = ap_write(fb, buf, nbyte);
 #else
-    rv = sendwithtimeout(fb->fd, buf, nbyte, 0, sec);
+    rv = fb->send(fb->fd, buf, nbyte, 0, sec);
 #endif /* WIN32 */
     return rv;
 }
@@ -468,6 +479,12 @@
 {
     fb->fd = fd_out;
     fb->fd_in = fd_in;
+}
+
+API_EXPORT(void) ap_bpushnetio(BUFF *fb, struct conn_type *netio)
+{
+    fb->recv = netio->recv;
+    fb->send = netio->send;
 }
 
 #ifdef WIN32
Index: main/fdqueue.c
===================================================================
RCS file: /home/cvs/apache-apr/pthreads/src/main/fdqueue.c,v
retrieving revision 1.14
diff -u -r1.14 fdqueue.c
--- fdqueue.c	1999/04/09 04:10:36	1.14
+++ fdqueue.c	1999/04/15 12:19:46
@@ -14,8 +14,12 @@
     queue->bounds = bounds;
     queue->blanks = 0;
     ap_register_cleanup(a, queue, (void (*)(void *))queue_destroy, ap_null_cleanup);
-    for (i=0; i < bounds; ++i)
-        queue->data[i].fd = -1;
+    for (i=0; i < bounds; ++i) {
+        queue->data[i].fd = (conn_type *)ap_pcalloc(a, sizeof(conn_type));
+        queue->data[i].fd->sd = -1;
+        queue->data[i].fd->recv = NULL;
+        queue->data[i].fd->send = NULL;
+    }
     return FD_QUEUE_SUCCESS;
 }
 
@@ -27,11 +31,13 @@
     return FD_QUEUE_SUCCESS;
 }
 
-int queue_push(FDQueue *queue, int fd, struct sockaddr *addr) {
+int queue_push(FDQueue *queue, conn_type *fd, struct sockaddr *addr) {
     if (pthread_mutex_lock(&queue->one_big_mutex) != 0) {
         return FD_QUEUE_FAILURE;
     }
-    queue->data[queue->tail].fd = fd;
+    queue->data[queue->tail].fd->sd = fd->sd;
+    queue->data[queue->tail].fd->recv = fd->recv;
+    queue->data[queue->tail].fd->send = fd->send;
     queue->data[queue->tail].addr = *addr;
     queue->tail = (queue->tail + 1) % queue->bounds;
     queue->blanks--;
@@ -45,10 +51,11 @@
     return FD_QUEUE_SUCCESS;
 }
 
-int queue_pop(FDQueue *queue, struct sockaddr *addr, int block_if_empty) {
-    int fd;
+conn_type *queue_pop(FDQueue *queue, struct sockaddr *addr, int block_if_empty, pool *p)

+{
+    conn_type *fd = (conn_type *)ap_pcalloc(p, sizeof(conn_type));
     if (pthread_mutex_lock(&queue->one_big_mutex) != 0) {
-        return FD_QUEUE_FAILURE;
+        return NULL;
     }
     if (queue->blanks > 0) {
         pthread_cond_signal(&queue->not_full);
@@ -58,18 +65,20 @@
             pthread_cond_wait(&queue->not_empty, &queue->one_big_mutex);
         else {
             pthread_mutex_unlock(&queue->one_big_mutex);
-            return FD_QUEUE_FAILURE;
+            return NULL;
         }
     } 
     
-    fd = queue->data[queue->head].fd;
+    fd->sd = queue->data[queue->head].fd->sd;
+    fd->recv = queue->data[queue->head].fd->recv;
+    fd->send = queue->data[queue->head].fd->send;
     *addr = queue->data[queue->head].addr;
-    queue->data[queue->head].fd = -1;
-    if (fd != -1) {
+    queue->data[queue->head].fd->sd = -1;
+    if (fd->sd != -1) {
         queue->head = (queue->head + 1) % queue->bounds;
     }
     if (pthread_mutex_unlock(&queue->one_big_mutex) != 0) {
-        return FD_QUEUE_FAILURE;
+        return NULL;
     }
     return fd;
 }
Index: main/http_accept.c
===================================================================
RCS file: /home/cvs/apache-apr/pthreads/src/main/http_accept.c,v
retrieving revision 1.3
diff -u -r1.3 http_accept.c
--- http_accept.c	1999/04/12 23:47:25	1.3
+++ http_accept.c	1999/04/15 12:19:46
@@ -80,9 +80,12 @@
     int my_pid = ti->pid;
     int my_tid = ti->tid;
     int sd = ti->sd;
+    acceptfunc newaccept = ti->accept;   
+ 
     int csd = 0;
     struct sockaddr sa_client;
     size_t len = sizeof(struct sockaddr);
+    conn_type *contype;
 
     free(ti);
 
@@ -106,14 +109,14 @@
             csd = -1;
         }
         else {
-            csd = accept(sd, &sa_client, &len);
+            contype = newaccept(sd, &sa_client, &len);
             requests_this_child--;
 	    SAFE_ACCEPT(accept_mutex_off(my_tid - ap_threads_per_child));
 	}
         (void) ap_update_child_status(my_pid, my_tid, SERVER_QUEUEING, 
 				      (request_rec *) NULL);
-	if (csd >= 0) {
-	    if (queue_push(&csd_queue, csd, &sa_client) != 0) {
+	if (contype->sd >= 0) {
+	    if (queue_push(&csd_queue, contype, &sa_client) != 0) {
 	        ap_log_error(APLOG_MARK, APLOG_ERR, ap_get_server_conf(),
 			 "queue_push:  couldn't put new connection on"
                          "queue");
@@ -241,8 +244,8 @@
 	    my_info->pid = my_child_num;
 	    my_info->tid = i++;
 	    my_info->sd = lr->fd;
+            my_info->accept = lr->accept;
 
-
 	    if (pthread_create(&thread, NULL, accept_thread, my_info)) {
 	        ap_log_error(APLOG_MARK, APLOG_ALERT, (const server_rec*) ap_get_server_conf(),
 			     "pthread_create: unable to create acceptor thread");
@@ -271,30 +274,31 @@
     my_info->pid = my_child_num;
     my_info->tid = i;
     my_info->sd = lr->fd;
+    my_info->accept = lr->accept;
 
     accept_thread(my_info);
 }
 
-int get_request(struct sockaddr *sa_client)
+conn_type *get_request(pool *p, struct sockaddr *sa_client)
 {
-    int csd = -1;
+    conn_type *csd = NULL;
     int block_if_empty = 1;
 
     increase_blanks(&csd_queue);
 
-    while (csd == -1) {
+    while (csd == NULL) {
         if (workers_may_exit)
             block_if_empty = 0;
 
-        csd = queue_pop(&csd_queue, sa_client, block_if_empty);
+        csd = queue_pop(&csd_queue, sa_client, block_if_empty, p);
 
         if (workers_may_exit)
             break;
     }
 
     return csd;
-
 }
+
 void stop_accepting_requests(pool* pconf) {
     requests_this_child = 0;
     /* The two functions to get all of our other threads to die off. */
Index: main/http_config.c
===================================================================
RCS file: /home/cvs/apache-apr/pthreads/src/main/http_config.c,v
retrieving revision 1.11
diff -u -r1.11 http_config.c
--- http_config.c	1999/03/17 17:01:18	1.11
+++ http_config.c	1999/04/15 12:19:46
@@ -1457,6 +1457,7 @@
     new->local_addr.sin_port = htons(s->port ? s->port : DEFAULT_HTTP_PORT);
     new->fd = -1;
     new->next = NULL;
+    new->accept = baseaccept;
     ap_listeners = new;
 }
 
Index: main/http_core.c
===================================================================
RCS file: /home/cvs/apache-apr/pthreads/src/main/http_core.c,v
retrieving revision 1.11
diff -u -r1.11 http_core.c
--- http_core.c	1999/03/17 17:01:18	1.11
+++ http_core.c	1999/04/15 12:19:47
@@ -69,6 +69,7 @@
 #include "util_md5.h"
 #include "scoreboard.h"
 #include "fnmatch.h"
+#include "buff.h"
 
 #ifdef USE_MMAP_FILES
 #include <sys/mman.h>
@@ -2383,6 +2384,67 @@
     return NULL;
 }
 
+static const char *set_porthandler(cmd_parms *cmd, void *dummy, char *ips, char *name)
+{
+    listen_rec *dptr = ap_listeners;
+    module *modp;
+    char *ports;
+    unsigned short port;
+    unsigned long ipaddr;
+
+    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+    if (err != NULL) {
+        return err;
+    }
+
+    ports = strchr(ips, ':');
+    if (ports != NULL) {
+	if (ports == ips) {
+	    return "Missing IP address";
+	}
+	else if (ports[1] == '\0') {
+	    return "Address must end in :<port-number>";
+	}
+	*(ports++) = '\0';
+    }
+    else {
+	ports = ips;
+    }
+
+    if (ports == ips) { /* no address */
+	ipaddr = htonl(INADDR_ANY);
+    }
+    else {
+	ipaddr = ap_get_virthost_addr(ips, NULL);
+    }
+    port = atoi(ports);
+    if (!port) {
+	return "Port must be numeric";
+    }
+
+    while (dptr) {
+        if ((dptr->local_addr.sin_port == port) &&
+            (dptr->local_addr.sin_addr.s_addr == ipaddr))
+            break;
+        else
+            dptr = dptr->next;
+    }
+
+    if (dptr == NULL)
+        return "Port must have been defined already.";
+
+    modp = ap_find_linked_module(name);
+
+    if (modp != NULL && modp->accept != NULL) {
+        dptr->accept = modp->accept;
+        return NULL;
+    }
+    if (modp)
+        return "Module must define a new accept func.";
+    else
+        return "Module must be loaded.";
+}
+
 static const char *set_listener(cmd_parms *cmd, void *dummy, char *ips)
 {
     listen_rec *new;
@@ -2427,6 +2489,8 @@
     new->fd = -1;    /*ZZZ change to NULL */
     new->used = 0;
     new->next = ap_listeners;
+    new->accept = baseaccept;
+
     ap_listeners = new;
     return NULL;
 }
@@ -2882,6 +2946,8 @@
    OR_ALL, TAKE12, "soft/hard limits for max number of processes per uid" },
 { "BindAddress", set_bind_address, NULL, RSRC_CONF, TAKE1,
   "'*', a numeric IP address, or the name of a host with a unique IP address"},
+{ "PortHandler", set_porthandler, NULL, RSRC_CONF, TAKE2,
+  "A port number and the module that will supply the accept function"},
 { "Listen", set_listener, NULL, RSRC_CONF, TAKE1,
   "A port number or a numeric IP address and a port number"},
 { "SendBufferSize", set_send_buffer_size, NULL, RSRC_CONF, TAKE1,
Index: main/http_main.c
===================================================================
RCS file: /home/cvs/apache-apr/pthreads/src/main/http_main.c,v
retrieving revision 1.68
diff -u -r1.68 http_main.c
--- http_main.c	1999/04/09 04:10:37	1.68
+++ http_main.c	1999/04/15 12:19:48
@@ -1662,7 +1662,7 @@
  * Child process main loop.
  */
 
-static void process_socket(pool *p, struct sockaddr *sa_client, int csd, int my_child_num,
int my_thread_num)
+static void process_socket(pool *p, struct sockaddr *sa_client, conn_type *csd, int my_child_num,
int my_thread_num)
 {
     struct sockaddr sa_server; /* ZZZZ */
     size_t len = sizeof(struct sockaddr);
@@ -1670,17 +1670,18 @@
     request_rec *r;
     conn_rec *current_conn;
 
-    ap_note_cleanups_for_fd(p, csd);
+    ap_note_cleanups_for_fd(p, csd->sd);
 
     /* ZZZ change to AP func */
-    if (getsockname(csd, &sa_server, &len) < 0) { 
+    if (getsockname(csd->sd, &sa_server, &len) < 0) { 
 	ap_log_error(APLOG_MARK, APLOG_ERR, server_conf, "getsockname");
 	return;
     }
     (void) ap_update_child_status(my_child_num, my_thread_num,  
 				  SERVER_BUSY_READ, (request_rec *) NULL);
     conn_io = ap_bcreate(p, B_RDWR | B_SOCKET);
-    ap_bpushfd(conn_io, csd, csd);
+    ap_bpushfd(conn_io, csd->sd, csd->sd);
+    ap_bpushnetio(conn_io, csd);
 
     current_conn = new_connection(p, server_conf, conn_io,
                                   (const struct sockaddr_in *) sa_client, 
@@ -1745,7 +1746,7 @@
     int process_slot = ti->pid;
     int thread_slot = ti->tid;
     struct sockaddr sa_client;
-    int csd;
+    conn_type *csd;
     pool *ptrans;		/* Pool for per-transaction stuff */
 
     free(ti);
@@ -1755,8 +1756,8 @@
     while (1) {
         (void) ap_update_child_status(process_slot, thread_slot, SERVER_READY, 
 				  (request_rec *) NULL);
-        csd = get_request(&sa_client);
-	if (csd < 0) {
+        csd = get_request(ptrans, &sa_client);
+	if (csd == NULL) {
             break;
         } 
         process_socket(ptrans, &sa_client, csd, process_slot, thread_slot);


_______________________________________________________________________
Ryan Bloom		rbb@raleigh.ibm.com
4205 S Miami Blvd	
RTP, NC 27709		It's a beautiful sight to see good dancers 
			doing simple steps.  It's a painful sight to
			see beginners doing complicated patterns.	


Mime
View raw message