├── deployment ├── run │ └── mongre2.pid ├── tests │ ├── favicon.ico │ └── index.html ├── config.sh ├── start.sh ├── assets │ ├── favicon.ico │ ├── index.html │ └── ws.html └── deployment.conf ├── .gitignore ├── lib ├── m2websocket.h ├── sample_handlers │ ├── body_toupper.c │ ├── ws_handshake.c │ └── fifo_reader.c ├── m2handler.h ├── Makefile ├── md5 │ ├── md5.h │ ├── config.h │ └── md5.c ├── bstr │ ├── bstraux.h │ ├── bstrlib.h │ └── bstraux.c ├── m2websocket.c └── m2handler.c ├── PROTOCOL.markdown └── README.markdown /deployment/run/mongre2.pid: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /deployment/tests/favicon.ico: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /deployment/tests/index.html: -------------------------------------------------------------------------------- 1 | Hi! 2 | -------------------------------------------------------------------------------- /deployment/config.sh: -------------------------------------------------------------------------------- 1 | m2sh load -config deployment.conf 2 | -------------------------------------------------------------------------------- /deployment/start.sh: -------------------------------------------------------------------------------- 1 | reset && m2sh start -host localhost 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | libm2handler* 3 | lib/nbproject/ 4 | Makefile-handler.mk 5 | config.sqlite 6 | -------------------------------------------------------------------------------- /deployment/assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/derdewey/mongrel2_c_handler/HEAD/deployment/assets/favicon.ico -------------------------------------------------------------------------------- /deployment/assets/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Welcome to the libm2handler interactive demo.

4 |

The body_toupper and fifo_reader handlers should be tested using curl.

5 |

View the websocket demo

6 |

Hi

7 | 8 | 9 | -------------------------------------------------------------------------------- /lib/m2websocket.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: m2websocket.h 3 | * Author: xavierlange 4 | * 5 | * Created on February 10, 2011, 3:07 PM 6 | */ 7 | 8 | #include "stdint.h" 9 | 10 | #ifndef M2WEBSOCKET_H 11 | #define M2WEBSOCKET_H 12 | 13 | int mongrel2_ws_reply_upgrade(mongrel2_request *req, mongrel2_socket *socket); 14 | bstring mongrel2_ws_upgrade_headers(mongrel2_request *req); 15 | bstring mongrel2_ws_upgrade_body(mongrel2_request *req); 16 | 17 | int mongrel2_ws_reply(mongrel2_socket *pub_socket, mongrel2_request *req, bstring data); 18 | 19 | // For testing the calculations... 20 | int mongrel2_ws_handshake_response(mongrel2_request *req, unsigned char response[16]); 21 | #endif /* M2WEBSOCKET_H */ 22 | 23 | -------------------------------------------------------------------------------- /deployment/deployment.conf: -------------------------------------------------------------------------------- 1 | body_toupper_handler = Handler( 2 | send_spec='tcp://127.0.0.1:9999', 3 | send_ident='54c6755b-9628-40a4-9a2d-cc82a816345e', 4 | recv_spec='tcp://127.0.0.1:9998', 5 | recv_ident='' 6 | ) 7 | 8 | fifo_reader_handler = Handler( 9 | send_spec='tcp://127.0.0.1:8999', 10 | send_ident='54c6755b-9628-40a4-9a2d-cc82a816345d', 11 | recv_spec='tcp://127.0.0.1:8998', 12 | recv_ident='' 13 | ) 14 | 15 | ws_handler = Handler( 16 | send_spec='tcp://127.0.0.1:7999', 17 | send_ident='54c6755b-9628-40a4-9a2d-cc82a816345c', 18 | recv_spec='tcp://127.0.0.1:7998', 19 | recv_ident='' 20 | ) 21 | 22 | main = Server( 23 | uuid="f400bf85-4538-4f7a-8908-67e313d515c2", 24 | access_log="/logs/access.log", 25 | error_log="/logs/error.log", 26 | chroot="./", 27 | default_host="localhost", 28 | name="test", 29 | pid_file="/run/mongrel2.pid", 30 | port=6767, 31 | hosts = [ 32 | Host(name="localhost", routes={ 33 | '/body_to_upper_handler' : body_toupper_handler, 34 | '/fifo_reader_handler' : fifo_reader_handler, 35 | '/ws_handler' : ws_handler, 36 | '/' : Dir(base='assets/', index_file='index.html', default_ctype='text/plain') 37 | }) 38 | ] 39 | ) 40 | 41 | servers = [main] 42 | -------------------------------------------------------------------------------- /lib/sample_handlers/body_toupper.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Start up your mongrel2 server 3 | * Run this program 4 | * Then test it out using curl 5 | * 6 | * Send a file from your current directory 7 | * curl localhost:6767/body_to_upper_handler -d @m2handler.c -v 8 | * 9 | * Send a string from the command line 10 | * curl localhost:6767/body_to_upper_handler -d "hello handler" -v 11 | * 12 | * 13 | */ 14 | #include "../m2handler.h" 15 | static const struct tagbstring SENDER = bsStatic("82209006-86FF-4982-B5EA-D1E29E55D481"); 16 | 17 | int main(int argc, char **args){ 18 | bstring pull_addr = bfromcstr("tcp://127.0.0.1:9999"); 19 | bstring pub_addr = bfromcstr("tcp://127.0.0.1:9998"); 20 | 21 | mongrel2_ctx *ctx = mongrel2_init(1); // Yes for threads? 22 | 23 | mongrel2_socket *pull_socket = mongrel2_pull_socket(ctx,bdata(&SENDER)); 24 | mongrel2_connect(pull_socket, bdata(pull_addr)); 25 | 26 | mongrel2_socket *pub_socket = mongrel2_pub_socket(ctx); 27 | mongrel2_connect(pub_socket, bdata(pub_addr)); 28 | 29 | const bstring headers = bfromcstr("HTTP/1.1 200 OK\r\nDate: Fri, 07 Jan 2011 01:15:42 GMT\r\nStatus: 200 OK\r\nConnection: close"); 30 | mongrel2_request *request; 31 | 32 | while(1){ 33 | request = mongrel2_recv(pull_socket); 34 | btoupper(request->body); 35 | mongrel2_reply_http(pub_socket, request, headers, request->body); 36 | mongrel2_disconnect(pub_socket, request); 37 | mongrel2_request_finalize(request); 38 | } 39 | 40 | bdestroy(headers); 41 | 42 | bdestroy(pull_addr); 43 | bdestroy(pub_addr); 44 | 45 | mongrel2_close(pull_socket); 46 | mongrel2_close(pub_socket); 47 | mongrel2_deinit(ctx); 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /deployment/assets/ws.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | WS Handshake Test 6 | 7 | 8 | 23 | 42 | 47 | 52 | 53 | 54 | 55 |

Interactive WebSocket Demo

56 | 57 | 58 | 59 | 60 | 61 |
Statusdisconnected
62 | 63 | 64 | 65 | 66 | 67 |

Debugging Messages

68 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /lib/m2handler.h: -------------------------------------------------------------------------------- 1 | /** 2 | Mongrel2 C handler 3 | * A reimplementation of the code that is in Zed's Mongrel2 code. 4 | * His libm2 has functionality for management, etc. This code is for 5 | * understanding the Mongrel2 protocol, for being able to dig into the code 6 | * from a handler's perspective only. No worrying about tasks, ragel, or whatever. 7 | * 8 | * The protocol is simple... so this code should simple, too! 9 | * 10 | * Lots of inspiration from the mongrel2 rack handler and the mongrel2 lua handler. 11 | */ 12 | 13 | #ifndef MONGREL_HANDLER_H 14 | #define MONGREL_HANDLER_H 15 | 16 | #include 17 | #include 18 | #include "bstr/bstrlib.h" 19 | #include "bstr/bstraux.h" 20 | 21 | struct mongrel2_ctx_t{ 22 | void* zmq_context; 23 | }; 24 | typedef struct mongrel2_ctx_t mongrel2_ctx; 25 | 26 | struct mongrel2_socket_t{ 27 | void* zmq_socket; 28 | }; 29 | typedef struct mongrel2_socket_t mongrel2_socket; 30 | 31 | struct mongrel2_request_t{ 32 | bstring uuid; 33 | int conn_id; 34 | bstring conn_id_bstr; 35 | bstring path; 36 | bstring raw_headers; 37 | json_t *headers; 38 | bstring body; 39 | }; 40 | typedef struct mongrel2_request_t mongrel2_request; 41 | 42 | mongrel2_ctx* mongrel2_init(int threads); 43 | int mongrel2_deinit(mongrel2_ctx *ctx); 44 | 45 | int mongrel2_connect(mongrel2_socket* socket, const char* dest); 46 | mongrel2_socket* mongrel2_pull_socket(mongrel2_ctx *ctx, char* identity); 47 | mongrel2_socket* mongrel2_pub_socket(mongrel2_ctx *ctx); 48 | int mongrel2_close(mongrel2_socket *socket); 49 | 50 | mongrel2_request *mongrel2_recv(mongrel2_socket *pull_socket); 51 | mongrel2_request *mongrel2_parse_request(bstring raw_mongrel_request); 52 | 53 | int mongrel2_send(mongrel2_socket *pub_socket, bstring response); 54 | int mongrel2_reply(mongrel2_socket *pub_socket, mongrel2_request *req, const_bstring payload); 55 | int mongrel2_reply_http(mongrel2_socket *pub_socket, mongrel2_request *req, const_bstring headers, const_bstring body); 56 | 57 | int mongrel2_request_for_disconnect(mongrel2_request *req); 58 | int mongrel2_disconnect(mongrel2_socket *pub_socket, mongrel2_request *req); 59 | 60 | bstring mongrel2_request_get_header(mongrel2_request *req, char* key); 61 | int mongrel2_request_finalize(mongrel2_request *req); 62 | #endif 63 | -------------------------------------------------------------------------------- /PROTOCOL.markdown: -------------------------------------------------------------------------------- 1 | How Messages From Mongrel2 Are Parsed 2 | ------------------------------------- 3 | 4 | Mongrel talks to handlers use zmq_msg_t's. You will be sending and receiving these over the course of your task. A zmq_mst_t has a opaque data field where your webserver-related info comes in -- you must parse the data field according the to the mongrel2 format (aka, a protocol on top of zmq). 5 | 6 | My C handler will parse for you and return a mongrel2_request_t. This has all the info you'll need to get going. 7 | 8 | Fields that may need explanation: 9 | UUID: The name of the mongrel2 instance that will be helping you out today. 128 bit number in hex with '-' thrown in. Always 36 characters. 10 | CONN_ID: Requests get an ID, a token to keep you and mongrel on the same page. Monotonic, always increasing int starts from 0. 11 | PATH: URL you know and love. 12 | HEADERS: JSON object (aka, a dictionary) 13 | BODY: An opaque buffer 14 | 15 | How data looks coming in from Mongrel2 16 | -------------------------------------- 17 | 18 | Spaces and commas are literal elements of the protocol. ZMQ message format for incoming requests: 19 | 20 | UUID CONN_ID PATH HEADER_NETSTRING,BODY_NETSTRING, 21 | 22 | Netstrings are defined as: 23 | 24 | STRINGIFEID_LENGTH_OF_DATA:DATA 25 | 26 | I sscanf the length into a uint32_t, allocate a buffer of that size, and put opaque_data into it. 27 | 28 | As my friend David says, they're like ASN.1 but easier. 29 | 30 | How data looks going back to Mongrel2 31 | ------------------------------------- 32 | 33 | Simpler than parsing the message. 34 | 35 | STR_CONN_LIST: 1-128 CONN_ID(s) seperated by a space. 36 | 37 | Example: "0 2 3" 38 | 39 | STR_CONN_LIST_LENGTH: The number of bytes, not entries, in the list. 40 | 41 | For STR_CONN_LIST example: 5 42 | 43 | CONN_NETSTRING: Expands as "STR_CONN_LIST_LENGTH:STR_CONN_LIST", where ':' is literal. 44 | OPAQUE_RESPONSE: Whatever you want, mongrel won't touch it 45 | 46 | High level description of the byte stream 47 | 48 | UUID CONN_NETSTRING, OPAQUE_RESPONSE 49 | 50 | Reasoning for a CONN_NETSTRING: Allow a single handler message to go to multiple clients. Web multicast made easy? Dunno, could be handy with websocket-y stuff. 51 | 52 | How disconnection works 53 | ----------------------- 54 | 55 | Disconnects are remote commands to mongrel2 saying, Hey, close that socket would ya? It is a special case of sending data to mongrel2 it's just that you send no data. Mongrel2 will interpret the empty payload as a CLOSE request. Don't forget the trailing space! 56 | 57 | UUID CONN_NETSTRING, 58 | 59 | 60 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | # Mongrel2 C Handler: libm2handler 2 | 3 | A C library for handling requests from Mongrel2. Includes a suite of sample handlers to get you up and running. 4 | 5 | ### Prequisites ### 6 | 7 | #### mongrel2 #### 8 | http://www.mongrel2.org/ 9 | Installed and configured to your liking. If you are trying out the sample handlers use ./config.sh in the deployment folder. 10 | 11 | #### libjansson #### 12 | http://www.digip.org/jansson/ 13 | https://github.com/akheron/jansson 14 | 15 | ### Valgrind ### 16 | 17 | This software was developed with valgrind in hand. 18 | 19 | valgrind --leak-check=full --gen-suppressions=yes ./mongrel_handler 20 | 21 | It throws a real shit fit about "Syscall param socketcall.sendto(msg) points to uninitialised byte(s)" and I have no idea how to work around it. It sounds harmless. 22 | 23 | AND I QUOTE (http://markmail.org/message/oqebrtdanawsiz62) 24 | This (common) problem is caused by writing to a socket (or a file) bytes derived from a structure which has alignment padding, which is uninitialised. That is harmless, but the problem is I don't know of a general way to suppress these errors which doesn't also potentially hide real bugs when you mistakenly write uninitialised data to a file/ socket. The best I can suggest is to do a case-by-case suppression yourself (--gen-suppressions=yes is your friend). 25 | END QUOTE 26 | 27 | ### Sample Handlers ### 28 | 29 | From inside of lib run 'make test' to build all the handlers. 30 | 31 | Test the WebSocket support 32 | (1) cd deployment && ./config.sh && ./start.sh 33 | (2) cd handler && make test && ./ws_handshake_handler 34 | (2) Open http://localhost:6767/ in Chrome (testing on 9.whatever and 10.whatever), browse to sample. 35 | 36 | Testing body_toupper_handler 37 | I use three terminal sessions: 38 | (1) cd deployment && ./config.sh && ./start.sh # Mongrel2 is up 39 | (2) cd handler && make test && ./body_toupper_handler 40 | (3) curl localhost:6767/body_to_upper_handler -d "hello handler" -v 41 | # The curl session should spit back the data but capitalized. 42 | 43 | Testing fifo_reader_handler 44 | Now we'll use four sessions 45 | (1) As before 46 | (2) cd handler && make test && ./fifo_reader_handler 47 | (3) curl http://localhost:6767/fifo_reader_handler 48 | (4) cd handler && cat Makefile > handler_pipe 49 | You will see the Makefile in the curl session. 50 | 51 | ### Contact ### 52 | Feel free to send me through github. Patches are welcome (and how!)! I'm also on mongrel2@librelist.com. 53 | 54 | Author: Xavier Lange 55 | License: My code is MIT. My websocket code uses the md5 function from PolarSSL -- that one is GPL. 56 | -------------------------------------------------------------------------------- /lib/Makefile: -------------------------------------------------------------------------------- 1 | OPTCFLAGS=-I/opt/local/include 2 | OPTLFLAGS=-L/opt/local/lib 3 | LOCAL_MONGREL2_LIB=-L. -lm2handler 4 | 5 | CFLAGS=-g -std=c99 -Wall -Werror $(OPTCFLAGS) 6 | LFLAGS=-L/opt/local/lib $(OPTLFLAGS) 7 | LIBS=-lzmq -ljansson 8 | PREFIX?=/usr/local 9 | 10 | SOURCES=m2handler.c bstr/bstrlib.c bstrlib.c 11 | 12 | all : lib 13 | 14 | m2handler.o : m2handler.h m2handler.c 15 | $(CC) $(CFLAGS) -c -o m2handler.o m2handler.c -I/opt/local/include 16 | 17 | m2websocket.o : m2websocket.h m2websocket.c 18 | $(CC) $(CFLAGS) -c -o m2websocket.o m2websocket.c -I/opt/local/include 19 | 20 | md5.o : md5/md5.h md5/md5.c md5/config.h 21 | $(CC) $(CFLAGS) -c -o md5.o md5/md5.c 22 | 23 | bstrlib.o : bstr/bstrlib.c bstr/bstrlib.h 24 | $(CC) $(CFLAGS) -c -o bstrlib.o bstr/bstrlib.c 25 | 26 | bstraux.o : bstr/bstraux.c bstr/bstraux.h 27 | $(CC) $(CFLAGS) -c -o bstraux.o bstr/bstraux.c -Ibstr 28 | 29 | lib: m2handler.o m2websocket.o md5.o bstrlib.o bstraux.o 30 | ar rcs libm2handler.a m2handler.o m2websocket.o md5.o bstrlib.o bstraux.o 31 | ranlib libm2handler.a 32 | 33 | test: body_toupper_handler fifo_reader_handler ws_handshake_handler 34 | 35 | body_toupper.o : sample_handlers/body_toupper.c 36 | $(CC) $(CFLAGS) -I. -c sample_handlers/body_toupper.c -o body_toupper.o 37 | 38 | body_toupper_handler: lib body_toupper.o bstrlib.o bstraux.o 39 | $(CC) $(LFLAGS) $(LIBS) -I. bstrlib.o bstraux.o body_toupper.o -o body_toupper_handler $(LOCAL_MONGREL2_LIB) 40 | 41 | fifo_reader.o : sample_handlers/fifo_reader.c 42 | $(CC) $(CFLAGS) -I. -c sample_handlers/fifo_reader.c -o fifo_reader.o 43 | 44 | fifo_reader_handler: lib fifo_reader.o bstrlib.o bstraux.o 45 | $(CC) $(LFLAGS) $(LIBS) -I. bstrlib.o bstraux.o fifo_reader.o -o fifo_reader_handler $(LOCAL_MONGREL2_LIB) 46 | 47 | ws_handshake.o : sample_handlers/ws_handshake.c 48 | $(CC) $(CFLAGS) -I. -c sample_handlers/ws_handshake.c -o ws_handshake.o 49 | 50 | ws_handshake_handler : lib ws_handshake.o bstrlib.o bstraux.o m2handler.o m2websocket.o 51 | $(CC) $(LFLAGS) $(LIBS) -I. bstrlib.o bstraux.o ws_handshake.o -o ws_handshake_handler $(LOCAL_MONGREL2_LIB) 52 | 53 | scan-build: 54 | scan-build make test 55 | 56 | install: lib 57 | install -d -o root $(PREFIX)/lib/ 58 | install -o root libm2handler.a $(PREFIX)/lib/ 59 | install -d -o root $(PREFIX)/include/ 60 | install -o root m2handler.h $(PREFIX)/include/ 61 | install -o root m2websocket.h $(PREFIX)/include/ 62 | install -d -o root $(PREFIX)/include/bstr/ 63 | install -o root bstr/bstrlib.h $(PREFIX)/include/bstr/ 64 | install -o root bstr/bstraux.h $(PREFIX)/include/bstr/ 65 | 66 | clean : 67 | rm -rf *.o m2handler libm2handler.a body_toupper_handler fifo_reader_handler ws_handshake_handler 68 | -------------------------------------------------------------------------------- /lib/sample_handlers/ws_handshake.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Start up your mongrel2 server 3 | * Run this program 4 | * Then test it out using Chrome 10 or higher 5 | */ 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "../m2handler.h" 13 | #include "../m2websocket.h" 14 | 15 | // Static function definitions 16 | static const struct tagbstring SENDER = bsStatic("82209006-86FF-4982-B5EA-D1E29E55D483"); 17 | 18 | // Shared variables 19 | static mongrel2_socket *pub_socket; 20 | static int shutdown = 0; 21 | 22 | static void call_for_stop(int sig_id){ 23 | if(sig_id == SIGINT){ 24 | if(shutdown == 1){ 25 | fprintf(stderr, "SHUTDOWN CALLED... ASSUMING MURDER!"); 26 | exit(EXIT_FAILURE); 27 | } 28 | shutdown = 1; 29 | } 30 | } 31 | 32 | int main(int argc, char **args){ 33 | signal(SIGINT,&call_for_stop); 34 | 35 | bstring pull_addr = bfromcstr("tcp://127.0.0.1:7999"); 36 | bstring pub_addr = bfromcstr("tcp://127.0.0.1:7998"); 37 | 38 | mongrel2_ctx *ctx = mongrel2_init(1); // Yes for threads? 39 | 40 | mongrel2_socket *pull_socket = mongrel2_pull_socket(ctx,bdata(&SENDER)); 41 | mongrel2_connect(pull_socket, bdata(pull_addr)); 42 | 43 | pub_socket = mongrel2_pub_socket(ctx); 44 | mongrel2_connect(pub_socket, bdata(pub_addr)); 45 | 46 | mongrel2_request *request; 47 | 48 | // Polling is done to show how to do a clean shutdown 49 | int poll_response; 50 | zmq_pollitem_t socket_tracker; 51 | socket_tracker.socket = pull_socket->zmq_socket; 52 | socket_tracker.events = ZMQ_POLLIN; 53 | 54 | while(shutdown != 1){ 55 | poll_response = zmq_poll(&socket_tracker,1,500*1000); 56 | if(poll_response > 0){ 57 | request = mongrel2_recv(pull_socket); 58 | fprintf(stdout,"got something..."); 59 | if(request != NULL && mongrel2_request_for_disconnect(request) != 1){ 60 | mongrel2_ws_reply_upgrade(request,pub_socket); 61 | bstring msg = bformat("{\"msg\" : \"hi there %d\"}", request->conn_id); 62 | mongrel2_ws_reply(pub_socket,request,msg); 63 | bdestroy(msg); 64 | mongrel2_request_finalize(request); 65 | } else { 66 | fprintf(stdout,"Connection %d disconnected\n", request->conn_id); 67 | } 68 | } else if (poll_response < 0){ 69 | fprintf(stdout, "Error on poll!"); 70 | shutdown = 1; 71 | } 72 | } 73 | 74 | bdestroy(pull_addr); 75 | bdestroy(pub_addr); 76 | 77 | mongrel2_close(pull_socket); 78 | mongrel2_close(pub_socket); 79 | mongrel2_deinit(ctx); 80 | fprintf(stdout,"\nClean shutdown done! Thanks for playing!\n"); 81 | return 0; 82 | } -------------------------------------------------------------------------------- /lib/sample_handlers/fifo_reader.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Start up your mongrel2 server 3 | * Run this program 4 | * Then test it out using curl. 5 | * 6 | * Loops on read, does not close initial request, just ctrl-c it to stop. 7 | * 8 | * 9 | * curl localhost:6767/fifo_reader_handler -d "hello handler" -v 10 | * 11 | * 12 | */ 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "../m2handler.h" 19 | static const struct tagbstring SENDER = bsStatic("82209006-86FF-4982-B5EA-D1E29E55D482"); 20 | 21 | int main(int argc, char **args){ 22 | bstring pull_addr = bfromcstr("tcp://127.0.0.1:8999"); 23 | bstring pub_addr = bfromcstr("tcp://127.0.0.1:8998"); 24 | 25 | mongrel2_ctx *ctx = mongrel2_init(1); // Yes for threads? 26 | 27 | mongrel2_socket *pull_socket = mongrel2_pull_socket(ctx,bdata(&SENDER)); 28 | mongrel2_connect(pull_socket, bdata(pull_addr)); 29 | 30 | mongrel2_socket *pub_socket = mongrel2_pub_socket(ctx); 31 | mongrel2_connect(pub_socket, bdata(pub_addr)); 32 | 33 | const bstring headers = bfromcstr("HTTP/1.1 200 OK\r\nDate: Fri, 07 Jan 2011 01:15:42 GMT\r\nStatus: 200 OK\r\nConnection: close"); 34 | mongrel2_request *request; 35 | 36 | // Need to set umask to allow file creation... then restore? Not sure! 37 | mode_t process_mask = umask(0); 38 | int retval; 39 | retval = mkfifo("handler_pipe", S_IRUSR); 40 | umask(process_mask); 41 | if(retval != 0){ 42 | switch(errno){ 43 | case EACCES : 44 | fprintf(stderr,"Insufficient permissions to create fifo handler_pipe"); 45 | case EEXIST : 46 | //fprintf(stderr,"handler_pipe already exists. That's cool tho."); 47 | goto no_mkfifo_error; 48 | case ENAMETOOLONG : 49 | fprintf(stderr,"handler_pipe is too long of a name. Unlikely!"); 50 | break; 51 | case ENOENT : 52 | fprintf(stderr,"path for handler_pipe does not exist"); 53 | break; 54 | case ENOSPC : 55 | fprintf(stderr,"no more room for handler_pipe"); 56 | break; 57 | case ENOTDIR : 58 | fprintf(stderr,"path for handler_pipe is not a directory"); 59 | break; 60 | case EROFS : 61 | fprintf(stderr,"handler_pipe cannot be created on read only fs"); 62 | break; 63 | default: 64 | fprintf(stderr,"Error creating fifo. Not sure what though. Sorry! %d",errno); 65 | break; 66 | } 67 | exit(EXIT_FAILURE); 68 | } 69 | no_mkfifo_error: 70 | fprintf(stdout,"Created handler_pipe AOK\n"); 71 | 72 | FILE *fifofd = fopen("handler_pipe","r"); 73 | if(fifofd == NULL){ 74 | fprintf(stderr,"Could not open handler_pipe"); 75 | exit(EXIT_FAILURE); 76 | } 77 | 78 | size_t read_size; 79 | request = mongrel2_recv(pull_socket); 80 | // A 1k buffer 81 | void* fifo_buffer = calloc(1024,1); 82 | //while(1){ 83 | read_size = fread(fifo_buffer, 1024, 1, fifofd); 84 | fprintf(stdout,"read_size from fifo: %zd", read_size); // z is for size_t's... weird! 85 | bdestroy(request->body); 86 | request->body = bfromcstralloc(1024,(const char*)fifo_buffer); 87 | mongrel2_reply_http(pub_socket, request, headers, request->body); 88 | mongrel2_disconnect(pub_socket, request); 89 | //} 90 | mongrel2_request_finalize(request); 91 | 92 | bdestroy(headers); 93 | 94 | bdestroy(pull_addr); 95 | bdestroy(pub_addr); 96 | 97 | mongrel2_close(pull_socket); 98 | mongrel2_close(pub_socket); 99 | mongrel2_deinit(ctx); 100 | return 0; 101 | } 102 | -------------------------------------------------------------------------------- /lib/md5/md5.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file md5.h 3 | * 4 | * \brief MD5 message digest algorithm (hash function) 5 | * 6 | * Copyright (C) 2006-2010, Brainspark B.V. 7 | * 8 | * This file is part of PolarSSL (http://www.polarssl.org) 9 | * Lead Maintainer: Paul Bakker 10 | * 11 | * All rights reserved. 12 | * 13 | * This program is free software; you can redistribute it and/or modify 14 | * it under the terms of the GNU General Public License as published by 15 | * the Free Software Foundation; either version 2 of the License, or 16 | * (at your option) any later version. 17 | * 18 | * This program is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | * GNU General Public License for more details. 22 | * 23 | * You should have received a copy of the GNU General Public License along 24 | * with this program; if not, write to the Free Software Foundation, Inc., 25 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 26 | */ 27 | #ifndef POLARSSL_MD5_H 28 | #define POLARSSL_MD5_H 29 | 30 | /** 31 | * \brief MD5 context structure 32 | */ 33 | typedef struct 34 | { 35 | unsigned long total[2]; /*!< number of bytes processed */ 36 | unsigned long state[4]; /*!< intermediate digest state */ 37 | unsigned char buffer[64]; /*!< data block being processed */ 38 | 39 | unsigned char ipad[64]; /*!< HMAC: inner padding */ 40 | unsigned char opad[64]; /*!< HMAC: outer padding */ 41 | } 42 | md5_context; 43 | 44 | #ifdef __cplusplus 45 | extern "C" { 46 | #endif 47 | 48 | /** 49 | * \brief MD5 context setup 50 | * 51 | * \param ctx context to be initialized 52 | */ 53 | void md5_starts( md5_context *ctx ); 54 | 55 | /** 56 | * \brief MD5 process buffer 57 | * 58 | * \param ctx MD5 context 59 | * \param input buffer holding the data 60 | * \param ilen length of the input data 61 | */ 62 | void md5_update( md5_context *ctx, const unsigned char *input, int ilen ); 63 | 64 | /** 65 | * \brief MD5 final digest 66 | * 67 | * \param ctx MD5 context 68 | * \param output MD5 checksum result 69 | */ 70 | void md5_finish( md5_context *ctx, unsigned char output[16] ); 71 | 72 | /** 73 | * \brief Output = MD5( input buffer ) 74 | * 75 | * \param input buffer holding the data 76 | * \param ilen length of the input data 77 | * \param output MD5 checksum result 78 | */ 79 | void md5( const unsigned char *input, int ilen, unsigned char output[16] ); 80 | 81 | /** 82 | * \brief Output = MD5( file contents ) 83 | * 84 | * \param path input file name 85 | * \param output MD5 checksum result 86 | * 87 | * \return 0 if successful, 1 if fopen failed, 88 | * or 2 if fread failed 89 | */ 90 | int md5_file( const char *path, unsigned char output[16] ); 91 | 92 | /** 93 | * \brief MD5 HMAC context setup 94 | * 95 | * \param ctx HMAC context to be initialized 96 | * \param key HMAC secret key 97 | * \param keylen length of the HMAC key 98 | */ 99 | void md5_hmac_starts( md5_context *ctx, 100 | const unsigned char *key, int keylen ); 101 | 102 | /** 103 | * \brief MD5 HMAC process buffer 104 | * 105 | * \param ctx HMAC context 106 | * \param input buffer holding the data 107 | * \param ilen length of the input data 108 | */ 109 | void md5_hmac_update( md5_context *ctx, 110 | const unsigned char *input, int ilen ); 111 | 112 | /** 113 | * \brief MD5 HMAC final digest 114 | * 115 | * \param ctx HMAC context 116 | * \param output MD5 HMAC checksum result 117 | */ 118 | void md5_hmac_finish( md5_context *ctx, unsigned char output[16] ); 119 | 120 | /** 121 | * \brief MD5 HMAC context reset 122 | * 123 | * \param ctx HMAC context to be reset 124 | */ 125 | void md5_hmac_reset( md5_context *ctx ); 126 | 127 | /** 128 | * \brief Output = HMAC-MD5( hmac key, input buffer ) 129 | * 130 | * \param key HMAC secret key 131 | * \param keylen length of the HMAC key 132 | * \param input buffer holding the data 133 | * \param ilen length of the input data 134 | * \param output HMAC-MD5 result 135 | */ 136 | void md5_hmac( const unsigned char *key, int keylen, 137 | const unsigned char *input, int ilen, 138 | unsigned char output[16] ); 139 | 140 | /** 141 | * \brief Checkup routine 142 | * 143 | * \return 0 if successful, or 1 if the test failed 144 | */ 145 | int md5_self_test( int verbose ); 146 | 147 | #ifdef __cplusplus 148 | } 149 | #endif 150 | 151 | #endif /* md5.h */ 152 | -------------------------------------------------------------------------------- /lib/bstr/bstraux.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This source file is part of the bstring string library. This code was 3 | * written by Paul Hsieh in 2002-2010, and is covered by either the 3-clause 4 | * BSD open source license or GPL v2.0. Refer to the accompanying documentation 5 | * for details on usage and license. 6 | */ 7 | 8 | /* 9 | * bstraux.h 10 | * 11 | * This file is not a necessary part of the core bstring library itself, but 12 | * is just an auxilliary module which includes miscellaneous or trivial 13 | * functions. 14 | */ 15 | 16 | #ifndef BSTRAUX_INCLUDE 17 | #define BSTRAUX_INCLUDE 18 | 19 | #include 20 | #include "bstrlib.h" 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | /* Safety mechanisms */ 27 | #define bstrDeclare(b) bstring (b) = NULL; 28 | #define bstrFree(b) {if ((b) != NULL && (b)->slen >= 0 && (b)->mlen >= (b)->slen) { bdestroy (b); (b) = NULL; }} 29 | 30 | /* Backward compatibilty with previous versions of Bstrlib */ 31 | #define bAssign(a,b) ((bassign)((a), (b))) 32 | #define bSubs(b,pos,len,a,c) ((breplace)((b),(pos),(len),(a),(unsigned char)(c))) 33 | #define bStrchr(b,c) ((bstrchr)((b), (c))) 34 | #define bStrchrFast(b,c) ((bstrchr)((b), (c))) 35 | #define bCatCstr(b,s) ((bcatcstr)((b), (s))) 36 | #define bCatBlk(b,s,len) ((bcatblk)((b),(s),(len))) 37 | #define bCatStatic(b,s) bCatBlk ((b), ("" s ""), sizeof (s) - 1) 38 | #define bTrunc(b,n) ((btrunc)((b), (n))) 39 | #define bReplaceAll(b,find,repl,pos) ((bfindreplace)((b),(find),(repl),(pos))) 40 | #define bUppercase(b) ((btoupper)(b)) 41 | #define bLowercase(b) ((btolower)(b)) 42 | #define bCaselessCmp(a,b) ((bstricmp)((a), (b))) 43 | #define bCaselessNCmp(a,b,n) ((bstrnicmp)((a), (b), (n))) 44 | #define bBase64Decode(b) (bBase64DecodeEx ((b), NULL)) 45 | #define bUuDecode(b) (bUuDecodeEx ((b), NULL)) 46 | 47 | /* Unusual functions */ 48 | extern struct bStream * bsFromBstr (const_bstring b); 49 | extern bstring bTail (bstring b, int n); 50 | extern bstring bHead (bstring b, int n); 51 | extern int bSetCstrChar (bstring a, int pos, char c); 52 | extern int bSetChar (bstring b, int pos, char c); 53 | extern int bFill (bstring a, char c, int len); 54 | extern int bReplicate (bstring b, int n); 55 | extern int bReverse (bstring b); 56 | extern int bInsertChrs (bstring b, int pos, int len, unsigned char c, unsigned char fill); 57 | extern bstring bStrfTime (const char * fmt, const struct tm * timeptr); 58 | #define bAscTime(t) (bStrfTime ("%c\n", (t))) 59 | #define bCTime(t) ((t) ? bAscTime (localtime (t)) : NULL) 60 | 61 | /* Spacing formatting */ 62 | extern int bJustifyLeft (bstring b, int space); 63 | extern int bJustifyRight (bstring b, int width, int space); 64 | extern int bJustifyMargin (bstring b, int width, int space); 65 | extern int bJustifyCenter (bstring b, int width, int space); 66 | 67 | /* Esoteric standards specific functions */ 68 | extern char * bStr2NetStr (const_bstring b); 69 | extern bstring bNetStr2Bstr (const char * buf); 70 | extern bstring bBase64Encode (const_bstring b); 71 | extern bstring bBase64DecodeEx (const_bstring b, int * boolTruncError); 72 | extern struct bStream * bsUuDecode (struct bStream * sInp, int * badlines); 73 | extern bstring bUuDecodeEx (const_bstring src, int * badlines); 74 | extern bstring bUuEncode (const_bstring src); 75 | extern bstring bYEncode (const_bstring src); 76 | extern bstring bYDecode (const_bstring src); 77 | 78 | /* Writable stream */ 79 | typedef int (* bNwrite) (const void * buf, size_t elsize, size_t nelem, void * parm); 80 | 81 | struct bwriteStream * bwsOpen (bNwrite writeFn, void * parm); 82 | int bwsWriteBstr (struct bwriteStream * stream, const_bstring b); 83 | int bwsWriteBlk (struct bwriteStream * stream, void * blk, int len); 84 | int bwsWriteFlush (struct bwriteStream * stream); 85 | int bwsIsEOF (const struct bwriteStream * stream); 86 | int bwsBuffLength (struct bwriteStream * stream, int sz); 87 | void * bwsClose (struct bwriteStream * stream); 88 | 89 | /* Security functions */ 90 | #define bSecureDestroy(b) { \ 91 | bstring bstr__tmp = (b); \ 92 | if (bstr__tmp && bstr__tmp->mlen > 0 && bstr__tmp->data) { \ 93 | (void) memset (bstr__tmp->data, 0, (size_t) bstr__tmp->mlen); \ 94 | bdestroy (bstr__tmp); \ 95 | } \ 96 | } 97 | #define bSecureWriteProtect(t) { \ 98 | if ((t).mlen >= 0) { \ 99 | if ((t).mlen > (t).slen)) { \ 100 | (void) memset ((t).data + (t).slen, 0, (size_t) (t).mlen - (t).slen); \ 101 | } \ 102 | (t).mlen = -1; \ 103 | } \ 104 | } 105 | extern bstring bSecureInput (int maxlen, int termchar, 106 | bNgetc vgetchar, void * vgcCtx); 107 | 108 | #ifdef __cplusplus 109 | } 110 | #endif 111 | 112 | #endif 113 | -------------------------------------------------------------------------------- /lib/md5/config.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file config.h 3 | * 4 | * \brief Configuration options (set of defines) 5 | * 6 | * Copyright (C) 2006-2010, Brainspark B.V. 7 | * 8 | * This file is part of PolarSSL (http://www.polarssl.org) 9 | * Lead Maintainer: Paul Bakker 10 | * 11 | * All rights reserved. 12 | * 13 | * This program is free software; you can redistribute it and/or modify 14 | * it under the terms of the GNU General Public License as published by 15 | * the Free Software Foundation; either version 2 of the License, or 16 | * (at your option) any later version. 17 | * 18 | * This program is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | * GNU General Public License for more details. 22 | * 23 | * You should have received a copy of the GNU General Public License along 24 | * with this program; if not, write to the Free Software Foundation, Inc., 25 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 26 | * 27 | * This set of compile-time options may be used to enable 28 | * or disable features selectively, and reduce the global 29 | * memory footprint. 30 | */ 31 | #ifndef POLARSSL_CONFIG_H 32 | #define POLARSSL_CONFIG_H 33 | 34 | #ifndef _CRT_SECURE_NO_DEPRECATE 35 | #define _CRT_SECURE_NO_DEPRECATE 1 36 | #endif 37 | 38 | /* 39 | * \name SECTION: System support 40 | * 41 | * This section sets system specific settings. 42 | * \{ 43 | */ 44 | 45 | /* 46 | * Uncomment if native integers are 8-bit wide. 47 | * 48 | #define POLARSSL_HAVE_INT8 49 | */ 50 | 51 | /* 52 | * Uncomment if native integers are 16-bit wide. 53 | * 54 | #define POLARSSL_HAVE_INT16 55 | */ 56 | 57 | /* 58 | * Uncomment if the compiler supports long long. 59 | * 60 | #define POLARSSL_HAVE_LONGLONG 61 | */ 62 | 63 | /* 64 | * Uncomment to enable the use of assembly code. 65 | * 66 | * Requires support for asm() in compiler. 67 | * 68 | * Used in: 69 | * library/timing.c 70 | * library/padlock.c 71 | * include/polarssl/bn_mul.h 72 | * 73 | */ 74 | #define POLARSSL_HAVE_ASM 75 | 76 | /* 77 | * Uncomment if the CPU supports SSE2 (IA-32 specific). 78 | * 79 | #define POLARSSL_HAVE_SSE2 80 | */ 81 | /* \} name */ 82 | 83 | /* 84 | * \name SECTION: PolarSSL feature support 85 | * 86 | * This section sets support for features that are or are not needed 87 | * within the modules that are enabled. 88 | * \{ 89 | */ 90 | 91 | /* 92 | * Enable all SSL/TLS debugging messages. 93 | */ 94 | #define POLARSSL_DEBUG_MSG 95 | 96 | /* 97 | * Enable the checkup functions (*_self_test). 98 | */ 99 | #define POLARSSL_SELF_TEST 100 | 101 | /* 102 | * Enable the prime-number generation code. 103 | */ 104 | #define POLARSSL_GENPRIME 105 | 106 | /* 107 | * Uncomment this macro to store the AES tables in ROM. 108 | * 109 | #define POLARSSL_AES_ROM_TABLES 110 | */ 111 | /* \} name */ 112 | 113 | /* 114 | * \name SECTION: PolarSSL modules 115 | * 116 | * This section enables or disables entire modules in PolarSSL 117 | * \{ 118 | */ 119 | 120 | /* 121 | * Module: library/aes.c 122 | * Caller: library/ssl_tls.c 123 | * 124 | * This module enables the following ciphersuites: 125 | * SSL_RSA_AES_128_SHA 126 | * SSL_RSA_AES_256_SHA 127 | * SSL_EDH_RSA_AES_256_SHA 128 | */ 129 | #define POLARSSL_AES_C 130 | 131 | /* 132 | * Module: library/arc4.c 133 | * Caller: library/ssl_tls.c 134 | * 135 | * This module enables the following ciphersuites: 136 | * SSL_RSA_RC4_128_MD5 137 | * SSL_RSA_RC4_128_SHA 138 | */ 139 | #define POLARSSL_ARC4_C 140 | 141 | /* 142 | * Module: library/base64.c 143 | * Caller: library/x509parse.c 144 | * 145 | * This module is required for X.509 support. 146 | */ 147 | #define POLARSSL_BASE64_C 148 | 149 | /* 150 | * Module: library/bignum.c 151 | * Caller: library/dhm.c 152 | * library/rsa.c 153 | * library/ssl_tls.c 154 | * library/x509parse.c 155 | * 156 | * This module is required for RSA and DHM support. 157 | */ 158 | #define POLARSSL_BIGNUM_C 159 | 160 | /* 161 | * Module: library/camellia.c 162 | * Caller: library/ssl_tls.c 163 | * 164 | * This module enabled the following cipher suites: 165 | * SSL_RSA_CAMELLIA_128_SHA 166 | * SSL_RSA_CAMELLIA_256_SHA 167 | * SSL_EDH_RSA_CAMELLIA_256_SHA 168 | */ 169 | #define POLARSSL_CAMELLIA_C 170 | 171 | /* 172 | * Module: library/certs.c 173 | * Caller: 174 | * 175 | * This module is used for testing (ssl_client/server). 176 | */ 177 | #define POLARSSL_CERTS_C 178 | 179 | /* 180 | * Module: library/cipher.c 181 | * Caller: 182 | * 183 | * Uncomment to enable generic cipher wrappers. 184 | */ 185 | #define POLARSSL_CIPHER_C 186 | 187 | /* 188 | * Module: library/debug.c 189 | * Caller: library/ssl_cli.c 190 | * library/ssl_srv.c 191 | * library/ssl_tls.c 192 | * 193 | * This module provides debugging functions. 194 | */ 195 | #define POLARSSL_DEBUG_C 196 | 197 | /* 198 | * Module: library/des.c 199 | * Caller: library/ssl_tls.c 200 | * 201 | * This module enables the following ciphersuites: 202 | * SSL_RSA_DES_168_SHA 203 | * SSL_EDH_RSA_DES_168_SHA 204 | */ 205 | #define POLARSSL_DES_C 206 | 207 | /* 208 | * Module: library/dhm.c 209 | * Caller: library/ssl_cli.c 210 | * library/ssl_srv.c 211 | * 212 | * This module enables the following ciphersuites: 213 | * SSL_EDH_RSA_DES_168_SHA 214 | * SSL_EDH_RSA_AES_256_SHA 215 | * SSL_EDH_RSA_CAMELLIA_256_SHA 216 | */ 217 | #define POLARSSL_DHM_C 218 | 219 | /* 220 | * Module: library/havege.c 221 | * Caller: 222 | * 223 | * This module enables the HAVEGE random number generator. 224 | */ 225 | #define POLARSSL_HAVEGE_C 226 | 227 | /* 228 | * Module: library/md.c 229 | * Caller: 230 | * 231 | * Uncomment to enable generic message digest wrappers. 232 | */ 233 | #define POLARSSL_MD_C 234 | 235 | /* 236 | * Module: library/md2.c 237 | * Caller: library/x509parse.c 238 | * 239 | * Uncomment to enable support for (rare) MD2-signed X.509 certs. 240 | * 241 | #define POLARSSL_MD2_C 242 | */ 243 | 244 | /* 245 | * Module: library/md4.c 246 | * Caller: library/x509parse.c 247 | * 248 | * Uncomment to enable support for (rare) MD4-signed X.509 certs. 249 | * 250 | #define POLARSSL_MD4_C 251 | */ 252 | 253 | /* 254 | * Module: library/md5.c 255 | * Caller: library/ssl_tls.c 256 | * library/x509parse.c 257 | * 258 | * This module is required for SSL/TLS and X.509. 259 | */ 260 | #define POLARSSL_MD5_C 261 | 262 | /* 263 | * Module: library/net.c 264 | * Caller: 265 | * 266 | * This module provides TCP/IP networking routines. 267 | */ 268 | #define POLARSSL_NET_C 269 | 270 | /* 271 | * Module: library/padlock.c 272 | * Caller: library/aes.c 273 | * 274 | * This modules adds support for the VIA PadLock on x86. 275 | */ 276 | #define POLARSSL_PADLOCK_C 277 | 278 | /* 279 | * Module: library/rsa.c 280 | * Caller: library/ssl_cli.c 281 | * library/ssl_srv.c 282 | * library/ssl_tls.c 283 | * library/x509.c 284 | * 285 | * This module is required for SSL/TLS and MD5-signed certificates. 286 | */ 287 | #define POLARSSL_RSA_C 288 | 289 | /* 290 | * Module: library/sha1.c 291 | * Caller: library/ssl_cli.c 292 | * library/ssl_srv.c 293 | * library/ssl_tls.c 294 | * library/x509parse.c 295 | * 296 | * This module is required for SSL/TLS and SHA1-signed certificates. 297 | */ 298 | #define POLARSSL_SHA1_C 299 | 300 | /* 301 | * Module: library/sha2.c 302 | * Caller: 303 | * 304 | * This module adds support for SHA-224 and SHA-256. 305 | */ 306 | #define POLARSSL_SHA2_C 307 | 308 | /* 309 | * Module: library/sha4.c 310 | * Caller: 311 | * 312 | * This module adds support for SHA-384 and SHA-512. 313 | */ 314 | #define POLARSSL_SHA4_C 315 | 316 | /* 317 | * Module: library/ssl_cli.c 318 | * Caller: 319 | * 320 | * This module is required for SSL/TLS client support. 321 | */ 322 | #define POLARSSL_SSL_CLI_C 323 | 324 | /* 325 | * Module: library/ssl_srv.c 326 | * Caller: 327 | * 328 | * This module is required for SSL/TLS server support. 329 | */ 330 | #define POLARSSL_SSL_SRV_C 331 | 332 | /* 333 | * Module: library/ssl_tls.c 334 | * Caller: library/ssl_cli.c 335 | * library/ssl_srv.c 336 | * 337 | * This module is required for SSL/TLS. 338 | */ 339 | #define POLARSSL_SSL_TLS_C 340 | 341 | /* 342 | * Module: library/ssl_srv.c 343 | * Caller: library/ssl_cli.c 344 | * library/ssl_srv.c 345 | * 346 | * This module is required for SSL/TLS PKCS #11 smartcard support. 347 | * Requires the presence of the PKCS#11 helper library (libpkcs11-helper) 348 | #define POLARSSL_PKCS11_C 349 | */ 350 | 351 | /* 352 | * Module: library/timing.c 353 | * Caller: library/havege.c 354 | * 355 | * This module is used by the HAVEGE random number generator. 356 | */ 357 | #define POLARSSL_TIMING_C 358 | 359 | /* 360 | * Module: library/version.c 361 | * 362 | * This module provides run-time version information. 363 | */ 364 | #define POLARSSL_VERSION_C 365 | 366 | /* 367 | * Module: library/x509parse.c 368 | * Caller: library/ssl_cli.c 369 | * library/ssl_srv.c 370 | * library/ssl_tls.c 371 | * 372 | * This module is required for X.509 certificate parsing. 373 | */ 374 | #define POLARSSL_X509_PARSE_C 375 | 376 | /* 377 | * Module: library/x509_write.c 378 | * Caller: 379 | * 380 | * This module is required for X.509 certificate writing. 381 | */ 382 | #define POLARSSL_X509_WRITE_C 383 | 384 | /* 385 | * Module: library/xtea.c 386 | * Caller: 387 | */ 388 | #define POLARSSL_XTEA_C 389 | /* \} name */ 390 | 391 | #endif /* config.h */ 392 | -------------------------------------------------------------------------------- /lib/m2websocket.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: m2websocket.c 3 | * Author: xavierlange 4 | * 5 | * Created on February 10, 2011, 3:07 PM 6 | */ 7 | 8 | #include 9 | #include 10 | #include "m2handler.h" 11 | #include "m2websocket.h" 12 | #include "md5/md5.h" 13 | 14 | #define START_CHAR (unsigned char)0x00 15 | #define TERM_CHAR (unsigned char)0xFF 16 | 17 | static uint32_t mongrel2_ws_concat_numbers(const char *incoming); 18 | static uint32_t mongrel2_ws_count_spaces(const char *incoming); 19 | static int mongrel2_ws_extract_seckey(const char* seckey_str, uint32_t *seckey); 20 | static int mongrel2_ws_calculate_response(uint32_t seckey1, uint32_t seckey2, bstring body, unsigned char md5output[16]); 21 | 22 | static const char* UPGRADE = 23 | "HTTP/1.1 101 WebSocket Protocol Handshake\r\n" 24 | "Upgrade: WebSocket\r\n" 25 | "Connection: Upgrade\r\n" 26 | "Sec-WebSocket-Location: %s\r\n" 27 | "Sec-WebSocket-Origin: %s\r\n" 28 | "Sec-WebSocket-Protocol: Sample"; 29 | 30 | int mongrel2_ws_reply_upgrade(mongrel2_request *req, mongrel2_socket *socket){ 31 | bstring headers = mongrel2_ws_upgrade_headers(req); 32 | bstring body = mongrel2_ws_upgrade_body(req); 33 | mongrel2_reply_http(socket,req,headers,body); 34 | bdestroy(headers); 35 | bdestroy(body); 36 | return 0; 37 | } 38 | 39 | bstring mongrel2_ws_upgrade_headers(mongrel2_request *req){ 40 | bstring origin = mongrel2_request_get_header(req,"origin"); 41 | bstring path = mongrel2_request_get_header(req,"PATH"); 42 | bstring host = mongrel2_request_get_header(req,"host"); 43 | 44 | //bstring location = bfromcstr("ws://localhost:6767/ws_handler"); 45 | //bstring origin = bfromcstr("http://localhost:6767"); 46 | bstring location = bformat("ws://%s%s",bdata(host),bdata(path)); 47 | fprintf(stdout,"LOCATION: %s", bdata(location)); 48 | bstring headers = bformat(UPGRADE,bdata(location),bdata(origin)); 49 | 50 | fprintf(stdout,"Headers: %s\n",bdata(req->raw_headers)); 51 | fprintf(stdout,"Body: %s\n",bdata(req->body)); 52 | fprintf(stdout,"Challenge Response: %s\n",bdata(headers)); 53 | 54 | bdestroy(location); 55 | bdestroy(host); 56 | bdestroy(path); 57 | bdestroy(origin); 58 | 59 | return headers; 60 | } 61 | 62 | bstring mongrel2_ws_upgrade_body(mongrel2_request *req){ 63 | unsigned char raw_response[16]; 64 | mongrel2_ws_handshake_response(req,raw_response); 65 | fprintf(stdout,"Response: %s\n",raw_response); 66 | // TODO: I assume this copies the content over! 67 | return blk2bstr(raw_response,16); 68 | } 69 | 70 | void mongrel2_ws_debug(bstring data){ 71 | if(data == NULL){ 72 | fprintf(stderr, "cannot debug null data"); 73 | return; 74 | } 75 | bstring single_hex = NULL; 76 | bstring single_char = NULL; 77 | 78 | bstring hex_dump = bfromcstr(""); 79 | bstring san_dump = bfromcstr(""); 80 | char* buf = calloc(4,sizeof(char)); 81 | if(buf == NULL || data == NULL){ 82 | fprintf(stderr, "debug could not allocate a conversion buffer"); 83 | goto exit; 84 | } 85 | 86 | unsigned char* raw_char; 87 | unsigned char* cstr = (unsigned char*)bdata(data); 88 | if(cstr == NULL){ 89 | goto exit; 90 | return; 91 | } 92 | 93 | for(int i=0; iraw_headers); 140 | bstring bseckey1 = mongrel2_request_get_header(req,"sec-websocket-key1"); 141 | bstring bseckey2 = mongrel2_request_get_header(req,"sec-websocket-key2"); 142 | if(bseckey1 == NULL || bseckey2 == NULL){ 143 | fprintf(stderr,"sec-websocket-key1 or 2 were not present"); 144 | bdestroy(bseckey1); 145 | bdestroy(bseckey2); 146 | return -1; 147 | } 148 | 149 | // TODO : This guy will be throwing error in the near future. 150 | // Gotta validate the websocket protocol anyway... 151 | uint32_t seckey2; 152 | mongrel2_ws_extract_seckey(bdata(bseckey2),&seckey2); 153 | uint32_t seckey1; 154 | mongrel2_ws_extract_seckey(bdata(bseckey1),&seckey1); 155 | 156 | mongrel2_ws_calculate_response(seckey1,seckey2,req->body, response); 157 | bdestroy(bseckey1); 158 | bdestroy(bseckey2); 159 | return 0; 160 | } 161 | 162 | static int mongrel2_ws_extract_seckey(const char* seckey_str, uint32_t *seckey){ 163 | uint32_t seckey_concat = mongrel2_ws_concat_numbers(seckey_str); 164 | uint32_t seckey_num_sp = mongrel2_ws_count_spaces(seckey_str); 165 | 166 | *seckey = seckey_concat/seckey_num_sp; 167 | return 0; 168 | } 169 | 170 | /** 171 | * Assumes little endian architecture! 172 | * Takes the inputs and returns the challenge response necessary 173 | * for completing a WS handshake. 174 | * @param seckey1 - Concated number, divided by number of spaces 175 | * @param seckey2 - Found same as seckey2 176 | * @param body - Body from their request 177 | * @param md5output - Room enough to store the md5'd result 178 | * @return 0 on success 179 | */ 180 | static int mongrel2_ws_calculate_response(uint32_t seckey1, uint32_t seckey2, bstring body, unsigned char md5output[16]){ 181 | // TODO test if body is 8 bytes. 182 | char* md5input = calloc(16,sizeof(char)); 183 | char* seckey1_bytes = (char*)&seckey1; 184 | char* seckey2_bytes = (char*)&seckey2; 185 | char* body_str = bdata(body); 186 | if(body_str == NULL){ 187 | fprintf(stderr, "mongrel2_ws_calculate_reponse got an empty body..."); 188 | return -1; 189 | } 190 | 191 | // TODO this assumes little endian arch. Do a runtime check in the future to make it cross platform. 192 | md5input[0] = seckey1_bytes[3]; 193 | md5input[1] = seckey1_bytes[2]; 194 | md5input[2] = seckey1_bytes[1]; 195 | md5input[3] = seckey1_bytes[0]; 196 | 197 | md5input[4] = seckey2_bytes[3]; 198 | md5input[5] = seckey2_bytes[2]; 199 | md5input[6] = seckey2_bytes[1]; 200 | md5input[7] = seckey2_bytes[0]; 201 | 202 | memcpy((void*)&md5input[8], body_str, 8); 203 | 204 | md5((const unsigned char *)md5input, 16, md5output); 205 | free(md5input); 206 | return 0; 207 | } 208 | 209 | /** 210 | * Take a normal C string, concats all the numbers characters 211 | * and then turns that into a computer-native value. 212 | * @param incoming 213 | * @return 214 | */ 215 | static uint32_t mongrel2_ws_concat_numbers(const char *incoming){ 216 | char* numbuff = calloc(16,sizeof(char)); 217 | int ni = 0; 218 | for(int i=0; i= 0 && incoming[i]-'9' <= 0){ 220 | numbuff[ni] = incoming[i]; 221 | ni = ni + 1; 222 | } 223 | } 224 | uint32_t extracted_number; 225 | sscanf(numbuff,"%u",&extracted_number); 226 | free(numbuff); 227 | return extracted_number; 228 | } 229 | 230 | static uint32_t mongrel2_ws_count_spaces(const char *incoming){ 231 | int count = 0; 232 | for(int i=0; iraw_headers = bfromcstr(headers); 255 | req->body = bfromcstr(body); 256 | unsigned char response[16]; 257 | mongrel2_ws_handshake_response(req, response); 258 | if(strncmp((const char*)response,"fQJ,fN/4F4!~K~MH",16) != 0){ 259 | fprintf(stdout,"Response did not match expection\n"); 260 | fprintf(stdout,"Exepcted: fQJ,fN/4F4!~K~MH\n"); 261 | fprintf(stdout,"Got: %s",response); 262 | } 263 | mongrel2_request_finalize(req); 264 | return 0; 265 | } 266 | -------------------------------------------------------------------------------- /lib/m2handler.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright Xavier Lange 2011 3 | * Simple handler for bridging C into mongrel2. Hopefully a useful 4 | * exploration of the simple protcol/pattern to setup plumbing. 5 | * 6 | * 7 | * ZMQ documentation: http://api.zeromq.org/ 8 | * Mongrel2 documentation: http://mongrel2.org/doc/tip/docs/manual/book.wiki 9 | * 10 | */ 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "m2handler.h" 17 | #include "bstr/bstrlib.h" 18 | #include "bstr/bstraux.h" 19 | #include 20 | 21 | #define DEBUG 22 | 23 | static const struct tagbstring SPACE = bsStatic(" "); 24 | static const struct tagbstring COLON = bsStatic(":"); 25 | static const struct tagbstring COMMA = bsStatic(","); 26 | static const struct tagbstring SEPERATOR = bsStatic("\r\n\r\n"); 27 | static const struct tagbstring JSON = bsStatic("JSON"); 28 | static const struct tagbstring DISCONNECT = bsStatic("disconnect"); 29 | static const char *RESPONSE_HEADER = "%s %d:%d, "; 30 | 31 | static void zmq_bstr_free(void *data, void *bstr){ 32 | bdestroy(bstr); 33 | } 34 | 35 | mongrel2_ctx* mongrel2_init(int threads){ 36 | mongrel2_ctx* ctx = calloc(1,sizeof(mongrel2_ctx)); 37 | ctx->zmq_context = zmq_init(threads); 38 | if(ctx->zmq_context == NULL){ 39 | fprintf(stderr, "Could not initialize zmq context"); 40 | exit(EXIT_FAILURE); 41 | } 42 | return ctx; 43 | } 44 | int mongrel2_deinit(mongrel2_ctx *ctx){ 45 | int zmq_retval = zmq_term(ctx->zmq_context); 46 | if(zmq_retval != 0){ 47 | fprintf(stderr,"Could not terminate ZMQ context"); 48 | exit(EXIT_FAILURE); 49 | } 50 | free(ctx); 51 | return 0; 52 | } 53 | /** 54 | * Made static because people don't necessarily need to use it. Thoughts? Should 55 | * it be publicly accessible? 56 | * @param ctx 57 | * @param type 58 | * @return 59 | */ 60 | static mongrel2_socket* mongrel2_alloc_socket(mongrel2_ctx *ctx, int type){ 61 | mongrel2_socket *ptr = calloc(1,sizeof(mongrel2_socket)); 62 | ptr->zmq_socket = zmq_socket(ctx->zmq_context, type); 63 | if(ptr == NULL || ptr->zmq_socket == NULL){ 64 | fprintf(stderr, "Could not allocate socket"); 65 | exit(EXIT_FAILURE); 66 | } 67 | return ptr; 68 | } 69 | /** 70 | * Identity is only needed for pull sockets (right?) so I'll only 71 | * mongrel2_pull_socket will call this. 72 | * @param ctx 73 | * @param socket 74 | * @param identity 75 | */ 76 | static void mongrel2_set_identity(mongrel2_ctx *ctx, mongrel2_socket *socket, const char* identity){ 77 | int zmq_retval = zmq_setsockopt(socket->zmq_socket,ZMQ_IDENTITY,identity,strlen(identity)); 78 | if(zmq_retval != 0){ 79 | switch(errno){ 80 | case EINVAL : { 81 | fprintf(stderr, "Unknown setsockopt property"); 82 | break; 83 | } 84 | case ETERM : { 85 | fprintf(stderr, "ZMQ context already terminated"); 86 | break; 87 | } 88 | case EFAULT : { 89 | fprintf(stderr, "Socket provided was not valid"); 90 | break; 91 | } 92 | } 93 | exit(EXIT_FAILURE); 94 | } 95 | } 96 | mongrel2_socket* mongrel2_pull_socket(mongrel2_ctx *ctx, char* identity){ 97 | mongrel2_socket *socket; 98 | socket = mongrel2_alloc_socket(ctx,ZMQ_PULL); 99 | 100 | mongrel2_set_identity(ctx,socket,identity); 101 | 102 | return socket; 103 | } 104 | mongrel2_socket* mongrel2_pub_socket(mongrel2_ctx *ctx){ 105 | mongrel2_socket *socket; 106 | socket = mongrel2_alloc_socket(ctx,ZMQ_PUB); 107 | return socket; 108 | } 109 | int mongrel2_connect(mongrel2_socket* socket, const char* dest){ 110 | int zmq_retval; 111 | zmq_retval = zmq_connect(socket->zmq_socket, dest); 112 | if(zmq_retval != 0){ 113 | switch(errno){ 114 | case EPROTONOSUPPORT : { 115 | fprintf(stderr, "Protocol not supported"); 116 | break; 117 | } 118 | case ENOCOMPATPROTO : { 119 | fprintf(stderr, "Protocol not compatible with socket type"); 120 | break; 121 | } 122 | case ETERM : { 123 | fprintf(stderr, "ZMQ context has already been terminated"); 124 | break; 125 | } 126 | case EFAULT : { 127 | fprintf(stderr, "A NULL socket was provided"); 128 | break; 129 | } 130 | } 131 | exit(EXIT_FAILURE); 132 | } 133 | return 0; 134 | } 135 | /** 136 | * Honky-dory hand-made parser for mongrel2's request format 137 | * 138 | * Will only work for small requests, although structure is generous. Beware! 139 | * 140 | * @param netstring 141 | * @return 142 | */ 143 | mongrel2_request *mongrel2_parse_request(bstring raw_request_bstr){ 144 | #ifdef DEBUG 145 | fprintf(stdout, "======NETSTRING======\n"); 146 | fprintf(stdout, "%.*s\n",blength(raw_request_bstr),bdata(raw_request_bstr)); 147 | fprintf(stdout, "=====================\n"); 148 | #endif 149 | 150 | mongrel2_request* req = calloc(1, sizeof(mongrel2_request)); 151 | if(req == NULL){ 152 | fprintf(stderr,"Could not allocate mongrel2_request"); 153 | goto error; 154 | } 155 | 156 | // bfromcstr(raw_mongrel_request); 157 | int suuid = 0, euuid; 158 | int sconnid, econnid; 159 | int spath, epath; 160 | int sheader, eheader; 161 | int sbody, ebody; 162 | 163 | // Extract the UUID 164 | euuid = binchr(raw_request_bstr, suuid, &SPACE); 165 | req->uuid = bmidstr(raw_request_bstr, suuid, euuid-suuid); 166 | if(req->uuid == NULL){ 167 | fprintf(stderr,"Could not extract UUID!"); 168 | goto error; 169 | } 170 | 171 | // Extract the Connection ID 172 | sconnid = euuid+1; // Skip over the space delimiter 173 | econnid = binchr(raw_request_bstr, sconnid, &SPACE); 174 | req->conn_id_bstr = bmidstr(raw_request_bstr,sconnid,econnid-sconnid); 175 | if(req->conn_id_bstr == NULL){ 176 | fprintf(stderr, "Could not extract connection id"); 177 | goto error; 178 | } 179 | sscanf(bdata(req->conn_id_bstr),"%d",&req->conn_id); 180 | 181 | // Extract the Path 182 | spath = econnid+1; // Skip over the space delimiter 183 | epath = binchr(raw_request_bstr, spath, &SPACE); 184 | req->path = bmidstr(raw_request_bstr,spath,epath-spath); 185 | if(req->path == NULL){ 186 | fprintf(stderr, "Could not extract Path"); 187 | goto error; 188 | } 189 | 190 | // Extract the headers 191 | // First we grab the length value as an int 192 | bstring tempheaderlenbstr; 193 | sheader = epath+1; // Skip over the space delimiter 194 | eheader = binchr(raw_request_bstr, sheader, &COLON); 195 | tempheaderlenbstr = bmidstr(raw_request_bstr,sheader,eheader-sheader); 196 | int headerlen; 197 | sscanf(bdata(tempheaderlenbstr),"%d",&headerlen); 198 | bdestroy(tempheaderlenbstr); 199 | 200 | // Now that we know the header length we can actually extract it 201 | sheader = eheader+1; // Skip over the number and the colon 202 | eheader = sheader+headerlen; 203 | req->raw_headers = bmidstr(raw_request_bstr,sheader,eheader-sheader); 204 | if(req->raw_headers == NULL){ 205 | fprintf(stderr,"could not extract headers"); 206 | goto error; 207 | } else if(blength(req->raw_headers) != headerlen){ 208 | fprintf(stderr,"Expected headerlen to be %d, got %d",headerlen,blength(req->raw_headers)); 209 | goto error; 210 | } 211 | 212 | // Extract the body 213 | // First we grab the length value as an int 214 | bstring tempbodylenbstr; 215 | sbody = eheader+1; // Skip over the comma 216 | ebody = binchr(raw_request_bstr,sbody,&COLON); 217 | tempbodylenbstr = bmidstr(raw_request_bstr,sbody,ebody-sbody); 218 | int bodylen; 219 | sscanf(bdata(tempbodylenbstr),"%d",&bodylen); 220 | bdestroy(tempbodylenbstr); 221 | 222 | // Nowe we have the body len we can extract the payload 223 | sbody = ebody+1; // Skip over the number and the colon 224 | ebody = sbody+bodylen; 225 | req->body = bmidstr(raw_request_bstr,sbody,ebody-sbody); 226 | if(req->body == NULL){ 227 | fprintf(stderr,"could not extract body"); 228 | goto error; 229 | } else if(blength(req->body) != bodylen){ 230 | fprintf(stderr,"Expected body to be %d, got %d",bodylen,blength(req->body)); 231 | goto error; 232 | } 233 | 234 | #ifdef DEBUG 235 | fprintf(stdout,"========PARSE_NETSTRING=========\n"); 236 | fprintf(stdout,"SERVER_UUID: %s\n",bdata(req->uuid)); 237 | fprintf(stdout,"CONNECTION_ID: %d\n",req->conn_id); 238 | fprintf(stdout,"PATH: %s\n",bdata(req->path)); 239 | fprintf(stdout,"HEADERS: %s\n",bdata(req->raw_headers)); 240 | fprintf(stdout,"BODY: %s\n",bdata(req->body)); 241 | fprintf(stdout,"================================\n"); 242 | #endif 243 | 244 | // TODO: error situations here? 245 | json_error_t header_err; 246 | req->headers = json_loads(bdata(req->raw_headers),0,&header_err);// json_string(bdata(req->raw_headers)); 247 | if(req->headers == NULL){ 248 | fprintf(stderr,"Problem parsing the inputs near position: %d, line: %d, col: %d",header_err.position,header_err.line,header_err.position); 249 | goto error; 250 | } 251 | if(json_typeof(req->headers) != JSON_OBJECT){ 252 | fprintf(stderr, "Headers did not turn into an object... ruh roh!"); 253 | } 254 | 255 | bdestroy(raw_request_bstr); 256 | return req; 257 | 258 | error: 259 | bdestroy(raw_request_bstr); 260 | mongrel2_request_finalize(req); 261 | return NULL; 262 | } 263 | 264 | /** 265 | * Valgrind thinks there's a memory leak happening from here... 266 | * A lot of 'syscall param socketcall.send(msg) point to unitialized byte(s)' 267 | * throughout my code. TBD! 268 | * @param pull_socket 269 | * @return 0 on success, -1 on failure. If failure, disconnect host and finalize. 270 | */ 271 | mongrel2_request *mongrel2_recv(mongrel2_socket *pull_socket){ 272 | zmq_msg_t *msg = calloc(1,sizeof(zmq_msg_t)); 273 | zmq_msg_init(msg); 274 | zmq_recv(pull_socket->zmq_socket,msg,0); 275 | 276 | bstring raw_request_bstr = blk2bstr(zmq_msg_data(msg),zmq_msg_size(msg)); 277 | mongrel2_request *req = mongrel2_parse_request(raw_request_bstr); 278 | 279 | zmq_msg_close(msg); 280 | free(msg); 281 | 282 | return req; 283 | } 284 | 285 | /** 286 | * The most raw interface to the Mongrel2 webserver. Takes ownership of response. 287 | * @param pub_socket 288 | * @param response_buff 289 | */ 290 | int mongrel2_send(mongrel2_socket *pub_socket, bstring response){ 291 | zmq_msg_t *msg = calloc(1,sizeof(zmq_msg_t)); 292 | 293 | /** 294 | * zmq_bstr_free was calling free on bdata(response) which was wrong! 295 | * It needs to be called on the bstring itself. So that gets passed 296 | * in as the hint. Whew. 297 | */ 298 | zmq_msg_init_data(msg,bdata(response),blength(response),zmq_bstr_free,response); 299 | 300 | zmq_send(pub_socket->zmq_socket,msg,0); 301 | zmq_msg_close(msg); 302 | free(msg); 303 | 304 | #ifdef DEBUG 305 | fprintf(stdout,"=======MONGREL2_SEND==========\n"); 306 | fprintf(stdout,"''%.*s''\n",blength(response),bdata(response)); 307 | fprintf(stdout,"==============================\n"); 308 | #endif 309 | return 0; 310 | } 311 | /** 312 | * Convenience method for when you have headers and a body. 313 | * @param pub_socket 314 | * @param req 315 | * @param headers 316 | * @param body 317 | * @return 318 | */ 319 | int mongrel2_reply_http(mongrel2_socket *pub_socket, mongrel2_request *req, const_bstring headers, const_bstring body){ 320 | bstring payload = bstrcpy(headers); 321 | bconcat(payload, &SEPERATOR); 322 | bconcat(payload,body); 323 | // mongrel2_send(pub_socket,response); 324 | int retval = mongrel2_reply(pub_socket, req, payload); 325 | bdestroy(payload); 326 | return retval; 327 | } 328 | /** 329 | * The big kahuna. Formats protocol message to mongrel2 and sends along your payload. 330 | * Does not take ownership of payload. 331 | * @param pub_socket 332 | * @param req 333 | * @param payload 334 | * @return 335 | */ 336 | int mongrel2_reply(mongrel2_socket *pub_socket, mongrel2_request *req, const_bstring payload){ 337 | bstring response = bformat(RESPONSE_HEADER,bdata(req->uuid),blength(req->conn_id_bstr),req->conn_id); 338 | bconcat(response,payload); 339 | return mongrel2_send(pub_socket,response); 340 | } 341 | 342 | int mongrel2_request_for_disconnect(mongrel2_request *req){ 343 | bstring header = NULL; 344 | json_t *json_body = NULL; 345 | json_t *method_obj = NULL; 346 | const char *method_str = NULL; 347 | 348 | const char* body_str = bdata(req->body); 349 | json_error_t jerr; 350 | json_body = json_loads(body_str,0,&jerr); 351 | if(json_body == NULL || !json_is_object(json_body)){ 352 | json_decref(json_body); 353 | bdestroy(header); 354 | return 0; 355 | } 356 | 357 | method_obj = json_object_get(json_body,"type"); 358 | if(method_obj == NULL){ 359 | json_decref(json_body); 360 | bdestroy(header); 361 | return 0; 362 | } 363 | 364 | method_str = json_string_value(method_obj); 365 | bstring method_bstr = bfromcstr(method_str); 366 | json_decref(method_obj); 367 | json_decref(json_body); 368 | 369 | if(method_obj == NULL || bstrcmp(method_bstr,&DISCONNECT) != 0){ 370 | bdestroy(method_bstr); 371 | json_decref(method_obj); 372 | json_decref(json_body); 373 | bdestroy(header); 374 | return 0; 375 | } 376 | bdestroy(method_bstr); 377 | 378 | json_decref(method_obj); 379 | json_decref(json_body); 380 | bdestroy(header); 381 | return 1; 382 | } 383 | 384 | /** 385 | * Convenience method for sending a close request. Essentially a mongrel2_reply with an empty payload. 386 | * @param pub_socket 387 | * @param req 388 | * @return 389 | */ 390 | int mongrel2_disconnect(mongrel2_socket *pub_socket, mongrel2_request *req){ 391 | if(req == NULL){ 392 | fprintf(stderr,"mongrel2_disconnect called with NULL pub_socket"); 393 | return -1; 394 | } else if (pub_socket == NULL){ 395 | fprintf(stderr,"mongrel2_disconnect called with NULL request"); 396 | return -1; 397 | } 398 | bstring close = bfromcstr(""); 399 | return mongrel2_reply(pub_socket,req,close); 400 | } 401 | 402 | /** 403 | * Returns a copy of the header value. You must free this yourself. 404 | * @param req 405 | * @param key 406 | * @return 407 | */ 408 | bstring mongrel2_request_get_header(mongrel2_request *req, char* key){ 409 | json_t *header_val_obj = json_object_get(req->headers,key); 410 | const char* val_str = json_string_value(header_val_obj); 411 | bstring retval = bfromcstr((char*)val_str); 412 | json_decref(header_val_obj); 413 | 414 | return retval; 415 | } 416 | 417 | // CLEANUP OPERATIONS 418 | int mongrel2_request_finalize(mongrel2_request *req){ 419 | bdestroy(req->body); 420 | bdestroy(req->raw_headers); 421 | bdestroy(req->path); 422 | bdestroy(req->uuid); 423 | bdestroy(req->conn_id_bstr); 424 | json_decref(req->headers); 425 | free(req); 426 | return 0; 427 | } 428 | int mongrel2_close(mongrel2_socket *socket){ 429 | if(socket == NULL || socket->zmq_socket == NULL){ 430 | fprintf(stderr, "called mongrel2_close on something weird"); 431 | exit(EXIT_FAILURE); 432 | } 433 | zmq_close(socket->zmq_socket); 434 | free(socket); 435 | return 0; 436 | } 437 | -------------------------------------------------------------------------------- /lib/bstr/bstrlib.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This source file is part of the bstring string library. This code was 3 | * written by Paul Hsieh in 2002-2010, and is covered by either the 3-clause 4 | * BSD open source license or GPL v2.0. Refer to the accompanying documentation 5 | * for details on usage and license. 6 | */ 7 | 8 | /* 9 | * bstrlib.h 10 | * 11 | * This file is the header file for the core module for implementing the 12 | * bstring functions. 13 | */ 14 | 15 | #ifndef BSTRLIB_INCLUDE 16 | #define BSTRLIB_INCLUDE 17 | 18 | #ifdef __cplusplus 19 | extern "C" { 20 | #endif 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #if !defined (BSTRLIB_VSNP_OK) && !defined (BSTRLIB_NOVSNP) 28 | # if defined (__TURBOC__) && !defined (__BORLANDC__) 29 | # define BSTRLIB_NOVSNP 30 | # endif 31 | #endif 32 | 33 | #define BSTR_ERR (-1) 34 | #define BSTR_OK (0) 35 | #define BSTR_BS_BUFF_LENGTH_GET (0) 36 | 37 | typedef struct tagbstring * bstring; 38 | typedef const struct tagbstring * const_bstring; 39 | 40 | /* Copy functions */ 41 | #define cstr2bstr bfromcstr 42 | extern bstring bfromcstr (const char * str); 43 | extern bstring bfromcstralloc (int mlen, const char * str); 44 | extern bstring blk2bstr (const void * blk, int len); 45 | extern char * bstr2cstr (const_bstring s, char z); 46 | extern int bcstrfree (char * s); 47 | extern bstring bstrcpy (const_bstring b1); 48 | extern int bassign (bstring a, const_bstring b); 49 | extern int bassignmidstr (bstring a, const_bstring b, int left, int len); 50 | extern int bassigncstr (bstring a, const char * str); 51 | extern int bassignblk (bstring a, const void * s, int len); 52 | 53 | /* Destroy function */ 54 | extern int bdestroy (bstring b); 55 | 56 | /* Space allocation hinting functions */ 57 | extern int balloc (bstring s, int len); 58 | extern int ballocmin (bstring b, int len); 59 | 60 | /* Substring extraction */ 61 | extern bstring bmidstr (const_bstring b, int left, int len); 62 | 63 | /* Various standard manipulations */ 64 | extern int bconcat (bstring b0, const_bstring b1); 65 | extern int bconchar (bstring b0, char c); 66 | extern int bcatcstr (bstring b, const char * s); 67 | extern int bcatblk (bstring b, const void * s, int len); 68 | extern int binsert (bstring s1, int pos, const_bstring s2, unsigned char fill); 69 | extern int binsertch (bstring s1, int pos, int len, unsigned char fill); 70 | extern int breplace (bstring b1, int pos, int len, const_bstring b2, unsigned char fill); 71 | extern int bdelete (bstring s1, int pos, int len); 72 | extern int bsetstr (bstring b0, int pos, const_bstring b1, unsigned char fill); 73 | extern int btrunc (bstring b, int n); 74 | 75 | /* Scan/search functions */ 76 | extern int bstricmp (const_bstring b0, const_bstring b1); 77 | extern int bstrnicmp (const_bstring b0, const_bstring b1, int n); 78 | extern int biseqcaseless (const_bstring b0, const_bstring b1); 79 | extern int bisstemeqcaselessblk (const_bstring b0, const void * blk, int len); 80 | extern int biseq (const_bstring b0, const_bstring b1); 81 | extern int bisstemeqblk (const_bstring b0, const void * blk, int len); 82 | extern int biseqcstr (const_bstring b, const char * s); 83 | extern int biseqcstrcaseless (const_bstring b, const char * s); 84 | extern int bstrcmp (const_bstring b0, const_bstring b1); 85 | extern int bstrncmp (const_bstring b0, const_bstring b1, int n); 86 | extern int binstr (const_bstring s1, int pos, const_bstring s2); 87 | extern int binstrr (const_bstring s1, int pos, const_bstring s2); 88 | extern int binstrcaseless (const_bstring s1, int pos, const_bstring s2); 89 | extern int binstrrcaseless (const_bstring s1, int pos, const_bstring s2); 90 | extern int bstrchrp (const_bstring b, int c, int pos); 91 | extern int bstrrchrp (const_bstring b, int c, int pos); 92 | #define bstrchr(b,c) bstrchrp ((b), (c), 0) 93 | #define bstrrchr(b,c) bstrrchrp ((b), (c), blength(b)-1) 94 | extern int binchr (const_bstring b0, int pos, const_bstring b1); 95 | extern int binchrr (const_bstring b0, int pos, const_bstring b1); 96 | extern int bninchr (const_bstring b0, int pos, const_bstring b1); 97 | extern int bninchrr (const_bstring b0, int pos, const_bstring b1); 98 | extern int bfindreplace (bstring b, const_bstring find, const_bstring repl, int pos); 99 | extern int bfindreplacecaseless (bstring b, const_bstring find, const_bstring repl, int pos); 100 | 101 | /* List of string container functions */ 102 | struct bstrList { 103 | int qty, mlen; 104 | bstring * entry; 105 | }; 106 | extern struct bstrList * bstrListCreate (void); 107 | extern int bstrListDestroy (struct bstrList * sl); 108 | extern int bstrListAlloc (struct bstrList * sl, int msz); 109 | extern int bstrListAllocMin (struct bstrList * sl, int msz); 110 | 111 | /* String split and join functions */ 112 | extern struct bstrList * bsplit (const_bstring str, unsigned char splitChar); 113 | extern struct bstrList * bsplits (const_bstring str, const_bstring splitStr); 114 | extern struct bstrList * bsplitstr (const_bstring str, const_bstring splitStr); 115 | extern bstring bjoin (const struct bstrList * bl, const_bstring sep); 116 | extern int bsplitcb (const_bstring str, unsigned char splitChar, int pos, 117 | int (* cb) (void * parm, int ofs, int len), void * parm); 118 | extern int bsplitscb (const_bstring str, const_bstring splitStr, int pos, 119 | int (* cb) (void * parm, int ofs, int len), void * parm); 120 | extern int bsplitstrcb (const_bstring str, const_bstring splitStr, int pos, 121 | int (* cb) (void * parm, int ofs, int len), void * parm); 122 | 123 | /* Miscellaneous functions */ 124 | extern int bpattern (bstring b, int len); 125 | extern int btoupper (bstring b); 126 | extern int btolower (bstring b); 127 | extern int bltrimws (bstring b); 128 | extern int brtrimws (bstring b); 129 | extern int btrimws (bstring b); 130 | 131 | /* <*>printf format functions */ 132 | #if !defined (BSTRLIB_NOVSNP) 133 | extern bstring bformat (const char * fmt, ...); 134 | extern int bformata (bstring b, const char * fmt, ...); 135 | extern int bassignformat (bstring b, const char * fmt, ...); 136 | extern int bvcformata (bstring b, int count, const char * fmt, va_list arglist); 137 | 138 | #define bvformata(ret, b, fmt, lastarg) { \ 139 | bstring bstrtmp_b = (b); \ 140 | const char * bstrtmp_fmt = (fmt); \ 141 | int bstrtmp_r = BSTR_ERR, bstrtmp_sz = 16; \ 142 | for (;;) { \ 143 | va_list bstrtmp_arglist; \ 144 | va_start (bstrtmp_arglist, lastarg); \ 145 | bstrtmp_r = bvcformata (bstrtmp_b, bstrtmp_sz, bstrtmp_fmt, bstrtmp_arglist); \ 146 | va_end (bstrtmp_arglist); \ 147 | if (bstrtmp_r >= 0) { /* Everything went ok */ \ 148 | bstrtmp_r = BSTR_OK; \ 149 | break; \ 150 | } else if (-bstrtmp_r <= bstrtmp_sz) { /* A real error? */ \ 151 | bstrtmp_r = BSTR_ERR; \ 152 | break; \ 153 | } \ 154 | bstrtmp_sz = -bstrtmp_r; /* Doubled or target size */ \ 155 | } \ 156 | ret = bstrtmp_r; \ 157 | } 158 | 159 | #endif 160 | 161 | typedef int (*bNgetc) (void *parm); 162 | typedef size_t (* bNread) (void *buff, size_t elsize, size_t nelem, void *parm); 163 | 164 | /* Input functions */ 165 | extern bstring bgets (bNgetc getcPtr, void * parm, char terminator); 166 | extern bstring bread (bNread readPtr, void * parm); 167 | extern int bgetsa (bstring b, bNgetc getcPtr, void * parm, char terminator); 168 | extern int bassigngets (bstring b, bNgetc getcPtr, void * parm, char terminator); 169 | extern int breada (bstring b, bNread readPtr, void * parm); 170 | 171 | /* Stream functions */ 172 | extern struct bStream * bsopen (bNread readPtr, void * parm); 173 | extern void * bsclose (struct bStream * s); 174 | extern int bsbufflength (struct bStream * s, int sz); 175 | extern int bsreadln (bstring b, struct bStream * s, char terminator); 176 | extern int bsreadlns (bstring r, struct bStream * s, const_bstring term); 177 | extern int bsread (bstring b, struct bStream * s, int n); 178 | extern int bsreadlna (bstring b, struct bStream * s, char terminator); 179 | extern int bsreadlnsa (bstring r, struct bStream * s, const_bstring term); 180 | extern int bsreada (bstring b, struct bStream * s, int n); 181 | extern int bsunread (struct bStream * s, const_bstring b); 182 | extern int bspeek (bstring r, const struct bStream * s); 183 | extern int bssplitscb (struct bStream * s, const_bstring splitStr, 184 | int (* cb) (void * parm, int ofs, const_bstring entry), void * parm); 185 | extern int bssplitstrcb (struct bStream * s, const_bstring splitStr, 186 | int (* cb) (void * parm, int ofs, const_bstring entry), void * parm); 187 | extern int bseof (const struct bStream * s); 188 | 189 | struct tagbstring { 190 | int mlen; 191 | int slen; 192 | unsigned char * data; 193 | }; 194 | 195 | /* Accessor macros */ 196 | #define blengthe(b, e) (((b) == (void *)0 || (b)->slen < 0) ? (int)(e) : ((b)->slen)) 197 | #define blength(b) (blengthe ((b), 0)) 198 | #define bdataofse(b, o, e) (((b) == (void *)0 || (b)->data == (void*)0) ? (char *)(e) : ((char *)(b)->data) + (o)) 199 | #define bdataofs(b, o) (bdataofse ((b), (o), (void *)0)) 200 | #define bdatae(b, e) (bdataofse (b, 0, e)) 201 | #define bdata(b) (bdataofs (b, 0)) 202 | #define bchare(b, p, e) ((((unsigned)(p)) < (unsigned)blength(b)) ? ((b)->data[(p)]) : (e)) 203 | #define bchar(b, p) bchare ((b), (p), '\0') 204 | 205 | /* Static constant string initialization macro */ 206 | #define bsStaticMlen(q,m) {(m), (int) sizeof(q)-1, (unsigned char *) ("" q "")} 207 | #if defined(_MSC_VER) 208 | /* There are many versions of MSVC which emit __LINE__ as a non-constant. */ 209 | # define bsStatic(q) bsStaticMlen(q,-32) 210 | #endif 211 | #ifndef bsStatic 212 | # define bsStatic(q) bsStaticMlen(q,-__LINE__) 213 | #endif 214 | 215 | /* Static constant block parameter pair */ 216 | #define bsStaticBlkParms(q) ((void *)("" q "")), ((int) sizeof(q)-1) 217 | 218 | /* Reference building macros */ 219 | #define cstr2tbstr btfromcstr 220 | #define btfromcstr(t,s) { \ 221 | (t).data = (unsigned char *) (s); \ 222 | (t).slen = ((t).data) ? ((int) (strlen) ((char *)(t).data)) : 0; \ 223 | (t).mlen = -1; \ 224 | } 225 | #define blk2tbstr(t,s,l) { \ 226 | (t).data = (unsigned char *) (s); \ 227 | (t).slen = l; \ 228 | (t).mlen = -1; \ 229 | } 230 | #define btfromblk(t,s,l) blk2tbstr(t,s,l) 231 | #define bmid2tbstr(t,b,p,l) { \ 232 | const_bstring bstrtmp_s = (b); \ 233 | if (bstrtmp_s && bstrtmp_s->data && bstrtmp_s->slen >= 0) { \ 234 | int bstrtmp_left = (p); \ 235 | int bstrtmp_len = (l); \ 236 | if (bstrtmp_left < 0) { \ 237 | bstrtmp_len += bstrtmp_left; \ 238 | bstrtmp_left = 0; \ 239 | } \ 240 | if (bstrtmp_len > bstrtmp_s->slen - bstrtmp_left) \ 241 | bstrtmp_len = bstrtmp_s->slen - bstrtmp_left; \ 242 | if (bstrtmp_len <= 0) { \ 243 | (t).data = (unsigned char *)""; \ 244 | (t).slen = 0; \ 245 | } else { \ 246 | (t).data = bstrtmp_s->data + bstrtmp_left; \ 247 | (t).slen = bstrtmp_len; \ 248 | } \ 249 | } else { \ 250 | (t).data = (unsigned char *)""; \ 251 | (t).slen = 0; \ 252 | } \ 253 | (t).mlen = -__LINE__; \ 254 | } 255 | #define btfromblkltrimws(t,s,l) { \ 256 | int bstrtmp_idx = 0, bstrtmp_len = (l); \ 257 | unsigned char * bstrtmp_s = (s); \ 258 | if (bstrtmp_s && bstrtmp_len >= 0) { \ 259 | for (; bstrtmp_idx < bstrtmp_len; bstrtmp_idx++) { \ 260 | if (!isspace (bstrtmp_s[bstrtmp_idx])) break; \ 261 | } \ 262 | } \ 263 | (t).data = bstrtmp_s + bstrtmp_idx; \ 264 | (t).slen = bstrtmp_len - bstrtmp_idx; \ 265 | (t).mlen = -__LINE__; \ 266 | } 267 | #define btfromblkrtrimws(t,s,l) { \ 268 | int bstrtmp_len = (l) - 1; \ 269 | unsigned char * bstrtmp_s = (s); \ 270 | if (bstrtmp_s && bstrtmp_len >= 0) { \ 271 | for (; bstrtmp_len >= 0; bstrtmp_len--) { \ 272 | if (!isspace (bstrtmp_s[bstrtmp_len])) break; \ 273 | } \ 274 | } \ 275 | (t).data = bstrtmp_s; \ 276 | (t).slen = bstrtmp_len + 1; \ 277 | (t).mlen = -__LINE__; \ 278 | } 279 | #define btfromblktrimws(t,s,l) { \ 280 | int bstrtmp_idx = 0, bstrtmp_len = (l) - 1; \ 281 | unsigned char * bstrtmp_s = (s); \ 282 | if (bstrtmp_s && bstrtmp_len >= 0) { \ 283 | for (; bstrtmp_idx <= bstrtmp_len; bstrtmp_idx++) { \ 284 | if (!isspace (bstrtmp_s[bstrtmp_idx])) break; \ 285 | } \ 286 | for (; bstrtmp_len >= bstrtmp_idx; bstrtmp_len--) { \ 287 | if (!isspace (bstrtmp_s[bstrtmp_len])) break; \ 288 | } \ 289 | } \ 290 | (t).data = bstrtmp_s + bstrtmp_idx; \ 291 | (t).slen = bstrtmp_len + 1 - bstrtmp_idx; \ 292 | (t).mlen = -__LINE__; \ 293 | } 294 | 295 | /* Write protection macros */ 296 | #define bwriteprotect(t) { if ((t).mlen >= 0) (t).mlen = -1; } 297 | #define bwriteallow(t) { if ((t).mlen == -1) (t).mlen = (t).slen + ((t).slen == 0); } 298 | #define biswriteprotected(t) ((t).mlen <= 0) 299 | 300 | #ifdef __cplusplus 301 | } 302 | #endif 303 | 304 | #endif 305 | -------------------------------------------------------------------------------- /lib/md5/md5.c: -------------------------------------------------------------------------------- 1 | /* 2 | * RFC 1321 compliant MD5 implementation 3 | * 4 | * Copyright (C) 2006-2010, Brainspark B.V. 5 | * 6 | * This file is part of PolarSSL (http://www.polarssl.org) 7 | * Lead Maintainer: Paul Bakker 8 | * 9 | * All rights reserved. 10 | * 11 | * This program is free software; you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation; either version 2 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License along 22 | * with this program; if not, write to the Free Software Foundation, Inc., 23 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 24 | */ 25 | /* 26 | * The MD5 algorithm was designed by Ron Rivest in 1991. 27 | * 28 | * http://www.ietf.org/rfc/rfc1321.txt 29 | */ 30 | 31 | #include "config.h" 32 | 33 | #if defined(POLARSSL_MD5_C) 34 | 35 | #include "md5.h" 36 | 37 | #include 38 | #include 39 | 40 | /* 41 | * 32-bit integer manipulation macros (little endian) 42 | */ 43 | #ifndef GET_ULONG_LE 44 | #define GET_ULONG_LE(n,b,i) \ 45 | { \ 46 | (n) = ( (unsigned long) (b)[(i) ] ) \ 47 | | ( (unsigned long) (b)[(i) + 1] << 8 ) \ 48 | | ( (unsigned long) (b)[(i) + 2] << 16 ) \ 49 | | ( (unsigned long) (b)[(i) + 3] << 24 ); \ 50 | } 51 | #endif 52 | 53 | #ifndef PUT_ULONG_LE 54 | #define PUT_ULONG_LE(n,b,i) \ 55 | { \ 56 | (b)[(i) ] = (unsigned char) ( (n) ); \ 57 | (b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \ 58 | (b)[(i) + 2] = (unsigned char) ( (n) >> 16 ); \ 59 | (b)[(i) + 3] = (unsigned char) ( (n) >> 24 ); \ 60 | } 61 | #endif 62 | 63 | /* 64 | * MD5 context setup 65 | */ 66 | void md5_starts( md5_context *ctx ) 67 | { 68 | ctx->total[0] = 0; 69 | ctx->total[1] = 0; 70 | 71 | ctx->state[0] = 0x67452301; 72 | ctx->state[1] = 0xEFCDAB89; 73 | ctx->state[2] = 0x98BADCFE; 74 | ctx->state[3] = 0x10325476; 75 | } 76 | 77 | static void md5_process( md5_context *ctx, const unsigned char data[64] ) 78 | { 79 | unsigned long X[16], A, B, C, D; 80 | 81 | GET_ULONG_LE( X[ 0], data, 0 ); 82 | GET_ULONG_LE( X[ 1], data, 4 ); 83 | GET_ULONG_LE( X[ 2], data, 8 ); 84 | GET_ULONG_LE( X[ 3], data, 12 ); 85 | GET_ULONG_LE( X[ 4], data, 16 ); 86 | GET_ULONG_LE( X[ 5], data, 20 ); 87 | GET_ULONG_LE( X[ 6], data, 24 ); 88 | GET_ULONG_LE( X[ 7], data, 28 ); 89 | GET_ULONG_LE( X[ 8], data, 32 ); 90 | GET_ULONG_LE( X[ 9], data, 36 ); 91 | GET_ULONG_LE( X[10], data, 40 ); 92 | GET_ULONG_LE( X[11], data, 44 ); 93 | GET_ULONG_LE( X[12], data, 48 ); 94 | GET_ULONG_LE( X[13], data, 52 ); 95 | GET_ULONG_LE( X[14], data, 56 ); 96 | GET_ULONG_LE( X[15], data, 60 ); 97 | 98 | #define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) 99 | 100 | #define P(a,b,c,d,k,s,t) \ 101 | { \ 102 | a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \ 103 | } 104 | 105 | A = ctx->state[0]; 106 | B = ctx->state[1]; 107 | C = ctx->state[2]; 108 | D = ctx->state[3]; 109 | 110 | #define F(x,y,z) (z ^ (x & (y ^ z))) 111 | 112 | P( A, B, C, D, 0, 7, 0xD76AA478 ); 113 | P( D, A, B, C, 1, 12, 0xE8C7B756 ); 114 | P( C, D, A, B, 2, 17, 0x242070DB ); 115 | P( B, C, D, A, 3, 22, 0xC1BDCEEE ); 116 | P( A, B, C, D, 4, 7, 0xF57C0FAF ); 117 | P( D, A, B, C, 5, 12, 0x4787C62A ); 118 | P( C, D, A, B, 6, 17, 0xA8304613 ); 119 | P( B, C, D, A, 7, 22, 0xFD469501 ); 120 | P( A, B, C, D, 8, 7, 0x698098D8 ); 121 | P( D, A, B, C, 9, 12, 0x8B44F7AF ); 122 | P( C, D, A, B, 10, 17, 0xFFFF5BB1 ); 123 | P( B, C, D, A, 11, 22, 0x895CD7BE ); 124 | P( A, B, C, D, 12, 7, 0x6B901122 ); 125 | P( D, A, B, C, 13, 12, 0xFD987193 ); 126 | P( C, D, A, B, 14, 17, 0xA679438E ); 127 | P( B, C, D, A, 15, 22, 0x49B40821 ); 128 | 129 | #undef F 130 | 131 | #define F(x,y,z) (y ^ (z & (x ^ y))) 132 | 133 | P( A, B, C, D, 1, 5, 0xF61E2562 ); 134 | P( D, A, B, C, 6, 9, 0xC040B340 ); 135 | P( C, D, A, B, 11, 14, 0x265E5A51 ); 136 | P( B, C, D, A, 0, 20, 0xE9B6C7AA ); 137 | P( A, B, C, D, 5, 5, 0xD62F105D ); 138 | P( D, A, B, C, 10, 9, 0x02441453 ); 139 | P( C, D, A, B, 15, 14, 0xD8A1E681 ); 140 | P( B, C, D, A, 4, 20, 0xE7D3FBC8 ); 141 | P( A, B, C, D, 9, 5, 0x21E1CDE6 ); 142 | P( D, A, B, C, 14, 9, 0xC33707D6 ); 143 | P( C, D, A, B, 3, 14, 0xF4D50D87 ); 144 | P( B, C, D, A, 8, 20, 0x455A14ED ); 145 | P( A, B, C, D, 13, 5, 0xA9E3E905 ); 146 | P( D, A, B, C, 2, 9, 0xFCEFA3F8 ); 147 | P( C, D, A, B, 7, 14, 0x676F02D9 ); 148 | P( B, C, D, A, 12, 20, 0x8D2A4C8A ); 149 | 150 | #undef F 151 | 152 | #define F(x,y,z) (x ^ y ^ z) 153 | 154 | P( A, B, C, D, 5, 4, 0xFFFA3942 ); 155 | P( D, A, B, C, 8, 11, 0x8771F681 ); 156 | P( C, D, A, B, 11, 16, 0x6D9D6122 ); 157 | P( B, C, D, A, 14, 23, 0xFDE5380C ); 158 | P( A, B, C, D, 1, 4, 0xA4BEEA44 ); 159 | P( D, A, B, C, 4, 11, 0x4BDECFA9 ); 160 | P( C, D, A, B, 7, 16, 0xF6BB4B60 ); 161 | P( B, C, D, A, 10, 23, 0xBEBFBC70 ); 162 | P( A, B, C, D, 13, 4, 0x289B7EC6 ); 163 | P( D, A, B, C, 0, 11, 0xEAA127FA ); 164 | P( C, D, A, B, 3, 16, 0xD4EF3085 ); 165 | P( B, C, D, A, 6, 23, 0x04881D05 ); 166 | P( A, B, C, D, 9, 4, 0xD9D4D039 ); 167 | P( D, A, B, C, 12, 11, 0xE6DB99E5 ); 168 | P( C, D, A, B, 15, 16, 0x1FA27CF8 ); 169 | P( B, C, D, A, 2, 23, 0xC4AC5665 ); 170 | 171 | #undef F 172 | 173 | #define F(x,y,z) (y ^ (x | ~z)) 174 | 175 | P( A, B, C, D, 0, 6, 0xF4292244 ); 176 | P( D, A, B, C, 7, 10, 0x432AFF97 ); 177 | P( C, D, A, B, 14, 15, 0xAB9423A7 ); 178 | P( B, C, D, A, 5, 21, 0xFC93A039 ); 179 | P( A, B, C, D, 12, 6, 0x655B59C3 ); 180 | P( D, A, B, C, 3, 10, 0x8F0CCC92 ); 181 | P( C, D, A, B, 10, 15, 0xFFEFF47D ); 182 | P( B, C, D, A, 1, 21, 0x85845DD1 ); 183 | P( A, B, C, D, 8, 6, 0x6FA87E4F ); 184 | P( D, A, B, C, 15, 10, 0xFE2CE6E0 ); 185 | P( C, D, A, B, 6, 15, 0xA3014314 ); 186 | P( B, C, D, A, 13, 21, 0x4E0811A1 ); 187 | P( A, B, C, D, 4, 6, 0xF7537E82 ); 188 | P( D, A, B, C, 11, 10, 0xBD3AF235 ); 189 | P( C, D, A, B, 2, 15, 0x2AD7D2BB ); 190 | P( B, C, D, A, 9, 21, 0xEB86D391 ); 191 | 192 | #undef F 193 | 194 | ctx->state[0] += A; 195 | ctx->state[1] += B; 196 | ctx->state[2] += C; 197 | ctx->state[3] += D; 198 | } 199 | 200 | /* 201 | * MD5 process buffer 202 | */ 203 | void md5_update( md5_context *ctx, const unsigned char *input, int ilen ) 204 | { 205 | int fill; 206 | unsigned long left; 207 | 208 | if( ilen <= 0 ) 209 | return; 210 | 211 | left = ctx->total[0] & 0x3F; 212 | fill = 64 - left; 213 | 214 | ctx->total[0] += ilen; 215 | ctx->total[0] &= 0xFFFFFFFF; 216 | 217 | if( ctx->total[0] < (unsigned long) ilen ) 218 | ctx->total[1]++; 219 | 220 | if( left && ilen >= fill ) 221 | { 222 | memcpy( (void *) (ctx->buffer + left), 223 | (void *) input, fill ); 224 | md5_process( ctx, ctx->buffer ); 225 | input += fill; 226 | ilen -= fill; 227 | left = 0; 228 | } 229 | 230 | while( ilen >= 64 ) 231 | { 232 | md5_process( ctx, input ); 233 | input += 64; 234 | ilen -= 64; 235 | } 236 | 237 | if( ilen > 0 ) 238 | { 239 | memcpy( (void *) (ctx->buffer + left), 240 | (void *) input, ilen ); 241 | } 242 | } 243 | 244 | static const unsigned char md5_padding[64] = 245 | { 246 | 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 247 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 248 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 249 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 250 | }; 251 | 252 | /* 253 | * MD5 final digest 254 | */ 255 | void md5_finish( md5_context *ctx, unsigned char output[16] ) 256 | { 257 | unsigned long last, padn; 258 | unsigned long high, low; 259 | unsigned char msglen[8]; 260 | 261 | high = ( ctx->total[0] >> 29 ) 262 | | ( ctx->total[1] << 3 ); 263 | low = ( ctx->total[0] << 3 ); 264 | 265 | PUT_ULONG_LE( low, msglen, 0 ); 266 | PUT_ULONG_LE( high, msglen, 4 ); 267 | 268 | last = ctx->total[0] & 0x3F; 269 | padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); 270 | 271 | md5_update( ctx, (unsigned char *) md5_padding, padn ); 272 | md5_update( ctx, msglen, 8 ); 273 | 274 | PUT_ULONG_LE( ctx->state[0], output, 0 ); 275 | PUT_ULONG_LE( ctx->state[1], output, 4 ); 276 | PUT_ULONG_LE( ctx->state[2], output, 8 ); 277 | PUT_ULONG_LE( ctx->state[3], output, 12 ); 278 | } 279 | 280 | /* 281 | * output = MD5( input buffer ) 282 | */ 283 | void md5( const unsigned char *input, int ilen, unsigned char output[16] ) 284 | { 285 | md5_context ctx; 286 | 287 | md5_starts( &ctx ); 288 | md5_update( &ctx, input, ilen ); 289 | md5_finish( &ctx, output ); 290 | 291 | memset( &ctx, 0, sizeof( md5_context ) ); 292 | } 293 | 294 | /* 295 | * output = MD5( file contents ) 296 | */ 297 | int md5_file( const char *path, unsigned char output[16] ) 298 | { 299 | FILE *f; 300 | size_t n; 301 | md5_context ctx; 302 | unsigned char buf[1024]; 303 | 304 | if( ( f = fopen( path, "rb" ) ) == NULL ) 305 | return( 1 ); 306 | 307 | md5_starts( &ctx ); 308 | 309 | while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 ) 310 | md5_update( &ctx, buf, (int) n ); 311 | 312 | md5_finish( &ctx, output ); 313 | 314 | memset( &ctx, 0, sizeof( md5_context ) ); 315 | 316 | if( ferror( f ) != 0 ) 317 | { 318 | fclose( f ); 319 | return( 2 ); 320 | } 321 | 322 | fclose( f ); 323 | return( 0 ); 324 | } 325 | 326 | /* 327 | * MD5 HMAC context setup 328 | */ 329 | void md5_hmac_starts( md5_context *ctx, const unsigned char *key, int keylen ) 330 | { 331 | int i; 332 | unsigned char sum[16]; 333 | 334 | if( keylen > 64 ) 335 | { 336 | md5( key, keylen, sum ); 337 | keylen = 16; 338 | key = sum; 339 | } 340 | 341 | memset( ctx->ipad, 0x36, 64 ); 342 | memset( ctx->opad, 0x5C, 64 ); 343 | 344 | for( i = 0; i < keylen; i++ ) 345 | { 346 | ctx->ipad[i] = (unsigned char)( ctx->ipad[i] ^ key[i] ); 347 | ctx->opad[i] = (unsigned char)( ctx->opad[i] ^ key[i] ); 348 | } 349 | 350 | md5_starts( ctx ); 351 | md5_update( ctx, ctx->ipad, 64 ); 352 | 353 | memset( sum, 0, sizeof( sum ) ); 354 | } 355 | 356 | /* 357 | * MD5 HMAC process buffer 358 | */ 359 | void md5_hmac_update( md5_context *ctx, const unsigned char *input, int ilen ) 360 | { 361 | md5_update( ctx, input, ilen ); 362 | } 363 | 364 | /* 365 | * MD5 HMAC final digest 366 | */ 367 | void md5_hmac_finish( md5_context *ctx, unsigned char output[16] ) 368 | { 369 | unsigned char tmpbuf[16]; 370 | 371 | md5_finish( ctx, tmpbuf ); 372 | md5_starts( ctx ); 373 | md5_update( ctx, ctx->opad, 64 ); 374 | md5_update( ctx, tmpbuf, 16 ); 375 | md5_finish( ctx, output ); 376 | 377 | memset( tmpbuf, 0, sizeof( tmpbuf ) ); 378 | } 379 | 380 | /* 381 | * MD5 HMAC context reset 382 | */ 383 | void md5_hmac_reset( md5_context *ctx ) 384 | { 385 | md5_starts( ctx ); 386 | md5_update( ctx, ctx->ipad, 64 ); 387 | } 388 | 389 | /* 390 | * output = HMAC-MD5( hmac key, input buffer ) 391 | */ 392 | void md5_hmac( const unsigned char *key, int keylen, 393 | const unsigned char *input, int ilen, 394 | unsigned char output[16] ) 395 | { 396 | md5_context ctx; 397 | 398 | md5_hmac_starts( &ctx, key, keylen ); 399 | md5_hmac_update( &ctx, input, ilen ); 400 | md5_hmac_finish( &ctx, output ); 401 | 402 | memset( &ctx, 0, sizeof( md5_context ) ); 403 | } 404 | 405 | #if defined(POLARSSL_SELF_TEST) 406 | /* 407 | * RFC 1321 test vectors 408 | */ 409 | static unsigned char md5_test_buf[7][81] = 410 | { 411 | { "" }, 412 | { "a" }, 413 | { "abc" }, 414 | { "message digest" }, 415 | { "abcdefghijklmnopqrstuvwxyz" }, 416 | { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" }, 417 | { "12345678901234567890123456789012345678901234567890123456789012" \ 418 | "345678901234567890" } 419 | }; 420 | 421 | static const int md5_test_buflen[7] = 422 | { 423 | 0, 1, 3, 14, 26, 62, 80 424 | }; 425 | 426 | static const unsigned char md5_test_sum[7][16] = 427 | { 428 | { 0xD4, 0x1D, 0x8C, 0xD9, 0x8F, 0x00, 0xB2, 0x04, 429 | 0xE9, 0x80, 0x09, 0x98, 0xEC, 0xF8, 0x42, 0x7E }, 430 | { 0x0C, 0xC1, 0x75, 0xB9, 0xC0, 0xF1, 0xB6, 0xA8, 431 | 0x31, 0xC3, 0x99, 0xE2, 0x69, 0x77, 0x26, 0x61 }, 432 | { 0x90, 0x01, 0x50, 0x98, 0x3C, 0xD2, 0x4F, 0xB0, 433 | 0xD6, 0x96, 0x3F, 0x7D, 0x28, 0xE1, 0x7F, 0x72 }, 434 | { 0xF9, 0x6B, 0x69, 0x7D, 0x7C, 0xB7, 0x93, 0x8D, 435 | 0x52, 0x5A, 0x2F, 0x31, 0xAA, 0xF1, 0x61, 0xD0 }, 436 | { 0xC3, 0xFC, 0xD3, 0xD7, 0x61, 0x92, 0xE4, 0x00, 437 | 0x7D, 0xFB, 0x49, 0x6C, 0xCA, 0x67, 0xE1, 0x3B }, 438 | { 0xD1, 0x74, 0xAB, 0x98, 0xD2, 0x77, 0xD9, 0xF5, 439 | 0xA5, 0x61, 0x1C, 0x2C, 0x9F, 0x41, 0x9D, 0x9F }, 440 | { 0x57, 0xED, 0xF4, 0xA2, 0x2B, 0xE3, 0xC9, 0x55, 441 | 0xAC, 0x49, 0xDA, 0x2E, 0x21, 0x07, 0xB6, 0x7A } 442 | }; 443 | 444 | /* 445 | * RFC 2202 test vectors 446 | */ 447 | static unsigned char md5_hmac_test_key[7][26] = 448 | { 449 | { "\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B" }, 450 | { "Jefe" }, 451 | { "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" }, 452 | { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10" 453 | "\x11\x12\x13\x14\x15\x16\x17\x18\x19" }, 454 | { "\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C" }, 455 | { "" }, /* 0xAA 80 times */ 456 | { "" } 457 | }; 458 | 459 | static const int md5_hmac_test_keylen[7] = 460 | { 461 | 16, 4, 16, 25, 16, 80, 80 462 | }; 463 | 464 | static unsigned char md5_hmac_test_buf[7][74] = 465 | { 466 | { "Hi There" }, 467 | { "what do ya want for nothing?" }, 468 | { "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" 469 | "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" 470 | "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" 471 | "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" 472 | "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" }, 473 | { "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" 474 | "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" 475 | "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" 476 | "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" 477 | "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" }, 478 | { "Test With Truncation" }, 479 | { "Test Using Larger Than Block-Size Key - Hash Key First" }, 480 | { "Test Using Larger Than Block-Size Key and Larger" 481 | " Than One Block-Size Data" } 482 | }; 483 | 484 | static const int md5_hmac_test_buflen[7] = 485 | { 486 | 8, 28, 50, 50, 20, 54, 73 487 | }; 488 | 489 | static const unsigned char md5_hmac_test_sum[7][16] = 490 | { 491 | { 0x92, 0x94, 0x72, 0x7A, 0x36, 0x38, 0xBB, 0x1C, 492 | 0x13, 0xF4, 0x8E, 0xF8, 0x15, 0x8B, 0xFC, 0x9D }, 493 | { 0x75, 0x0C, 0x78, 0x3E, 0x6A, 0xB0, 0xB5, 0x03, 494 | 0xEA, 0xA8, 0x6E, 0x31, 0x0A, 0x5D, 0xB7, 0x38 }, 495 | { 0x56, 0xBE, 0x34, 0x52, 0x1D, 0x14, 0x4C, 0x88, 496 | 0xDB, 0xB8, 0xC7, 0x33, 0xF0, 0xE8, 0xB3, 0xF6 }, 497 | { 0x69, 0x7E, 0xAF, 0x0A, 0xCA, 0x3A, 0x3A, 0xEA, 498 | 0x3A, 0x75, 0x16, 0x47, 0x46, 0xFF, 0xAA, 0x79 }, 499 | { 0x56, 0x46, 0x1E, 0xF2, 0x34, 0x2E, 0xDC, 0x00, 500 | 0xF9, 0xBA, 0xB9, 0x95 }, 501 | { 0x6B, 0x1A, 0xB7, 0xFE, 0x4B, 0xD7, 0xBF, 0x8F, 502 | 0x0B, 0x62, 0xE6, 0xCE, 0x61, 0xB9, 0xD0, 0xCD }, 503 | { 0x6F, 0x63, 0x0F, 0xAD, 0x67, 0xCD, 0xA0, 0xEE, 504 | 0x1F, 0xB1, 0xF5, 0x62, 0xDB, 0x3A, 0xA5, 0x3E } 505 | }; 506 | 507 | /* 508 | * Checkup routine 509 | */ 510 | int md5_self_test( int verbose ) 511 | { 512 | int i, buflen; 513 | unsigned char buf[1024]; 514 | unsigned char md5sum[16]; 515 | md5_context ctx; 516 | 517 | for( i = 0; i < 7; i++ ) 518 | { 519 | if( verbose != 0 ) 520 | printf( " MD5 test #%d: ", i + 1 ); 521 | 522 | md5( md5_test_buf[i], md5_test_buflen[i], md5sum ); 523 | 524 | if( memcmp( md5sum, md5_test_sum[i], 16 ) != 0 ) 525 | { 526 | if( verbose != 0 ) 527 | printf( "failed\n" ); 528 | 529 | return( 1 ); 530 | } 531 | 532 | if( verbose != 0 ) 533 | printf( "passed\n" ); 534 | } 535 | 536 | if( verbose != 0 ) 537 | printf( "\n" ); 538 | 539 | for( i = 0; i < 7; i++ ) 540 | { 541 | if( verbose != 0 ) 542 | printf( " HMAC-MD5 test #%d: ", i + 1 ); 543 | 544 | if( i == 5 || i == 6 ) 545 | { 546 | memset( buf, '\xAA', buflen = 80 ); 547 | md5_hmac_starts( &ctx, buf, buflen ); 548 | } 549 | else 550 | md5_hmac_starts( &ctx, md5_hmac_test_key[i], 551 | md5_hmac_test_keylen[i] ); 552 | 553 | md5_hmac_update( &ctx, md5_hmac_test_buf[i], 554 | md5_hmac_test_buflen[i] ); 555 | 556 | md5_hmac_finish( &ctx, md5sum ); 557 | 558 | buflen = ( i == 4 ) ? 12 : 16; 559 | 560 | if( memcmp( md5sum, md5_hmac_test_sum[i], buflen ) != 0 ) 561 | { 562 | if( verbose != 0 ) 563 | printf( "failed\n" ); 564 | 565 | return( 1 ); 566 | } 567 | 568 | if( verbose != 0 ) 569 | printf( "passed\n" ); 570 | } 571 | 572 | if( verbose != 0 ) 573 | printf( "\n" ); 574 | 575 | return( 0 ); 576 | } 577 | 578 | #endif 579 | 580 | #endif 581 | -------------------------------------------------------------------------------- /lib/bstr/bstraux.c: -------------------------------------------------------------------------------- 1 | #ifdef _MSC_VER 2 | #define _CRT_SECURE_NO_WARNINGS 3 | #endif 4 | 5 | /* 6 | * This source file is part of the bstring string library. This code was 7 | * written by Paul Hsieh in 2002-2010, and is covered by either the 3-clause 8 | * BSD open source license or GPL v2.0. Refer to the accompanying documentation 9 | * for details on usage and license. 10 | */ 11 | 12 | /* 13 | * bstraux.c 14 | * 15 | * This file is not necessarily part of the core bstring library itself, but 16 | * is just an auxilliary module which includes miscellaneous or trivial 17 | * functions. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include "bstrlib.h" 26 | #include "bstraux.h" 27 | 28 | /* bstring bTail (bstring b, int n) 29 | * 30 | * Return with a string of the last n characters of b. 31 | */ 32 | bstring bTail (bstring b, int n) { 33 | if (b == NULL || n < 0 || (b->mlen < b->slen && b->mlen > 0)) return NULL; 34 | if (n >= b->slen) return bstrcpy (b); 35 | return bmidstr (b, b->slen - n, n); 36 | } 37 | 38 | /* bstring bHead (bstring b, int n) 39 | * 40 | * Return with a string of the first n characters of b. 41 | */ 42 | bstring bHead (bstring b, int n) { 43 | if (b == NULL || n < 0 || (b->mlen < b->slen && b->mlen > 0)) return NULL; 44 | if (n >= b->slen) return bstrcpy (b); 45 | return bmidstr (b, 0, n); 46 | } 47 | 48 | /* int bFill (bstring a, char c, int len) 49 | * 50 | * Fill a given bstring with the character in parameter c, for a length n. 51 | */ 52 | int bFill (bstring b, char c, int len) { 53 | if (b == NULL || len < 0 || (b->mlen < b->slen && b->mlen > 0)) return -__LINE__; 54 | b->slen = 0; 55 | return bsetstr (b, len, NULL, c); 56 | } 57 | 58 | /* int bReplicate (bstring b, int n) 59 | * 60 | * Replicate the contents of b end to end n times and replace it in b. 61 | */ 62 | int bReplicate (bstring b, int n) { 63 | return bpattern (b, n * b->slen); 64 | } 65 | 66 | /* int bReverse (bstring b) 67 | * 68 | * Reverse the contents of b in place. 69 | */ 70 | int bReverse (bstring b) { 71 | int i, n, m; 72 | unsigned char t; 73 | 74 | if (b == NULL || b->slen < 0 || b->mlen < b->slen) return -__LINE__; 75 | n = b->slen; 76 | if (2 <= n) { 77 | m = ((unsigned)n) >> 1; 78 | n--; 79 | for (i=0; i < m; i++) { 80 | t = b->data[n - i]; 81 | b->data[n - i] = b->data[i]; 82 | b->data[i] = t; 83 | } 84 | } 85 | return 0; 86 | } 87 | 88 | /* int bInsertChrs (bstring b, int pos, int len, unsigned char c, unsigned char fill) 89 | * 90 | * Insert a repeated sequence of a given character into the string at 91 | * position pos for a length len. 92 | */ 93 | int bInsertChrs (bstring b, int pos, int len, unsigned char c, unsigned char fill) { 94 | if (b == NULL || b->slen < 0 || b->mlen < b->slen || pos < 0 || len <= 0) return -__LINE__; 95 | 96 | if (pos > b->slen 97 | && 0 > bsetstr (b, pos, NULL, fill)) return -__LINE__; 98 | 99 | if (0 > balloc (b, b->slen + len)) return -__LINE__; 100 | if (pos < b->slen) memmove (b->data + pos + len, b->data + pos, b->slen - pos); 101 | memset (b->data + pos, c, len); 102 | b->slen += len; 103 | b->data[b->slen] = (unsigned char) '\0'; 104 | return BSTR_OK; 105 | } 106 | 107 | /* int bJustifyLeft (bstring b, int space) 108 | * 109 | * Left justify a string. 110 | */ 111 | int bJustifyLeft (bstring b, int space) { 112 | int j, i, s, t; 113 | unsigned char c = (unsigned char) space; 114 | 115 | if (b == NULL || b->slen < 0 || b->mlen < b->slen) return -__LINE__; 116 | if (space != (int) c) return BSTR_OK; 117 | 118 | for (s=j=i=0; i < b->slen; i++) { 119 | t = s; 120 | s = c != (b->data[j] = b->data[i]); 121 | j += (t|s); 122 | } 123 | if (j > 0 && b->data[j-1] == c) j--; 124 | 125 | b->data[j] = (unsigned char) '\0'; 126 | b->slen = j; 127 | return BSTR_OK; 128 | } 129 | 130 | /* int bJustifyRight (bstring b, int width, int space) 131 | * 132 | * Right justify a string to within a given width. 133 | */ 134 | int bJustifyRight (bstring b, int width, int space) { 135 | int ret; 136 | if (width <= 0) return -__LINE__; 137 | if (0 > (ret = bJustifyLeft (b, space))) return ret; 138 | if (b->slen <= width) 139 | return bInsertChrs (b, 0, width - b->slen, (unsigned char) space, (unsigned char) space); 140 | return BSTR_OK; 141 | } 142 | 143 | /* int bJustifyCenter (bstring b, int width, int space) 144 | * 145 | * Center a string's non-white space characters to within a given width by 146 | * inserting whitespaces at the beginning. 147 | */ 148 | int bJustifyCenter (bstring b, int width, int space) { 149 | int ret; 150 | if (width <= 0) return -__LINE__; 151 | if (0 > (ret = bJustifyLeft (b, space))) return ret; 152 | if (b->slen <= width) 153 | return bInsertChrs (b, 0, (width - b->slen + 1) >> 1, (unsigned char) space, (unsigned char) space); 154 | return BSTR_OK; 155 | } 156 | 157 | /* int bJustifyMargin (bstring b, int width, int space) 158 | * 159 | * Stretch a string to flush against left and right margins by evenly 160 | * distributing additional white space between words. If the line is too 161 | * long to be margin justified, it is left justified. 162 | */ 163 | int bJustifyMargin (bstring b, int width, int space) { 164 | struct bstrList * sl; 165 | int i, l, c; 166 | 167 | if (b == NULL || b->slen < 0 || b->mlen == 0 || b->mlen < b->slen) return -__LINE__; 168 | if (NULL == (sl = bsplit (b, (unsigned char) space))) return -__LINE__; 169 | for (l=c=i=0; i < sl->qty; i++) { 170 | if (sl->entry[i]->slen > 0) { 171 | c ++; 172 | l += sl->entry[i]->slen; 173 | } 174 | } 175 | 176 | if (l + c >= width || c < 2) { 177 | bstrListDestroy (sl); 178 | return bJustifyLeft (b, space); 179 | } 180 | 181 | b->slen = 0; 182 | for (i=0; i < sl->qty; i++) { 183 | if (sl->entry[i]->slen > 0) { 184 | if (b->slen > 0) { 185 | int s = (width - l + (c / 2)) / c; 186 | bInsertChrs (b, b->slen, s, (unsigned char) space, (unsigned char) space); 187 | l += s; 188 | } 189 | bconcat (b, sl->entry[i]); 190 | c--; 191 | if (c <= 0) break; 192 | } 193 | } 194 | 195 | bstrListDestroy (sl); 196 | return BSTR_OK; 197 | } 198 | 199 | static size_t readNothing (void *buff, size_t elsize, size_t nelem, void *parm) { 200 | buff = buff; 201 | elsize = elsize; 202 | nelem = nelem; 203 | parm = parm; 204 | return 0; /* Immediately indicate EOF. */ 205 | } 206 | 207 | /* struct bStream * bsFromBstr (const_bstring b); 208 | * 209 | * Create a bStream whose contents are a copy of the bstring passed in. 210 | * This allows the use of all the bStream APIs with bstrings. 211 | */ 212 | struct bStream * bsFromBstr (const_bstring b) { 213 | struct bStream * s = bsopen ((bNread) readNothing, NULL); 214 | bsunread (s, b); /* Push the bstring data into the empty bStream. */ 215 | return s; 216 | } 217 | 218 | static size_t readRef (void *buff, size_t elsize, size_t nelem, void *parm) { 219 | struct tagbstring * t = (struct tagbstring *) parm; 220 | size_t tsz = elsize * nelem; 221 | 222 | if (tsz > (size_t) t->slen) tsz = (size_t) t->slen; 223 | if (tsz > 0) { 224 | memcpy (buff, t->data, tsz); 225 | t->slen -= (int) tsz; 226 | t->data += tsz; 227 | return tsz / elsize; 228 | } 229 | return 0; 230 | } 231 | 232 | /* The "by reference" version of the above function. This function puts 233 | * a number of restrictions on the call site (the passed in struct 234 | * tagbstring *will* be modified by this function, and the source data 235 | * must remain alive and constant for the lifetime of the bStream). 236 | * Hence it is not presented as an extern. 237 | */ 238 | static struct bStream * bsFromBstrRef (struct tagbstring * t) { 239 | if (!t) return NULL; 240 | return bsopen ((bNread) readRef, t); 241 | } 242 | 243 | /* char * bStr2NetStr (const_bstring b) 244 | * 245 | * Convert a bstring to a netstring. See 246 | * http://cr.yp.to/proto/netstrings.txt for a description of netstrings. 247 | * Note: 1) The value returned should be freed with a call to bcstrfree() at 248 | * the point when it will no longer be referenced to avoid a memory 249 | * leak. 250 | * 2) If the returned value is non-NULL, then it also '\0' terminated 251 | * in the character position one past the "," terminator. 252 | */ 253 | char * bStr2NetStr (const_bstring b) { 254 | char strnum[sizeof (b->slen) * 3 + 1]; 255 | bstring s; 256 | unsigned char * buff; 257 | 258 | if (b == NULL || b->data == NULL || b->slen < 0) return NULL; 259 | sprintf (strnum, "%d:", b->slen); 260 | if (NULL == (s = bfromcstr (strnum)) 261 | || bconcat (s, b) == BSTR_ERR || bconchar (s, (char) ',') == BSTR_ERR) { 262 | bdestroy (s); 263 | return NULL; 264 | } 265 | buff = s->data; 266 | bcstrfree ((char *) s); 267 | return (char *) buff; 268 | } 269 | 270 | /* bstring bNetStr2Bstr (const char * buf) 271 | * 272 | * Convert a netstring to a bstring. See 273 | * http://cr.yp.to/proto/netstrings.txt for a description of netstrings. 274 | * Note that the terminating "," *must* be present, however a following '\0' 275 | * is *not* required. 276 | */ 277 | bstring bNetStr2Bstr (const char * buff) { 278 | int i, x; 279 | bstring b; 280 | if (buff == NULL) return NULL; 281 | x = 0; 282 | for (i=0; buff[i] != ':'; i++) { 283 | unsigned int v = buff[i] - '0'; 284 | if (v > 9 || x > ((INT_MAX - (signed int)v) / 10)) return NULL; 285 | x = (x * 10) + v; 286 | } 287 | 288 | /* This thing has to be properly terminated */ 289 | if (buff[i + 1 + x] != ',') return NULL; 290 | 291 | if (NULL == (b = bfromcstr (""))) return NULL; 292 | if (balloc (b, x + 1) != BSTR_OK) { 293 | bdestroy (b); 294 | return NULL; 295 | } 296 | memcpy (b->data, buff + i + 1, x); 297 | b->data[x] = (unsigned char) '\0'; 298 | b->slen = x; 299 | return b; 300 | } 301 | 302 | static char b64ETable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 303 | 304 | /* bstring bBase64Encode (const_bstring b) 305 | * 306 | * Generate a base64 encoding. See: RFC1341 307 | */ 308 | bstring bBase64Encode (const_bstring b) { 309 | int i, c0, c1, c2, c3; 310 | bstring out; 311 | 312 | if (b == NULL || b->slen < 0 || b->data == NULL) return NULL; 313 | 314 | out = bfromcstr (""); 315 | for (i=0; i + 2 < b->slen; i += 3) { 316 | if (i && ((i % 57) == 0)) { 317 | if (bconchar (out, (char) '\015') < 0 || bconchar (out, (char) '\012') < 0) { 318 | bdestroy (out); 319 | return NULL; 320 | } 321 | } 322 | c0 = b->data[i] >> 2; 323 | c1 = ((b->data[i] << 4) | 324 | (b->data[i+1] >> 4)) & 0x3F; 325 | c2 = ((b->data[i+1] << 2) | 326 | (b->data[i+2] >> 6)) & 0x3F; 327 | c3 = b->data[i+2] & 0x3F; 328 | if (bconchar (out, b64ETable[c0]) < 0 || 329 | bconchar (out, b64ETable[c1]) < 0 || 330 | bconchar (out, b64ETable[c2]) < 0 || 331 | bconchar (out, b64ETable[c3]) < 0) { 332 | bdestroy (out); 333 | return NULL; 334 | } 335 | } 336 | 337 | if (i && ((i % 57) == 0)) { 338 | if (bconchar (out, (char) '\015') < 0 || bconchar (out, (char) '\012') < 0) { 339 | bdestroy (out); 340 | return NULL; 341 | } 342 | } 343 | 344 | switch (i + 2 - b->slen) { 345 | case 0: c0 = b->data[i] >> 2; 346 | c1 = ((b->data[i] << 4) | 347 | (b->data[i+1] >> 4)) & 0x3F; 348 | c2 = (b->data[i+1] << 2) & 0x3F; 349 | if (bconchar (out, b64ETable[c0]) < 0 || 350 | bconchar (out, b64ETable[c1]) < 0 || 351 | bconchar (out, b64ETable[c2]) < 0 || 352 | bconchar (out, (char) '=') < 0) { 353 | bdestroy (out); 354 | return NULL; 355 | } 356 | break; 357 | case 1: c0 = b->data[i] >> 2; 358 | c1 = (b->data[i] << 4) & 0x3F; 359 | if (bconchar (out, b64ETable[c0]) < 0 || 360 | bconchar (out, b64ETable[c1]) < 0 || 361 | bconchar (out, (char) '=') < 0 || 362 | bconchar (out, (char) '=') < 0) { 363 | bdestroy (out); 364 | return NULL; 365 | } 366 | break; 367 | case 2: break; 368 | } 369 | 370 | return out; 371 | } 372 | 373 | #define B64_PAD (-2) 374 | #define B64_ERR (-1) 375 | 376 | static int base64DecodeSymbol (unsigned char alpha) { 377 | if ((alpha >= 'A') && (alpha <= 'Z')) return (int)(alpha - 'A'); 378 | else if ((alpha >= 'a') && (alpha <= 'z')) 379 | return 26 + (int)(alpha - 'a'); 380 | else if ((alpha >= '0') && (alpha <= '9')) 381 | return 52 + (int)(alpha - '0'); 382 | else if (alpha == '+') return 62; 383 | else if (alpha == '/') return 63; 384 | else if (alpha == '=') return B64_PAD; 385 | else return B64_ERR; 386 | } 387 | 388 | /* bstring bBase64DecodeEx (const_bstring b, int * boolTruncError) 389 | * 390 | * Decode a base64 block of data. All MIME headers are assumed to have been 391 | * removed. See: RFC1341 392 | */ 393 | bstring bBase64DecodeEx (const_bstring b, int * boolTruncError) { 394 | int i, v; 395 | unsigned char c0, c1, c2; 396 | bstring out; 397 | 398 | if (b == NULL || b->slen < 0 || b->data == NULL) return NULL; 399 | if (boolTruncError) *boolTruncError = 0; 400 | out = bfromcstr (""); 401 | i = 0; 402 | for (;;) { 403 | do { 404 | if (i >= b->slen) return out; 405 | if (b->data[i] == '=') { /* Bad "too early" truncation */ 406 | if (boolTruncError) { 407 | *boolTruncError = 1; 408 | return out; 409 | } 410 | bdestroy (out); 411 | return NULL; 412 | } 413 | v = base64DecodeSymbol (b->data[i]); 414 | i++; 415 | } while (v < 0); 416 | c0 = (unsigned char) (v << 2); 417 | do { 418 | if (i >= b->slen || b->data[i] == '=') { /* Bad "too early" truncation */ 419 | if (boolTruncError) { 420 | *boolTruncError = 1; 421 | return out; 422 | } 423 | bdestroy (out); 424 | return NULL; 425 | } 426 | v = base64DecodeSymbol (b->data[i]); 427 | i++; 428 | } while (v < 0); 429 | c0 |= (unsigned char) (v >> 4); 430 | c1 = (unsigned char) (v << 4); 431 | do { 432 | if (i >= b->slen) { 433 | if (boolTruncError) { 434 | *boolTruncError = 1; 435 | return out; 436 | } 437 | bdestroy (out); 438 | return NULL; 439 | } 440 | if (b->data[i] == '=') { 441 | i++; 442 | if (i >= b->slen || b->data[i] != '=' || bconchar (out, c0) < 0) { 443 | if (boolTruncError) { 444 | *boolTruncError = 1; 445 | return out; 446 | } 447 | bdestroy (out); /* Missing "=" at the end. */ 448 | return NULL; 449 | } 450 | return out; 451 | } 452 | v = base64DecodeSymbol (b->data[i]); 453 | i++; 454 | } while (v < 0); 455 | c1 |= (unsigned char) (v >> 2); 456 | c2 = (unsigned char) (v << 6); 457 | do { 458 | if (i >= b->slen) { 459 | if (boolTruncError) { 460 | *boolTruncError = 1; 461 | return out; 462 | } 463 | bdestroy (out); 464 | return NULL; 465 | } 466 | if (b->data[i] == '=') { 467 | if (bconchar (out, c0) < 0 || bconchar (out, c1) < 0) { 468 | if (boolTruncError) { 469 | *boolTruncError = 1; 470 | return out; 471 | } 472 | bdestroy (out); 473 | return NULL; 474 | } 475 | if (boolTruncError) *boolTruncError = 0; 476 | return out; 477 | } 478 | v = base64DecodeSymbol (b->data[i]); 479 | i++; 480 | } while (v < 0); 481 | c2 |= (unsigned char) (v); 482 | if (bconchar (out, c0) < 0 || 483 | bconchar (out, c1) < 0 || 484 | bconchar (out, c2) < 0) { 485 | if (boolTruncError) { 486 | *boolTruncError = -1; 487 | return out; 488 | } 489 | bdestroy (out); 490 | return NULL; 491 | } 492 | } 493 | } 494 | 495 | #define UU_DECODE_BYTE(b) (((b) == (signed int)'`') ? 0 : (b) - (signed int)' ') 496 | 497 | struct bUuInOut { 498 | bstring src, dst; 499 | int * badlines; 500 | }; 501 | 502 | #define UU_MAX_LINELEN 45 503 | 504 | static int bUuDecLine (void * parm, int ofs, int len) { 505 | struct bUuInOut * io = (struct bUuInOut *) parm; 506 | bstring s = io->src; 507 | bstring t = io->dst; 508 | int i, llen, otlen, ret, c0, c1, c2, c3, d0, d1, d2, d3; 509 | 510 | if (len == 0) return 0; 511 | llen = UU_DECODE_BYTE (s->data[ofs]); 512 | ret = 0; 513 | 514 | otlen = t->slen; 515 | 516 | if (((unsigned) llen) > UU_MAX_LINELEN) { ret = -__LINE__; 517 | goto bl; 518 | } 519 | 520 | llen += t->slen; 521 | 522 | for (i=1; i < s->slen && t->slen < llen;i += 4) { 523 | unsigned char outoctet[3]; 524 | c0 = UU_DECODE_BYTE (d0 = (int) bchare (s, i+ofs+0, ' ' - 1)); 525 | c1 = UU_DECODE_BYTE (d1 = (int) bchare (s, i+ofs+1, ' ' - 1)); 526 | c2 = UU_DECODE_BYTE (d2 = (int) bchare (s, i+ofs+2, ' ' - 1)); 527 | c3 = UU_DECODE_BYTE (d3 = (int) bchare (s, i+ofs+3, ' ' - 1)); 528 | 529 | if (((unsigned) (c0|c1) >= 0x40)) { if (!ret) ret = -__LINE__; 530 | if (d0 > 0x60 || (d0 < (' ' - 1) && !isspace (d0)) || 531 | d1 > 0x60 || (d1 < (' ' - 1) && !isspace (d1))) { 532 | t->slen = otlen; 533 | goto bl; 534 | } 535 | c0 = c1 = 0; 536 | } 537 | outoctet[0] = (unsigned char) ((c0 << 2) | ((unsigned) c1 >> 4)); 538 | if (t->slen+1 >= llen) { 539 | if (0 > bconchar (t, (char) outoctet[0])) return -__LINE__; 540 | break; 541 | } 542 | if ((unsigned) c2 >= 0x40) { if (!ret) ret = -__LINE__; 543 | if (d2 > 0x60 || (d2 < (' ' - 1) && !isspace (d2))) { 544 | t->slen = otlen; 545 | goto bl; 546 | } 547 | c2 = 0; 548 | } 549 | outoctet[1] = (unsigned char) ((c1 << 4) | ((unsigned) c2 >> 2)); 550 | if (t->slen+2 >= llen) { 551 | if (0 > bcatblk (t, outoctet, 2)) return -__LINE__; 552 | break; 553 | } 554 | if ((unsigned) c3 >= 0x40) { if (!ret) ret = -__LINE__; 555 | if (d3 > 0x60 || (d3 < (' ' - 1) && !isspace (d3))) { 556 | t->slen = otlen; 557 | goto bl; 558 | } 559 | c3 = 0; 560 | } 561 | outoctet[2] = (unsigned char) ((c2 << 6) | ((unsigned) c3)); 562 | if (0 > bcatblk (t, outoctet, 3)) return -__LINE__; 563 | } 564 | if (t->slen < llen) { if (0 == ret) ret = -__LINE__; 565 | t->slen = otlen; 566 | } 567 | bl:; 568 | if (ret && io->badlines) { 569 | (*io->badlines)++; 570 | return 0; 571 | } 572 | return ret; 573 | } 574 | 575 | /* bstring bUuDecodeEx (const_bstring src, int * badlines) 576 | * 577 | * Performs a UUDecode of a block of data. If there are errors in the 578 | * decoding, they are counted up and returned in "badlines", if badlines is 579 | * not NULL. It is assumed that the "begin" and "end" lines have already 580 | * been stripped off. The potential security problem of writing the 581 | * filename in the begin line is something that is beyond the scope of a 582 | * portable library. 583 | */ 584 | 585 | #ifdef _MSC_VER 586 | #pragma warning(disable:4204) 587 | #endif 588 | 589 | bstring bUuDecodeEx (const_bstring src, int * badlines) { 590 | struct tagbstring t; 591 | struct bStream * s; 592 | struct bStream * d; 593 | bstring b; 594 | 595 | if (!src) return NULL; 596 | t = *src; /* Short lifetime alias to header of src */ 597 | s = bsFromBstrRef (&t); /* t is undefined after this */ 598 | if (!s) return NULL; 599 | d = bsUuDecode (s, badlines); 600 | b = bfromcstralloc (256, ""); 601 | if (NULL == b || 0 > bsread (b, d, INT_MAX)) { 602 | bdestroy (b); 603 | bsclose (d); 604 | bsclose (s); 605 | return NULL; 606 | } 607 | return b; 608 | } 609 | 610 | struct bsUuCtx { 611 | struct bUuInOut io; 612 | struct bStream * sInp; 613 | }; 614 | 615 | static size_t bsUuDecodePart (void *buff, size_t elsize, size_t nelem, void *parm) { 616 | static struct tagbstring eol = bsStatic ("\r\n"); 617 | struct bsUuCtx * luuCtx = (struct bsUuCtx *) parm; 618 | size_t tsz; 619 | int l, lret; 620 | 621 | if (NULL == buff || NULL == parm) return 0; 622 | tsz = elsize * nelem; 623 | 624 | CheckInternalBuffer:; 625 | /* If internal buffer has sufficient data, just output it */ 626 | if (((size_t) luuCtx->io.dst->slen) > tsz) { 627 | memcpy (buff, luuCtx->io.dst->data, tsz); 628 | bdelete (luuCtx->io.dst, 0, (int) tsz); 629 | return nelem; 630 | } 631 | 632 | DecodeMore:; 633 | if (0 <= (l = binchr (luuCtx->io.src, 0, &eol))) { 634 | int ol = 0; 635 | struct tagbstring t; 636 | bstring s = luuCtx->io.src; 637 | luuCtx->io.src = &t; 638 | 639 | do { 640 | if (l > ol) { 641 | bmid2tbstr (t, s, ol, l - ol); 642 | lret = bUuDecLine (&luuCtx->io, 0, t.slen); 643 | if (0 > lret) { 644 | luuCtx->io.src = s; 645 | goto Done; 646 | } 647 | } 648 | ol = l + 1; 649 | if (((size_t) luuCtx->io.dst->slen) > tsz) break; 650 | l = binchr (s, ol, &eol); 651 | } while (BSTR_ERR != l); 652 | bdelete (s, 0, ol); 653 | luuCtx->io.src = s; 654 | goto CheckInternalBuffer; 655 | } 656 | 657 | if (BSTR_ERR != bsreada (luuCtx->io.src, luuCtx->sInp, bsbufflength (luuCtx->sInp, BSTR_BS_BUFF_LENGTH_GET))) { 658 | goto DecodeMore; 659 | } 660 | 661 | bUuDecLine (&luuCtx->io, 0, luuCtx->io.src->slen); 662 | 663 | Done:; 664 | /* Output any lingering data that has been translated */ 665 | if (((size_t) luuCtx->io.dst->slen) > 0) { 666 | if (((size_t) luuCtx->io.dst->slen) > tsz) goto CheckInternalBuffer; 667 | memcpy (buff, luuCtx->io.dst->data, luuCtx->io.dst->slen); 668 | tsz = luuCtx->io.dst->slen / elsize; 669 | luuCtx->io.dst->slen = 0; 670 | if (tsz > 0) return tsz; 671 | } 672 | 673 | /* Deallocate once EOF becomes triggered */ 674 | bdestroy (luuCtx->io.dst); 675 | bdestroy (luuCtx->io.src); 676 | free (luuCtx); 677 | return 0; 678 | } 679 | 680 | /* bStream * bsUuDecode (struct bStream * sInp, int * badlines) 681 | * 682 | * Creates a bStream which performs the UUDecode of an an input stream. If 683 | * there are errors in the decoding, they are counted up and returned in 684 | * "badlines", if badlines is not NULL. It is assumed that the "begin" and 685 | * "end" lines have already been stripped off. The potential security 686 | * problem of writing the filename in the begin line is something that is 687 | * beyond the scope of a portable library. 688 | */ 689 | 690 | struct bStream * bsUuDecode (struct bStream * sInp, int * badlines) { 691 | struct bsUuCtx * luuCtx = (struct bsUuCtx *) malloc (sizeof (struct bsUuCtx)); 692 | struct bStream * sOut; 693 | 694 | if (NULL == luuCtx) return NULL; 695 | 696 | luuCtx->io.src = bfromcstr (""); 697 | luuCtx->io.dst = bfromcstr (""); 698 | if (NULL == luuCtx->io.dst || NULL == luuCtx->io.src) { 699 | CleanUpFailureToAllocate:; 700 | bdestroy (luuCtx->io.dst); 701 | bdestroy (luuCtx->io.src); 702 | free (luuCtx); 703 | return NULL; 704 | } 705 | luuCtx->io.badlines = badlines; 706 | if (badlines) *badlines = 0; 707 | 708 | luuCtx->sInp = sInp; 709 | 710 | sOut = bsopen ((bNread) bsUuDecodePart, luuCtx); 711 | if (NULL == sOut) goto CleanUpFailureToAllocate; 712 | return sOut; 713 | } 714 | 715 | #define UU_ENCODE_BYTE(b) (char) (((b) == 0) ? '`' : ((b) + ' ')) 716 | 717 | /* bstring bUuEncode (const_bstring src) 718 | * 719 | * Performs a UUEncode of a block of data. The "begin" and "end" lines are 720 | * not appended. 721 | */ 722 | bstring bUuEncode (const_bstring src) { 723 | bstring out; 724 | int i, j, jm; 725 | unsigned int c0, c1, c2; 726 | if (src == NULL || src->slen < 0 || src->data == NULL) return NULL; 727 | if ((out = bfromcstr ("")) == NULL) return NULL; 728 | for (i=0; i < src->slen; i += UU_MAX_LINELEN) { 729 | if ((jm = i + UU_MAX_LINELEN) > src->slen) jm = src->slen; 730 | if (bconchar (out, UU_ENCODE_BYTE (jm - i)) < 0) { 731 | bstrFree (out); 732 | break; 733 | } 734 | for (j = i; j < jm; j += 3) { 735 | c0 = (unsigned int) bchar (src, j ); 736 | c1 = (unsigned int) bchar (src, j + 1); 737 | c2 = (unsigned int) bchar (src, j + 2); 738 | if (bconchar (out, UU_ENCODE_BYTE ( (c0 & 0xFC) >> 2)) < 0 || 739 | bconchar (out, UU_ENCODE_BYTE (((c0 & 0x03) << 4) | ((c1 & 0xF0) >> 4))) < 0 || 740 | bconchar (out, UU_ENCODE_BYTE (((c1 & 0x0F) << 2) | ((c2 & 0xC0) >> 6))) < 0 || 741 | bconchar (out, UU_ENCODE_BYTE ( (c2 & 0x3F))) < 0) { 742 | bstrFree (out); 743 | goto End; 744 | } 745 | } 746 | if (bconchar (out, (char) '\r') < 0 || bconchar (out, (char) '\n') < 0) { 747 | bstrFree (out); 748 | break; 749 | } 750 | } 751 | End:; 752 | return out; 753 | } 754 | 755 | /* bstring bYEncode (const_bstring src) 756 | * 757 | * Performs a YEncode of a block of data. No header or tail info is 758 | * appended. See: http://www.yenc.org/whatis.htm and 759 | * http://www.yenc.org/yenc-draft.1.3.txt 760 | */ 761 | bstring bYEncode (const_bstring src) { 762 | int i; 763 | bstring out; 764 | unsigned char c; 765 | 766 | if (src == NULL || src->slen < 0 || src->data == NULL) return NULL; 767 | if ((out = bfromcstr ("")) == NULL) return NULL; 768 | for (i=0; i < src->slen; i++) { 769 | c = (unsigned char)(src->data[i] + 42); 770 | if (c == '=' || c == '\0' || c == '\r' || c == '\n') { 771 | if (0 > bconchar (out, (char) '=')) { 772 | bdestroy (out); 773 | return NULL; 774 | } 775 | c += (unsigned char) 64; 776 | } 777 | if (0 > bconchar (out, c)) { 778 | bdestroy (out); 779 | return NULL; 780 | } 781 | } 782 | return out; 783 | } 784 | 785 | /* bstring bYDecode (const_bstring src) 786 | * 787 | * Performs a YDecode of a block of data. See: 788 | * http://www.yenc.org/whatis.htm and http://www.yenc.org/yenc-draft.1.3.txt 789 | */ 790 | #define MAX_OB_LEN (64) 791 | 792 | bstring bYDecode (const_bstring src) { 793 | int i; 794 | bstring out; 795 | unsigned char c; 796 | unsigned char octetbuff[MAX_OB_LEN]; 797 | int obl; 798 | 799 | if (src == NULL || src->slen < 0 || src->data == NULL) return NULL; 800 | if ((out = bfromcstr ("")) == NULL) return NULL; 801 | 802 | obl = 0; 803 | 804 | for (i=0; i < src->slen; i++) { 805 | if ('=' == (c = src->data[i])) { /* The = escape mode */ 806 | i++; 807 | if (i >= src->slen) { 808 | bdestroy (out); 809 | return NULL; 810 | } 811 | c = (unsigned char) (src->data[i] - 64); 812 | } else { 813 | if ('\0' == c) { 814 | bdestroy (out); 815 | return NULL; 816 | } 817 | 818 | /* Extraneous CR/LFs are to be ignored. */ 819 | if (c == '\r' || c == '\n') continue; 820 | } 821 | 822 | octetbuff[obl] = (unsigned char) ((int) c - 42); 823 | obl++; 824 | 825 | if (obl >= MAX_OB_LEN) { 826 | if (0 > bcatblk (out, octetbuff, obl)) { 827 | bdestroy (out); 828 | return NULL; 829 | } 830 | obl = 0; 831 | } 832 | } 833 | 834 | if (0 > bcatblk (out, octetbuff, obl)) { 835 | bdestroy (out); 836 | out = NULL; 837 | } 838 | return out; 839 | } 840 | 841 | /* bstring bStrfTime (const char * fmt, const struct tm * timeptr) 842 | * 843 | * Takes a format string that is compatible with strftime and a struct tm 844 | * pointer, formats the time according to the format string and outputs 845 | * the bstring as a result. Note that if there is an early generation of a 846 | * '\0' character, the bstring will be truncated to this end point. 847 | */ 848 | bstring bStrfTime (const char * fmt, const struct tm * timeptr) { 849 | #if defined (__TURBOC__) && !defined (__BORLANDC__) 850 | static struct tagbstring ns = bsStatic ("bStrfTime Not supported"); 851 | fmt = fmt; 852 | timeptr = timeptr; 853 | return &ns; 854 | #else 855 | bstring buff; 856 | int n; 857 | size_t r; 858 | 859 | if (fmt == NULL) return NULL; 860 | 861 | /* Since the length is not determinable beforehand, a search is 862 | performed using the truncating "strftime" call on increasing 863 | potential sizes for the output result. */ 864 | 865 | if ((n = (int) (2*strlen (fmt))) < 16) n = 16; 866 | buff = bfromcstralloc (n+2, ""); 867 | 868 | for (;;) { 869 | if (BSTR_OK != balloc (buff, n + 2)) { 870 | bdestroy (buff); 871 | return NULL; 872 | } 873 | 874 | r = strftime ((char *) buff->data, n + 1, fmt, timeptr); 875 | 876 | if (r > 0) { 877 | buff->slen = (int) r; 878 | break; 879 | } 880 | 881 | n += n; 882 | } 883 | 884 | return buff; 885 | #endif 886 | } 887 | 888 | /* int bSetCstrChar (bstring a, int pos, char c) 889 | * 890 | * Sets the character at position pos to the character c in the bstring a. 891 | * If the character c is NUL ('\0') then the string is truncated at this 892 | * point. Note: this does not enable any other '\0' character in the bstring 893 | * as terminator indicator for the string. pos must be in the position 894 | * between 0 and b->slen inclusive, otherwise BSTR_ERR will be returned. 895 | */ 896 | int bSetCstrChar (bstring b, int pos, char c) { 897 | if (NULL == b || b->mlen <= 0 || b->slen < 0 || b->mlen < b->slen) 898 | return BSTR_ERR; 899 | if (pos < 0 || pos > b->slen) return BSTR_ERR; 900 | 901 | if (pos == b->slen) { 902 | if ('\0' != c) return bconchar (b, c); 903 | return 0; 904 | } 905 | 906 | b->data[pos] = (unsigned char) c; 907 | if ('\0' == c) b->slen = pos; 908 | 909 | return 0; 910 | } 911 | 912 | /* int bSetChar (bstring b, int pos, char c) 913 | * 914 | * Sets the character at position pos to the character c in the bstring a. 915 | * The string is not truncated if the character c is NUL ('\0'). pos must 916 | * be in the position between 0 and b->slen inclusive, otherwise BSTR_ERR 917 | * will be returned. 918 | */ 919 | int bSetChar (bstring b, int pos, char c) { 920 | if (NULL == b || b->mlen <= 0 || b->slen < 0 || b->mlen < b->slen) 921 | return BSTR_ERR; 922 | if (pos < 0 || pos > b->slen) return BSTR_ERR; 923 | 924 | if (pos == b->slen) { 925 | return bconchar (b, c); 926 | } 927 | 928 | b->data[pos] = (unsigned char) c; 929 | return 0; 930 | } 931 | 932 | #define INIT_SECURE_INPUT_LENGTH (256) 933 | 934 | /* bstring bSecureInput (int maxlen, int termchar, 935 | * bNgetc vgetchar, void * vgcCtx) 936 | * 937 | * Read input from an abstracted input interface, for a length of at most 938 | * maxlen characters. If maxlen <= 0, then there is no length limit put 939 | * on the input. The result is terminated early if vgetchar() return EOF 940 | * or the user specified value termchar. 941 | * 942 | */ 943 | bstring bSecureInput (int maxlen, int termchar, bNgetc vgetchar, void * vgcCtx) { 944 | int i, m, c; 945 | bstring b, t; 946 | 947 | if (!vgetchar) return NULL; 948 | 949 | b = bfromcstralloc (INIT_SECURE_INPUT_LENGTH, ""); 950 | if ((c = UCHAR_MAX + 1) == termchar) c++; 951 | 952 | for (i=0; ; i++) { 953 | if (termchar == c || (maxlen > 0 && i >= maxlen)) c = EOF; 954 | else c = vgetchar (vgcCtx); 955 | 956 | if (EOF == c) break; 957 | 958 | if (i+1 >= b->mlen) { 959 | 960 | /* Double size, but deal with unusual case of numeric 961 | overflows */ 962 | 963 | if ((m = b->mlen << 1) <= b->mlen && 964 | (m = b->mlen + 1024) <= b->mlen && 965 | (m = b->mlen + 16) <= b->mlen && 966 | (m = b->mlen + 1) <= b->mlen) t = NULL; 967 | else t = bfromcstralloc (m, ""); 968 | 969 | if (t) memcpy (t->data, b->data, i); 970 | bSecureDestroy (b); /* Cleanse previous buffer */ 971 | b = t; 972 | if (!b) return b; 973 | } 974 | 975 | b->data[i] = (unsigned char) c; 976 | } 977 | 978 | b->slen = i; 979 | b->data[i] = (unsigned char) '\0'; 980 | return b; 981 | } 982 | 983 | #define BWS_BUFF_SZ (1024) 984 | 985 | struct bwriteStream { 986 | bstring buff; /* Buffer for underwrites */ 987 | void * parm; /* The stream handle for core stream */ 988 | bNwrite writeFn; /* fwrite work-a-like fnptr for core stream */ 989 | int isEOF; /* track stream's EOF state */ 990 | int minBuffSz; 991 | }; 992 | 993 | /* struct bwriteStream * bwsOpen (bNwrite writeFn, void * parm) 994 | * 995 | * Wrap a given open stream (described by a fwrite work-a-like function 996 | * pointer and stream handle) into an open bwriteStream suitable for write 997 | * streaming functions. 998 | */ 999 | struct bwriteStream * bwsOpen (bNwrite writeFn, void * parm) { 1000 | struct bwriteStream * ws; 1001 | 1002 | if (NULL == writeFn) return NULL; 1003 | ws = (struct bwriteStream *) malloc (sizeof (struct bwriteStream)); 1004 | if (ws) { 1005 | if (NULL == (ws->buff = bfromcstr (""))) { 1006 | free (ws); 1007 | ws = NULL; 1008 | } else { 1009 | ws->parm = parm; 1010 | ws->writeFn = writeFn; 1011 | ws->isEOF = 0; 1012 | ws->minBuffSz = BWS_BUFF_SZ; 1013 | } 1014 | } 1015 | return ws; 1016 | } 1017 | 1018 | #define internal_bwswriteout(ws,b) { \ 1019 | if ((b)->slen > 0) { \ 1020 | if (1 != (ws->writeFn ((b)->data, (b)->slen, 1, ws->parm))) { \ 1021 | ws->isEOF = 1; \ 1022 | return BSTR_ERR; \ 1023 | } \ 1024 | } \ 1025 | } 1026 | 1027 | /* int bwsWriteFlush (struct bwriteStream * ws) 1028 | * 1029 | * Force any pending data to be written to the core stream. 1030 | */ 1031 | int bwsWriteFlush (struct bwriteStream * ws) { 1032 | if (NULL == ws || ws->isEOF || 0 >= ws->minBuffSz || 1033 | NULL == ws->writeFn || NULL == ws->buff) return BSTR_ERR; 1034 | internal_bwswriteout (ws, ws->buff); 1035 | ws->buff->slen = 0; 1036 | return 0; 1037 | } 1038 | 1039 | /* int bwsWriteBstr (struct bwriteStream * ws, const_bstring b) 1040 | * 1041 | * Send a bstring to a bwriteStream. If the stream is at EOF BSTR_ERR is 1042 | * returned. Note that there is no deterministic way to determine the exact 1043 | * cut off point where the core stream stopped accepting data. 1044 | */ 1045 | int bwsWriteBstr (struct bwriteStream * ws, const_bstring b) { 1046 | struct tagbstring t; 1047 | int l; 1048 | 1049 | if (NULL == ws || NULL == b || NULL == ws->buff || 1050 | ws->isEOF || 0 >= ws->minBuffSz || NULL == ws->writeFn) 1051 | return BSTR_ERR; 1052 | 1053 | /* Buffer prepacking optimization */ 1054 | if (b->slen > 0 && ws->buff->mlen - ws->buff->slen > b->slen) { 1055 | static struct tagbstring empty = bsStatic (""); 1056 | if (0 > bconcat (ws->buff, b)) return BSTR_ERR; 1057 | return bwsWriteBstr (ws, &empty); 1058 | } 1059 | 1060 | if (0 > (l = ws->minBuffSz - ws->buff->slen)) { 1061 | internal_bwswriteout (ws, ws->buff); 1062 | ws->buff->slen = 0; 1063 | l = ws->minBuffSz; 1064 | } 1065 | 1066 | if (b->slen < l) return bconcat (ws->buff, b); 1067 | 1068 | if (0 > bcatblk (ws->buff, b->data, l)) return BSTR_ERR; 1069 | internal_bwswriteout (ws, ws->buff); 1070 | ws->buff->slen = 0; 1071 | 1072 | bmid2tbstr (t, (bstring) b, l, b->slen); 1073 | 1074 | if (t.slen >= ws->minBuffSz) { 1075 | internal_bwswriteout (ws, &t); 1076 | return 0; 1077 | } 1078 | 1079 | return bassign (ws->buff, &t); 1080 | } 1081 | 1082 | /* int bwsWriteBlk (struct bwriteStream * ws, void * blk, int len) 1083 | * 1084 | * Send a block of data a bwriteStream. If the stream is at EOF BSTR_ERR is 1085 | * returned. 1086 | */ 1087 | int bwsWriteBlk (struct bwriteStream * ws, void * blk, int len) { 1088 | struct tagbstring t; 1089 | if (NULL == blk || len < 0) return BSTR_ERR; 1090 | blk2tbstr (t, blk, len); 1091 | return bwsWriteBstr (ws, &t); 1092 | } 1093 | 1094 | /* int bwsIsEOF (const struct bwriteStream * ws) 1095 | * 1096 | * Returns 0 if the stream is currently writable, 1 if the core stream has 1097 | * responded by not accepting the previous attempted write. 1098 | */ 1099 | int bwsIsEOF (const struct bwriteStream * ws) { 1100 | if (NULL == ws || NULL == ws->buff || 0 > ws->minBuffSz || 1101 | NULL == ws->writeFn) return BSTR_ERR; 1102 | return ws->isEOF; 1103 | } 1104 | 1105 | /* int bwsBuffLength (struct bwriteStream * ws, int sz) 1106 | * 1107 | * Set the length of the buffer used by the bwsStream. If sz is zero, the 1108 | * length is not set. This function returns with the previous length. 1109 | */ 1110 | int bwsBuffLength (struct bwriteStream * ws, int sz) { 1111 | int oldSz; 1112 | if (ws == NULL || sz < 0) return BSTR_ERR; 1113 | oldSz = ws->minBuffSz; 1114 | if (sz > 0) ws->minBuffSz = sz; 1115 | return oldSz; 1116 | } 1117 | 1118 | /* void * bwsClose (struct bwriteStream * s) 1119 | * 1120 | * Close the bwriteStream, and return the handle to the stream that was 1121 | * originally used to open the given stream. Note that even if the stream 1122 | * is at EOF it still needs to be closed with a call to bwsClose. 1123 | */ 1124 | void * bwsClose (struct bwriteStream * ws) { 1125 | void * parm; 1126 | if (NULL == ws || NULL == ws->buff || 0 >= ws->minBuffSz || 1127 | NULL == ws->writeFn) return NULL; 1128 | bwsWriteFlush (ws); 1129 | parm = ws->parm; 1130 | ws->parm = NULL; 1131 | ws->minBuffSz = -1; 1132 | ws->writeFn = NULL; 1133 | bstrFree (ws->buff); 1134 | free (ws); 1135 | return parm; 1136 | } 1137 | 1138 | --------------------------------------------------------------------------------