├── buffered-echo-server ├── Makefile ├── README.txt └── libevent_echosrv_buffered.c ├── chat-server ├── Makefile ├── README.txt ├── chat-server.c └── queue.h └── echo-server ├── Makefile ├── README.txt ├── libevent_echosrv1.c ├── libevent_echosrv2.c └── queue.h /buffered-echo-server/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS = -I$(LIBEVENT) -Wall 2 | LIBS = $(LIBEVENT)/.libs/libevent.a -lrt 3 | 4 | libevent_echosrv_buffered: libevent_echosrv_buffered.c 5 | $(CC) $(CFLAGS) -o $@ libevent_echosrv_buffered.c $(LIBS) 6 | clean: 7 | rm -f libevent_echosrv_buffered *~ 8 | -------------------------------------------------------------------------------- /buffered-echo-server/README.txt: -------------------------------------------------------------------------------- 1 | Libevent buffered event echo server example 2 | ------------------------------------------------------------------------------- 3 | 4 | NOTE: These examples were built back in the libevent 1 days. I 5 | suggest new applications use libevent 2. Excellent documentation for 6 | the libevent 2 API can be found in the libevent book including an echo 7 | server example. 8 | 9 | http://www.wangafu.net/~nickm/libevent-book/ 10 | 11 | First you must download and build libevent, you do not need to install 12 | it. 13 | libevent homepage: http://www.monkey.org/~provos/libevent/ 14 | 15 | To build libevent_echosrv: 16 | 17 | LIBEVENT=~/src/libevent-1.1a make 18 | 19 | where LIBEVENT points to the location of your built libevent. 20 | 21 | USAGE 22 | 23 | Run the server: 24 | 25 | ./libevent_echosrv_buffered 26 | 27 | Then telnet to localhost port 5555. Anything you type will be 28 | echoed back to you. 29 | 30 | -- 31 | Jason Ish 32 | -------------------------------------------------------------------------------- /buffered-echo-server/libevent_echosrv_buffered.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * Copyright (c) 2011 Jason Ish 4 | * 5 | * Permission is hereby granted, free of charge, to any person 6 | * obtaining a copy of this software and associated documentation 7 | * files (the "Software"), to deal in the Software without 8 | * restriction, including without limitation the rights to use, copy, 9 | * modify, merge, publish, distribute, sublicense, and/or sell copies 10 | * of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | * DEALINGS IN THE SOFTWARE. 24 | */ 25 | 26 | /* 27 | * libevent echo server example using buffered events. 28 | */ 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | /* Required by event.h. */ 36 | #include 37 | 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | /* Libevent. */ 47 | #include 48 | 49 | /* Port to listen on. */ 50 | #define SERVER_PORT 5555 51 | 52 | /** 53 | * A struct for client specific data, also includes pointer to create 54 | * a list of clients. 55 | */ 56 | struct client { 57 | /* The clients socket. */ 58 | int fd; 59 | 60 | /* The bufferedevent for this client. */ 61 | struct bufferevent *buf_ev; 62 | }; 63 | 64 | /** 65 | * Set a socket to non-blocking mode. 66 | */ 67 | int 68 | setnonblock(int fd) 69 | { 70 | int flags; 71 | 72 | flags = fcntl(fd, F_GETFL); 73 | if (flags < 0) 74 | return flags; 75 | flags |= O_NONBLOCK; 76 | if (fcntl(fd, F_SETFL, flags) < 0) 77 | return -1; 78 | 79 | return 0; 80 | } 81 | 82 | /** 83 | * Called by libevent when there is data to read. 84 | */ 85 | void 86 | buffered_on_read(struct bufferevent *bev, void *arg) 87 | { 88 | /* Write back the read buffer. It is important to note that 89 | * bufferevent_write_buffer will drain the incoming data so it 90 | * is effectively gone after we call it. */ 91 | bufferevent_write_buffer(bev, bev->input); 92 | } 93 | 94 | /** 95 | * Called by libevent when the write buffer reaches 0. We only 96 | * provide this because libevent expects it, but we don't use it. 97 | */ 98 | void 99 | buffered_on_write(struct bufferevent *bev, void *arg) 100 | { 101 | } 102 | 103 | /** 104 | * Called by libevent when there is an error on the underlying socket 105 | * descriptor. 106 | */ 107 | void 108 | buffered_on_error(struct bufferevent *bev, short what, void *arg) 109 | { 110 | struct client *client = (struct client *)arg; 111 | 112 | if (what & EVBUFFER_EOF) { 113 | /* Client disconnected, remove the read event and the 114 | * free the client structure. */ 115 | printf("Client disconnected.\n"); 116 | } 117 | else { 118 | warn("Client socket error, disconnecting.\n"); 119 | } 120 | bufferevent_free(client->buf_ev); 121 | close(client->fd); 122 | free(client); 123 | } 124 | 125 | /** 126 | * This function will be called by libevent when there is a connection 127 | * ready to be accepted. 128 | */ 129 | void 130 | on_accept(int fd, short ev, void *arg) 131 | { 132 | int client_fd; 133 | struct sockaddr_in client_addr; 134 | socklen_t client_len = sizeof(client_addr); 135 | struct client *client; 136 | 137 | client_fd = accept(fd, (struct sockaddr *)&client_addr, &client_len); 138 | if (client_fd < 0) { 139 | warn("accept failed"); 140 | return; 141 | } 142 | 143 | /* Set the client socket to non-blocking mode. */ 144 | if (setnonblock(client_fd) < 0) 145 | warn("failed to set client socket non-blocking"); 146 | 147 | /* We've accepted a new client, create a client object. */ 148 | client = calloc(1, sizeof(*client)); 149 | if (client == NULL) 150 | err(1, "malloc failed"); 151 | client->fd = client_fd; 152 | 153 | /* Create the buffered event. 154 | * 155 | * The first argument is the file descriptor that will trigger 156 | * the events, in this case the clients socket. 157 | * 158 | * The second argument is the callback that will be called 159 | * when data has been read from the socket and is available to 160 | * the application. 161 | * 162 | * The third argument is a callback to a function that will be 163 | * called when the write buffer has reached a low watermark. 164 | * That usually means that when the write buffer is 0 length, 165 | * this callback will be called. It must be defined, but you 166 | * don't actually have to do anything in this callback. 167 | * 168 | * The fourth argument is a callback that will be called when 169 | * there is a socket error. This is where you will detect 170 | * that the client disconnected or other socket errors. 171 | * 172 | * The fifth and final argument is to store an argument in 173 | * that will be passed to the callbacks. We store the client 174 | * object here. 175 | */ 176 | client->buf_ev = bufferevent_new(client_fd, buffered_on_read, 177 | buffered_on_write, buffered_on_error, client); 178 | 179 | /* We have to enable it before our callbacks will be 180 | * called. */ 181 | bufferevent_enable(client->buf_ev, EV_READ); 182 | 183 | printf("Accepted connection from %s\n", 184 | inet_ntoa(client_addr.sin_addr)); 185 | } 186 | 187 | int 188 | main(int argc, char **argv) 189 | { 190 | int listen_fd; 191 | struct sockaddr_in listen_addr; 192 | struct event ev_accept; 193 | int reuseaddr_on; 194 | 195 | /* Initialize libevent. */ 196 | event_init(); 197 | 198 | /* Create our listening socket. */ 199 | listen_fd = socket(AF_INET, SOCK_STREAM, 0); 200 | if (listen_fd < 0) 201 | err(1, "listen failed"); 202 | memset(&listen_addr, 0, sizeof(listen_addr)); 203 | listen_addr.sin_family = AF_INET; 204 | listen_addr.sin_addr.s_addr = INADDR_ANY; 205 | listen_addr.sin_port = htons(SERVER_PORT); 206 | if (bind(listen_fd, (struct sockaddr *)&listen_addr, 207 | sizeof(listen_addr)) < 0) 208 | err(1, "bind failed"); 209 | if (listen(listen_fd, 5) < 0) 210 | err(1, "listen failed"); 211 | reuseaddr_on = 1; 212 | setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr_on, 213 | sizeof(reuseaddr_on)); 214 | 215 | /* Set the socket to non-blocking, this is essential in event 216 | * based programming with libevent. */ 217 | if (setnonblock(listen_fd) < 0) 218 | err(1, "failed to set server socket to non-blocking"); 219 | 220 | /* We now have a listening socket, we create a read event to 221 | * be notified when a client connects. */ 222 | event_set(&ev_accept, listen_fd, EV_READ|EV_PERSIST, on_accept, NULL); 223 | event_add(&ev_accept, NULL); 224 | 225 | /* Start the event loop. */ 226 | event_dispatch(); 227 | 228 | return 0; 229 | } 230 | -------------------------------------------------------------------------------- /chat-server/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS = -I$(LIBEVENT)/include -Wall 2 | 3 | LIBS = $(LIBEVENT)/.libs/libevent.a -lrt 4 | 5 | chat-server: chat-server.c 6 | $(CC) $(CFLAGS) -o $@ $^ $(LIBS) 7 | 8 | clean: 9 | rm -f chat-server *~ 10 | -------------------------------------------------------------------------------- /chat-server/README.txt: -------------------------------------------------------------------------------- 1 | A simple chat server using libevent. 2 | ------------------------------------------------------------------------------- 3 | 4 | Requires libevent 2.0+. 5 | 6 | First you must download and build libevent, you do not need to install 7 | it. 8 | 9 | libevent homepage: http://www.monkey.org/~provos/libevent/ 10 | 11 | To build libevent_echosrv: 12 | 13 | LIBEVENT=~/src/libevent-2.0.12-stable make 14 | 15 | where LIBEVENT points to the location of your built libevent. 16 | 17 | USAGE 18 | 19 | Run the server: 20 | 21 | ./chat-server 22 | 23 | Then telnet to localhost port 5555 from multiple terminals. 24 | Anything you type in one terminal will be sent to the other 25 | connected terminals. 26 | 27 | -- 28 | Jason Ish 29 | -------------------------------------------------------------------------------- /chat-server/chat-server.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * Copyright (c) 2011 Jason Ish 4 | * 5 | * Permission is hereby granted, free of charge, to any person 6 | * obtaining a copy of this software and associated documentation 7 | * files (the "Software"), to deal in the Software without 8 | * restriction, including without limitation the rights to use, copy, 9 | * modify, merge, publish, distribute, sublicense, and/or sell copies 10 | * of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | * DEALINGS IN THE SOFTWARE. 24 | */ 25 | 26 | /* 27 | * A simple chat server using libevent. 28 | * 29 | * @todo Check API usage with libevent2 proper API usage. 30 | * @todo IPv6 support - using libevent socket helpers, if any. 31 | */ 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | /* Required by event.h. */ 39 | #include 40 | 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | 49 | /* On some systems (OpenBSD/NetBSD/FreeBSD) you could include 50 | * , but for portability we'll include the local copy. */ 51 | #include "queue.h" 52 | 53 | /* Libevent. */ 54 | #include 55 | #include 56 | #include 57 | #include 58 | 59 | /* Port to listen on. */ 60 | #define SERVER_PORT 5555 61 | 62 | /* The libevent event base. In libevent 1 you didn't need to worry 63 | * about this for simple programs, but its used more in the libevent 2 64 | * API. */ 65 | static struct event_base *evbase; 66 | 67 | /** 68 | * A struct for client specific data. 69 | * 70 | * This also includes the tailq entry item so this struct can become a 71 | * member of a tailq - the linked list of all connected clients. 72 | */ 73 | struct client { 74 | /* The clients socket. */ 75 | int fd; 76 | 77 | /* The bufferedevent for this client. */ 78 | struct bufferevent *buf_ev; 79 | 80 | /* 81 | * This holds the pointers to the next and previous entries in 82 | * the tail queue. 83 | */ 84 | TAILQ_ENTRY(client) entries; 85 | }; 86 | 87 | /** 88 | * The head of our tailq of all connected clients. This is what will 89 | * be iterated to send a received message to all connected clients. 90 | */ 91 | TAILQ_HEAD(, client) client_tailq_head; 92 | 93 | /** 94 | * Set a socket to non-blocking mode. 95 | */ 96 | int 97 | setnonblock(int fd) 98 | { 99 | int flags; 100 | 101 | flags = fcntl(fd, F_GETFL); 102 | if (flags < 0) 103 | return flags; 104 | flags |= O_NONBLOCK; 105 | if (fcntl(fd, F_SETFL, flags) < 0) 106 | return -1; 107 | 108 | return 0; 109 | } 110 | 111 | /** 112 | * Called by libevent when there is data to read. 113 | */ 114 | void 115 | buffered_on_read(struct bufferevent *bev, void *arg) 116 | { 117 | struct client *this_client = arg; 118 | struct client *client; 119 | uint8_t data[8192]; 120 | size_t n; 121 | 122 | /* Read 8k at a time and send it to all connected clients. */ 123 | for (;;) { 124 | n = bufferevent_read(bev, data, sizeof(data)); 125 | if (n <= 0) { 126 | /* Done. */ 127 | break; 128 | } 129 | 130 | /* Send data to all connected clients except for the 131 | * client that sent the data. */ 132 | TAILQ_FOREACH(client, &client_tailq_head, entries) { 133 | if (client != this_client) { 134 | bufferevent_write(client->buf_ev, data, n); 135 | } 136 | } 137 | } 138 | 139 | } 140 | 141 | /** 142 | * Called by libevent when there is an error on the underlying socket 143 | * descriptor. 144 | */ 145 | void 146 | buffered_on_error(struct bufferevent *bev, short what, void *arg) 147 | { 148 | struct client *client = (struct client *)arg; 149 | 150 | if (what & BEV_EVENT_EOF) { 151 | /* Client disconnected, remove the read event and the 152 | * free the client structure. */ 153 | printf("Client disconnected.\n"); 154 | } 155 | else { 156 | warn("Client socket error, disconnecting.\n"); 157 | } 158 | 159 | /* Remove the client from the tailq. */ 160 | TAILQ_REMOVE(&client_tailq_head, client, entries); 161 | 162 | bufferevent_free(client->buf_ev); 163 | close(client->fd); 164 | free(client); 165 | } 166 | 167 | /** 168 | * This function will be called by libevent when there is a connection 169 | * ready to be accepted. 170 | */ 171 | void 172 | on_accept(int fd, short ev, void *arg) 173 | { 174 | int client_fd; 175 | struct sockaddr_in client_addr; 176 | socklen_t client_len = sizeof(client_addr); 177 | struct client *client; 178 | 179 | client_fd = accept(fd, (struct sockaddr *)&client_addr, &client_len); 180 | if (client_fd < 0) { 181 | warn("accept failed"); 182 | return; 183 | } 184 | 185 | /* Set the client socket to non-blocking mode. */ 186 | if (setnonblock(client_fd) < 0) 187 | warn("failed to set client socket non-blocking"); 188 | 189 | /* We've accepted a new client, create a client object. */ 190 | client = calloc(1, sizeof(*client)); 191 | if (client == NULL) 192 | err(1, "malloc failed"); 193 | client->fd = client_fd; 194 | 195 | client->buf_ev = bufferevent_socket_new(evbase, client_fd, 0); 196 | bufferevent_setcb(client->buf_ev, buffered_on_read, NULL, 197 | buffered_on_error, client); 198 | 199 | /* We have to enable it before our callbacks will be 200 | * called. */ 201 | bufferevent_enable(client->buf_ev, EV_READ); 202 | 203 | /* Add the new client to the tailq. */ 204 | TAILQ_INSERT_TAIL(&client_tailq_head, client, entries); 205 | 206 | printf("Accepted connection from %s\n", 207 | inet_ntoa(client_addr.sin_addr)); 208 | } 209 | 210 | int 211 | main(int argc, char **argv) 212 | { 213 | int listen_fd; 214 | struct sockaddr_in listen_addr; 215 | struct event ev_accept; 216 | int reuseaddr_on; 217 | 218 | /* Initialize libevent. */ 219 | evbase = event_base_new(); 220 | 221 | /* Initialize the tailq. */ 222 | TAILQ_INIT(&client_tailq_head); 223 | 224 | /* Create our listening socket. */ 225 | listen_fd = socket(AF_INET, SOCK_STREAM, 0); 226 | if (listen_fd < 0) 227 | err(1, "listen failed"); 228 | memset(&listen_addr, 0, sizeof(listen_addr)); 229 | listen_addr.sin_family = AF_INET; 230 | listen_addr.sin_addr.s_addr = INADDR_ANY; 231 | listen_addr.sin_port = htons(SERVER_PORT); 232 | if (bind(listen_fd, (struct sockaddr *)&listen_addr, 233 | sizeof(listen_addr)) < 0) 234 | err(1, "bind failed"); 235 | if (listen(listen_fd, 5) < 0) 236 | err(1, "listen failed"); 237 | reuseaddr_on = 1; 238 | setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr_on, 239 | sizeof(reuseaddr_on)); 240 | 241 | /* Set the socket to non-blocking, this is essential in event 242 | * based programming with libevent. */ 243 | if (setnonblock(listen_fd) < 0) 244 | err(1, "failed to set server socket to non-blocking"); 245 | 246 | /* We now have a listening socket, we create a read event to 247 | * be notified when a client connects. */ 248 | event_assign(&ev_accept, evbase, listen_fd, EV_READ|EV_PERSIST, 249 | on_accept, NULL); 250 | event_add(&ev_accept, NULL); 251 | 252 | /* Start the event loop. */ 253 | event_base_dispatch(evbase); 254 | 255 | return 0; 256 | } 257 | -------------------------------------------------------------------------------- /chat-server/queue.h: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: queue.h,v 1.31 2005/11/25 08:06:25 otto Exp $ */ 2 | /* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */ 3 | 4 | /* 5 | * Copyright (c) 1991, 1993 6 | * The Regents of the University of California. All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 1. Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 3. Neither the name of the University nor the names of its contributors 17 | * may be used to endorse or promote products derived from this software 18 | * without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 | * SUCH DAMAGE. 31 | * 32 | * @(#)queue.h 8.5 (Berkeley) 8/20/94 33 | */ 34 | 35 | #ifndef _SYS_QUEUE_H_ 36 | #define _SYS_QUEUE_H_ 37 | 38 | /* 39 | * This file defines five types of data structures: singly-linked lists, 40 | * lists, simple queues, tail queues, and circular queues. 41 | * 42 | * 43 | * A singly-linked list is headed by a single forward pointer. The elements 44 | * are singly linked for minimum space and pointer manipulation overhead at 45 | * the expense of O(n) removal for arbitrary elements. New elements can be 46 | * added to the list after an existing element or at the head of the list. 47 | * Elements being removed from the head of the list should use the explicit 48 | * macro for this purpose for optimum efficiency. A singly-linked list may 49 | * only be traversed in the forward direction. Singly-linked lists are ideal 50 | * for applications with large datasets and few or no removals or for 51 | * implementing a LIFO queue. 52 | * 53 | * A list is headed by a single forward pointer (or an array of forward 54 | * pointers for a hash table header). The elements are doubly linked 55 | * so that an arbitrary element can be removed without a need to 56 | * traverse the list. New elements can be added to the list before 57 | * or after an existing element or at the head of the list. A list 58 | * may only be traversed in the forward direction. 59 | * 60 | * A simple queue is headed by a pair of pointers, one the head of the 61 | * list and the other to the tail of the list. The elements are singly 62 | * linked to save space, so elements can only be removed from the 63 | * head of the list. New elements can be added to the list before or after 64 | * an existing element, at the head of the list, or at the end of the 65 | * list. A simple queue may only be traversed in the forward direction. 66 | * 67 | * A tail queue is headed by a pair of pointers, one to the head of the 68 | * list and the other to the tail of the list. The elements are doubly 69 | * linked so that an arbitrary element can be removed without a need to 70 | * traverse the list. New elements can be added to the list before or 71 | * after an existing element, at the head of the list, or at the end of 72 | * the list. A tail queue may be traversed in either direction. 73 | * 74 | * A circle queue is headed by a pair of pointers, one to the head of the 75 | * list and the other to the tail of the list. The elements are doubly 76 | * linked so that an arbitrary element can be removed without a need to 77 | * traverse the list. New elements can be added to the list before or after 78 | * an existing element, at the head of the list, or at the end of the list. 79 | * A circle queue may be traversed in either direction, but has a more 80 | * complex end of list detection. 81 | * 82 | * For details on the use of these macros, see the queue(3) manual page. 83 | */ 84 | 85 | #ifdef QUEUE_MACRO_DEBUG 86 | #define _Q_INVALIDATE(a) (a) = ((void *)-1) 87 | #else 88 | #define _Q_INVALIDATE(a) 89 | #endif 90 | 91 | /* 92 | * Singly-linked List definitions. 93 | */ 94 | #define SLIST_HEAD(name, type) \ 95 | struct name { \ 96 | struct type *slh_first; /* first element */ \ 97 | } 98 | 99 | #define SLIST_HEAD_INITIALIZER(head) \ 100 | { NULL } 101 | 102 | #define SLIST_ENTRY(type) \ 103 | struct { \ 104 | struct type *sle_next; /* next element */ \ 105 | } 106 | 107 | /* 108 | * Singly-linked List access methods. 109 | */ 110 | #define SLIST_FIRST(head) ((head)->slh_first) 111 | #define SLIST_END(head) NULL 112 | #define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head)) 113 | #define SLIST_NEXT(elm, field) ((elm)->field.sle_next) 114 | 115 | #define SLIST_FOREACH(var, head, field) \ 116 | for((var) = SLIST_FIRST(head); \ 117 | (var) != SLIST_END(head); \ 118 | (var) = SLIST_NEXT(var, field)) 119 | 120 | #define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ 121 | for ((varp) = &SLIST_FIRST((head)); \ 122 | ((var) = *(varp)) != SLIST_END(head); \ 123 | (varp) = &SLIST_NEXT((var), field)) 124 | 125 | /* 126 | * Singly-linked List functions. 127 | */ 128 | #define SLIST_INIT(head) { \ 129 | SLIST_FIRST(head) = SLIST_END(head); \ 130 | } 131 | 132 | #define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ 133 | (elm)->field.sle_next = (slistelm)->field.sle_next; \ 134 | (slistelm)->field.sle_next = (elm); \ 135 | } while (0) 136 | 137 | #define SLIST_INSERT_HEAD(head, elm, field) do { \ 138 | (elm)->field.sle_next = (head)->slh_first; \ 139 | (head)->slh_first = (elm); \ 140 | } while (0) 141 | 142 | #define SLIST_REMOVE_NEXT(head, elm, field) do { \ 143 | (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \ 144 | } while (0) 145 | 146 | #define SLIST_REMOVE_HEAD(head, field) do { \ 147 | (head)->slh_first = (head)->slh_first->field.sle_next; \ 148 | } while (0) 149 | 150 | #define SLIST_REMOVE(head, elm, type, field) do { \ 151 | if ((head)->slh_first == (elm)) { \ 152 | SLIST_REMOVE_HEAD((head), field); \ 153 | } else { \ 154 | struct type *curelm = (head)->slh_first; \ 155 | \ 156 | while (curelm->field.sle_next != (elm)) \ 157 | curelm = curelm->field.sle_next; \ 158 | curelm->field.sle_next = \ 159 | curelm->field.sle_next->field.sle_next; \ 160 | _Q_INVALIDATE((elm)->field.sle_next); \ 161 | } \ 162 | } while (0) 163 | 164 | /* 165 | * List definitions. 166 | */ 167 | #define LIST_HEAD(name, type) \ 168 | struct name { \ 169 | struct type *lh_first; /* first element */ \ 170 | } 171 | 172 | #define LIST_HEAD_INITIALIZER(head) \ 173 | { NULL } 174 | 175 | #define LIST_ENTRY(type) \ 176 | struct { \ 177 | struct type *le_next; /* next element */ \ 178 | struct type **le_prev; /* address of previous next element */ \ 179 | } 180 | 181 | /* 182 | * List access methods 183 | */ 184 | #define LIST_FIRST(head) ((head)->lh_first) 185 | #define LIST_END(head) NULL 186 | #define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head)) 187 | #define LIST_NEXT(elm, field) ((elm)->field.le_next) 188 | 189 | #define LIST_FOREACH(var, head, field) \ 190 | for((var) = LIST_FIRST(head); \ 191 | (var)!= LIST_END(head); \ 192 | (var) = LIST_NEXT(var, field)) 193 | 194 | /* 195 | * List functions. 196 | */ 197 | #define LIST_INIT(head) do { \ 198 | LIST_FIRST(head) = LIST_END(head); \ 199 | } while (0) 200 | 201 | #define LIST_INSERT_AFTER(listelm, elm, field) do { \ 202 | if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ 203 | (listelm)->field.le_next->field.le_prev = \ 204 | &(elm)->field.le_next; \ 205 | (listelm)->field.le_next = (elm); \ 206 | (elm)->field.le_prev = &(listelm)->field.le_next; \ 207 | } while (0) 208 | 209 | #define LIST_INSERT_BEFORE(listelm, elm, field) do { \ 210 | (elm)->field.le_prev = (listelm)->field.le_prev; \ 211 | (elm)->field.le_next = (listelm); \ 212 | *(listelm)->field.le_prev = (elm); \ 213 | (listelm)->field.le_prev = &(elm)->field.le_next; \ 214 | } while (0) 215 | 216 | #define LIST_INSERT_HEAD(head, elm, field) do { \ 217 | if (((elm)->field.le_next = (head)->lh_first) != NULL) \ 218 | (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ 219 | (head)->lh_first = (elm); \ 220 | (elm)->field.le_prev = &(head)->lh_first; \ 221 | } while (0) 222 | 223 | #define LIST_REMOVE(elm, field) do { \ 224 | if ((elm)->field.le_next != NULL) \ 225 | (elm)->field.le_next->field.le_prev = \ 226 | (elm)->field.le_prev; \ 227 | *(elm)->field.le_prev = (elm)->field.le_next; \ 228 | _Q_INVALIDATE((elm)->field.le_prev); \ 229 | _Q_INVALIDATE((elm)->field.le_next); \ 230 | } while (0) 231 | 232 | #define LIST_REPLACE(elm, elm2, field) do { \ 233 | if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ 234 | (elm2)->field.le_next->field.le_prev = \ 235 | &(elm2)->field.le_next; \ 236 | (elm2)->field.le_prev = (elm)->field.le_prev; \ 237 | *(elm2)->field.le_prev = (elm2); \ 238 | _Q_INVALIDATE((elm)->field.le_prev); \ 239 | _Q_INVALIDATE((elm)->field.le_next); \ 240 | } while (0) 241 | 242 | /* 243 | * Simple queue definitions. 244 | */ 245 | #define SIMPLEQ_HEAD(name, type) \ 246 | struct name { \ 247 | struct type *sqh_first; /* first element */ \ 248 | struct type **sqh_last; /* addr of last next element */ \ 249 | } 250 | 251 | #define SIMPLEQ_HEAD_INITIALIZER(head) \ 252 | { NULL, &(head).sqh_first } 253 | 254 | #define SIMPLEQ_ENTRY(type) \ 255 | struct { \ 256 | struct type *sqe_next; /* next element */ \ 257 | } 258 | 259 | /* 260 | * Simple queue access methods. 261 | */ 262 | #define SIMPLEQ_FIRST(head) ((head)->sqh_first) 263 | #define SIMPLEQ_END(head) NULL 264 | #define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head)) 265 | #define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) 266 | 267 | #define SIMPLEQ_FOREACH(var, head, field) \ 268 | for((var) = SIMPLEQ_FIRST(head); \ 269 | (var) != SIMPLEQ_END(head); \ 270 | (var) = SIMPLEQ_NEXT(var, field)) 271 | 272 | /* 273 | * Simple queue functions. 274 | */ 275 | #define SIMPLEQ_INIT(head) do { \ 276 | (head)->sqh_first = NULL; \ 277 | (head)->sqh_last = &(head)->sqh_first; \ 278 | } while (0) 279 | 280 | #define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ 281 | if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ 282 | (head)->sqh_last = &(elm)->field.sqe_next; \ 283 | (head)->sqh_first = (elm); \ 284 | } while (0) 285 | 286 | #define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ 287 | (elm)->field.sqe_next = NULL; \ 288 | *(head)->sqh_last = (elm); \ 289 | (head)->sqh_last = &(elm)->field.sqe_next; \ 290 | } while (0) 291 | 292 | #define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ 293 | if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ 294 | (head)->sqh_last = &(elm)->field.sqe_next; \ 295 | (listelm)->field.sqe_next = (elm); \ 296 | } while (0) 297 | 298 | #define SIMPLEQ_REMOVE_HEAD(head, field) do { \ 299 | if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ 300 | (head)->sqh_last = &(head)->sqh_first; \ 301 | } while (0) 302 | 303 | /* 304 | * Tail queue definitions. 305 | */ 306 | #define TAILQ_HEAD(name, type) \ 307 | struct name { \ 308 | struct type *tqh_first; /* first element */ \ 309 | struct type **tqh_last; /* addr of last next element */ \ 310 | } 311 | 312 | #define TAILQ_HEAD_INITIALIZER(head) \ 313 | { NULL, &(head).tqh_first } 314 | 315 | #define TAILQ_ENTRY(type) \ 316 | struct { \ 317 | struct type *tqe_next; /* next element */ \ 318 | struct type **tqe_prev; /* address of previous next element */ \ 319 | } 320 | 321 | /* 322 | * tail queue access methods 323 | */ 324 | #define TAILQ_FIRST(head) ((head)->tqh_first) 325 | #define TAILQ_END(head) NULL 326 | #define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) 327 | #define TAILQ_LAST(head, headname) \ 328 | (*(((struct headname *)((head)->tqh_last))->tqh_last)) 329 | /* XXX */ 330 | #define TAILQ_PREV(elm, headname, field) \ 331 | (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) 332 | #define TAILQ_EMPTY(head) \ 333 | (TAILQ_FIRST(head) == TAILQ_END(head)) 334 | 335 | #define TAILQ_FOREACH(var, head, field) \ 336 | for((var) = TAILQ_FIRST(head); \ 337 | (var) != TAILQ_END(head); \ 338 | (var) = TAILQ_NEXT(var, field)) 339 | 340 | #define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ 341 | for((var) = TAILQ_LAST(head, headname); \ 342 | (var) != TAILQ_END(head); \ 343 | (var) = TAILQ_PREV(var, headname, field)) 344 | 345 | /* 346 | * Tail queue functions. 347 | */ 348 | #define TAILQ_INIT(head) do { \ 349 | (head)->tqh_first = NULL; \ 350 | (head)->tqh_last = &(head)->tqh_first; \ 351 | } while (0) 352 | 353 | #define TAILQ_INSERT_HEAD(head, elm, field) do { \ 354 | if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ 355 | (head)->tqh_first->field.tqe_prev = \ 356 | &(elm)->field.tqe_next; \ 357 | else \ 358 | (head)->tqh_last = &(elm)->field.tqe_next; \ 359 | (head)->tqh_first = (elm); \ 360 | (elm)->field.tqe_prev = &(head)->tqh_first; \ 361 | } while (0) 362 | 363 | #define TAILQ_INSERT_TAIL(head, elm, field) do { \ 364 | (elm)->field.tqe_next = NULL; \ 365 | (elm)->field.tqe_prev = (head)->tqh_last; \ 366 | *(head)->tqh_last = (elm); \ 367 | (head)->tqh_last = &(elm)->field.tqe_next; \ 368 | } while (0) 369 | 370 | #define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ 371 | if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ 372 | (elm)->field.tqe_next->field.tqe_prev = \ 373 | &(elm)->field.tqe_next; \ 374 | else \ 375 | (head)->tqh_last = &(elm)->field.tqe_next; \ 376 | (listelm)->field.tqe_next = (elm); \ 377 | (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ 378 | } while (0) 379 | 380 | #define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ 381 | (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ 382 | (elm)->field.tqe_next = (listelm); \ 383 | *(listelm)->field.tqe_prev = (elm); \ 384 | (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ 385 | } while (0) 386 | 387 | #define TAILQ_REMOVE(head, elm, field) do { \ 388 | if (((elm)->field.tqe_next) != NULL) \ 389 | (elm)->field.tqe_next->field.tqe_prev = \ 390 | (elm)->field.tqe_prev; \ 391 | else \ 392 | (head)->tqh_last = (elm)->field.tqe_prev; \ 393 | *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ 394 | _Q_INVALIDATE((elm)->field.tqe_prev); \ 395 | _Q_INVALIDATE((elm)->field.tqe_next); \ 396 | } while (0) 397 | 398 | #define TAILQ_REPLACE(head, elm, elm2, field) do { \ 399 | if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \ 400 | (elm2)->field.tqe_next->field.tqe_prev = \ 401 | &(elm2)->field.tqe_next; \ 402 | else \ 403 | (head)->tqh_last = &(elm2)->field.tqe_next; \ 404 | (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ 405 | *(elm2)->field.tqe_prev = (elm2); \ 406 | _Q_INVALIDATE((elm)->field.tqe_prev); \ 407 | _Q_INVALIDATE((elm)->field.tqe_next); \ 408 | } while (0) 409 | 410 | /* 411 | * Circular queue definitions. 412 | */ 413 | #define CIRCLEQ_HEAD(name, type) \ 414 | struct name { \ 415 | struct type *cqh_first; /* first element */ \ 416 | struct type *cqh_last; /* last element */ \ 417 | } 418 | 419 | #define CIRCLEQ_HEAD_INITIALIZER(head) \ 420 | { CIRCLEQ_END(&head), CIRCLEQ_END(&head) } 421 | 422 | #define CIRCLEQ_ENTRY(type) \ 423 | struct { \ 424 | struct type *cqe_next; /* next element */ \ 425 | struct type *cqe_prev; /* previous element */ \ 426 | } 427 | 428 | /* 429 | * Circular queue access methods 430 | */ 431 | #define CIRCLEQ_FIRST(head) ((head)->cqh_first) 432 | #define CIRCLEQ_LAST(head) ((head)->cqh_last) 433 | #define CIRCLEQ_END(head) ((void *)(head)) 434 | #define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) 435 | #define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) 436 | #define CIRCLEQ_EMPTY(head) \ 437 | (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head)) 438 | 439 | #define CIRCLEQ_FOREACH(var, head, field) \ 440 | for((var) = CIRCLEQ_FIRST(head); \ 441 | (var) != CIRCLEQ_END(head); \ 442 | (var) = CIRCLEQ_NEXT(var, field)) 443 | 444 | #define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ 445 | for((var) = CIRCLEQ_LAST(head); \ 446 | (var) != CIRCLEQ_END(head); \ 447 | (var) = CIRCLEQ_PREV(var, field)) 448 | 449 | /* 450 | * Circular queue functions. 451 | */ 452 | #define CIRCLEQ_INIT(head) do { \ 453 | (head)->cqh_first = CIRCLEQ_END(head); \ 454 | (head)->cqh_last = CIRCLEQ_END(head); \ 455 | } while (0) 456 | 457 | #define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ 458 | (elm)->field.cqe_next = (listelm)->field.cqe_next; \ 459 | (elm)->field.cqe_prev = (listelm); \ 460 | if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \ 461 | (head)->cqh_last = (elm); \ 462 | else \ 463 | (listelm)->field.cqe_next->field.cqe_prev = (elm); \ 464 | (listelm)->field.cqe_next = (elm); \ 465 | } while (0) 466 | 467 | #define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ 468 | (elm)->field.cqe_next = (listelm); \ 469 | (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ 470 | if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \ 471 | (head)->cqh_first = (elm); \ 472 | else \ 473 | (listelm)->field.cqe_prev->field.cqe_next = (elm); \ 474 | (listelm)->field.cqe_prev = (elm); \ 475 | } while (0) 476 | 477 | #define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ 478 | (elm)->field.cqe_next = (head)->cqh_first; \ 479 | (elm)->field.cqe_prev = CIRCLEQ_END(head); \ 480 | if ((head)->cqh_last == CIRCLEQ_END(head)) \ 481 | (head)->cqh_last = (elm); \ 482 | else \ 483 | (head)->cqh_first->field.cqe_prev = (elm); \ 484 | (head)->cqh_first = (elm); \ 485 | } while (0) 486 | 487 | #define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ 488 | (elm)->field.cqe_next = CIRCLEQ_END(head); \ 489 | (elm)->field.cqe_prev = (head)->cqh_last; \ 490 | if ((head)->cqh_first == CIRCLEQ_END(head)) \ 491 | (head)->cqh_first = (elm); \ 492 | else \ 493 | (head)->cqh_last->field.cqe_next = (elm); \ 494 | (head)->cqh_last = (elm); \ 495 | } while (0) 496 | 497 | #define CIRCLEQ_REMOVE(head, elm, field) do { \ 498 | if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \ 499 | (head)->cqh_last = (elm)->field.cqe_prev; \ 500 | else \ 501 | (elm)->field.cqe_next->field.cqe_prev = \ 502 | (elm)->field.cqe_prev; \ 503 | if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \ 504 | (head)->cqh_first = (elm)->field.cqe_next; \ 505 | else \ 506 | (elm)->field.cqe_prev->field.cqe_next = \ 507 | (elm)->field.cqe_next; \ 508 | _Q_INVALIDATE((elm)->field.cqe_prev); \ 509 | _Q_INVALIDATE((elm)->field.cqe_next); \ 510 | } while (0) 511 | 512 | #define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \ 513 | if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \ 514 | CIRCLEQ_END(head)) \ 515 | (head).cqh_last = (elm2); \ 516 | else \ 517 | (elm2)->field.cqe_next->field.cqe_prev = (elm2); \ 518 | if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \ 519 | CIRCLEQ_END(head)) \ 520 | (head).cqh_first = (elm2); \ 521 | else \ 522 | (elm2)->field.cqe_prev->field.cqe_next = (elm2); \ 523 | _Q_INVALIDATE((elm)->field.cqe_prev); \ 524 | _Q_INVALIDATE((elm)->field.cqe_next); \ 525 | } while (0) 526 | 527 | #endif /* !_SYS_QUEUE_H_ */ 528 | -------------------------------------------------------------------------------- /echo-server/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS = -I$(LIBEVENT) -Wall 2 | LIBS = $(LIBEVENT)/.libs/libevent.a -lrt 3 | 4 | all: libevent_echosrv1 libevent_echosrv2 5 | 6 | 7 | libevent_echosrv1: libevent_echosrv1.c 8 | $(CC) $(CFLAGS) -g -O2 -o $@ libevent_echosrv1.c $(LIBS) 9 | 10 | libevent_echosrv2: libevent_echosrv2.c 11 | $(CC) $(CFLAGS) -g -O2 -o $@ libevent_echosrv2.c $(LIBS) 12 | 13 | clean: 14 | rm -f libevent_echosrv1 libevent_echosrv2 *~ 15 | 16 | -------------------------------------------------------------------------------- /echo-server/README.txt: -------------------------------------------------------------------------------- 1 | Libevent based echo server example 2 | ------------------------------------------------------------------------------- 3 | 4 | NOTE: These examples were built back in the libevent 1 days. I 5 | suggest new applications use libevent 2. Excellent documentation for 6 | the libevent 2 API can be found in the libevent book include an echo 7 | server example. 8 | 9 | http://www.wangafu.net/~nickm/libevent-book/ 10 | 11 | First you must download and build libevent, you do not need to install 12 | it. 13 | libevent homepage: http://www.monkey.org/~provos/libevent/ 14 | 15 | To build libevent_echosrv: 16 | 17 | LIBEVENT=~/src/libevent-1.1a make 18 | 19 | where LIBEVENT points to the location of your built libevent. 20 | 21 | libevent_echosrv1 22 | 23 | This is the more basic of the 2 example apps. It does not handle 24 | writing data the proper way for an event based non-blocking 25 | application. For the sake of simplicity it echoes the data back 26 | to the socket as soon as it is received. 27 | 28 | libevent_echosrv2 29 | 30 | This example puts read data onto a queue and schedules a write 31 | event. It then waits for libevent to call the write callback 32 | before any data is written. This demonstrates the proper way to 33 | handle writing in an event based non-blocking socket application. 34 | 35 | USAGE 36 | 37 | Run the server: 38 | 39 | ./libevent_echosrc1 40 | 41 | OR 42 | 43 | ./libevent_echosrv2 44 | 45 | Then telnet to localhost port 5555. Anything you type will be 46 | echoed back to you. 47 | 48 | -- 49 | Jason Ish 50 | -------------------------------------------------------------------------------- /echo-server/libevent_echosrv1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011, Jason Ish 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 9 | * - Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 12 | * - Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in 14 | * the documentation and/or other materials provided with the 15 | * distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 | * SUCH DAMAGE. 28 | */ 29 | 30 | /* 31 | * libevent echo server example. 32 | */ 33 | 34 | #include 35 | #include 36 | #include 37 | 38 | /* For inet_ntoa. */ 39 | #include 40 | 41 | /* Required by event.h. */ 42 | #include 43 | 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | 52 | /* Libevent. */ 53 | #include 54 | 55 | /* Port to listen on. */ 56 | #define SERVER_PORT 5555 57 | 58 | /** 59 | * A struct for client specific data, in this simple case the only 60 | * client specific data is the read event. 61 | */ 62 | struct client { 63 | struct event ev_read; 64 | }; 65 | 66 | /** 67 | * Set a socket to non-blocking mode. 68 | */ 69 | int 70 | setnonblock(int fd) 71 | { 72 | int flags; 73 | 74 | flags = fcntl(fd, F_GETFL); 75 | if (flags < 0) 76 | return flags; 77 | flags |= O_NONBLOCK; 78 | if (fcntl(fd, F_SETFL, flags) < 0) 79 | return -1; 80 | 81 | return 0; 82 | } 83 | 84 | /** 85 | * This function will be called by libevent when the client socket is 86 | * ready for reading. 87 | */ 88 | void 89 | on_read(int fd, short ev, void *arg) 90 | { 91 | struct client *client = (struct client *)arg; 92 | u_char buf[8196]; 93 | int len, wlen; 94 | 95 | len = read(fd, buf, sizeof(buf)); 96 | if (len == 0) { 97 | /* Client disconnected, remove the read event and the 98 | * free the client structure. */ 99 | printf("Client disconnected.\n"); 100 | close(fd); 101 | event_del(&client->ev_read); 102 | free(client); 103 | return; 104 | } 105 | else if (len < 0) { 106 | /* Some other error occurred, close the socket, remove 107 | * the event and free the client structure. */ 108 | printf("Socket failure, disconnecting client: %s", 109 | strerror(errno)); 110 | close(fd); 111 | event_del(&client->ev_read); 112 | free(client); 113 | return; 114 | } 115 | 116 | /* XXX For the sake of simplicity we'll echo the data write 117 | * back to the client. Normally we shouldn't do this in a 118 | * non-blocking app, we should queue the data and wait to be 119 | * told that we can write. 120 | */ 121 | wlen = write(fd, buf, len); 122 | if (wlen < len) { 123 | /* We didn't write all our data. If we had proper 124 | * queueing/buffering setup, we'd finish off the write 125 | * when told we can write again. For this simple case 126 | * we'll just lose the data that didn't make it in the 127 | * write. 128 | */ 129 | printf("Short write, not all data echoed back to client.\n"); 130 | } 131 | } 132 | 133 | /** 134 | * This function will be called by libevent when there is a connection 135 | * ready to be accepted. 136 | */ 137 | void 138 | on_accept(int fd, short ev, void *arg) 139 | { 140 | int client_fd; 141 | struct sockaddr_in client_addr; 142 | socklen_t client_len = sizeof(client_addr); 143 | struct client *client; 144 | 145 | /* Accept the new connection. */ 146 | client_fd = accept(fd, (struct sockaddr *)&client_addr, &client_len); 147 | if (client_fd == -1) { 148 | warn("accept failed"); 149 | return; 150 | } 151 | 152 | /* Set the client socket to non-blocking mode. */ 153 | if (setnonblock(client_fd) < 0) 154 | warn("failed to set client socket non-blocking"); 155 | 156 | /* We've accepted a new client, allocate a client object to 157 | * maintain the state of this client. */ 158 | client = calloc(1, sizeof(*client)); 159 | if (client == NULL) 160 | err(1, "malloc failed"); 161 | 162 | /* Setup the read event, libevent will call on_read() whenever 163 | * the clients socket becomes read ready. We also make the 164 | * read event persistent so we don't have to re-add after each 165 | * read. */ 166 | event_set(&client->ev_read, client_fd, EV_READ|EV_PERSIST, on_read, 167 | client); 168 | 169 | /* Setting up the event does not activate, add the event so it 170 | * becomes active. */ 171 | event_add(&client->ev_read, NULL); 172 | 173 | printf("Accepted connection from %s\n", 174 | inet_ntoa(client_addr.sin_addr)); 175 | } 176 | 177 | int 178 | main(int argc, char **argv) 179 | { 180 | int listen_fd; 181 | struct sockaddr_in listen_addr; 182 | int reuseaddr_on = 1; 183 | 184 | /* The socket accept event. */ 185 | struct event ev_accept; 186 | 187 | /* Initialize libevent. */ 188 | event_init(); 189 | 190 | /* Create our listening socket. This is largely boiler plate 191 | * code that I'll abstract away in the future. */ 192 | listen_fd = socket(AF_INET, SOCK_STREAM, 0); 193 | if (listen_fd < 0) 194 | err(1, "listen failed"); 195 | if (setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr_on, 196 | sizeof(reuseaddr_on)) == -1) 197 | err(1, "setsockopt failed"); 198 | memset(&listen_addr, 0, sizeof(listen_addr)); 199 | listen_addr.sin_family = AF_INET; 200 | listen_addr.sin_addr.s_addr = INADDR_ANY; 201 | listen_addr.sin_port = htons(SERVER_PORT); 202 | if (bind(listen_fd, (struct sockaddr *)&listen_addr, 203 | sizeof(listen_addr)) < 0) 204 | err(1, "bind failed"); 205 | if (listen(listen_fd, 5) < 0) 206 | err(1, "listen failed"); 207 | 208 | /* Set the socket to non-blocking, this is essential in event 209 | * based programming with libevent. */ 210 | if (setnonblock(listen_fd) < 0) 211 | err(1, "failed to set server socket to non-blocking"); 212 | 213 | /* We now have a listening socket, we create a read event to 214 | * be notified when a client connects. */ 215 | event_set(&ev_accept, listen_fd, EV_READ|EV_PERSIST, on_accept, NULL); 216 | event_add(&ev_accept, NULL); 217 | 218 | /* Start the libevent event loop. */ 219 | event_dispatch(); 220 | 221 | return 0; 222 | } 223 | -------------------------------------------------------------------------------- /echo-server/libevent_echosrv2.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011, Jason Ish 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 9 | * - Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 12 | * - Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in 14 | * the documentation and/or other materials provided with the 15 | * distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 | * SUCH DAMAGE. 28 | */ 29 | 30 | /* 31 | * libevent echo server example. 32 | */ 33 | 34 | #include 35 | #include 36 | #include 37 | 38 | /* For inet_ntoa. */ 39 | #include 40 | 41 | /* Required by event.h. */ 42 | #include 43 | 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | 52 | /* Easy sensible linked lists. */ 53 | #include "queue.h" 54 | 55 | /* Libevent. */ 56 | #include 57 | 58 | /* Port to listen on. */ 59 | #define SERVER_PORT 5555 60 | 61 | /* Length of each buffer in the buffer queue. Also becomes the amount 62 | * of data we try to read per call to read(2). */ 63 | #define BUFLEN 1024 64 | 65 | /** 66 | * In event based programming we need to queue up data to be written 67 | * until we are told by libevent that we can write. This is a simple 68 | * queue of buffers to be written implemented by a TAILQ from queue.h. 69 | */ 70 | struct bufferq { 71 | /* The buffer. */ 72 | u_char *buf; 73 | 74 | /* The length of buf. */ 75 | int len; 76 | 77 | /* The offset into buf to start writing from. */ 78 | int offset; 79 | 80 | /* For the linked list structure. */ 81 | TAILQ_ENTRY(bufferq) entries; 82 | }; 83 | 84 | /** 85 | * A struct for client specific data, also includes pointer to create 86 | * a list of clients. 87 | * 88 | * In event based programming it is usually necessary to keep some 89 | * sort of object per client for state information. 90 | */ 91 | struct client { 92 | /* Events. We need 2 event structures, one for read event 93 | * notification and the other for writing. */ 94 | struct event ev_read; 95 | struct event ev_write; 96 | 97 | /* This is the queue of data to be written to this client. As 98 | * we can't call write(2) until libevent tells us the socket 99 | * is ready for writing. */ 100 | TAILQ_HEAD(, bufferq) writeq; 101 | }; 102 | 103 | /** 104 | * Set a socket to non-blocking mode. 105 | */ 106 | int 107 | setnonblock(int fd) 108 | { 109 | int flags; 110 | 111 | flags = fcntl(fd, F_GETFL); 112 | if (flags < 0) 113 | return flags; 114 | flags |= O_NONBLOCK; 115 | if (fcntl(fd, F_SETFL, flags) < 0) 116 | return -1; 117 | 118 | return 0; 119 | } 120 | 121 | /** 122 | * This function will be called by libevent when the client socket is 123 | * ready for reading. 124 | */ 125 | void 126 | on_read(int fd, short ev, void *arg) 127 | { 128 | struct client *client = (struct client *)arg; 129 | struct bufferq *bufferq; 130 | u_char *buf; 131 | int len; 132 | 133 | /* Because we are event based and need to be told when we can 134 | * write, we have to malloc the read buffer and put it on the 135 | * clients write queue. */ 136 | buf = malloc(BUFLEN); 137 | if (buf == NULL) 138 | err(1, "malloc failed"); 139 | 140 | len = read(fd, buf, BUFLEN); 141 | if (len == 0) { 142 | /* Client disconnected, remove the read event and the 143 | * free the client structure. */ 144 | printf("Client disconnected.\n"); 145 | close(fd); 146 | event_del(&client->ev_read); 147 | free(client); 148 | return; 149 | } 150 | else if (len < 0) { 151 | /* Some other error occurred, close the socket, remove 152 | * the event and free the client structure. */ 153 | printf("Socket failure, disconnecting client: %s", 154 | strerror(errno)); 155 | close(fd); 156 | event_del(&client->ev_read); 157 | free(client); 158 | return; 159 | } 160 | 161 | /* We can't just write the buffer back as we need to be told 162 | * when we can write by libevent. Put the buffer on the 163 | * client's write queue and schedule a write event. */ 164 | bufferq = calloc(1, sizeof(*bufferq)); 165 | if (bufferq == NULL) 166 | err(1, "malloc faild"); 167 | bufferq->buf = buf; 168 | bufferq->len = len; 169 | bufferq->offset = 0; 170 | TAILQ_INSERT_TAIL(&client->writeq, bufferq, entries); 171 | 172 | /* Since we now have data that needs to be written back to the 173 | * client, add a write event. */ 174 | event_add(&client->ev_write, NULL); 175 | } 176 | 177 | /** 178 | * This function will be called by libevent when the client socket is 179 | * ready for writing. 180 | */ 181 | void 182 | on_write(int fd, short ev, void *arg) 183 | { 184 | struct client *client = (struct client *)arg; 185 | struct bufferq *bufferq; 186 | int len; 187 | 188 | /* Pull the first item off of the write queue. We probably 189 | * should never see an empty write queue, but make sure the 190 | * item returned is not NULL. */ 191 | bufferq = TAILQ_FIRST(&client->writeq); 192 | if (bufferq == NULL) 193 | return; 194 | 195 | /* Write the buffer. A portion of the buffer may have been 196 | * written in a previous write, so only write the remaining 197 | * bytes. */ 198 | len = bufferq->len - bufferq->offset; 199 | len = write(fd, bufferq->buf + bufferq->offset, 200 | bufferq->len - bufferq->offset); 201 | if (len == -1) { 202 | if (errno == EINTR || errno == EAGAIN) { 203 | /* The write was interrupted by a signal or we 204 | * were not able to write any data to it, 205 | * reschedule and return. */ 206 | event_add(&client->ev_write, NULL); 207 | return; 208 | } 209 | else { 210 | /* Some other socket error occurred, exit. */ 211 | err(1, "write"); 212 | } 213 | } 214 | else if ((bufferq->offset + len) < bufferq->len) { 215 | /* Not all the data was written, update the offset and 216 | * reschedule the write event. */ 217 | bufferq->offset += len; 218 | event_add(&client->ev_write, NULL); 219 | return; 220 | } 221 | 222 | /* The data was completely written, remove the buffer from the 223 | * write queue. */ 224 | TAILQ_REMOVE(&client->writeq, bufferq, entries); 225 | free(bufferq->buf); 226 | free(bufferq); 227 | } 228 | 229 | /** 230 | * This function will be called by libevent when there is a connection 231 | * ready to be accepted. 232 | */ 233 | void 234 | on_accept(int fd, short ev, void *arg) 235 | { 236 | int client_fd; 237 | struct sockaddr_in client_addr; 238 | socklen_t client_len = sizeof(client_addr); 239 | struct client *client; 240 | 241 | /* Accept the new connection. */ 242 | client_fd = accept(fd, (struct sockaddr *)&client_addr, &client_len); 243 | if (client_fd == -1) { 244 | warn("accept failed"); 245 | return; 246 | } 247 | 248 | /* Set the client socket to non-blocking mode. */ 249 | if (setnonblock(client_fd) < 0) 250 | warn("failed to set client socket non-blocking"); 251 | 252 | /* We've accepted a new client, allocate a client object to 253 | * maintain the state of this client. */ 254 | client = calloc(1, sizeof(*client)); 255 | if (client == NULL) 256 | err(1, "malloc failed"); 257 | 258 | /* Setup the read event, libevent will call on_read() whenever 259 | * the clients socket becomes read ready. We also make the 260 | * read event persistent so we don't have to re-add after each 261 | * read. */ 262 | event_set(&client->ev_read, client_fd, EV_READ|EV_PERSIST, on_read, 263 | client); 264 | 265 | /* Setting up the event does not activate, add the event so it 266 | * becomes active. */ 267 | event_add(&client->ev_read, NULL); 268 | 269 | /* Create the write event, but don't add it until we have 270 | * something to write. */ 271 | event_set(&client->ev_write, client_fd, EV_WRITE, on_write, client); 272 | 273 | /* Initialize the clients write queue. */ 274 | TAILQ_INIT(&client->writeq); 275 | 276 | printf("Accepted connection from %s\n", 277 | inet_ntoa(client_addr.sin_addr)); 278 | } 279 | 280 | int 281 | main(int argc, char **argv) 282 | { 283 | int listen_fd; 284 | struct sockaddr_in listen_addr; 285 | int reuseaddr_on = 1; 286 | 287 | /* The socket accept event. */ 288 | struct event ev_accept; 289 | 290 | /* Initialize libevent. */ 291 | event_init(); 292 | 293 | /* Create our listening socket. This is largely boiler plate 294 | * code that I'll abstract away in the future. */ 295 | listen_fd = socket(AF_INET, SOCK_STREAM, 0); 296 | if (listen_fd < 0) 297 | err(1, "listen failed"); 298 | if (setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr_on, 299 | sizeof(reuseaddr_on)) == -1) 300 | err(1, "setsockopt failed"); 301 | memset(&listen_addr, 0, sizeof(listen_addr)); 302 | listen_addr.sin_family = AF_INET; 303 | listen_addr.sin_addr.s_addr = INADDR_ANY; 304 | listen_addr.sin_port = htons(SERVER_PORT); 305 | if (bind(listen_fd, (struct sockaddr *)&listen_addr, 306 | sizeof(listen_addr)) < 0) 307 | err(1, "bind failed"); 308 | if (listen(listen_fd, 5) < 0) 309 | err(1, "listen failed"); 310 | 311 | /* Set the socket to non-blocking, this is essential in event 312 | * based programming with libevent. */ 313 | if (setnonblock(listen_fd) < 0) 314 | err(1, "failed to set server socket to non-blocking"); 315 | 316 | /* We now have a listening socket, we create a read event to 317 | * be notified when a client connects. */ 318 | event_set(&ev_accept, listen_fd, EV_READ|EV_PERSIST, on_accept, NULL); 319 | event_add(&ev_accept, NULL); 320 | 321 | /* Start the libevent event loop. */ 322 | event_dispatch(); 323 | 324 | return 0; 325 | } 326 | -------------------------------------------------------------------------------- /echo-server/queue.h: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: queue.h,v 1.31 2005/11/25 08:06:25 otto Exp $ */ 2 | /* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */ 3 | 4 | /* 5 | * Copyright (c) 1991, 1993 6 | * The Regents of the University of California. All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 1. Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 3. Neither the name of the University nor the names of its contributors 17 | * may be used to endorse or promote products derived from this software 18 | * without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 | * SUCH DAMAGE. 31 | * 32 | * @(#)queue.h 8.5 (Berkeley) 8/20/94 33 | */ 34 | 35 | #ifndef _SYS_QUEUE_H_ 36 | #define _SYS_QUEUE_H_ 37 | 38 | /* 39 | * This file defines five types of data structures: singly-linked lists, 40 | * lists, simple queues, tail queues, and circular queues. 41 | * 42 | * 43 | * A singly-linked list is headed by a single forward pointer. The elements 44 | * are singly linked for minimum space and pointer manipulation overhead at 45 | * the expense of O(n) removal for arbitrary elements. New elements can be 46 | * added to the list after an existing element or at the head of the list. 47 | * Elements being removed from the head of the list should use the explicit 48 | * macro for this purpose for optimum efficiency. A singly-linked list may 49 | * only be traversed in the forward direction. Singly-linked lists are ideal 50 | * for applications with large datasets and few or no removals or for 51 | * implementing a LIFO queue. 52 | * 53 | * A list is headed by a single forward pointer (or an array of forward 54 | * pointers for a hash table header). The elements are doubly linked 55 | * so that an arbitrary element can be removed without a need to 56 | * traverse the list. New elements can be added to the list before 57 | * or after an existing element or at the head of the list. A list 58 | * may only be traversed in the forward direction. 59 | * 60 | * A simple queue is headed by a pair of pointers, one the head of the 61 | * list and the other to the tail of the list. The elements are singly 62 | * linked to save space, so elements can only be removed from the 63 | * head of the list. New elements can be added to the list before or after 64 | * an existing element, at the head of the list, or at the end of the 65 | * list. A simple queue may only be traversed in the forward direction. 66 | * 67 | * A tail queue is headed by a pair of pointers, one to the head of the 68 | * list and the other to the tail of the list. The elements are doubly 69 | * linked so that an arbitrary element can be removed without a need to 70 | * traverse the list. New elements can be added to the list before or 71 | * after an existing element, at the head of the list, or at the end of 72 | * the list. A tail queue may be traversed in either direction. 73 | * 74 | * A circle queue is headed by a pair of pointers, one to the head of the 75 | * list and the other to the tail of the list. The elements are doubly 76 | * linked so that an arbitrary element can be removed without a need to 77 | * traverse the list. New elements can be added to the list before or after 78 | * an existing element, at the head of the list, or at the end of the list. 79 | * A circle queue may be traversed in either direction, but has a more 80 | * complex end of list detection. 81 | * 82 | * For details on the use of these macros, see the queue(3) manual page. 83 | */ 84 | 85 | #ifdef QUEUE_MACRO_DEBUG 86 | #define _Q_INVALIDATE(a) (a) = ((void *)-1) 87 | #else 88 | #define _Q_INVALIDATE(a) 89 | #endif 90 | 91 | /* 92 | * Singly-linked List definitions. 93 | */ 94 | #define SLIST_HEAD(name, type) \ 95 | struct name { \ 96 | struct type *slh_first; /* first element */ \ 97 | } 98 | 99 | #define SLIST_HEAD_INITIALIZER(head) \ 100 | { NULL } 101 | 102 | #define SLIST_ENTRY(type) \ 103 | struct { \ 104 | struct type *sle_next; /* next element */ \ 105 | } 106 | 107 | /* 108 | * Singly-linked List access methods. 109 | */ 110 | #define SLIST_FIRST(head) ((head)->slh_first) 111 | #define SLIST_END(head) NULL 112 | #define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head)) 113 | #define SLIST_NEXT(elm, field) ((elm)->field.sle_next) 114 | 115 | #define SLIST_FOREACH(var, head, field) \ 116 | for((var) = SLIST_FIRST(head); \ 117 | (var) != SLIST_END(head); \ 118 | (var) = SLIST_NEXT(var, field)) 119 | 120 | #define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ 121 | for ((varp) = &SLIST_FIRST((head)); \ 122 | ((var) = *(varp)) != SLIST_END(head); \ 123 | (varp) = &SLIST_NEXT((var), field)) 124 | 125 | /* 126 | * Singly-linked List functions. 127 | */ 128 | #define SLIST_INIT(head) { \ 129 | SLIST_FIRST(head) = SLIST_END(head); \ 130 | } 131 | 132 | #define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ 133 | (elm)->field.sle_next = (slistelm)->field.sle_next; \ 134 | (slistelm)->field.sle_next = (elm); \ 135 | } while (0) 136 | 137 | #define SLIST_INSERT_HEAD(head, elm, field) do { \ 138 | (elm)->field.sle_next = (head)->slh_first; \ 139 | (head)->slh_first = (elm); \ 140 | } while (0) 141 | 142 | #define SLIST_REMOVE_NEXT(head, elm, field) do { \ 143 | (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \ 144 | } while (0) 145 | 146 | #define SLIST_REMOVE_HEAD(head, field) do { \ 147 | (head)->slh_first = (head)->slh_first->field.sle_next; \ 148 | } while (0) 149 | 150 | #define SLIST_REMOVE(head, elm, type, field) do { \ 151 | if ((head)->slh_first == (elm)) { \ 152 | SLIST_REMOVE_HEAD((head), field); \ 153 | } else { \ 154 | struct type *curelm = (head)->slh_first; \ 155 | \ 156 | while (curelm->field.sle_next != (elm)) \ 157 | curelm = curelm->field.sle_next; \ 158 | curelm->field.sle_next = \ 159 | curelm->field.sle_next->field.sle_next; \ 160 | _Q_INVALIDATE((elm)->field.sle_next); \ 161 | } \ 162 | } while (0) 163 | 164 | /* 165 | * List definitions. 166 | */ 167 | #define LIST_HEAD(name, type) \ 168 | struct name { \ 169 | struct type *lh_first; /* first element */ \ 170 | } 171 | 172 | #define LIST_HEAD_INITIALIZER(head) \ 173 | { NULL } 174 | 175 | #define LIST_ENTRY(type) \ 176 | struct { \ 177 | struct type *le_next; /* next element */ \ 178 | struct type **le_prev; /* address of previous next element */ \ 179 | } 180 | 181 | /* 182 | * List access methods 183 | */ 184 | #define LIST_FIRST(head) ((head)->lh_first) 185 | #define LIST_END(head) NULL 186 | #define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head)) 187 | #define LIST_NEXT(elm, field) ((elm)->field.le_next) 188 | 189 | #define LIST_FOREACH(var, head, field) \ 190 | for((var) = LIST_FIRST(head); \ 191 | (var)!= LIST_END(head); \ 192 | (var) = LIST_NEXT(var, field)) 193 | 194 | /* 195 | * List functions. 196 | */ 197 | #define LIST_INIT(head) do { \ 198 | LIST_FIRST(head) = LIST_END(head); \ 199 | } while (0) 200 | 201 | #define LIST_INSERT_AFTER(listelm, elm, field) do { \ 202 | if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ 203 | (listelm)->field.le_next->field.le_prev = \ 204 | &(elm)->field.le_next; \ 205 | (listelm)->field.le_next = (elm); \ 206 | (elm)->field.le_prev = &(listelm)->field.le_next; \ 207 | } while (0) 208 | 209 | #define LIST_INSERT_BEFORE(listelm, elm, field) do { \ 210 | (elm)->field.le_prev = (listelm)->field.le_prev; \ 211 | (elm)->field.le_next = (listelm); \ 212 | *(listelm)->field.le_prev = (elm); \ 213 | (listelm)->field.le_prev = &(elm)->field.le_next; \ 214 | } while (0) 215 | 216 | #define LIST_INSERT_HEAD(head, elm, field) do { \ 217 | if (((elm)->field.le_next = (head)->lh_first) != NULL) \ 218 | (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ 219 | (head)->lh_first = (elm); \ 220 | (elm)->field.le_prev = &(head)->lh_first; \ 221 | } while (0) 222 | 223 | #define LIST_REMOVE(elm, field) do { \ 224 | if ((elm)->field.le_next != NULL) \ 225 | (elm)->field.le_next->field.le_prev = \ 226 | (elm)->field.le_prev; \ 227 | *(elm)->field.le_prev = (elm)->field.le_next; \ 228 | _Q_INVALIDATE((elm)->field.le_prev); \ 229 | _Q_INVALIDATE((elm)->field.le_next); \ 230 | } while (0) 231 | 232 | #define LIST_REPLACE(elm, elm2, field) do { \ 233 | if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ 234 | (elm2)->field.le_next->field.le_prev = \ 235 | &(elm2)->field.le_next; \ 236 | (elm2)->field.le_prev = (elm)->field.le_prev; \ 237 | *(elm2)->field.le_prev = (elm2); \ 238 | _Q_INVALIDATE((elm)->field.le_prev); \ 239 | _Q_INVALIDATE((elm)->field.le_next); \ 240 | } while (0) 241 | 242 | /* 243 | * Simple queue definitions. 244 | */ 245 | #define SIMPLEQ_HEAD(name, type) \ 246 | struct name { \ 247 | struct type *sqh_first; /* first element */ \ 248 | struct type **sqh_last; /* addr of last next element */ \ 249 | } 250 | 251 | #define SIMPLEQ_HEAD_INITIALIZER(head) \ 252 | { NULL, &(head).sqh_first } 253 | 254 | #define SIMPLEQ_ENTRY(type) \ 255 | struct { \ 256 | struct type *sqe_next; /* next element */ \ 257 | } 258 | 259 | /* 260 | * Simple queue access methods. 261 | */ 262 | #define SIMPLEQ_FIRST(head) ((head)->sqh_first) 263 | #define SIMPLEQ_END(head) NULL 264 | #define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head)) 265 | #define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) 266 | 267 | #define SIMPLEQ_FOREACH(var, head, field) \ 268 | for((var) = SIMPLEQ_FIRST(head); \ 269 | (var) != SIMPLEQ_END(head); \ 270 | (var) = SIMPLEQ_NEXT(var, field)) 271 | 272 | /* 273 | * Simple queue functions. 274 | */ 275 | #define SIMPLEQ_INIT(head) do { \ 276 | (head)->sqh_first = NULL; \ 277 | (head)->sqh_last = &(head)->sqh_first; \ 278 | } while (0) 279 | 280 | #define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ 281 | if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ 282 | (head)->sqh_last = &(elm)->field.sqe_next; \ 283 | (head)->sqh_first = (elm); \ 284 | } while (0) 285 | 286 | #define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ 287 | (elm)->field.sqe_next = NULL; \ 288 | *(head)->sqh_last = (elm); \ 289 | (head)->sqh_last = &(elm)->field.sqe_next; \ 290 | } while (0) 291 | 292 | #define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ 293 | if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ 294 | (head)->sqh_last = &(elm)->field.sqe_next; \ 295 | (listelm)->field.sqe_next = (elm); \ 296 | } while (0) 297 | 298 | #define SIMPLEQ_REMOVE_HEAD(head, field) do { \ 299 | if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ 300 | (head)->sqh_last = &(head)->sqh_first; \ 301 | } while (0) 302 | 303 | /* 304 | * Tail queue definitions. 305 | */ 306 | #define TAILQ_HEAD(name, type) \ 307 | struct name { \ 308 | struct type *tqh_first; /* first element */ \ 309 | struct type **tqh_last; /* addr of last next element */ \ 310 | } 311 | 312 | #define TAILQ_HEAD_INITIALIZER(head) \ 313 | { NULL, &(head).tqh_first } 314 | 315 | #define TAILQ_ENTRY(type) \ 316 | struct { \ 317 | struct type *tqe_next; /* next element */ \ 318 | struct type **tqe_prev; /* address of previous next element */ \ 319 | } 320 | 321 | /* 322 | * tail queue access methods 323 | */ 324 | #define TAILQ_FIRST(head) ((head)->tqh_first) 325 | #define TAILQ_END(head) NULL 326 | #define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) 327 | #define TAILQ_LAST(head, headname) \ 328 | (*(((struct headname *)((head)->tqh_last))->tqh_last)) 329 | /* XXX */ 330 | #define TAILQ_PREV(elm, headname, field) \ 331 | (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) 332 | #define TAILQ_EMPTY(head) \ 333 | (TAILQ_FIRST(head) == TAILQ_END(head)) 334 | 335 | #define TAILQ_FOREACH(var, head, field) \ 336 | for((var) = TAILQ_FIRST(head); \ 337 | (var) != TAILQ_END(head); \ 338 | (var) = TAILQ_NEXT(var, field)) 339 | 340 | #define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ 341 | for((var) = TAILQ_LAST(head, headname); \ 342 | (var) != TAILQ_END(head); \ 343 | (var) = TAILQ_PREV(var, headname, field)) 344 | 345 | /* 346 | * Tail queue functions. 347 | */ 348 | #define TAILQ_INIT(head) do { \ 349 | (head)->tqh_first = NULL; \ 350 | (head)->tqh_last = &(head)->tqh_first; \ 351 | } while (0) 352 | 353 | #define TAILQ_INSERT_HEAD(head, elm, field) do { \ 354 | if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ 355 | (head)->tqh_first->field.tqe_prev = \ 356 | &(elm)->field.tqe_next; \ 357 | else \ 358 | (head)->tqh_last = &(elm)->field.tqe_next; \ 359 | (head)->tqh_first = (elm); \ 360 | (elm)->field.tqe_prev = &(head)->tqh_first; \ 361 | } while (0) 362 | 363 | #define TAILQ_INSERT_TAIL(head, elm, field) do { \ 364 | (elm)->field.tqe_next = NULL; \ 365 | (elm)->field.tqe_prev = (head)->tqh_last; \ 366 | *(head)->tqh_last = (elm); \ 367 | (head)->tqh_last = &(elm)->field.tqe_next; \ 368 | } while (0) 369 | 370 | #define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ 371 | if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ 372 | (elm)->field.tqe_next->field.tqe_prev = \ 373 | &(elm)->field.tqe_next; \ 374 | else \ 375 | (head)->tqh_last = &(elm)->field.tqe_next; \ 376 | (listelm)->field.tqe_next = (elm); \ 377 | (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ 378 | } while (0) 379 | 380 | #define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ 381 | (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ 382 | (elm)->field.tqe_next = (listelm); \ 383 | *(listelm)->field.tqe_prev = (elm); \ 384 | (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ 385 | } while (0) 386 | 387 | #define TAILQ_REMOVE(head, elm, field) do { \ 388 | if (((elm)->field.tqe_next) != NULL) \ 389 | (elm)->field.tqe_next->field.tqe_prev = \ 390 | (elm)->field.tqe_prev; \ 391 | else \ 392 | (head)->tqh_last = (elm)->field.tqe_prev; \ 393 | *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ 394 | _Q_INVALIDATE((elm)->field.tqe_prev); \ 395 | _Q_INVALIDATE((elm)->field.tqe_next); \ 396 | } while (0) 397 | 398 | #define TAILQ_REPLACE(head, elm, elm2, field) do { \ 399 | if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \ 400 | (elm2)->field.tqe_next->field.tqe_prev = \ 401 | &(elm2)->field.tqe_next; \ 402 | else \ 403 | (head)->tqh_last = &(elm2)->field.tqe_next; \ 404 | (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ 405 | *(elm2)->field.tqe_prev = (elm2); \ 406 | _Q_INVALIDATE((elm)->field.tqe_prev); \ 407 | _Q_INVALIDATE((elm)->field.tqe_next); \ 408 | } while (0) 409 | 410 | /* 411 | * Circular queue definitions. 412 | */ 413 | #define CIRCLEQ_HEAD(name, type) \ 414 | struct name { \ 415 | struct type *cqh_first; /* first element */ \ 416 | struct type *cqh_last; /* last element */ \ 417 | } 418 | 419 | #define CIRCLEQ_HEAD_INITIALIZER(head) \ 420 | { CIRCLEQ_END(&head), CIRCLEQ_END(&head) } 421 | 422 | #define CIRCLEQ_ENTRY(type) \ 423 | struct { \ 424 | struct type *cqe_next; /* next element */ \ 425 | struct type *cqe_prev; /* previous element */ \ 426 | } 427 | 428 | /* 429 | * Circular queue access methods 430 | */ 431 | #define CIRCLEQ_FIRST(head) ((head)->cqh_first) 432 | #define CIRCLEQ_LAST(head) ((head)->cqh_last) 433 | #define CIRCLEQ_END(head) ((void *)(head)) 434 | #define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) 435 | #define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) 436 | #define CIRCLEQ_EMPTY(head) \ 437 | (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head)) 438 | 439 | #define CIRCLEQ_FOREACH(var, head, field) \ 440 | for((var) = CIRCLEQ_FIRST(head); \ 441 | (var) != CIRCLEQ_END(head); \ 442 | (var) = CIRCLEQ_NEXT(var, field)) 443 | 444 | #define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ 445 | for((var) = CIRCLEQ_LAST(head); \ 446 | (var) != CIRCLEQ_END(head); \ 447 | (var) = CIRCLEQ_PREV(var, field)) 448 | 449 | /* 450 | * Circular queue functions. 451 | */ 452 | #define CIRCLEQ_INIT(head) do { \ 453 | (head)->cqh_first = CIRCLEQ_END(head); \ 454 | (head)->cqh_last = CIRCLEQ_END(head); \ 455 | } while (0) 456 | 457 | #define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ 458 | (elm)->field.cqe_next = (listelm)->field.cqe_next; \ 459 | (elm)->field.cqe_prev = (listelm); \ 460 | if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \ 461 | (head)->cqh_last = (elm); \ 462 | else \ 463 | (listelm)->field.cqe_next->field.cqe_prev = (elm); \ 464 | (listelm)->field.cqe_next = (elm); \ 465 | } while (0) 466 | 467 | #define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ 468 | (elm)->field.cqe_next = (listelm); \ 469 | (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ 470 | if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \ 471 | (head)->cqh_first = (elm); \ 472 | else \ 473 | (listelm)->field.cqe_prev->field.cqe_next = (elm); \ 474 | (listelm)->field.cqe_prev = (elm); \ 475 | } while (0) 476 | 477 | #define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ 478 | (elm)->field.cqe_next = (head)->cqh_first; \ 479 | (elm)->field.cqe_prev = CIRCLEQ_END(head); \ 480 | if ((head)->cqh_last == CIRCLEQ_END(head)) \ 481 | (head)->cqh_last = (elm); \ 482 | else \ 483 | (head)->cqh_first->field.cqe_prev = (elm); \ 484 | (head)->cqh_first = (elm); \ 485 | } while (0) 486 | 487 | #define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ 488 | (elm)->field.cqe_next = CIRCLEQ_END(head); \ 489 | (elm)->field.cqe_prev = (head)->cqh_last; \ 490 | if ((head)->cqh_first == CIRCLEQ_END(head)) \ 491 | (head)->cqh_first = (elm); \ 492 | else \ 493 | (head)->cqh_last->field.cqe_next = (elm); \ 494 | (head)->cqh_last = (elm); \ 495 | } while (0) 496 | 497 | #define CIRCLEQ_REMOVE(head, elm, field) do { \ 498 | if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \ 499 | (head)->cqh_last = (elm)->field.cqe_prev; \ 500 | else \ 501 | (elm)->field.cqe_next->field.cqe_prev = \ 502 | (elm)->field.cqe_prev; \ 503 | if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \ 504 | (head)->cqh_first = (elm)->field.cqe_next; \ 505 | else \ 506 | (elm)->field.cqe_prev->field.cqe_next = \ 507 | (elm)->field.cqe_next; \ 508 | _Q_INVALIDATE((elm)->field.cqe_prev); \ 509 | _Q_INVALIDATE((elm)->field.cqe_next); \ 510 | } while (0) 511 | 512 | #define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \ 513 | if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \ 514 | CIRCLEQ_END(head)) \ 515 | (head).cqh_last = (elm2); \ 516 | else \ 517 | (elm2)->field.cqe_next->field.cqe_prev = (elm2); \ 518 | if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \ 519 | CIRCLEQ_END(head)) \ 520 | (head).cqh_first = (elm2); \ 521 | else \ 522 | (elm2)->field.cqe_prev->field.cqe_next = (elm2); \ 523 | _Q_INVALIDATE((elm)->field.cqe_prev); \ 524 | _Q_INVALIDATE((elm)->field.cqe_next); \ 525 | } while (0) 526 | 527 | #endif /* !_SYS_QUEUE_H_ */ 528 | --------------------------------------------------------------------------------