1 /*- 2 * Copyright (c) 2011 NetApp, Inc. 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 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD$ 27 */ 28 29 /* 30 * Test program for the micro event library. Set up a simple TCP echo 31 * service. 32 * 33 * cc mevent_test.c mevent.c -lpthread 34 */ 35 36 #include <sys/types.h> 37 #include <sys/socket.h> 38 #include <netinet/in.h> 39 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <pthread.h> 43 44 #include "mevent.h" 45 46 #define TEST_PORT 4321 47 48 static pthread_mutex_t accept_mutex = PTHREAD_MUTEX_INITIALIZER; 49 static pthread_cond_t accept_condvar = PTHREAD_COND_INITIALIZER; 50 51 #define MEVENT_ECHO 52 53 #ifdef MEVENT_ECHO 54 struct esync { 55 pthread_mutex_t e_mt; 56 pthread_cond_t e_cond; 57 }; 58 59 static void 60 echoer_callback(int fd, enum ev_type type, void *param) 61 { 62 struct esync *sync = param; 63 64 pthread_mutex_lock(&sync->e_mt); 65 pthread_cond_signal(&sync->e_cond); 66 pthread_mutex_unlock(&sync->e_mt); 67 } 68 69 static void * 70 echoer(void *param) 71 { 72 struct esync sync; 73 struct mevent *mev; 74 char buf[128]; 75 int fd = (int)(uintptr_t) param; 76 int len; 77 78 pthread_mutex_init(&sync.e_mt, NULL); 79 pthread_cond_init(&sync.e_cond, NULL); 80 81 pthread_mutex_lock(&sync.e_mt); 82 83 mev = mevent_add(fd, EVF_READ, echoer_callback, &sync); 84 if (mev == NULL) { 85 printf("Could not allocate echoer event\n"); 86 exit(1); 87 } 88 89 while (!pthread_cond_wait(&sync.e_cond, &sync.e_mt)) { 90 len = read(fd, buf, sizeof(buf)); 91 if (len > 0) { 92 write(fd, buf, len); 93 write(0, buf, len); 94 } else { 95 break; 96 } 97 } 98 99 mevent_delete_close(mev); 100 101 pthread_mutex_unlock(&sync.e_mt); 102 pthread_mutex_destroy(&sync.e_mt); 103 pthread_cond_destroy(&sync.e_cond); 104 } 105 106 #else 107 108 static void * 109 echoer(void *param) 110 { 111 char buf[128]; 112 int fd = (int)(uintptr_t) param; 113 int len; 114 115 while ((len = read(fd, buf, sizeof(buf))) > 0) { 116 write(1, buf, len); 117 } 118 } 119 #endif /* MEVENT_ECHO */ 120 121 static void 122 acceptor_callback(int fd, enum ev_type type, void *param) 123 { 124 pthread_mutex_lock(&accept_mutex); 125 pthread_cond_signal(&accept_condvar); 126 pthread_mutex_unlock(&accept_mutex); 127 } 128 129 static void * 130 acceptor(void *param) 131 { 132 struct sockaddr_in sin; 133 pthread_t tid; 134 int news; 135 int s; 136 137 if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 138 perror("socket"); 139 exit(1); 140 } 141 142 sin.sin_len = sizeof(sin); 143 sin.sin_family = AF_INET; 144 sin.sin_addr.s_addr = htonl(INADDR_ANY); 145 sin.sin_port = htons(TEST_PORT); 146 147 if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { 148 perror("bind"); 149 exit(1); 150 } 151 152 if (listen(s, 1) < 0) { 153 perror("listen"); 154 exit(1); 155 } 156 157 (void) mevent_add(s, EVF_READ, acceptor_callback, NULL); 158 159 pthread_mutex_lock(&accept_mutex); 160 161 while (!pthread_cond_wait(&accept_condvar, &accept_mutex)) { 162 news = accept(s, NULL, NULL); 163 if (news < 0) { 164 perror("accept error"); 165 } else { 166 printf("incoming connection, spawning thread\n"); 167 pthread_create(&tid, NULL, echoer, 168 (void *)(uintptr_t)news); 169 } 170 } 171 } 172 173 main() 174 { 175 pthread_t tid; 176 177 pthread_create(&tid, NULL, acceptor, NULL); 178 179 mevent_dispatch(); 180 } 181