├── 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 | | Status |
59 | disconnected |
60 |
61 |
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 |
--------------------------------------------------------------------------------