int pn_messenger_subscribe(pn_messenger_t *messenger, const char *source) { int len = strlen(source); if (len >= 3 && source[0] == '/' && source[1] == '/' && source[2] == '~') { pn_listener_t *lnr = pn_messenger_isource(messenger, source); if (lnr) { return 0; } else { return pn_error_format(messenger->error, PN_ERR, "unable to subscribe to source: %s (%s)", source, pn_driver_error(messenger->driver)); } } else if (len >= 2 && source[0] == '/' && source[1] == '/') { pn_link_t *src = pn_messenger_source(messenger, source); if (src) { return 0; } else { return pn_error_format(messenger->error, PN_ERR, "unable to subscribe to source: %s (%s)", source, pn_driver_error(messenger->driver)); } } else { return 0; } }
static uint8_t pn_type2code(pn_encoder_t *encoder, pn_type_t type) { switch (type) { case PN_NULL: return PNE_NULL; case PN_BOOL: return PNE_BOOLEAN; case PN_UBYTE: return PNE_UBYTE; case PN_BYTE: return PNE_BYTE; case PN_USHORT: return PNE_USHORT; case PN_SHORT: return PNE_SHORT; case PN_UINT: return PNE_UINT; case PN_INT: return PNE_INT; case PN_CHAR: return PNE_UTF32; case PN_FLOAT: return PNE_FLOAT; case PN_LONG: return PNE_LONG; case PN_TIMESTAMP: return PNE_MS64; case PN_DOUBLE: return PNE_DOUBLE; case PN_DECIMAL32: return PNE_DECIMAL32; case PN_DECIMAL64: return PNE_DECIMAL64; case PN_DECIMAL128: return PNE_DECIMAL128; case PN_UUID: return PNE_UUID; case PN_ULONG: return PNE_ULONG; case PN_BINARY: return PNE_VBIN32; case PN_STRING: return PNE_STR32_UTF8; case PN_SYMBOL: return PNE_SYM32; case PN_LIST: return PNE_LIST32; case PN_ARRAY: return PNE_ARRAY32; case PN_MAP: return PNE_MAP32; case PN_DESCRIBED: return PNE_DESCRIPTOR; default: return pn_error_format(encoder->error, PN_ERR, "not a value type: %u\n", type); } }
pn_socket_t pn_connect(pn_io_t *io, const char *host, const char *port) { struct addrinfo *addr; int code = getaddrinfo(host, port, NULL, &addr); if (code) { pn_error_format(io->error, PN_ERR, "getaddrinfo(%s, %s): %s", host, port, gai_strerror(code)); return PN_INVALID_SOCKET; } pn_socket_t sock = pn_create_socket(addr->ai_family); if (sock == PN_INVALID_SOCKET) { pn_i_error_from_errno(io->error, "pn_create_socket"); return PN_INVALID_SOCKET; } pn_configure_sock(io, sock); if (connect(sock, addr->ai_addr, addr->ai_addrlen) == -1) { if (errno != EINPROGRESS) { pn_i_error_from_errno(io->error, "connect"); freeaddrinfo(addr); close(sock); return PN_INVALID_SOCKET; } } freeaddrinfo(addr); return sock; }
int pni_win32_error(pn_error_t *error, const char *msg, HRESULT code) { // Error code can be from GetLastError or WSAGetLastError, char err[1024] = {0}; FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, code, 0, (LPSTR)&err, sizeof(err), NULL); return pn_error_format(error, PN_ERR, "%s: %s", msg, err); }
int pn_i_error_from_errno(pn_error_t *error, const char *msg) { char err[1024]; pn_i_strerror(errno, err, 1024); int code = PN_ERR; if (errno == EINTR) code = PN_INTR; return pn_error_format(error, code, "%s: %s", msg, err); }
int pn_messenger_recv(pn_messenger_t *messenger, int n) { if (!messenger) return PN_ARG_ERR; if (!messenger->listeners && !messenger->size) return pn_error_format(messenger->error, PN_STATE_ERR, "no valid sources"); messenger->credit += n; pn_messenger_flow(messenger); return pn_messenger_sync(messenger, pn_messenger_rcvd); }
pn_socket_t pn_listen(pn_io_t *io, const char *host, const char *port) { struct addrinfo *addr; int code = getaddrinfo(host, amqp_service(port), NULL, &addr); if (code) { pn_error_format(io->error, PN_ERR, "getaddrinfo(%s, %s): %s\n", host, port, gai_strerror(code)); return INVALID_SOCKET; } pn_socket_t sock = pni_create_socket(addr->ai_family); if (sock == INVALID_SOCKET) { pni_win32_error(io->error, "pni_create_socket", WSAGetLastError()); return INVALID_SOCKET; } ensure_unique(io, sock); bool optval = 1; if (setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char *) &optval, sizeof(optval)) == -1) { pni_win32_error(io->error, "setsockopt", WSAGetLastError()); closesocket(sock); return INVALID_SOCKET; } if (bind(sock, addr->ai_addr, addr->ai_addrlen) == -1) { pni_win32_error(io->error, "bind", WSAGetLastError()); freeaddrinfo(addr); closesocket(sock); return INVALID_SOCKET; } freeaddrinfo(addr); if (listen(sock, 50) == -1) { pni_win32_error(io->error, "listen", WSAGetLastError()); closesocket(sock); return INVALID_SOCKET; } if (io->iocp->selector) { iocpdesc_t *iocpd = pni_iocpdesc_create(io->iocp, sock, false); if (!iocpd) { pn_i_error_from_errno(io->error, "register"); closesocket(sock); return INVALID_SOCKET; } pni_iocpdesc_start(iocpd); } return sock; }
// unrecoverable SSL failure occured, notify transport and generate error code. static int ssl_failed(pn_ssl_t *ssl) { SSL_set_shutdown(ssl->ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); ssl->ssl_closed = true; ssl->app_input_closed = ssl->app_output_closed = PN_ERR; // fake a shutdown so the i/o processing code will close properly SSL_set_shutdown(ssl->ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); // try to grab the first SSL error to add to the failure log char buf[128] = "Unknown error."; unsigned long ssl_err = ERR_get_error(); if (ssl_err) { ERR_error_string_n( ssl_err, buf, sizeof(buf) ); } _log_ssl_error(NULL); // spit out any remaining errors to the log file return pn_error_format( ssl->transport->error, PN_ERR, "SSL Failure: %s", buf ); }
int pn_messenger_put(pn_messenger_t *messenger, pn_message_t *msg) { if (!messenger) return PN_ARG_ERR; if (!msg) return pn_error_set(messenger->error, PN_ARG_ERR, "null message"); outward_munge(messenger, msg); const char *address = pn_message_get_address(msg); pn_link_t *sender = pn_messenger_target(messenger, address); if (!sender) return pn_error_format(messenger->error, PN_ERR, "unable to send to address: %s (%s)", address, pn_driver_error(messenger->driver)); // XXX: proper tag char tag[8]; void *ptr = &tag; uint64_t next = messenger->next_tag++; *((uint32_t *) ptr) = next; pn_delivery(sender, pn_dtag(tag, 8)); size_t size = 1024; // XXX: max message size while (size < 16*1024) { char encoded[size]; int err = pn_message_encode(msg, encoded, &size); if (err == PN_OVERFLOW) { size *= 2; } else if (err) { return err; } else { ssize_t n = pn_send(sender, encoded, size); if (n < 0) { return n; } else { pn_advance(sender); pn_messenger_tsync(messenger, false_pred, 0); return 0; } } } return PN_ERR; }
pn_socket_t pn_listen(pn_io_t *io, const char *host, const char *port) { struct addrinfo *addr; int code = getaddrinfo(host, port, NULL, &addr); if (code) { pn_error_format(io->error, PN_ERR, "getaddrinfo(%s, %s): %s\n", host, port, gai_strerror(code)); return PN_INVALID_SOCKET; } pn_socket_t sock = pn_create_socket(addr->ai_family); if (sock == PN_INVALID_SOCKET) { pn_i_error_from_errno(io->error, "pn_create_socket"); return PN_INVALID_SOCKET; } int optval = 1; if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == -1) { pn_i_error_from_errno(io->error, "setsockopt"); close(sock); return PN_INVALID_SOCKET; } if (bind(sock, addr->ai_addr, addr->ai_addrlen) == -1) { pn_i_error_from_errno(io->error, "bind"); freeaddrinfo(addr); close(sock); return PN_INVALID_SOCKET; } freeaddrinfo(addr); if (listen(sock, 50) == -1) { pn_i_error_from_errno(io->error, "listen"); close(sock); return PN_INVALID_SOCKET; } return sock; }
pn_socket_t pn_accept(pn_io_t *io, pn_socket_t listen_sock, char *name, size_t size) { struct sockaddr_in addr = {0}; addr.sin_family = AF_INET; socklen_t addrlen = sizeof(addr); iocpdesc_t *listend = pni_iocpdesc_map_get(io->iocp, listen_sock); pn_socket_t accept_sock; if (listend) accept_sock = pni_iocp_end_accept(listend, (struct sockaddr *) &addr, &addrlen, &io->wouldblock, io->error); else { // User supplied socket accept_sock = accept(listen_sock, (struct sockaddr *) &addr, &addrlen); if (accept_sock == INVALID_SOCKET) pni_win32_error(io->error, "sync accept", WSAGetLastError()); } if (accept_sock == INVALID_SOCKET) return accept_sock; int code = getnameinfo((struct sockaddr *) &addr, addrlen, io->host, NI_MAXHOST, io->serv, NI_MAXSERV, 0); if (code) code = getnameinfo((struct sockaddr *) &addr, addrlen, io->host, NI_MAXHOST, io->serv, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV); if (code) { pn_error_format(io->error, PN_ERR, "getnameinfo: %s\n", gai_strerror(code)); pn_close(io, accept_sock); return INVALID_SOCKET; } else { pn_configure_sock(io, accept_sock); snprintf(name, size, "%s:%s", io->host, io->serv); if (listend) { pni_iocpdesc_start(pni_iocpdesc_map_get(io->iocp, accept_sock)); } return accept_sock; } }
pn_socket_t pn_connect(pn_io_t *io, const char *hostarg, const char *port) { // convert "0.0.0.0" to "127.0.0.1" on Windows for outgoing sockets const char *host = strcmp("0.0.0.0", hostarg) ? hostarg : "127.0.0.1"; struct addrinfo *addr; int code = getaddrinfo(host, amqp_service(port), NULL, &addr); if (code) { pn_error_format(io->error, PN_ERR, "getaddrinfo(%s, %s): %s", host, port, gai_strerror(code)); return INVALID_SOCKET; } pn_socket_t sock = pni_create_socket(addr->ai_family); if (sock == INVALID_SOCKET) { pni_win32_error(io->error, "proton pni_create_socket", WSAGetLastError()); freeaddrinfo(addr); return INVALID_SOCKET; } ensure_unique(io, sock); pn_configure_sock(io, sock); if (io->iocp->selector) { return pni_iocp_begin_connect(io->iocp, sock, addr, io->error); } else { if (connect(sock, addr->ai_addr, addr->ai_addrlen) != 0) { if (WSAGetLastError() != WSAEWOULDBLOCK) { pni_win32_error(io->error, "connect", WSAGetLastError()); freeaddrinfo(addr); closesocket(sock); return INVALID_SOCKET; } } freeaddrinfo(addr); return sock; } }
pn_socket_t pn_accept(pn_io_t *io, pn_socket_t socket, char *name, size_t size) { struct sockaddr_in addr = {0}; addr.sin_family = AF_UNSPEC; socklen_t addrlen = sizeof(addr); pn_socket_t sock = accept(socket, (struct sockaddr *) &addr, &addrlen); if (sock == PN_INVALID_SOCKET) { pn_i_error_from_errno(io->error, "accept"); return sock; } else { int code; if ((code = getnameinfo((struct sockaddr *) &addr, addrlen, io->host, MAX_HOST, io->serv, MAX_SERV, 0))) { pn_error_format(io->error, PN_ERR, "getnameinfo: %s\n", gai_strerror(code)); if (close(sock) == -1) pn_i_error_from_errno(io->error, "close"); return PN_INVALID_SOCKET; } else { pn_configure_sock(io, sock); snprintf(name, size, "%s:%s", io->host, io->serv); return sock; } } }
int pn_messenger_get(pn_messenger_t *messenger, pn_message_t *msg) { if (!messenger) return PN_ARG_ERR; for (int i = 0; i < messenger->size; i++) { pn_connector_t *ctor = messenger->connectors[i]; pn_connection_t *conn = pn_connector_connection(ctor); pn_delivery_t *d = pn_work_head(conn); while (d) { if (pn_readable(d)) { // XXX: buf size, eof, etc char buf[1024]; pn_link_t *l = pn_link(d); ssize_t n = pn_recv(l, buf, 1024); pn_settle(d); if (n < 0) return n; if (msg) { int err = pn_message_decode(msg, buf, n); if (err) { return pn_error_format(messenger->error, err, "error decoding message: %s", pn_message_error(msg)); } else { return 0; } } else { return 0; } } d = pn_work_next(d); } } // XXX: need to drain credit before returning EOS return PN_EOS; }
static int pni_encoder_enter(void *ctx, pn_data_t *data, pni_node_t *node) { pn_encoder_t *encoder = (pn_encoder_t *) ctx; pni_node_t *parent = pn_data_node(data, node->parent); int err; pn_atom_t *atom = &node->atom; uint8_t code; conv_t c; /** In an array we don't write the code before each element, only the first. */ if (pn_is_in_array(data, parent, node)) { code = pn_type2code(encoder, parent->type); if (pn_is_first_in_array(data, parent, node)) { err = pn_encoder_writef8(encoder, code); if (err) return err; } } else { code = pn_node2code(encoder, node); err = pn_encoder_writef8(encoder, code); if (err) return err; } switch (code) { case PNE_DESCRIPTOR: case PNE_NULL: case PNE_TRUE: case PNE_FALSE: return 0; case PNE_BOOLEAN: return pn_encoder_writef8(encoder, atom->u.as_bool); case PNE_UBYTE: return pn_encoder_writef8(encoder, atom->u.as_ubyte); case PNE_BYTE: return pn_encoder_writef8(encoder, atom->u.as_byte); case PNE_USHORT: return pn_encoder_writef16(encoder, atom->u.as_ushort); case PNE_SHORT: return pn_encoder_writef16(encoder, atom->u.as_short); case PNE_UINT0: return 0; case PNE_SMALLUINT: return pn_encoder_writef8(encoder, atom->u.as_uint); case PNE_UINT: return pn_encoder_writef32(encoder, atom->u.as_uint); case PNE_SMALLINT: return pn_encoder_writef8(encoder, atom->u.as_int); case PNE_INT: return pn_encoder_writef32(encoder, atom->u.as_int); case PNE_UTF32: return pn_encoder_writef32(encoder, atom->u.as_char); case PNE_ULONG: return pn_encoder_writef64(encoder, atom->u.as_ulong); case PNE_SMALLULONG: return pn_encoder_writef8(encoder, atom->u.as_ulong); case PNE_LONG: return pn_encoder_writef64(encoder, atom->u.as_long); case PNE_SMALLLONG: return pn_encoder_writef8(encoder, atom->u.as_long); case PNE_MS64: return pn_encoder_writef64(encoder, atom->u.as_timestamp); case PNE_FLOAT: c.f = atom->u.as_float; return pn_encoder_writef32(encoder, c.i); case PNE_DOUBLE: c.d = atom->u.as_double; return pn_encoder_writef64(encoder, c.l); case PNE_DECIMAL32: return pn_encoder_writef32(encoder, atom->u.as_decimal32); case PNE_DECIMAL64: return pn_encoder_writef64(encoder, atom->u.as_decimal64); case PNE_DECIMAL128: return pn_encoder_writef128(encoder, atom->u.as_decimal128.bytes); case PNE_UUID: return pn_encoder_writef128(encoder, atom->u.as_uuid.bytes); case PNE_VBIN8: return pn_encoder_writev8(encoder, &atom->u.as_bytes); case PNE_VBIN32: return pn_encoder_writev32(encoder, &atom->u.as_bytes); case PNE_STR8_UTF8: return pn_encoder_writev8(encoder, &atom->u.as_bytes); case PNE_STR32_UTF8: return pn_encoder_writev32(encoder, &atom->u.as_bytes); case PNE_SYM8: return pn_encoder_writev8(encoder, &atom->u.as_bytes); case PNE_SYM32: return pn_encoder_writev32(encoder, &atom->u.as_bytes); case PNE_ARRAY32: node->start = encoder->position; node->small = false; // we'll backfill the size on exit if (pn_encoder_remaining(encoder) < 4) return PN_OVERFLOW; encoder->position += 4; err = pn_encoder_writef32(encoder, node->described ? node->children - 1 : node->children); if (err) return err; if (node->described) { err = pn_encoder_writef8(encoder, 0); if (err) return err; } return 0; case PNE_LIST32: case PNE_MAP32: node->start = encoder->position; node->small = false; // we'll backfill the size later if (pn_encoder_remaining(encoder) < 4) return PN_OVERFLOW; encoder->position += 4; return pn_encoder_writef32(encoder, node->children); default: return pn_error_format(data->error, PN_ERR, "unrecognized encoding: %u", code); } }