1 /* 2 * ustream-ssl - library for SSL over ustream 3 * 4 * Copyright (C) 2012 Felix Fietkau <nbd@openwrt.org> 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/socket.h> 20 #include <netinet/in.h> 21 22 #include <stdio.h> 23 #include <getopt.h> 24 #include <stdlib.h> 25 #include <string.h> 26 #include <unistd.h> 27 #include <signal.h> 28 29 #include <libubox/ustream.h> 30 #include <libubox/uloop.h> 31 #include <libubox/usock.h> 32 #include "ustream-ssl.h" 33 34 static struct ustream_ssl_ctx *ctx; 35 36 static struct uloop_fd server; 37 static const char *port = "10000"; 38 static struct client *next_client = NULL; 39 40 struct client { 41 struct sockaddr_in sin; 42 43 struct ustream_fd s; 44 struct ustream_ssl ssl; 45 int ctr; 46 47 int state; 48 }; 49 50 enum { 51 STATE_INITIAL, 52 STATE_HEADERS, 53 STATE_DONE, 54 }; 55 56 static void client_read_cb(struct ustream *s, int bytes) 57 { 58 struct client *cl = container_of(s, struct client, ssl.stream); 59 struct ustream_buf *buf = s->r.head; 60 char *newline, *str; 61 62 do { 63 str = ustream_get_read_buf(s, NULL); 64 if (!str) 65 break; 66 67 newline = strchr(buf->data, '\n'); 68 if (!newline) 69 break; 70 71 *newline = 0; 72 switch (cl->state) { 73 case STATE_INITIAL: 74 ustream_printf(s, "HTTP/1.1 200 OK\nContent-Type:text/plain\n\n"); 75 ustream_printf(s, "Got request header: %s\n", str); 76 cl->state++; 77 break; 78 case STATE_HEADERS: 79 switch(str[0]) { 80 case '\r': 81 case '\n': 82 s->eof = true; 83 ustream_state_change(s); 84 cl->state++; 85 break; 86 default: 87 ustream_printf(s, "%s\n", str); 88 break; 89 } 90 break; 91 default: 92 break; 93 } 94 ustream_consume(s, newline + 1 - str); 95 cl->ctr += newline + 1 - str; 96 } while(1); 97 98 if (s->w.data_bytes > 256 && !ustream_read_blocked(s)) { 99 fprintf(stderr, "Block read, bytes: %d\n", s->w.data_bytes); 100 ustream_set_read_blocked(s, true); 101 } 102 } 103 104 static void client_close(struct client *cl) 105 { 106 fprintf(stderr, "Connection closed\n"); 107 ustream_free(&cl->ssl.stream); 108 ustream_free(&cl->s.stream); 109 close(cl->s.fd.fd); 110 free(cl); 111 } 112 113 static void client_notify_write(struct ustream *s, int bytes) 114 { 115 fprintf(stderr, "Wrote %d bytes, pending: %d\n", bytes, s->w.data_bytes); 116 117 if (s->w.data_bytes < 128 && ustream_read_blocked(s)) { 118 fprintf(stderr, "Unblock read\n"); 119 ustream_set_read_blocked(s, false); 120 } 121 } 122 123 static void client_notify_state(struct ustream *s) 124 { 125 struct client *cl = container_of(s, struct client, ssl.stream); 126 127 if (!s->eof) 128 return; 129 130 fprintf(stderr, "eof!, pending: %d, total: %d\n", s->w.data_bytes, cl->ctr); 131 if (!s->w.data_bytes) 132 return client_close(cl); 133 } 134 135 static void client_notify_connected(struct ustream_ssl *ssl) 136 { 137 fprintf(stderr, "SSL connection established\n"); 138 } 139 140 static void client_notify_error(struct ustream_ssl *ssl, int error, const char *str) 141 { 142 struct client *cl = container_of(ssl, struct client, ssl); 143 144 fprintf(stderr, "SSL connection error(%d): %s\n", error, str); 145 client_close(cl); 146 } 147 148 static void server_cb(struct uloop_fd *fd, unsigned int events) 149 { 150 struct client *cl; 151 unsigned int sl = sizeof(struct sockaddr_in); 152 int sfd; 153 154 if (!next_client) 155 next_client = calloc(1, sizeof(*next_client)); 156 157 cl = next_client; 158 sfd = accept(server.fd, (struct sockaddr *) &cl->sin, &sl); 159 if (sfd < 0) { 160 fprintf(stderr, "Accept failed\n"); 161 return; 162 } 163 164 cl->ssl.stream.string_data = true; 165 cl->ssl.stream.notify_read = client_read_cb; 166 cl->ssl.stream.notify_state = client_notify_state; 167 cl->ssl.stream.notify_write = client_notify_write; 168 cl->ssl.notify_connected = client_notify_connected; 169 cl->ssl.notify_error = client_notify_error; 170 171 ustream_fd_init(&cl->s, sfd); 172 ustream_ssl_init(&cl->ssl, &cl->s.stream, ctx, true); 173 next_client = NULL; 174 fprintf(stderr, "New connection\n"); 175 } 176 177 static int run_server(void) 178 { 179 180 server.cb = server_cb; 181 server.fd = usock(USOCK_TCP | USOCK_SERVER | USOCK_IPV4ONLY | USOCK_NUMERIC, "127.0.0.1", port); 182 if (server.fd < 0) { 183 perror("usock"); 184 return 1; 185 } 186 187 uloop_init(); 188 uloop_fd_add(&server, ULOOP_READ); 189 uloop_run(); 190 191 return 0; 192 } 193 194 static int usage(const char *name) 195 { 196 fprintf(stderr, "Usage: %s -p <port>\n", name); 197 return 1; 198 } 199 200 int main(int argc, char **argv) 201 { 202 int ch; 203 204 signal(SIGPIPE, SIG_IGN); 205 ctx = ustream_ssl_context_new(true); 206 ustream_ssl_context_set_crt_file(ctx, "example.crt"); 207 ustream_ssl_context_set_key_file(ctx, "example.key"); 208 209 while ((ch = getopt(argc, argv, "p:")) != -1) { 210 switch(ch) { 211 case 'p': 212 port = optarg; 213 break; 214 default: 215 return usage(argv[0]); 216 } 217 } 218 219 return run_server(); 220 } 221
This page was automatically generated by LXR 0.3.1. • OpenWrt