/* Exect a read() to return EOF */ static int expect_close(ne_socket *sock) { ssize_t n = ne_sock_read(sock, buffer, 1); ONV(n > 0, ("read got %" NE_FMT_SSIZE_T " bytes not closure", n)); ONV(n < 0 && n != NE_SOCK_CLOSED, ("read got error not closure: `%s'", ne_sock_error(sock))); return OK; }
/* do a sock_read() on sock for 'len' bytes, and expect 'str'. */ static int read_expect(ne_socket *sock, const char *str, size_t len) { ssize_t ret = ne_sock_read(sock, buffer, len); ONV((ssize_t)len != ret, ("read got %" NE_FMT_SSIZE_T " bytes not %" NE_FMT_SIZE_T, ret, len)); ONV(memcmp(str, buffer, len), ("read mismatch: `%.*s' not `%.*s'", (int)len, buffer, (int)len, str)); return OK; }
/* close 'sock', performing lingering close to avoid premature RST. */ static int close_socket(ne_socket *sock) { #ifdef HAVE_SHUTDOWN char buf[20]; int fd = ne_sock_fd(sock); shutdown(fd, 0); while (ne_sock_read(sock, buf, sizeof buf) > 0); #endif return ne_sock_close(sock); }
/* when an EOF is received without a clean shutdown (close_notify message). */ static int ssl_truncate(void) { ne_socket *sock; int ret; CALL(begin(&sock, serve_truncate, NULL)); ret = ne_sock_read(sock, buffer, 1); ONV(ret != NE_SOCK_TRUNC, ("socket got error %d not truncation: `%s'", ret, ne_sock_error(sock))); return finish(sock, 0); }
ssize_t ne_sock_fullread(ne_socket *sock, char *buffer, size_t buflen) { ssize_t len; while (buflen > 0) { len = ne_sock_read(sock, buffer, buflen); if (len < 0) return len; buflen -= len; buffer += len; } return 0; }
/* Read more bytes than were written. */ static int larger_read(void) { ne_socket *sock; ssize_t nb; DECL(hello, STR); CALL(begin(&sock, serve_sstring, &hello)); nb = ne_sock_read(sock, buffer, hello.len + 10); ONV(nb != (ssize_t)hello.len, ("read gave too many bytes (%" NE_FMT_SSIZE_T ")", nb)); ONN("read gave wrong data", memcmp(buffer, hello.data, hello.len)); return finish(sock, 1); }
static int read_reset(void) { ne_socket *sock; ssize_t ret; CALL(begin(&sock, serve_reset, NULL)); CALL(full_write(sock, "a", 1)); CALL(await_server()); ret = ne_sock_read(sock, buffer, 1); if (ret == NE_SOCK_CLOSED) { ne_sock_close(sock); return SKIP; } ONV(ret != NE_SOCK_RESET, ("read got %" NE_FMT_SSIZE_T " not reset: %s", ret, ne_sock_error(sock))); return good_close(sock); }
int discard_body(ne_socket *sock) { while (clength > 0) { char buf[BUFSIZ]; size_t bytes = clength; ssize_t ret; if (bytes > sizeof(buf)) bytes = sizeof(buf); NE_DEBUG(NE_DBG_HTTP, "Discarding %" NE_FMT_SIZE_T " bytes.\n", bytes); ret = ne_sock_read(sock, buf, bytes); ONV(ret < 0, ("socket read failed (%" NE_FMT_SSIZE_T "): %s", ret, ne_sock_error(sock))); clength -= ret; NE_DEBUG(NE_DBG_HTTP, "Got %" NE_FMT_SSIZE_T " bytes.\n", ret); } NE_DEBUG(NE_DBG_HTTP, "Discard successful.\n"); return OK; }
static int serve_expect(ne_socket *sock, void *ud) { struct string *str = ud; ssize_t ret; while (str->len && (ret = ne_sock_read(sock, buffer, sizeof(buffer))) > 0) { NE_DEBUG(NE_DBG_SOCKET, "Got %" NE_FMT_SSIZE_T " bytes.\n", ret); ONV(memcmp(str->data, buffer, ret), ("unexpected data: [%.*s] not [%.*s]", (int)ret, buffer, (int)ret, str->data)); str->data += ret; str->len -= ret; NE_DEBUG(NE_DBG_SOCKET, "%" NE_FMT_SIZE_T " bytes left.\n", str->len); } NE_DEBUG(NE_DBG_SOCKET, "All data read.\n"); return OK; }
static int netxml_alarm_subscribe(const char *page) { int ret, port = -1, secret = -1; char buf[LARGEBUF], *s; ne_request *request; ne_sock_addr *addr; const ne_inet_addr *ai; char resp_buf[LARGEBUF]; /* Clear response buffer */ memset(resp_buf, 0, sizeof(resp_buf)); upsdebugx(2, "%s: %s", __func__, page); sock = ne_sock_create(); if (gethostname(buf, sizeof(buf)) == 0) { dstate_setinfo("driver.hostname", "%s", buf); } else { dstate_setinfo("driver.hostname", "<unknown>"); } #ifdef HAVE_NE_SOCK_CONNECT_TIMEOUT ne_sock_connect_timeout(sock, timeout); #endif ne_sock_read_timeout(sock, 1); netxml_get_page(subdriver->configure); snprintf(buf, sizeof(buf), "<?xml version=\"1.0\"?>\n"); snprintfcat(buf, sizeof(buf), "<Subscribe>\n"); snprintfcat(buf, sizeof(buf), "<Class>%s v%s</Class>\n", progname, DRIVER_VERSION); snprintfcat(buf, sizeof(buf), "<Type>connected socket</Type>\n"); snprintfcat(buf, sizeof(buf), "<HostName>%s</HostName>\n", dstate_getinfo("driver.hostname")); snprintfcat(buf, sizeof(buf), "<XMLClientParameters>\n"); snprintfcat(buf, sizeof(buf), "<ShutdownDuration>%d</ShutdownDuration>\n", shutdown_duration); if( shutdown_timer > 0 ) { snprintfcat(buf, sizeof(buf), "<ShutdownTimer>%d</ShutdownTimer>\r\n", shutdown_timer); } else { snprintfcat(buf, sizeof(buf), "<ShutdownTimer>NONE</ShutdownTimer>\n"); } snprintfcat(buf, sizeof(buf), "<AutoConfig>LOCAL</AutoConfig>\n"); snprintfcat(buf, sizeof(buf), "<OutletGroup>1</OutletGroup>\n"); snprintfcat(buf, sizeof(buf), "</XMLClientParameters>\n"); snprintfcat(buf, sizeof(buf), "<Warning></Warning>\n"); snprintfcat(buf, sizeof(buf), "</Subscribe>\n"); /* now send subscription message setting all the proper flags */ request = ne_request_create(session, "POST", page); ne_set_request_body_buffer(request, buf, strlen(buf)); /* as the NMC reply is not xml standard compliant let's parse it this way */ do { #ifndef HAVE_NE_SOCK_CONNECT_TIMEOUT alarm(timeout+1); #endif ret = ne_begin_request(request); #ifndef HAVE_NE_SOCK_CONNECT_TIMEOUT alarm(0); #endif if (ret != NE_OK) { break; } ret = ne_read_response_block(request, resp_buf, sizeof(resp_buf)); if (ret == NE_OK) { ret = ne_end_request(request); } } while (ret == NE_RETRY); ne_request_destroy(request); /* due to different formats used by the various NMCs, we need to\ break up the reply in lines and parse each one separately */ for (s = strtok(resp_buf, "\r\n"); s != NULL; s = strtok(NULL, "\r\n")) { upsdebugx(2, "%s: parsing %s", __func__, s); if (!strncasecmp(s, "<Port>", 6) && (sscanf(s+6, "%u", &port) != 1)) { return NE_RETRY; } if (!strncasecmp(s, "<Secret>", 8) && (sscanf(s+8, "%u", &secret) != 1)) { return NE_RETRY; } } if ((port == -1) || (secret == -1)) { upsdebugx(2, "%s: parsing initial subcription failed", __func__); return NE_RETRY; } /* Resolve the given hostname. 'flags' must be zero. Hex * string IPv6 addresses (e.g. `::1') may be enclosed in brackets * (e.g. `[::1]'). */ addr = ne_addr_resolve(uri.host, 0); /* Returns zero if name resolution was successful, non-zero on * error. */ if (ne_addr_result(addr) != 0) { upsdebugx(2, "%s: name resolution failure on %s: %s", __func__, uri.host, ne_addr_error(addr, buf, sizeof(buf))); ne_addr_destroy(addr); return NE_RETRY; } for (ai = ne_addr_first(addr); ai != NULL; ai = ne_addr_next(addr)) { upsdebugx(2, "%s: connecting to host %s port %d", __func__, ne_iaddr_print(ai, buf, sizeof(buf)), port); #ifndef HAVE_NE_SOCK_CONNECT_TIMEOUT alarm(timeout+1); #endif ret = ne_sock_connect(sock, ai, port); #ifndef HAVE_NE_SOCK_CONNECT_TIMEOUT alarm(0); #endif if (ret == NE_OK) { upsdebugx(2, "%s: connection to %s open on fd %d", __func__, uri.host, ne_sock_fd(sock)); break; } } ne_addr_destroy(addr); if (ai == NULL) { upsdebugx(2, "%s: failed to create listening socket", __func__); return NE_RETRY; } snprintf(buf, sizeof(buf), "<Subscription Identification=\"%u\"></Subscription>", secret); ret = ne_sock_fullwrite(sock, buf, strlen(buf) + 1); if (ret != NE_OK) { upsdebugx(2, "%s: send failed: %s", __func__, ne_sock_error(sock)); return NE_RETRY; } ret = ne_sock_read(sock, buf, sizeof(buf)); if (ret < 1) { upsdebugx(2, "%s: read failed: %s", __func__, ne_sock_error(sock)); return NE_RETRY; } if (strcasecmp(buf, "<Subscription Answer=\"ok\"></Subscription>")) { upsdebugx(2, "%s: subscription rejected", __func__); return NE_RETRY; } upslogx(LOG_INFO, "NSM connection to '%s' established", uri.host); return NE_OK; }
void upsdrv_updateinfo(void) { int ret, errors = 0; /* We really should be dealing with alarms through a separate callback, so that we can keep the * processing of alarms and polling for data separated. Currently, this isn't supported by the * driver main body, so we'll have to revert to polling each time we're called, unless the * socket indicates we're no longer connected. */ if (testvar("subscribe")) { char buf[LARGEBUF]; ret = ne_sock_read(sock, buf, sizeof(buf)); if (ret > 0) { /* alarm message received */ ne_xml_parser *parser = ne_xml_create(); upsdebugx(2, "%s: ne_sock_read(%d bytes) => %s", __func__, ret, buf); ne_xml_push_handler(parser, subdriver->startelm_cb, subdriver->cdata_cb, subdriver->endelm_cb, NULL); ne_xml_parse(parser, buf, strlen(buf)); ne_xml_destroy(parser); time(&lastheard); } else if ((ret == NE_SOCK_TIMEOUT) && (difftime(time(NULL), lastheard) < 180)) { /* timed out */ upsdebugx(2, "%s: ne_sock_read(timeout)", __func__); } else { /* connection closed or unknown error */ upslogx(LOG_ERR, "NSM connection with '%s' lost", uri.host); upsdebugx(2, "%s: ne_sock_read(%d) => %s", __func__, ret, ne_sock_error(sock)); ne_sock_close(sock); if (netxml_alarm_subscribe(subdriver->subscribe) == NE_OK) { extrafd = ne_sock_fd(sock); time(&lastheard); return; } dstate_datastale(); extrafd = -1; return; } } /* get additional data */ ret = netxml_get_page(subdriver->getobject); if (ret != NE_OK) { errors++; } ret = netxml_get_page(subdriver->summary); if (ret != NE_OK) { errors++; } if (errors > 1) { dstate_datastale(); return; } status_init(); alarm_init(); netxml_alarm_set(); alarm_commit(); netxml_status_set(); status_commit(); dstate_dataok(); }
static int read_timeout(void) { TO_BEGIN; TO_OP(ne_sock_read(sock, buffer, 1)); TO_FINISH; }
/* Exect a ne_sock_peek() to return EOF */ static int expect_peek_close(ne_socket *sock) { ssize_t n = ne_sock_read(sock, buffer, 1); ONV(n != NE_SOCK_CLOSED, ("peek gave %" NE_FMT_SSIZE_T " not closure", n)); return OK; }