├── .gitignore ├── .travis.yml ├── Makefile ├── README.md ├── docs ├── COPYING └── README ├── mk └── dmo.mk └── src ├── sip_ua ├── demo.mk └── sip_ua.c ├── tcp_server ├── demo.mk └── tcp_server.c ├── udp_server ├── demo.mk └── udp_server.c └── websocket_server ├── demo.mk └── websocket_server.c /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | /*.o 3 | /*.ko 4 | 5 | # Libraries 6 | /*.lib 7 | /*.a 8 | 9 | # Shared objects (inc. Windows DLLs) 10 | /*.dll 11 | /*.so 12 | /*.so.* 13 | /*.dylib 14 | 15 | # Executables 16 | /*.exe 17 | /*.out 18 | /*.app 19 | /build-* 20 | /sip_ua 21 | /udp_server 22 | /tcp_server 23 | /websocket_server 24 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | 3 | before_install: 4 | - sudo apt-get -qq update 5 | - sudo apt-get -y install libssl-dev 6 | 7 | install: 8 | - git clone https://github.com/creytiv/re.git 9 | - cd re && make && sudo make install && cd .. 10 | - sudo ldconfig 11 | - wget "https://github.com/alfredh/pytools/raw/master/ccheck.py" 12 | 13 | script: 14 | - make EXTRA_CFLAGS=-Werror 15 | - python2 ccheck.py 16 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Makefile 3 | # 4 | # Copyright (C) 2011 Creytiv.com 5 | # 6 | 7 | PROJECT := redemo 8 | VERSION := 0.6.0 9 | 10 | DEMOS += sip_ua 11 | DEMOS += tcp_server 12 | DEMOS += udp_server 13 | DEMOS += websocket_server 14 | 15 | 16 | LIBRE_MK := $(shell [ -f ../re/mk/re.mk ] && \ 17 | echo "../re/mk/re.mk") 18 | ifeq ($(LIBRE_MK),) 19 | LIBRE_MK := $(shell [ -f /usr/share/re/re.mk ] && \ 20 | echo "/usr/share/re/re.mk") 21 | endif 22 | ifeq ($(LIBRE_MK),) 23 | LIBRE_MK := $(shell [ -f /usr/local/share/re/re.mk ] && \ 24 | echo "/usr/local/share/re/re.mk") 25 | endif 26 | 27 | include $(LIBRE_MK) 28 | 29 | CFLAGS += -I$(LIBRE_INC) 30 | 31 | 32 | DEMO_MK := $(patsubst %,src/%/demo.mk,$(DEMOS)) 33 | DEMO_BLD := $(patsubst %,$(BUILD)/%,$(DEMOS)) 34 | BINS := $(patsubst %,%$(BIN_SUFFIX),$(DEMOS)) 35 | 36 | include $(DEMO_MK) 37 | 38 | 39 | all: $(BINS) 40 | 41 | $(BUILD): Makefile 42 | @mkdir -p $(DEMO_BLD) 43 | @touch $@ 44 | 45 | clean: 46 | @rm -rf $(BINS) $(BUILD) 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | redemo 2 | ====== 3 | 4 | Demo example applications using libre 5 | 6 | [![Build Status](https://travis-ci.org/creytiv/redemo.svg?branch=master)](https://travis-ci.org/creytiv/redemo) 7 | -------------------------------------------------------------------------------- /docs/COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010 - 2013, Creytiv.com 2 | All rights reserved. 3 | 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions 7 | are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright 13 | notice, this list of conditions and the following disclaimer in the 14 | documentation and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the Creytiv.com nor the names of its contributors 17 | may be used to endorse or promote products derived from this software 18 | without specific prior written permission. 19 | 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /docs/README: -------------------------------------------------------------------------------- 1 | README 2 | ------ 3 | 4 | redemo - libre example and demonstration programs 5 | Copyright (c) 2010 - 2013 Creytiv.com 6 | 7 | Distributed under BSD license 8 | 9 | 10 | Feedback: 11 | 12 | - Please send feedback to 13 | 14 | 15 | External dependencies: 16 | 17 | libre 18 | -------------------------------------------------------------------------------- /mk/dmo.mk: -------------------------------------------------------------------------------- 1 | # 2 | # dmo.mk 3 | # 4 | # Copyright (C) 2011 Creytiv.com 5 | # 6 | 7 | $(DEMO)_OBJS := $(patsubst %.c,$(BUILD)/$(DEMO)/%.o,$($(DEMO)_SRCS)) 8 | 9 | -include $($(DEMO)_OBJS:.o=.d) 10 | 11 | $(DEMO)$(BIN_SUFFIX): $($(DEMO)_OBJS) 12 | @echo " LD $@" 13 | @$(LD) $(LFLAGS) $($(basename $@)_OBJS) \ 14 | $($(basename $@)_LFLAGS) -L$(LIBRE_SO) -lre $(LIBS) -o $@ 15 | 16 | $(BUILD)/$(DEMO)/%.o: src/$(DEMO)/%.c $(BUILD) Makefile mk/dmo.mk \ 17 | src/$(DEMO)/demo.mk 18 | @echo " CC $@" 19 | @$(CC) $(CFLAGS) -c $< -o $@ $(DFLAGS) 20 | -------------------------------------------------------------------------------- /src/sip_ua/demo.mk: -------------------------------------------------------------------------------- 1 | # 2 | # demo.mk 3 | # 4 | # Copyright (C) 2011 Creytiv.com 5 | # 6 | 7 | DEMO := sip_ua 8 | $(DEMO)_SRCS += sip_ua.c 9 | $(DEMO)_LFLAGS += 10 | 11 | include mk/dmo.mk 12 | -------------------------------------------------------------------------------- /src/sip_ua/sip_ua.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file sip_ua.c SIP User Agent Demo 3 | * 4 | * 5 | * To test inbound calls, invoke without arguments. sip_ua will 6 | * register and wait for an inbound call: 7 | * 8 | * $ ./sip_ua 9 | * 10 | * 11 | * To test outbound calls, invoke with a SIP URI argument. 12 | * sip_ua will invite provided URI: 13 | * 14 | * $ ./sip_ua sip:echo@creytiv.com 15 | * 16 | * 17 | * Copyright (C) 2011 Creytiv.com 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | 24 | static struct sipsess_sock *sess_sock; /* SIP session socket */ 25 | static struct sdp_session *sdp; /* SDP session */ 26 | static struct sdp_media *sdp_media; /* SDP media */ 27 | static struct sipsess *sess; /* SIP session */ 28 | static struct sipreg *reg; /* SIP registration */ 29 | static struct sip *sip; /* SIP stack */ 30 | static struct rtp_sock *rtp; /* RTP socket */ 31 | 32 | const char *registrar = "sip:creytiv.com"; 33 | const char *uri = "sip:demo@creytiv.com"; 34 | const char *name = "demo"; 35 | 36 | 37 | /* terminate */ 38 | static void terminate(void) 39 | { 40 | /* terminate session */ 41 | sess = mem_deref(sess); 42 | 43 | /* terminate registration */ 44 | reg = mem_deref(reg); 45 | 46 | /* wait for pending transactions to finish */ 47 | sip_close(sip, false); 48 | } 49 | 50 | 51 | /* called for every received RTP packet */ 52 | static void rtp_handler(const struct sa *src, const struct rtp_header *hdr, 53 | struct mbuf *mb, void *arg) 54 | { 55 | (void)hdr; 56 | (void)arg; 57 | 58 | re_printf("rtp: recv %zu bytes from %J\n", mbuf_get_left(mb), src); 59 | } 60 | 61 | 62 | /* called for every received RTCP packet */ 63 | static void rtcp_handler(const struct sa *src, struct rtcp_msg *msg, void *arg) 64 | { 65 | (void)arg; 66 | 67 | re_printf("rtcp: recv %s from %J\n", rtcp_type_name(msg->hdr.pt), src); 68 | } 69 | 70 | 71 | /* called when challenged for credentials */ 72 | static int auth_handler(char **user, char **pass, const char *realm, void *arg) 73 | { 74 | int err = 0; 75 | (void)realm; 76 | (void)arg; 77 | 78 | err |= str_dup(user, "demo"); 79 | err |= str_dup(pass, "secret"); 80 | 81 | return err; 82 | } 83 | 84 | 85 | /* print SDP status */ 86 | static void update_media(void) 87 | { 88 | const struct sdp_format *fmt; 89 | 90 | re_printf("SDP peer address: %J\n", sdp_media_raddr(sdp_media)); 91 | 92 | fmt = sdp_media_rformat(sdp_media, NULL); 93 | if (!fmt) { 94 | re_printf("no common media format found\n"); 95 | return; 96 | } 97 | 98 | re_printf("SDP media format: %s/%u/%u (payload type: %u)\n", 99 | fmt->name, fmt->srate, fmt->ch, fmt->pt); 100 | } 101 | 102 | 103 | /* 104 | * called when an SDP offer is received (got offer: true) or 105 | * when an offer is to be sent (got_offer: false) 106 | */ 107 | static int offer_handler(struct mbuf **mbp, const struct sip_msg *msg, 108 | void *arg) 109 | { 110 | const bool got_offer = mbuf_get_left(msg->mb); 111 | int err; 112 | (void)arg; 113 | 114 | if (got_offer) { 115 | 116 | err = sdp_decode(sdp, msg->mb, true); 117 | if (err) { 118 | re_fprintf(stderr, "unable to decode SDP offer: %s\n", 119 | strerror(err)); 120 | return err; 121 | } 122 | 123 | re_printf("SDP offer received\n"); 124 | update_media(); 125 | } 126 | else { 127 | re_printf("sending SDP offer\n"); 128 | } 129 | 130 | return sdp_encode(mbp, sdp, !got_offer); 131 | } 132 | 133 | 134 | /* called when an SDP answer is received */ 135 | static int answer_handler(const struct sip_msg *msg, void *arg) 136 | { 137 | int err; 138 | (void)arg; 139 | 140 | re_printf("SDP answer received\n"); 141 | 142 | err = sdp_decode(sdp, msg->mb, false); 143 | if (err) { 144 | re_fprintf(stderr, "unable to decode SDP answer: %s\n", 145 | strerror(err)); 146 | return err; 147 | } 148 | 149 | update_media(); 150 | 151 | return 0; 152 | } 153 | 154 | 155 | /* called when SIP progress (like 180 Ringing) responses are received */ 156 | static void progress_handler(const struct sip_msg *msg, void *arg) 157 | { 158 | (void)arg; 159 | 160 | re_printf("session progress: %u %r\n", msg->scode, &msg->reason); 161 | } 162 | 163 | 164 | /* called when the session is established */ 165 | static void establish_handler(const struct sip_msg *msg, void *arg) 166 | { 167 | (void)msg; 168 | (void)arg; 169 | 170 | re_printf("session established\n"); 171 | } 172 | 173 | 174 | /* called when the session fails to connect or is terminated from peer */ 175 | static void close_handler(int err, const struct sip_msg *msg, void *arg) 176 | { 177 | (void)arg; 178 | 179 | if (err) 180 | re_printf("session closed: %s\n", strerror(err)); 181 | else 182 | re_printf("session closed: %u %r\n", msg->scode, &msg->reason); 183 | 184 | terminate(); 185 | } 186 | 187 | 188 | /* called upon incoming calls */ 189 | static void connect_handler(const struct sip_msg *msg, void *arg) 190 | { 191 | struct mbuf *mb; 192 | bool got_offer; 193 | int err; 194 | (void)arg; 195 | 196 | if (sess) { 197 | /* Already in a call */ 198 | (void)sip_treply(NULL, sip, msg, 486, "Busy Here"); 199 | return; 200 | } 201 | 202 | got_offer = (mbuf_get_left(msg->mb) > 0); 203 | 204 | /* Decode SDP offer if incoming INVITE contains SDP */ 205 | if (got_offer) { 206 | 207 | err = sdp_decode(sdp, msg->mb, true); 208 | if (err) { 209 | re_fprintf(stderr, "unable to decode SDP offer: %s\n", 210 | strerror(err)); 211 | goto out; 212 | } 213 | 214 | update_media(); 215 | } 216 | 217 | /* Encode SDP */ 218 | err = sdp_encode(&mb, sdp, !got_offer); 219 | if (err) { 220 | re_fprintf(stderr, "unable to encode SDP: %s\n", 221 | strerror(err)); 222 | goto out; 223 | } 224 | 225 | /* Answer incoming call */ 226 | err = sipsess_accept(&sess, sess_sock, msg, 200, "OK", 227 | name, "application/sdp", mb, 228 | auth_handler, NULL, false, 229 | offer_handler, answer_handler, 230 | establish_handler, NULL, NULL, 231 | close_handler, NULL, NULL); 232 | mem_deref(mb); /* free SDP buffer */ 233 | if (err) { 234 | re_fprintf(stderr, "session accept error: %s\n", 235 | strerror(err)); 236 | goto out; 237 | } 238 | 239 | out: 240 | if (err) { 241 | (void)sip_treply(NULL, sip, msg, 500, strerror(err)); 242 | } 243 | else { 244 | re_printf("accepting incoming call from <%r>\n", 245 | &msg->from.auri); 246 | } 247 | } 248 | 249 | 250 | /* called when register responses are received */ 251 | static void register_handler(int err, const struct sip_msg *msg, void *arg) 252 | { 253 | (void)arg; 254 | 255 | if (err) 256 | re_printf("register error: %s\n", strerror(err)); 257 | else 258 | re_printf("register reply: %u %r\n", msg->scode, &msg->reason); 259 | } 260 | 261 | 262 | /* called when all sip transactions are completed */ 263 | static void exit_handler(void *arg) 264 | { 265 | (void)arg; 266 | 267 | /* stop libre main loop */ 268 | re_cancel(); 269 | } 270 | 271 | 272 | /* called upon reception of SIGINT, SIGALRM or SIGTERM */ 273 | static void signal_handler(int sig) 274 | { 275 | re_printf("terminating on signal %d...\n", sig); 276 | 277 | terminate(); 278 | } 279 | 280 | 281 | int main(int argc, char *argv[]) 282 | { 283 | struct sa nsv[16]; 284 | struct dnsc *dnsc = NULL; 285 | struct sa laddr; 286 | uint32_t nsc; 287 | int err; /* errno return values */ 288 | 289 | /* enable coredumps to aid debugging */ 290 | (void)sys_coredump_set(true); 291 | 292 | /* initialize libre state */ 293 | err = libre_init(); 294 | if (err) { 295 | re_fprintf(stderr, "re init failed: %s\n", strerror(err)); 296 | goto out; 297 | } 298 | 299 | nsc = ARRAY_SIZE(nsv); 300 | 301 | /* fetch list of DNS server IP addresses */ 302 | err = dns_srv_get(NULL, 0, nsv, &nsc); 303 | if (err) { 304 | re_fprintf(stderr, "unable to get dns servers: %s\n", 305 | strerror(err)); 306 | goto out; 307 | } 308 | 309 | /* create DNS client */ 310 | err = dnsc_alloc(&dnsc, NULL, nsv, nsc); 311 | if (err) { 312 | re_fprintf(stderr, "unable to create dns client: %s\n", 313 | strerror(err)); 314 | goto out; 315 | } 316 | 317 | /* create SIP stack instance */ 318 | err = sip_alloc(&sip, dnsc, 32, 32, 32, 319 | "ua demo v" VERSION " (" ARCH "/" OS ")", 320 | exit_handler, NULL); 321 | if (err) { 322 | re_fprintf(stderr, "sip error: %s\n", strerror(err)); 323 | goto out; 324 | } 325 | 326 | /* fetch local IP address */ 327 | err = net_default_source_addr_get(AF_INET, &laddr); 328 | if (err) { 329 | re_fprintf(stderr, "local address error: %s\n", strerror(err)); 330 | goto out; 331 | } 332 | 333 | /* listen on random port */ 334 | sa_set_port(&laddr, 0); 335 | 336 | /* add supported SIP transports */ 337 | err |= sip_transp_add(sip, SIP_TRANSP_UDP, &laddr); 338 | err |= sip_transp_add(sip, SIP_TRANSP_TCP, &laddr); 339 | if (err) { 340 | re_fprintf(stderr, "transport error: %s\n", strerror(err)); 341 | goto out; 342 | } 343 | 344 | /* create SIP session socket */ 345 | err = sipsess_listen(&sess_sock, sip, 32, connect_handler, NULL); 346 | if (err) { 347 | re_fprintf(stderr, "session listen error: %s\n", 348 | strerror(err)); 349 | goto out; 350 | } 351 | 352 | /* create the RTP/RTCP socket */ 353 | err = rtp_listen(&rtp, IPPROTO_UDP, &laddr, 10000, 30000, true, 354 | rtp_handler, rtcp_handler, NULL); 355 | if (err) { 356 | re_fprintf(stderr, "rtp listen error: %m\n", err); 357 | goto out; 358 | } 359 | 360 | re_printf("local RTP port is %u\n", sa_port(rtp_local(rtp))); 361 | 362 | /* create SDP session */ 363 | err = sdp_session_alloc(&sdp, &laddr); 364 | if (err) { 365 | re_fprintf(stderr, "sdp session error: %s\n", strerror(err)); 366 | goto out; 367 | } 368 | 369 | /* add audio sdp media, using port from RTP socket */ 370 | err = sdp_media_add(&sdp_media, sdp, "audio", 371 | sa_port(rtp_local(rtp)), "RTP/AVP"); 372 | if (err) { 373 | re_fprintf(stderr, "sdp media error: %s\n", strerror(err)); 374 | goto out; 375 | } 376 | 377 | /* add G.711 sdp media format */ 378 | err = sdp_format_add(NULL, sdp_media, false, "0", "PCMU", 8000, 1, 379 | NULL, NULL, NULL, false, NULL); 380 | if (err) { 381 | re_fprintf(stderr, "sdp format error: %s\n", strerror(err)); 382 | goto out; 383 | } 384 | 385 | /* invite provided URI */ 386 | if (argc > 1) { 387 | 388 | struct mbuf *mb; 389 | 390 | /* create SDP offer */ 391 | err = sdp_encode(&mb, sdp, true); 392 | if (err) { 393 | re_fprintf(stderr, "sdp encode error: %s\n", 394 | strerror(err)); 395 | goto out; 396 | } 397 | 398 | err = sipsess_connect(&sess, sess_sock, argv[1], name, 399 | uri, name, 400 | NULL, 0, "application/sdp", mb, 401 | auth_handler, NULL, false, 402 | offer_handler, answer_handler, 403 | progress_handler, establish_handler, 404 | NULL, NULL, close_handler, NULL, NULL); 405 | mem_deref(mb); /* free SDP buffer */ 406 | if (err) { 407 | re_fprintf(stderr, "session connect error: %s\n", 408 | strerror(err)); 409 | goto out; 410 | } 411 | 412 | re_printf("inviting <%s>...\n", argv[1]); 413 | } 414 | else { 415 | 416 | err = sipreg_register(®, sip, registrar, uri, 417 | NULL, uri, 60, name, 418 | NULL, 0, 0, auth_handler, NULL, false, 419 | register_handler, NULL, NULL, NULL); 420 | if (err) { 421 | re_fprintf(stderr, "register error: %s\n", 422 | strerror(err)); 423 | goto out; 424 | } 425 | 426 | re_printf("registering <%s>...\n", uri); 427 | } 428 | 429 | /* main loop */ 430 | err = re_main(signal_handler); 431 | 432 | out: 433 | /* clean up/free all state */ 434 | mem_deref(sdp); /* will also free sdp_media */ 435 | mem_deref(rtp); 436 | mem_deref(sess_sock); 437 | mem_deref(sip); 438 | mem_deref(dnsc); 439 | 440 | /* free libre state */ 441 | libre_close(); 442 | 443 | /* check for memory leaks */ 444 | tmr_debug(); 445 | mem_debug(); 446 | 447 | return err; 448 | } 449 | -------------------------------------------------------------------------------- /src/tcp_server/demo.mk: -------------------------------------------------------------------------------- 1 | # 2 | # demo.mk 3 | # 4 | # Copyright (C) 2011 Creytiv.com 5 | # 6 | 7 | DEMO := tcp_server 8 | $(DEMO)_SRCS += tcp_server.c 9 | $(DEMO)_LFLAGS += 10 | 11 | include mk/dmo.mk 12 | -------------------------------------------------------------------------------- /src/tcp_server/tcp_server.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file tc_server.c TCP Server Demo 3 | * 4 | * The demo can for instance be tested with the telnet tool: 5 | * $ telnet 127.0.0.1 3456 6 | * 7 | * Copyright (C) 2011 Creytiv.com 8 | */ 9 | 10 | #include 11 | #include 12 | 13 | 14 | /* Application connection context */ 15 | struct conn { 16 | struct le le; /* list entry */ 17 | struct sa peer; /* peer address and port */ 18 | struct tcp_conn *tc; /* TCP connection */ 19 | }; 20 | 21 | 22 | /* TCP Socket */ 23 | static struct tcp_sock *ts; 24 | 25 | /* Linked list of active TCP connections */ 26 | static struct list connl; 27 | 28 | 29 | /* called upon reception of SIGINT, SIGALRM or SIGTERM */ 30 | static void signal_handler(int sig) 31 | { 32 | re_printf("terminating on signal %d...\n", sig); 33 | 34 | /* stop libre main loop */ 35 | re_cancel(); 36 | } 37 | 38 | 39 | /* destructor called when reference count on conn reach zero */ 40 | static void destructor(void *arg) 41 | { 42 | struct conn *conn = arg; 43 | 44 | /* remove this connection entry from the list */ 45 | list_unlink(&conn->le); 46 | 47 | /* clean up local TCP connection state */ 48 | mem_deref(conn->tc); 49 | } 50 | 51 | 52 | static void establish_handler(void *arg) 53 | { 54 | struct conn *conn = arg; 55 | 56 | re_printf("connection from %J established\n", &conn->peer); 57 | } 58 | 59 | 60 | static void recv_handler(struct mbuf *mb, void *arg) 61 | { 62 | struct conn *conn = arg; 63 | 64 | re_printf("got %zu bytes of TCP data from %J\n", 65 | mbuf_get_left(mb), &conn->peer); 66 | 67 | /* received data is echoed back */ 68 | (void)tcp_send(conn->tc, mb); 69 | } 70 | 71 | 72 | static void close_handler(int err, void *arg) 73 | { 74 | struct conn *conn = arg; 75 | 76 | re_printf("connection from %J closed (%s)\n", &conn->peer, 77 | strerror(err)); 78 | 79 | /* destroy connection state */ 80 | mem_deref(conn); 81 | } 82 | 83 | 84 | static void connect_handler(const struct sa *peer, void *arg) 85 | { 86 | struct conn *conn; 87 | int err; 88 | (void)arg; 89 | 90 | /* allocate connection state */ 91 | conn = mem_zalloc(sizeof(*conn), destructor); 92 | if (!conn) { 93 | err = ENOMEM; 94 | goto out; 95 | } 96 | 97 | /* append connection to connection list */ 98 | list_append(&connl, &conn->le, conn); 99 | 100 | /* save peer address/port */ 101 | conn->peer = *peer; 102 | 103 | /* accept connection */ 104 | err = tcp_accept(&conn->tc, ts, establish_handler, 105 | recv_handler, close_handler, conn); 106 | if (err) 107 | goto out; 108 | 109 | re_printf("accepting new connection from %J\n", peer); 110 | 111 | out: 112 | if (err) { 113 | /* destroy state */ 114 | mem_deref(conn); 115 | 116 | /* reject connection */ 117 | tcp_reject(ts); 118 | } 119 | } 120 | 121 | 122 | int main(void) 123 | { 124 | struct sa laddr; 125 | int err; /* errno return values */ 126 | 127 | /* enable coredumps to aid debugging */ 128 | (void)sys_coredump_set(true); 129 | 130 | /* initialize libre state */ 131 | err = libre_init(); 132 | if (err) { 133 | re_fprintf(stderr, "re init failed: %s\n", strerror(err)); 134 | goto out; 135 | } 136 | 137 | (void)sa_set_str(&laddr, "0.0.0.0", 3456); 138 | 139 | /* Create listening TCP socket, IP address 0.0.0.0, TCP port 3456 */ 140 | err = tcp_listen(&ts, &laddr, connect_handler, NULL); 141 | if (err) { 142 | re_fprintf(stderr, "tcp listen error: %s\n", strerror(err)); 143 | goto out; 144 | } 145 | 146 | re_printf("listening on TCP socket: %J\n", &laddr); 147 | 148 | /* main loop */ 149 | err = re_main(signal_handler); 150 | 151 | out: 152 | /* destroy active TCP connections */ 153 | list_flush(&connl); 154 | 155 | /* free TCP socket */ 156 | ts = mem_deref(ts); 157 | 158 | /* free library state */ 159 | libre_close(); 160 | 161 | /* check for memory leaks */ 162 | tmr_debug(); 163 | mem_debug(); 164 | 165 | return err; 166 | } 167 | -------------------------------------------------------------------------------- /src/udp_server/demo.mk: -------------------------------------------------------------------------------- 1 | # 2 | # demo.mk 3 | # 4 | # Copyright (C) 2011 Creytiv.com 5 | # 6 | 7 | DEMO := udp_server 8 | $(DEMO)_SRCS += udp_server.c 9 | $(DEMO)_LFLAGS += 10 | 11 | include mk/dmo.mk 12 | -------------------------------------------------------------------------------- /src/udp_server/udp_server.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file udp_server.c UDP Server Demo 3 | * 4 | * The demo can for instance be tested with the netcat tool: 5 | * $ nc -u 127.0.0.1 3456 6 | * 7 | * Copyright (C) 2011 Creytiv.com 8 | */ 9 | 10 | #include 11 | #include 12 | 13 | 14 | /* UDP Socket */ 15 | static struct udp_sock *us; 16 | 17 | 18 | /* called upon reception of SIGINT, SIGALRM or SIGTERM */ 19 | static void signal_handler(int sig) 20 | { 21 | re_printf("terminating on signal %d...\n", sig); 22 | 23 | /* stop libre main loop */ 24 | re_cancel(); 25 | } 26 | 27 | 28 | /* Asynchronus UDP callback, called when UDP packets are received */ 29 | static void recv_handler(const struct sa *src, struct mbuf *mb, void *arg) 30 | { 31 | /* callback argument not used */ 32 | (void)arg; 33 | 34 | re_printf("got %zu bytes of UDP data from %J\n", 35 | mbuf_get_left(mb), src); 36 | 37 | /* received data is echoed back */ 38 | (void)udp_send(us, src, mb); 39 | } 40 | 41 | 42 | int main(void) 43 | { 44 | struct sa laddr; 45 | int err; /* errno return values */ 46 | 47 | /* enable coredumps to aid debugging */ 48 | (void)sys_coredump_set(true); 49 | 50 | /* initialize libre state */ 51 | err = libre_init(); 52 | if (err) { 53 | re_fprintf(stderr, "re init failed: %s\n", strerror(err)); 54 | goto out; 55 | } 56 | 57 | (void)sa_set_str(&laddr, "0.0.0.0", 3456); 58 | 59 | /* Create listening UDP socket, IP address 0.0.0.0, UDP port 3456 */ 60 | err = udp_listen(&us, &laddr, recv_handler, NULL); 61 | if (err) { 62 | re_fprintf(stderr, "udp listen error: %s\n", strerror(err)); 63 | goto out; 64 | } 65 | 66 | re_printf("listening on UDP socket: %J\n", &laddr); 67 | 68 | /* main loop */ 69 | err = re_main(signal_handler); 70 | 71 | out: 72 | /* free UDP socket */ 73 | us = mem_deref(us); 74 | 75 | /* free library state */ 76 | libre_close(); 77 | 78 | /* check for memory leaks */ 79 | tmr_debug(); 80 | mem_debug(); 81 | 82 | return err; 83 | } 84 | -------------------------------------------------------------------------------- /src/websocket_server/demo.mk: -------------------------------------------------------------------------------- 1 | # 2 | # demo.mk 3 | # 4 | # Copyright (C) 2011 Creytiv.com 5 | # 6 | 7 | DEMO := websocket_server 8 | $(DEMO)_SRCS += websocket_server.c 9 | $(DEMO)_LFLAGS += 10 | 11 | include mk/dmo.mk 12 | -------------------------------------------------------------------------------- /src/websocket_server/websocket_server.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file websocket_server.c Websocket Server Demo 3 | * 4 | * The demo can for instance be tested by pasting this into 5 | * a web browser javascript console: 6 | * var ws = new WebSocket('ws://localhost:3456'); 7 | * ws.addEventListener('open', () => ws.send('hello')); 8 | * ws.addEventListener('close', (e) => console.log('close', e)); 9 | * ws.addEventListener('message', (e) => console.log('msg', e)); 10 | * 11 | * Copyright (C) 2018 Creytiv.com 12 | */ 13 | 14 | #include 15 | 16 | 17 | struct websocket { 18 | struct le le; /* list entry */ 19 | struct websock_conn *conn; /* Websocket connection */ 20 | }; 21 | 22 | static struct websock *server; 23 | 24 | /* Linked list of active Websocket connections */ 25 | static struct list connl; 26 | 27 | /* called upon reception of SIGINT, SIGALRM or SIGTERM */ 28 | static void signal_handler(int sig) 29 | { 30 | re_printf("terminating on signal %d...\n", sig); 31 | 32 | /* destroy active Websocket connections */ 33 | list_flush(&connl); 34 | 35 | websock_shutdown(server); 36 | } 37 | 38 | 39 | static void websock_shutdown_handler(void *arg) 40 | { 41 | (void)arg; 42 | re_printf("websocket server shutting down\n"); 43 | 44 | /* stop libre main loop */ 45 | re_cancel(); 46 | } 47 | 48 | 49 | /* destructor called when reference count on conn reach zero */ 50 | static void destructor(void *arg) 51 | { 52 | struct websocket *ws = arg; 53 | 54 | /* remove this connection entry from the list */ 55 | list_unlink(&ws->le); 56 | 57 | /* clean up local Websocket connection state */ 58 | mem_deref(ws->conn); 59 | } 60 | 61 | 62 | /* called when a message is received from the other side */ 63 | static void srv_websock_recv_handler(const struct websock_hdr *hdr, 64 | struct mbuf *mb, void *arg) 65 | { 66 | struct websocket *ws = arg; 67 | int err; 68 | 69 | err = websock_send(ws->conn, hdr->opcode, "%b", 70 | mbuf_buf(mb), mbuf_get_left(mb)); 71 | if (err) 72 | re_fprintf(stderr, "ws send error: %m\n", err); 73 | } 74 | 75 | 76 | /* called when the websocket is closed by the other side */ 77 | static void srv_websock_close_handler(int err, void *arg) 78 | { 79 | struct websocket *ws = arg; 80 | 81 | re_printf("ws close %m\n", err); 82 | mem_deref(ws); 83 | } 84 | 85 | 86 | /* HTTP request handler */ 87 | static void http_req_handler(struct http_conn *conn, 88 | const struct http_msg *msg, void *arg) 89 | { 90 | struct websocket *ws; 91 | int err; 92 | 93 | /* allocate connection state */ 94 | ws = mem_zalloc(sizeof(*ws), destructor); 95 | if (!ws) { 96 | err = ENOMEM; 97 | re_fprintf(stderr, "http req handler alloc error: %m\n", err); 98 | goto out; 99 | } 100 | 101 | err = websock_accept(&ws->conn, server, conn, msg, 102 | 0, srv_websock_recv_handler, 103 | srv_websock_close_handler, ws); 104 | if (err) { 105 | re_fprintf(stderr, "websocket accept error: %m\n", err); 106 | goto out; 107 | } 108 | 109 | /* append connection to connection list */ 110 | list_append(&connl, &ws->le, ws); 111 | out: 112 | if (err) { 113 | http_reply(conn, 500, "Server Error", NULL); 114 | /* destroy state */ 115 | mem_deref(ws); 116 | } 117 | } 118 | 119 | 120 | int main(void) 121 | { 122 | struct sa laddr; 123 | struct http_sock *httpsock = NULL; 124 | int err; /* errno return values */ 125 | 126 | /* enable coredumps to aid debugging */ 127 | (void)sys_coredump_set(true); 128 | 129 | /* initialize libre state */ 130 | err = libre_init(); 131 | if (err) { 132 | re_fprintf(stderr, "re init failed: %m\n", err); 133 | goto out; 134 | } 135 | 136 | (void)sa_set_str(&laddr, "0.0.0.0", 3456); 137 | 138 | /* Create listening HTTP server, IP address 0.0.0.0, TCP port 3456 */ 139 | err = http_listen(&httpsock, &laddr, http_req_handler, NULL); 140 | if (err) { 141 | re_fprintf(stderr, "http listen error: %m\n", err); 142 | goto out; 143 | } 144 | 145 | err = websock_alloc(&server, websock_shutdown_handler, NULL); 146 | if (err) { 147 | re_fprintf(stderr, "websocket alloc error: %m\n", err); 148 | goto out; 149 | } 150 | 151 | re_printf("listening on WS socket: %J\n", &laddr); 152 | 153 | /* main loop */ 154 | err = re_main(signal_handler); 155 | 156 | out: 157 | /* free HTTP socket */ 158 | httpsock = mem_deref(httpsock); 159 | 160 | /* free Websocket server */ 161 | server = mem_deref(server); 162 | 163 | /* free library state */ 164 | libre_close(); 165 | 166 | /* check for memory leaks */ 167 | tmr_debug(); 168 | mem_debug(); 169 | 170 | return err; 171 | } 172 | --------------------------------------------------------------------------------