/c_src/erlzmq_nif.c
C | 1283 lines | 1118 code | 115 blank | 50 comment | 155 complexity | 82b242fe104cab7952b74c8ddbeb6207 MD5 | raw file
1// -*- coding:utf-8;Mode:C;tab-width:2;c-basic-offset:2;indent-tabs-mode:nil -*- 2// ex: set softtabstop=2 tabstop=2 shiftwidth=2 expandtab fileencoding=utf-8: 3// 4// Copyright (c) 2011 Yurii Rashkovskii, Evax Software and Michael Truog 5// 6// Permission is hereby granted, free of charge, to any person obtaining a copy 7// of this software and associated documentation files (the "Software"), to deal 8// in the Software without restriction, including without limitation the rights 9// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10// copies of the Software, and to permit persons to whom the Software is 11// furnished to do so, subject to the following conditions: 12// 13// The above copyright notice and this permission notice shall be included in 14// all copies or substantial portions of the Software. 15// 16// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22// THE SOFTWARE. 23 24#include "zmq.h" 25#include "erl_nif.h" 26#include "vector.h" 27#include <string.h> 28#include <stdio.h> 29#include <assert.h> 30 31#define ERLZMQ_MAX_CONCURRENT_REQUESTS 16384 32 33static ErlNifResourceType* erlzmq_nif_resource_context; 34static ErlNifResourceType* erlzmq_nif_resource_socket; 35 36typedef struct erlzmq_context { 37 void * context_zmq; 38 void * thread_socket; 39 char * thread_socket_name; 40 int64_t socket_index; 41 ErlNifTid polling_tid; 42 ErlNifMutex * mutex; 43} erlzmq_context_t; 44 45#define ERLZMQ_SOCKET_ACTIVE_OFF 0 46#define ERLZMQ_SOCKET_ACTIVE_PENDING 1 47#define ERLZMQ_SOCKET_ACTIVE_ON 2 48 49typedef struct erlzmq_socket { 50 erlzmq_context_t * context; 51 int64_t socket_index; 52 void * socket_zmq; 53 int active; 54 ErlNifMutex * mutex; 55} erlzmq_socket_t; 56 57#define ERLZMQ_THREAD_REQUEST_SEND 1 58#define ERLZMQ_THREAD_REQUEST_RECV 2 59#define ERLZMQ_THREAD_REQUEST_CLOSE 3 60#define ERLZMQ_THREAD_REQUEST_TERM 4 61 62typedef struct { 63 int type; 64 union { 65 struct { 66 erlzmq_socket_t * socket; 67 ErlNifEnv * env; 68 ERL_NIF_TERM ref; 69 int flags; 70 zmq_msg_t msg; 71 ErlNifPid pid; 72 } send; 73 struct { 74 erlzmq_socket_t * socket; 75 ErlNifEnv * env; 76 ERL_NIF_TERM ref; 77 int flags; 78 ErlNifPid pid; 79 } recv; 80 struct { 81 erlzmq_socket_t * socket; 82 ErlNifEnv * env; 83 ERL_NIF_TERM ref; 84 ErlNifPid pid; 85 } close; 86 struct { 87 ErlNifEnv * env; 88 ERL_NIF_TERM ref; 89 ErlNifPid pid; 90 } term; 91 } data; 92} erlzmq_thread_request_t; 93 94// Prototypes 95#define NIF(name) \ 96 ERL_NIF_TERM name(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) 97 98NIF(erlzmq_nif_context); 99NIF(erlzmq_nif_socket); 100NIF(erlzmq_nif_bind); 101NIF(erlzmq_nif_connect); 102NIF(erlzmq_nif_setsockopt); 103NIF(erlzmq_nif_getsockopt); 104NIF(erlzmq_nif_send); 105NIF(erlzmq_nif_recv); 106NIF(erlzmq_nif_close); 107NIF(erlzmq_nif_term); 108NIF(erlzmq_nif_version); 109 110static void * polling_thread(void * handle); 111static ERL_NIF_TERM add_active_req(ErlNifEnv* env, erlzmq_socket_t * socket); 112static ERL_NIF_TERM return_zmq_errno(ErlNifEnv* env, int const value); 113 114static ErlNifFunc nif_funcs[] = 115{ 116 {"context", 1, erlzmq_nif_context}, 117 {"socket", 3, erlzmq_nif_socket}, 118 {"bind", 2, erlzmq_nif_bind}, 119 {"connect", 2, erlzmq_nif_connect}, 120 {"setsockopt", 3, erlzmq_nif_setsockopt}, 121 {"getsockopt", 2, erlzmq_nif_getsockopt}, 122 {"send", 3, erlzmq_nif_send}, 123 {"recv", 2, erlzmq_nif_recv}, 124 {"close", 1, erlzmq_nif_close}, 125 {"term", 1, erlzmq_nif_term}, 126 {"version", 0, erlzmq_nif_version} 127}; 128 129NIF(erlzmq_nif_context) 130{ 131 int thread_count; 132 133 if (! enif_get_int(env, argv[0], &thread_count)) { 134 return enif_make_badarg(env); 135 } 136 137 erlzmq_context_t * context = enif_alloc_resource(erlzmq_nif_resource_context, 138 sizeof(erlzmq_context_t)); 139 assert(context); 140 context->context_zmq = zmq_init(thread_count); 141 if (!context->context_zmq) { 142 return return_zmq_errno(env, zmq_errno()); 143 } 144 145 char thread_socket_id[64]; 146 sprintf(thread_socket_id, "inproc://erlzmq-%ld", (long int) context); 147 context->thread_socket = zmq_socket(context->context_zmq, ZMQ_PUSH); 148 assert(context->thread_socket); 149 context->mutex = enif_mutex_create("erlzmq_context_t_mutex"); 150 assert(context->mutex); 151 if (zmq_bind(context->thread_socket, thread_socket_id)) { 152 zmq_close(context->thread_socket); 153 enif_mutex_destroy(context->mutex); 154 zmq_term(context->context_zmq); 155 enif_release_resource(context); 156 return return_zmq_errno(env, zmq_errno()); 157 } 158 context->thread_socket_name = strdup(thread_socket_id); 159 assert(context->thread_socket_name); 160 context->socket_index = 1; 161 162 int const value_errno = enif_thread_create("erlzmq_polling_thread", 163 &context->polling_tid, 164 polling_thread, context, NULL); 165 if (value_errno) { 166 free(context->thread_socket_name); 167 zmq_close(context->thread_socket); 168 zmq_term(context->context_zmq); 169 enif_release_resource(context); 170 return return_zmq_errno(env, value_errno); 171 } 172 173 return enif_make_tuple2(env, enif_make_atom(env, "ok"), 174 enif_make_resource(env, context)); 175} 176 177NIF(erlzmq_nif_socket) 178{ 179 erlzmq_context_t * context; 180 int socket_type; 181 int active; 182 183 if (! enif_get_resource(env, argv[0], erlzmq_nif_resource_context, 184 (void **) &context)) { 185 return enif_make_badarg(env); 186 } 187 188 if (! enif_get_int(env, argv[1], &socket_type)) { 189 return enif_make_badarg(env); 190 } 191 192 if (! enif_get_int(env, argv[2], &active)) { 193 return enif_make_badarg(env); 194 } 195 196 erlzmq_socket_t * socket = enif_alloc_resource(erlzmq_nif_resource_socket, 197 sizeof(erlzmq_socket_t)); 198 assert(socket); 199 socket->context = context; 200 socket->socket_index = context->socket_index++; 201 socket->socket_zmq = zmq_socket(context->context_zmq, socket_type); 202 if (!socket->socket_zmq) { 203 return return_zmq_errno(env, zmq_errno()); 204 } 205 socket->active = active; 206 socket->mutex = enif_mutex_create("erlzmq_socket_t_mutex"); 207 assert(socket->mutex); 208 209 return enif_make_tuple2(env, enif_make_atom(env, "ok"), enif_make_tuple2(env, 210 enif_make_uint64(env, socket->socket_index), 211 enif_make_resource(env, socket))); 212} 213 214NIF(erlzmq_nif_bind) 215{ 216 erlzmq_socket_t * socket; 217 unsigned endpoint_length; 218 219 if (! enif_get_resource(env, argv[0], erlzmq_nif_resource_socket, 220 (void **) &socket)) { 221 return enif_make_badarg(env); 222 } 223 224 if (! enif_get_list_length(env, argv[1], &endpoint_length)) { 225 return enif_make_badarg(env); 226 } 227 228 char * endpoint = (char *) malloc(endpoint_length + 1); 229 if (! enif_get_string(env, argv[1], endpoint, endpoint_length + 1, 230 ERL_NIF_LATIN1)) { 231 return enif_make_badarg(env); 232 } 233 234 enif_mutex_lock(socket->mutex); 235 if (zmq_bind(socket->socket_zmq, endpoint)) { 236 enif_mutex_unlock(socket->mutex); 237 free(endpoint); 238 return return_zmq_errno(env, zmq_errno()); 239 } 240 else { 241 enif_mutex_unlock(socket->mutex); 242 free(endpoint); 243 if (socket->active == ERLZMQ_SOCKET_ACTIVE_PENDING) { 244 return add_active_req(env, socket); 245 } 246 else { 247 return enif_make_atom(env, "ok"); 248 } 249 } 250} 251 252NIF(erlzmq_nif_connect) 253{ 254 erlzmq_socket_t * socket; 255 unsigned endpoint_length; 256 257 if (! enif_get_resource(env, argv[0], erlzmq_nif_resource_socket, 258 (void **) &socket)) { 259 return enif_make_badarg(env); 260 } 261 262 if (! enif_get_list_length(env, argv[1], &endpoint_length)) { 263 return enif_make_badarg(env); 264 } 265 266 char * endpoint = (char *) malloc(endpoint_length + 1); 267 if (! enif_get_string(env, argv[1], endpoint, endpoint_length + 1, 268 ERL_NIF_LATIN1)) { 269 return enif_make_badarg(env); 270 } 271 272 enif_mutex_lock(socket->mutex); 273 if (zmq_connect(socket->socket_zmq, endpoint)) { 274 enif_mutex_unlock(socket->mutex); 275 free(endpoint); 276 return return_zmq_errno(env, zmq_errno()); 277 } 278 else { 279 enif_mutex_unlock(socket->mutex); 280 free(endpoint); 281 if (socket->active == ERLZMQ_SOCKET_ACTIVE_PENDING) { 282 return add_active_req(env, socket); 283 } 284 else { 285 return enif_make_atom(env, "ok"); 286 } 287 } 288} 289 290NIF(erlzmq_nif_setsockopt) 291{ 292 erlzmq_socket_t * socket; 293 int option_name; 294 295 if (! enif_get_resource(env, argv[0], erlzmq_nif_resource_socket, 296 (void **) &socket)) { 297 return enif_make_badarg(env); 298 } 299 300 if (! enif_get_int(env, argv[1], &option_name)) { 301 return enif_make_badarg(env); 302 } 303 304 ErlNifUInt64 value_uint64; 305 ErlNifSInt64 value_int64; 306 ErlNifBinary value_binary; 307 int value_int; 308 void *option_value; 309 size_t option_len; 310 switch (option_name) { 311 // uint64_t 312 case ZMQ_HWM: 313 case ZMQ_AFFINITY: 314 case ZMQ_SNDBUF: 315 case ZMQ_RCVBUF: 316 if (! enif_get_uint64(env, argv[2], &value_uint64)) { 317 return enif_make_badarg(env); 318 } 319 option_value = &value_uint64; 320 option_len = sizeof(int64_t); 321 break; 322 // int64_t 323 case ZMQ_SWAP: 324 case ZMQ_RATE: 325 case ZMQ_RECOVERY_IVL: 326 case ZMQ_MCAST_LOOP: 327 if (! enif_get_int64(env, argv[2], &value_int64)) { 328 return enif_make_badarg(env); 329 } 330 option_value = &value_int64; 331 option_len = sizeof(int64_t); 332 break; 333 // binary 334 case ZMQ_IDENTITY: 335 case ZMQ_SUBSCRIBE: 336 case ZMQ_UNSUBSCRIBE: 337 if (! enif_inspect_iolist_as_binary(env, argv[2], &value_binary)) { 338 return enif_make_badarg(env); 339 } 340 option_value = value_binary.data; 341 option_len = value_binary.size; 342 break; 343 // int 344 case ZMQ_LINGER: 345 case ZMQ_RECONNECT_IVL: 346 case ZMQ_BACKLOG: 347 if (! enif_get_int(env, argv[2], &value_int)) { 348 return enif_make_badarg(env); 349 } 350 option_value = &value_int; 351 option_len = sizeof(int); 352 break; 353 default: 354 return enif_make_badarg(env); 355 } 356 357 enif_mutex_lock(socket->mutex); 358 if (zmq_setsockopt(socket->socket_zmq, option_name, 359 option_value, option_len)) { 360 enif_mutex_unlock(socket->mutex); 361 return return_zmq_errno(env, zmq_errno()); 362 } 363 else { 364 enif_mutex_unlock(socket->mutex); 365 return enif_make_atom(env, "ok"); 366 } 367} 368 369NIF(erlzmq_nif_getsockopt) 370{ 371 erlzmq_socket_t * socket; 372 int option_name; 373 374 if (! enif_get_resource(env, argv[0], erlzmq_nif_resource_socket, 375 (void **) &socket)) { 376 return enif_make_badarg(env); 377 } 378 379 if (! enif_get_int(env, argv[1], &option_name)) { 380 return enif_make_badarg(env); 381 } 382 383 ErlNifBinary value_binary; 384 int64_t value_int64; 385 int64_t value_uint64; 386 char option_value[256]; 387 int value_int; 388 size_t option_len; 389 switch(option_name) { 390 // int64_t 391 case ZMQ_RCVMORE: 392 case ZMQ_SWAP: 393 case ZMQ_RATE: 394 case ZMQ_RECOVERY_IVL: 395 case ZMQ_RECOVERY_IVL_MSEC: 396 case ZMQ_MCAST_LOOP: 397 option_len = sizeof(value_int64); 398 enif_mutex_lock(socket->mutex); 399 if (zmq_getsockopt(socket->socket_zmq, option_name, 400 &value_int64, &option_len)) { 401 enif_mutex_unlock(socket->mutex); 402 return return_zmq_errno(env, zmq_errno()); 403 } 404 enif_mutex_unlock(socket->mutex); 405 return enif_make_tuple2(env, enif_make_atom(env, "ok"), 406 enif_make_int64(env, value_int64)); 407 // uint64_t 408 case ZMQ_HWM: 409 case ZMQ_AFFINITY: 410 case ZMQ_SNDBUF: 411 case ZMQ_RCVBUF: 412 option_len = sizeof(value_uint64); 413 enif_mutex_lock(socket->mutex); 414 if (zmq_getsockopt(socket->socket_zmq, option_name, 415 &value_uint64, &option_len)) { 416 enif_mutex_unlock(socket->mutex); 417 return return_zmq_errno(env, zmq_errno()); 418 } 419 enif_mutex_unlock(socket->mutex); 420 return enif_make_tuple2(env, enif_make_atom(env, "ok"), 421 enif_make_uint64(env, value_uint64)); 422 // binary 423 case ZMQ_IDENTITY: 424 option_len = sizeof(option_value); 425 enif_mutex_lock(socket->mutex); 426 if (zmq_getsockopt(socket->socket_zmq, option_name, 427 option_value, &option_len)) { 428 enif_mutex_unlock(socket->mutex); 429 return return_zmq_errno(env, zmq_errno()); 430 } 431 enif_mutex_unlock(socket->mutex); 432 enif_alloc_binary(option_len, &value_binary); 433 memcpy(value_binary.data, option_value, option_len); 434 return enif_make_tuple2(env, enif_make_atom(env, "ok"), 435 enif_make_binary(env, &value_binary)); 436 // int 437 case ZMQ_TYPE: 438 case ZMQ_LINGER: 439 case ZMQ_RECONNECT_IVL: 440 case ZMQ_RECONNECT_IVL_MAX: 441 case ZMQ_BACKLOG: 442 case ZMQ_FD: // FIXME: ZMQ_FD returns SOCKET on Windows 443 option_len = sizeof(value_int); 444 enif_mutex_lock(socket->mutex); 445 if (zmq_getsockopt(socket->socket_zmq, option_name, 446 &value_int, &option_len)) { 447 enif_mutex_unlock(socket->mutex); 448 return return_zmq_errno(env, zmq_errno()); 449 } 450 enif_mutex_unlock(socket->mutex); 451 return enif_make_tuple2(env, enif_make_atom(env, "ok"), 452 enif_make_int(env, value_int)); 453 default: 454 return enif_make_badarg(env); 455 } 456} 457 458NIF(erlzmq_nif_send) 459{ 460 erlzmq_thread_request_t req; 461 erlzmq_socket_t * socket; 462 ErlNifBinary binary; 463 464 if (! enif_get_resource(env, argv[0], erlzmq_nif_resource_socket, 465 (void **) &socket)) { 466 return enif_make_badarg(env); 467 } 468 469 if (! enif_inspect_iolist_as_binary(env, argv[1], &binary)) { 470 return enif_make_badarg(env); 471 } 472 473 if (! enif_get_int(env, argv[2], &req.data.send.flags)) { 474 return enif_make_badarg(env); 475 } 476 477 if (zmq_msg_init_size(&req.data.send.msg, binary.size)) { 478 return return_zmq_errno(env, zmq_errno()); 479 } 480 481 memcpy(zmq_msg_data(&req.data.send.msg), binary.data, binary.size); 482 483 int polling_thread_send = 1; 484 if (! socket->active) { 485 enif_mutex_lock(socket->mutex); 486 if (zmq_send(socket->socket_zmq, &req.data.send.msg, 487 req.data.send.flags | ZMQ_NOBLOCK)) { 488 enif_mutex_unlock(socket->mutex); 489 int const error = zmq_errno(); 490 if (error != EAGAIN || 491 (error == EAGAIN && (req.data.send.flags & ZMQ_NOBLOCK))) { 492 zmq_msg_close(&req.data.send.msg); 493 return return_zmq_errno(env, error); 494 } 495 } 496 else { 497 enif_mutex_unlock(socket->mutex); 498 polling_thread_send = 0; 499 } 500 } 501 502 if (polling_thread_send) { 503 req.type = ERLZMQ_THREAD_REQUEST_SEND; 504 req.data.send.env = enif_alloc_env(); 505 req.data.send.ref = enif_make_ref(req.data.send.env); 506 enif_self(env, &req.data.send.pid); 507 req.data.send.socket = socket; 508 509 zmq_msg_t msg; 510 if (zmq_msg_init_size(&msg, sizeof(erlzmq_thread_request_t))) { 511 zmq_msg_close(&req.data.send.msg); 512 enif_free_env(req.data.send.env); 513 return return_zmq_errno(env, zmq_errno()); 514 } 515 516 memcpy(zmq_msg_data(&msg), &req, sizeof(erlzmq_thread_request_t)); 517 518 enif_mutex_lock(socket->context->mutex); 519 if (socket->context->thread_socket_name == NULL) { 520 enif_mutex_unlock(socket->context->mutex); 521 return return_zmq_errno(env, ETERM); 522 } 523 if (zmq_send(socket->context->thread_socket, &msg, 0)) { 524 enif_mutex_unlock(socket->context->mutex); 525 526 zmq_msg_close(&msg); 527 zmq_msg_close(&req.data.send.msg); 528 enif_free_env(req.data.send.env); 529 return return_zmq_errno(env, zmq_errno()); 530 } 531 else { 532 enif_mutex_unlock(socket->context->mutex); 533 534 zmq_msg_close(&msg); 535 // each pointer to the socket in a request increments the reference 536 enif_keep_resource(socket); 537 538 return enif_make_copy(env, req.data.send.ref); 539 } 540 } 541 else { 542 zmq_msg_close(&req.data.send.msg); 543 544 return enif_make_atom(env, "ok"); 545 } 546} 547 548NIF(erlzmq_nif_recv) 549{ 550 erlzmq_thread_request_t req; 551 erlzmq_socket_t * socket; 552 553 if (! enif_get_resource(env, argv[0], erlzmq_nif_resource_socket, 554 (void **) &socket)) { 555 return enif_make_badarg(env); 556 } 557 558 if (! enif_get_int(env, argv[1], &req.data.recv.flags)) { 559 return enif_make_badarg(env); 560 } 561 562 if (socket->active) { 563 return enif_make_tuple2(env, enif_make_atom(env, "error"), 564 enif_make_atom(env, "active")); 565 } 566 567 zmq_msg_t msg; 568 if (zmq_msg_init(&msg)) { 569 return return_zmq_errno(env, zmq_errno()); 570 } 571 572 // try recv with noblock 573 enif_mutex_lock(socket->mutex); 574 if (zmq_recv(socket->socket_zmq, &msg, ZMQ_NOBLOCK)) { 575 enif_mutex_unlock(socket->mutex); 576 zmq_msg_close(&msg); 577 578 int const error = zmq_errno(); 579 if (error != EAGAIN || 580 (error == EAGAIN && (req.data.recv.flags & ZMQ_NOBLOCK))) { 581 return return_zmq_errno(env, error); 582 } 583 req.type = ERLZMQ_THREAD_REQUEST_RECV; 584 req.data.recv.env = enif_alloc_env(); 585 req.data.recv.ref = enif_make_ref(req.data.recv.env); 586 enif_self(env, &req.data.recv.pid); 587 req.data.recv.socket = socket; 588 589 if (zmq_msg_init_size(&msg, sizeof(erlzmq_thread_request_t))) { 590 enif_free_env(req.data.recv.env); 591 return return_zmq_errno(env, zmq_errno()); 592 } 593 594 memcpy(zmq_msg_data(&msg), &req, sizeof(erlzmq_thread_request_t)); 595 596 enif_mutex_lock(socket->context->mutex); 597 if (socket->context->thread_socket_name == NULL) { 598 enif_mutex_unlock(socket->context->mutex); 599 return return_zmq_errno(env, ETERM); 600 } 601 if (zmq_send(socket->context->thread_socket, &msg, 0)) { 602 enif_mutex_unlock(socket->context->mutex); 603 604 zmq_msg_close(&msg); 605 enif_free_env(req.data.recv.env); 606 return return_zmq_errno(env, zmq_errno()); 607 } 608 else { 609 enif_mutex_unlock(socket->context->mutex); 610 611 zmq_msg_close(&msg); 612 // each pointer to the socket in a request increments the reference 613 enif_keep_resource(socket); 614 615 return enif_make_copy(env, req.data.recv.ref); 616 } 617 } 618 else { 619 enif_mutex_unlock(socket->mutex); 620 621 ErlNifBinary binary; 622 enif_alloc_binary(zmq_msg_size(&msg), &binary); 623 memcpy(binary.data, zmq_msg_data(&msg), zmq_msg_size(&msg)); 624 625 zmq_msg_close(&msg); 626 627 return enif_make_tuple2(env, enif_make_atom(env, "ok"), 628 enif_make_binary(env, &binary)); 629 } 630} 631 632NIF(erlzmq_nif_close) 633{ 634 erlzmq_socket_t * socket; 635 636 if (! enif_get_resource(env, argv[0], erlzmq_nif_resource_socket, 637 (void **) &socket)) { 638 return enif_make_badarg(env); 639 } 640 641 erlzmq_thread_request_t req; 642 req.type = ERLZMQ_THREAD_REQUEST_CLOSE; 643 req.data.close.env = enif_alloc_env(); 644 req.data.close.ref = enif_make_ref(req.data.close.env); 645 enif_self(env, &req.data.close.pid); 646 req.data.close.socket = socket; 647 648 zmq_msg_t msg; 649 if (zmq_msg_init_size(&msg, sizeof(erlzmq_thread_request_t))) { 650 enif_free_env(req.data.close.env); 651 return return_zmq_errno(env, zmq_errno()); 652 } 653 654 memcpy(zmq_msg_data(&msg), &req, sizeof(erlzmq_thread_request_t)); 655 656 enif_mutex_lock(socket->context->mutex); 657 if (socket->context->thread_socket_name == NULL) { 658 // context is gone 659 enif_mutex_lock(socket->mutex); 660 zmq_msg_close(&msg); 661 zmq_close(socket->socket_zmq); 662 enif_mutex_unlock(socket->mutex); 663 enif_mutex_destroy(socket->mutex); 664 enif_release_resource(socket); 665 enif_mutex_unlock(socket->context->mutex); 666 return enif_make_atom(env, "ok"); 667 } 668 if (zmq_send(socket->context->thread_socket, &msg, 0)) { 669 enif_mutex_unlock(socket->context->mutex); 670 zmq_msg_close(&msg); 671 enif_free_env(req.data.close.env); 672 return return_zmq_errno(env, zmq_errno()); 673 } 674 else { 675 enif_mutex_unlock(socket->context->mutex); 676 zmq_msg_close(&msg); 677 // each pointer to the socket in a request increments the reference 678 enif_keep_resource(socket); 679 return enif_make_copy(env, req.data.close.ref); 680 } 681} 682 683NIF(erlzmq_nif_term) 684{ 685 erlzmq_context_t * context; 686 687 if (!enif_get_resource(env, argv[0], erlzmq_nif_resource_context, 688 (void **) &context)) { 689 return enif_make_badarg(env); 690 } 691 692 erlzmq_thread_request_t req; 693 req.type = ERLZMQ_THREAD_REQUEST_TERM; 694 req.data.term.env = enif_alloc_env(); 695 req.data.term.ref = enif_make_ref(req.data.term.env); 696 enif_self(env, &req.data.term.pid); 697 698 zmq_msg_t msg; 699 if (zmq_msg_init_size(&msg, sizeof(erlzmq_thread_request_t))) { 700 enif_free_env(req.data.term.env); 701 return return_zmq_errno(env, zmq_errno()); 702 } 703 704 memcpy(zmq_msg_data(&msg), &req, sizeof(erlzmq_thread_request_t)); 705 706 enif_mutex_lock(context->mutex); 707 if (zmq_send(context->thread_socket, &msg, 0)) { 708 enif_mutex_unlock(context->mutex); 709 zmq_msg_close(&msg); 710 enif_free_env(req.data.term.env); 711 return return_zmq_errno(env, zmq_errno()); 712 } 713 else { 714 enif_mutex_unlock(context->mutex); 715 zmq_msg_close(&msg); 716 // thread has a reference to the context, decrement here 717 enif_release_resource(context); 718 return enif_make_copy(env, req.data.term.ref); 719 } 720} 721 722NIF(erlzmq_nif_version) 723{ 724 int major, minor, patch; 725 zmq_version(&major, &minor, &patch); 726 return enif_make_tuple3(env, enif_make_int(env, major), 727 enif_make_int(env, minor), 728 enif_make_int(env, patch)); 729} 730 731static void * polling_thread(void * handle) 732{ 733 erlzmq_context_t * context = (erlzmq_context_t *) handle; 734 enif_keep_resource(context); 735 736 void * thread_socket = zmq_socket(context->context_zmq, ZMQ_PULL); 737 assert(thread_socket); 738 int status = zmq_connect(thread_socket, context->thread_socket_name); 739 assert(status == 0); 740 741 vector_t items_zmq; 742 status = vector_initialize_pow2(zmq_pollitem_t, &items_zmq, 1, 743 ERLZMQ_MAX_CONCURRENT_REQUESTS); 744 assert(status == 0); 745 zmq_pollitem_t thread_socket_poll_zmq = {thread_socket, 0, ZMQ_POLLIN, 0}; 746 status = vector_append(zmq_pollitem_t, &items_zmq, &thread_socket_poll_zmq); 747 assert(status == 0); 748 749 vector_t requests; 750 status = vector_initialize_pow2(erlzmq_thread_request_t, &requests, 1, 751 ERLZMQ_MAX_CONCURRENT_REQUESTS); 752 assert(status == 0); 753 erlzmq_thread_request_t request_empty; 754 memset(&request_empty, 0, sizeof(erlzmq_thread_request_t)); 755 status = vector_append(erlzmq_thread_request_t, &requests, &request_empty); 756 assert(status == 0); 757 758 int i; 759 for (;;) { 760 int count = zmq_poll(vector_p(zmq_pollitem_t, &items_zmq), 761 vector_count(&items_zmq), -1); 762 assert(count != -1); 763 if (vector_get(zmq_pollitem_t, &items_zmq, 0)->revents & ZMQ_POLLIN) { 764 --count; 765 } 766 for (i = 1; i < vector_count(&items_zmq); ++i) { 767 zmq_pollitem_t * item = vector_get(zmq_pollitem_t, &items_zmq, i); 768 erlzmq_thread_request_t * r = vector_get(erlzmq_thread_request_t, 769 &requests, i); 770 if (item->revents & ZMQ_POLLIN) { 771 size_t value_len = sizeof(int64_t); 772 int64_t flag_value = 0; 773 774 assert(r->type == ERLZMQ_THREAD_REQUEST_RECV); 775 --count; 776 777 zmq_msg_t msg; 778 zmq_msg_init(&msg); 779 enif_mutex_lock(r->data.recv.socket->mutex); 780 if (zmq_recv(r->data.recv.socket->socket_zmq, &msg, 781 r->data.recv.flags) || 782 (r->data.recv.socket->active == ERLZMQ_SOCKET_ACTIVE_ON && 783 zmq_getsockopt(r->data.recv.socket->socket_zmq, 784 ZMQ_RCVMORE, &flag_value, &value_len)) ) 785 { 786 enif_mutex_unlock(r->data.recv.socket->mutex); 787 if (r->data.recv.socket->active == ERLZMQ_SOCKET_ACTIVE_ON) { 788 enif_send(NULL, &r->data.recv.pid, r->data.recv.env, 789 enif_make_tuple3(r->data.recv.env, 790 enif_make_atom(r->data.recv.env, "zmq"), 791 enif_make_tuple2(r->data.recv.env, 792 enif_make_uint64(r->data.recv.env, 793 r->data.recv.socket->socket_index), 794 enif_make_resource(r->data.recv.env, r->data.recv.socket)), 795 return_zmq_errno(r->data.recv.env, zmq_errno()))); 796 enif_free_env(r->data.recv.env); 797 r->data.recv.env = enif_alloc_env(); 798 item->revents = 0; 799 } 800 else { 801 assert(0); 802 } 803 } 804 else { 805 enif_mutex_unlock(r->data.recv.socket->mutex); 806 } 807 808 ErlNifBinary binary; 809 enif_alloc_binary(zmq_msg_size(&msg), &binary); 810 memcpy(binary.data, zmq_msg_data(&msg), zmq_msg_size(&msg)); 811 zmq_msg_close(&msg); 812 813 if (r->data.recv.socket->active == ERLZMQ_SOCKET_ACTIVE_ON) { 814 ERL_NIF_TERM flags_list; 815 816 // Should we send the multipart flag 817 if(flag_value == 1) { 818 flags_list = enif_make_list1(r->data.recv.env, enif_make_atom(r->data.recv.env, "rcvmore")); 819 } else { 820 flags_list = enif_make_list(r->data.recv.env, 0); 821 } 822 823 enif_send(NULL, &r->data.recv.pid, r->data.recv.env, 824 enif_make_tuple4(r->data.recv.env, 825 enif_make_atom(r->data.recv.env, "zmq"), 826 enif_make_tuple2(r->data.recv.env, 827 enif_make_uint64(r->data.recv.env, 828 r->data.recv.socket->socket_index), 829 enif_make_resource(r->data.recv.env, r->data.recv.socket)), 830 enif_make_binary(r->data.recv.env, &binary), 831 flags_list)); 832 enif_free_env(r->data.recv.env); 833 r->data.recv.env = enif_alloc_env(); 834 item->revents = 0; 835 } 836 else { 837 enif_send(NULL, &r->data.recv.pid, r->data.recv.env, 838 enif_make_tuple2(r->data.recv.env, 839 enif_make_copy(r->data.recv.env, r->data.recv.ref), 840 enif_make_binary(r->data.recv.env, &binary))); 841 842 enif_free_env(r->data.recv.env); 843 enif_release_resource(r->data.recv.socket); 844 845 status = vector_remove(&items_zmq, i); 846 assert(status == 0); 847 status = vector_remove(&requests, i); 848 assert(status == 0); 849 --i; 850 } 851 } 852 else if (item->revents & ZMQ_POLLOUT) { 853 assert(r->type == ERLZMQ_THREAD_REQUEST_SEND); 854 --count; 855 856 enif_mutex_lock(r->data.send.socket->mutex); 857 if (zmq_send(r->data.send.socket->socket_zmq, 858 &r->data.send.msg, r->data.send.flags)) { 859 enif_mutex_unlock(r->data.send.socket->mutex); 860 enif_send(NULL, &r->data.send.pid, r->data.send.env, 861 enif_make_tuple2(r->data.send.env, 862 enif_make_copy(r->data.send.env, r->data.send.ref), 863 return_zmq_errno(r->data.send.env, zmq_errno()))); 864 } else { 865 enif_mutex_unlock(r->data.send.socket->mutex); 866 enif_send(NULL, &r->data.send.pid, r->data.send.env, 867 enif_make_tuple2(r->data.send.env, 868 enif_make_copy(r->data.send.env, r->data.send.ref), 869 enif_make_atom(r->data.send.env, "ok"))); 870 } 871 zmq_msg_close(&r->data.send.msg); 872 enif_free_env(r->data.send.env); 873 enif_release_resource(r->data.send.socket); 874 875 status = vector_remove(&items_zmq, i); 876 assert(status == 0); 877 status = vector_remove(&requests, i); 878 assert(status == 0); 879 --i; 880 } 881 } 882 883 if (vector_get(zmq_pollitem_t, &items_zmq, 0)->revents & ZMQ_POLLIN) { 884 vector_get(zmq_pollitem_t, &items_zmq, 0)->revents = 0; 885 zmq_msg_t msg; 886 zmq_msg_init(&msg); 887 enif_mutex_lock(context->mutex); 888 status = zmq_recv(thread_socket, &msg, 0); 889 enif_mutex_unlock(context->mutex); 890 assert(status == 0); 891 892 assert(zmq_msg_size(&msg) == sizeof(erlzmq_thread_request_t)); 893 894 erlzmq_thread_request_t * r = 895 (erlzmq_thread_request_t *) zmq_msg_data(&msg); 896 if (r->type == ERLZMQ_THREAD_REQUEST_SEND) { 897 zmq_pollitem_t item_zmq = {r->data.send.socket->socket_zmq, 898 0, ZMQ_POLLOUT, 0}; 899 status = vector_append(zmq_pollitem_t, &items_zmq, &item_zmq); 900 assert(status == 0); 901 status = vector_append(erlzmq_thread_request_t, &requests, r); 902 assert(status == 0); 903 zmq_msg_close(&msg); 904 } 905 else if (r->type == ERLZMQ_THREAD_REQUEST_RECV) { 906 zmq_pollitem_t item_zmq = {r->data.recv.socket->socket_zmq, 907 0, ZMQ_POLLIN, 0}; 908 status = vector_append(zmq_pollitem_t, &items_zmq, &item_zmq); 909 assert(status == 0); 910 status = vector_append(erlzmq_thread_request_t, &requests, r); 911 assert(status == 0); 912 zmq_msg_close(&msg); 913 } 914 else if (r->type == ERLZMQ_THREAD_REQUEST_CLOSE) { 915 // remove all entries with this socket 916 for (i = vector_count(&items_zmq) - 1; i > 0; --i) { 917 zmq_pollitem_t * item = vector_get(zmq_pollitem_t, &items_zmq, i); 918 if (item->socket == r->data.close.socket->socket_zmq) { 919 erlzmq_thread_request_t * r_old = 920 vector_get(erlzmq_thread_request_t, &requests, i); 921 if (r_old->type == ERLZMQ_THREAD_REQUEST_RECV) { 922 enif_clear_env(r_old->data.recv.env); 923 // FIXME 924 // causes crash on R14B01, works fine on R14B02 925 // (repeated enif_send with active receive broken on R14B01) 926 //enif_free_env(r_old->data.recv.env); 927 enif_release_resource(r_old->data.recv.socket); 928 } 929 else if (r_old->type == ERLZMQ_THREAD_REQUEST_SEND) { 930 zmq_msg_close(&(r_old->data.send.msg)); 931 enif_free_env(r_old->data.send.env); 932 enif_release_resource(r_old->data.send.socket); 933 } 934 else { 935 assert(0); 936 } 937 status = vector_remove(&items_zmq, i); 938 assert(status == 0); 939 status = vector_remove(&requests, i); 940 assert(status == 0); 941 } 942 } 943 // close the socket 944 enif_mutex_lock(r->data.close.socket->mutex); 945 zmq_close(r->data.close.socket->socket_zmq); 946 enif_mutex_unlock(r->data.close.socket->mutex); 947 enif_mutex_destroy(r->data.close.socket->mutex); 948 enif_release_resource(r->data.close.socket); 949 // notify the waiting request 950 enif_send(NULL, &r->data.close.pid, r->data.close.env, 951 enif_make_tuple2(r->data.close.env, 952 enif_make_copy(r->data.close.env, r->data.close.ref), 953 enif_make_atom(r->data.close.env, "ok"))); 954 enif_free_env(r->data.close.env); 955 zmq_msg_close(&msg); 956 } 957 else if (r->type == ERLZMQ_THREAD_REQUEST_TERM) { 958 enif_mutex_lock(context->mutex); 959 free(context->thread_socket_name); 960 // use this to flag context is over 961 context->thread_socket_name = NULL; 962 enif_mutex_unlock(context->mutex); 963 // cleanup pending requests 964 for (i = 1; i < vector_count(&requests); ++i) { 965 erlzmq_thread_request_t * r_old = vector_get(erlzmq_thread_request_t, 966 &requests, i); 967 if (r_old->type == ERLZMQ_THREAD_REQUEST_RECV) { 968 enif_free_env(r_old->data.recv.env); 969 enif_release_resource(r_old->data.recv.socket); 970 zmq_close(r_old->data.recv.socket->socket_zmq); 971 } 972 else if (r_old->type == ERLZMQ_THREAD_REQUEST_SEND) { 973 zmq_msg_close(&r_old->data.send.msg); 974 enif_free_env(r_old->data.send.env); 975 enif_release_resource(r_old->data.send.socket); 976 zmq_close(r_old->data.send.socket->socket_zmq); 977 } 978 } 979 // terminate the context 980 enif_mutex_lock(context->mutex); 981 zmq_close(thread_socket); 982 zmq_close(context->thread_socket); 983 enif_mutex_unlock(context->mutex); 984 zmq_term(context->context_zmq); 985 enif_mutex_lock(context->mutex); 986 enif_mutex_unlock(context->mutex); 987 enif_mutex_destroy(context->mutex); 988 enif_release_resource(context); 989 // notify the waiting request 990 enif_send(NULL, &r->data.term.pid, r->data.term.env, 991 enif_make_tuple2(r->data.term.env, 992 enif_make_copy(r->data.term.env, r->data.term.ref), 993 enif_make_atom(r->data.term.env, "ok"))); 994 enif_free_env(r->data.term.env); 995 zmq_msg_close(&msg); 996 vector_destroy(&items_zmq); 997 vector_destroy(&requests); 998 return NULL; 999 } 1000 else { 1001 assert(0); 1002 } 1003 } 1004 } 1005 return NULL; 1006} 1007 1008static ERL_NIF_TERM add_active_req(ErlNifEnv* env, erlzmq_socket_t * socket) 1009{ 1010 socket->active = ERLZMQ_SOCKET_ACTIVE_ON; 1011 1012 erlzmq_thread_request_t req; 1013 req.type = ERLZMQ_THREAD_REQUEST_RECV; 1014 req.data.recv.env = enif_alloc_env(); 1015 req.data.recv.flags = 0; 1016 enif_self(env, &req.data.recv.pid); 1017 req.data.recv.socket = socket; 1018 1019 zmq_msg_t msg; 1020 if (zmq_msg_init_size(&msg, sizeof(erlzmq_thread_request_t))) { 1021 enif_free_env(req.data.recv.env); 1022 return return_zmq_errno(env, zmq_errno()); 1023 } 1024 1025 memcpy(zmq_msg_data(&msg), &req, sizeof(erlzmq_thread_request_t)); 1026 1027 if (zmq_send(socket->context->thread_socket, &msg, 0)) { 1028 zmq_msg_close(&msg); 1029 enif_free_env(req.data.recv.env); 1030 return return_zmq_errno(env, zmq_errno()); 1031 } 1032 else { 1033 zmq_msg_close(&msg); 1034 // each pointer to the socket in a request increments the reference 1035 enif_keep_resource(socket); 1036 return enif_make_atom(env, "ok"); 1037 } 1038} 1039 1040static ERL_NIF_TERM return_zmq_errno(ErlNifEnv* env, int const value) 1041{ 1042 switch (value) { 1043 case EPERM: 1044 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1045 enif_make_atom(env, "eperm")); 1046 case ENOENT: 1047 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1048 enif_make_atom(env, "enoent")); 1049 case ESRCH: 1050 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1051 enif_make_atom(env, "esrch")); 1052 case EINTR: 1053 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1054 enif_make_atom(env, "eintr")); 1055 case EIO: 1056 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1057 enif_make_atom(env, "eio")); 1058 case ENXIO: 1059 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1060 enif_make_atom(env, "enxio")); 1061 case ENOEXEC: 1062 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1063 enif_make_atom(env, "enoexec")); 1064 case EBADF: 1065 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1066 enif_make_atom(env, "ebadf")); 1067 case ECHILD: 1068 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1069 enif_make_atom(env, "echild")); 1070 case EDEADLK: 1071 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1072 enif_make_atom(env, "edeadlk")); 1073 case ENOMEM: 1074 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1075 enif_make_atom(env, "enomem")); 1076 case EACCES: 1077 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1078 enif_make_atom(env, "eacces")); 1079 case EFAULT: 1080 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1081 enif_make_atom(env, "efault")); 1082 case ENOTBLK: 1083 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1084 enif_make_atom(env, "enotblk")); 1085 case EBUSY: 1086 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1087 enif_make_atom(env, "ebusy")); 1088 case EEXIST: 1089 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1090 enif_make_atom(env, "eexist")); 1091 case EXDEV: 1092 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1093 enif_make_atom(env, "exdev")); 1094 case ENODEV: 1095 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1096 enif_make_atom(env, "enodev")); 1097 case ENOTDIR: 1098 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1099 enif_make_atom(env, "enotdir")); 1100 case EISDIR: 1101 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1102 enif_make_atom(env, "eisdir")); 1103 case EINVAL: 1104 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1105 enif_make_atom(env, "einval")); 1106 case ENFILE: 1107 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1108 enif_make_atom(env, "enfile")); 1109 case EMFILE: 1110 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1111 enif_make_atom(env, "emfile")); 1112 case ETXTBSY: 1113 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1114 enif_make_atom(env, "etxtbsy")); 1115 case EFBIG: 1116 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1117 enif_make_atom(env, "efbig")); 1118 case ENOSPC: 1119 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1120 enif_make_atom(env, "enospc")); 1121 case ESPIPE: 1122 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1123 enif_make_atom(env, "espipe")); 1124 case EROFS: 1125 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1126 enif_make_atom(env, "erofs")); 1127 case EMLINK: 1128 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1129 enif_make_atom(env, "emlink")); 1130 case EPIPE: 1131 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1132 enif_make_atom(env, "epipe")); 1133 case EAGAIN: 1134 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1135 enif_make_atom(env, "eagain")); 1136 case EINPROGRESS: 1137 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1138 enif_make_atom(env, "einprogress")); 1139 case EALREADY: 1140 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1141 enif_make_atom(env, "ealready")); 1142 case ENOTSOCK: 1143 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1144 enif_make_atom(env, "enotsock")); 1145 case EDESTADDRREQ: 1146 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1147 enif_make_atom(env, "edestaddrreq")); 1148 case EMSGSIZE: 1149 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1150 enif_make_atom(env, "emsgsize")); 1151 case EPROTOTYPE: 1152 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1153 enif_make_atom(env, "eprototype")); 1154 case ENOPROTOOPT: 1155 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1156 enif_make_atom(env, "eprotoopt")); 1157 case EPROTONOSUPPORT: 1158 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1159 enif_make_atom(env, "eprotonosupport")); 1160 case ESOCKTNOSUPPORT: 1161 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1162 enif_make_atom(env, "esocktnosupport")); 1163 case ENOTSUP: 1164 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1165 enif_make_atom(env, "enotsup")); 1166 case EPFNOSUPPORT: 1167 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1168 enif_make_atom(env, "epfnosupport")); 1169 case EAFNOSUPPORT: 1170 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1171 enif_make_atom(env, "eafnosupport")); 1172 case EADDRINUSE: 1173 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1174 enif_make_atom(env, "eaddrinuse")); 1175 case EADDRNOTAVAIL: 1176 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1177 enif_make_atom(env, "eaddrnotavail")); 1178 case ENETDOWN: 1179 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1180 enif_make_atom(env, "enetdown")); 1181 case ENETUNREACH: 1182 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1183 enif_make_atom(env, "enetunreach")); 1184 case ENETRESET: 1185 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1186 enif_make_atom(env, "enetreset")); 1187 case ECONNABORTED: 1188 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1189 enif_make_atom(env, "econnaborted")); 1190 case ECONNRESET: 1191 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1192 enif_make_atom(env, "econnreset")); 1193 case ENOBUFS: 1194 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1195 enif_make_atom(env, "enobufs")); 1196 case EISCONN: 1197 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1198 enif_make_atom(env, "eisconn")); 1199 case ENOTCONN: 1200 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1201 enif_make_atom(env, "enotconn")); 1202 case ESHUTDOWN: 1203 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1204 enif_make_atom(env, "eshutdown")); 1205 case ETOOMANYREFS: 1206 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1207 enif_make_atom(env, "etoomanyrefs")); 1208 case ETIMEDOUT: 1209 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1210 enif_make_atom(env, "etimedout")); 1211 case ECONNREFUSED: 1212 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1213 enif_make_atom(env, "econnrefused")); 1214 case ELOOP: 1215 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1216 enif_make_atom(env, "eloop")); 1217 case ENAMETOOLONG: 1218 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1219 enif_make_atom(env, "enametoolong")); 1220 case (ZMQ_HAUSNUMERO + 1): 1221 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1222 enif_make_atom(env, "enotsup")); 1223 case (ZMQ_HAUSNUMERO + 2): 1224 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1225 enif_make_atom(env, "eprotonosupport")); 1226 case (ZMQ_HAUSNUMERO + 3): 1227 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1228 enif_make_atom(env, "enobufs")); 1229 case (ZMQ_HAUSNUMERO + 4): 1230 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1231 enif_make_atom(env, "enetdown")); 1232 case (ZMQ_HAUSNUMERO + 5): 1233 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1234 enif_make_atom(env, "eaddrinuse")); 1235 case (ZMQ_HAUSNUMERO + 6): 1236 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1237 enif_make_atom(env, "eaddrnotavail")); 1238 case (ZMQ_HAUSNUMERO + 7): 1239 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1240 enif_make_atom(env, "econnrefused")); 1241 case (ZMQ_HAUSNUMERO + 8): 1242 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1243 enif_make_atom(env, "einprogress")); 1244 case (ZMQ_HAUSNUMERO + 51): 1245 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1246 enif_make_atom(env, "efsm")); 1247 case (ZMQ_HAUSNUMERO + 52): 1248 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1249 enif_make_atom(env, "enocompatproto")); 1250 case (ZMQ_HAUSNUMERO + 53): 1251 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1252 enif_make_atom(env, "eterm")); 1253 case (ZMQ_HAUSNUMERO + 54): 1254 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1255 enif_make_atom(env, "emthread")); 1256 default: 1257 return enif_make_tuple2(env, enif_make_atom(env, "error"), 1258 enif_make_int(env, value)); 1259 } 1260} 1261 1262static int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) 1263{ 1264 erlzmq_nif_resource_context = 1265 enif_open_resource_type(env, "erlzmq_nif", 1266 "erlzmq_nif_resource_context", 1267 NULL, 1268 ERL_NIF_RT_CREATE | ERL_NIF_RT_TAKEOVER, 1269 0); 1270 erlzmq_nif_resource_socket = 1271 enif_open_resource_type(env, "erlzmq_nif", 1272 "erlzmq_nif_resource_socket", 1273 NULL, 1274 ERL_NIF_RT_CREATE | ERL_NIF_RT_TAKEOVER, 1275 0); 1276 return 0; 1277} 1278 1279static void on_unload(ErlNifEnv* env, void* priv_data) { 1280} 1281 1282ERL_NIF_INIT(erlzmq_nif, nif_funcs, &on_load, NULL, NULL, &on_unload); 1283