From 02454b3e8645dc6a4eab40490ef946de38868c98 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Tue, 7 Aug 2012 21:28:40 -0700 Subject: [PATCH] hammer2 - SPAN protocol work * Initial implementation of the LNK_SPAN protocol between two hammer service daemons running on different machines. There's still lots to do. mount x P PFSs (P pipes) (machine A) | service daemon (machine A) (handling P + 1 connections) | INET SOCKET | service daemon (machine B) (handling Q + 1 connections) | mount x Q PFSs (Q pipes) (machine B) * Service deamons starts with LNK_CONN and then interconnect SPANs. * SPAN protocol allows any number of connections between services daemons and from service daemons to physical HAMMER2 mounts. * Fixed a message write() sequencing bug * Added some additional debug directives, and also added a remote debug directive to connect from one already-running service daemon to another. --- sbin/hammer2/cmd_debug.c | 96 ++++++++++++++++++++++++++++---------------- sbin/hammer2/cmd_service.c | 4 +- sbin/hammer2/crypto.c | 39 +++++++++++++++++- sbin/hammer2/hammer2.h | 7 +++- sbin/hammer2/icrc.c | 2 +- sbin/hammer2/main.c | 12 +++++ sbin/hammer2/msg.c | 77 ++++++++++++++++++++--------------- sbin/hammer2/msg_lnk.c | 41 ++++++++++++------- sbin/hammer2/network.h | 3 + sbin/hammer2/subs.c | 45 ++++++++++++++++++++ 10 files changed, 238 insertions(+), 88 deletions(-) diff --git a/sbin/hammer2/cmd_debug.c b/sbin/hammer2/cmd_debug.c index da2a1db..d400714 100644 --- a/sbin/hammer2/cmd_debug.c +++ b/sbin/hammer2/cmd_debug.c @@ -48,52 +48,22 @@ static void hammer2_shell_parse(hammer2_iocom_t *iocom, hammer2_msg_t *msg); int cmd_shell(const char *hostname) { - struct sockaddr_in lsin; struct hammer2_iocom iocom; hammer2_msg_t *msg; - struct hostent *hen; int fd; /* - * Acquire socket and set options - */ - if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - fprintf(stderr, "cmd_debug: socket(): %s\n", - strerror(errno)); - return 1; - } - - /* * Connect to the target */ - bzero(&lsin, sizeof(lsin)); - lsin.sin_family = AF_INET; - lsin.sin_addr.s_addr = 0; - lsin.sin_port = htons(HAMMER2_LISTEN_PORT); - - if (hostname) { - hen = gethostbyname2(hostname, AF_INET); - if (hen == NULL) { - if (inet_pton(AF_INET, hostname, &lsin.sin_addr) != 1) { - fprintf(stderr, - "Cannot resolve %s\n", hostname); - return 1; - } - } else { - bcopy(hen->h_addr, &lsin.sin_addr, hen->h_length); - } - } - if (connect(fd, (struct sockaddr *)&lsin, sizeof(lsin)) < 0) { - close(fd); - fprintf(stderr, "debug: connect failed: %s\n", - strerror(errno)); - return 0; - } + fd = hammer2_connect(hostname); + if (fd < 0) + return 1; /* * Run the session. The remote end transmits our prompt. */ hammer2_iocom_init(&iocom, fd, 0, NULL, shell_rcvmsg, shell_ttymsg); + fcntl(0, F_SETFL, O_NONBLOCK); printf("debug: connected\n"); msg = hammer2_msg_alloc(&iocom, 0, HAMMER2_DBG_SHELL); @@ -163,12 +133,14 @@ shell_ttymsg(hammer2_iocom_t *iocom) msg = hammer2_msg_alloc(iocom, len, HAMMER2_DBG_SHELL); bcopy(buf, msg->aux_data, len); hammer2_msg_write(iocom, msg, NULL, NULL, NULL); - } else { + } else if (feof(stdin)) { /* * Set EOF flag without setting any error code for normal * EOF. */ iocom->flags |= HAMMER2_IOCOMF_EOF; + } else { + clearerr(stdin); } } @@ -215,8 +187,35 @@ hammer2_shell_parse(hammer2_iocom_t *iocom, hammer2_msg_t *msg) if (cmd == NULL || *cmd == 0) { ; + } else if (strcmp(cmd, "span") == 0) { + const char *hostname = strsep(&cmdbuf, " \t"); + pthread_t thread; + int fd; + + /* + * Connect to the target + */ + if (hostname == NULL) { + fd = -1; + } else { + fd = hammer2_connect(hostname); + } + + /* + * Start master service + */ + if (fd < 0) { + iocom_printf(iocom, 0, "Connection to %s failed\n", + hostname); + } else { + iocom_printf(iocom, 0, "Connected to %s\n", hostname); + pthread_create(&thread, NULL, + master_service, (void *)(intptr_t)fd); + /*pthread_join(thread, &res);*/ + } } else if (strcmp(cmd, "help") == 0 || strcmp(cmd, "?") == 0) { iocom_printf(iocom, 0, "help Command help\n"); + iocom_printf(iocom, 0, "span Span to target host\n"); } else { iocom_printf(iocom, 0, "Unrecognized command: %s\n", cmd); } @@ -254,6 +253,33 @@ iocom_printf(hammer2_iocom_t *iocom, uint32_t cmd, const char *ctl, ...) } /************************************************************************ + * DEBUGSPAN * + ************************************************************************ + * + * Connect to the target manually (not via the cluster list embedded in + * a hammer2 filesystem) and initiate the SPAN protocol. + */ +int +cmd_debugspan(const char *hostname) +{ + pthread_t thread; + int fd; + void *res; + + /* + * Connect to the target + */ + fd = hammer2_connect(hostname); + if (fd < 0) + return 1; + + printf("debugspan: connected to %s, starting CONN/SPAN\n", hostname); + pthread_create(&thread, NULL, master_service, (void *)(intptr_t)fd); + pthread_join(thread, &res); + return(0); +} + +/************************************************************************ * SHOW * ************************************************************************/ diff --git a/sbin/hammer2/cmd_service.c b/sbin/hammer2/cmd_service.c index 76d1153..2ccfad4 100644 --- a/sbin/hammer2/cmd_service.c +++ b/sbin/hammer2/cmd_service.c @@ -36,7 +36,6 @@ #include "hammer2.h" static void *master_accept(void *data); -static void *master_service(void *data); static void master_auth_state(hammer2_iocom_t *iocom); static void master_auth_rxmsg(hammer2_iocom_t *iocom, hammer2_msg_t *msg); static void master_link_state(hammer2_iocom_t *iocom); @@ -154,8 +153,9 @@ master_accept(void *data) /* * Service an accepted connection (runs as a pthread) + * + * (also called from a couple of other places) */ -static void * master_service(void *data) { diff --git a/sbin/hammer2/crypto.c b/sbin/hammer2/crypto.c index 248764d0..f945fd1 100644 --- a/sbin/hammer2/crypto.c +++ b/sbin/hammer2/crypto.c @@ -36,6 +36,41 @@ #include "hammer2.h" /* + * Setup crypto for pthreads + */ +static pthread_mutex_t *crypto_locks; +int crypto_count; + +static +unsigned long +hammer2_crypto_id_callback(void) +{ + return ((unsigned long)(uintptr_t)pthread_self()); +} + +static +void +hammer2_crypto_locking_callback(int mode, int type, + const char *file __unused, int line __unused) +{ + assert(type >= 0 && type < crypto_count); + if (mode & CRYPTO_LOCK) { + pthread_mutex_lock(&crypto_locks[type]); + } else { + pthread_mutex_unlock(&crypto_locks[type]); + } +} + +void +hammer2_crypto_setup(void) +{ + crypto_count = CRYPTO_num_locks(); + crypto_locks = calloc(crypto_count, sizeof(crypto_locks[0])); + CRYPTO_set_id_callback(hammer2_crypto_id_callback); + CRYPTO_set_locking_callback(hammer2_crypto_locking_callback); +} + +/* * Synchronously negotiate crypto for a new session. This must occur * within 10 seconds or the connection is error'd out. * @@ -484,7 +519,7 @@ hammer2_crypto_decrypt_aux(hammer2_iocom_t *iocom, hammer2_ioq_t *ioq, int hammer2_crypto_encrypt(hammer2_iocom_t *iocom, hammer2_ioq_t *ioq, - struct iovec *iov, int n) + struct iovec *iov, int n, size_t *nmaxp) { int p_len; int i; @@ -503,6 +538,7 @@ hammer2_crypto_encrypt(hammer2_iocom_t *iocom, hammer2_ioq_t *ioq, continue; } p_len -= already; + p_len &= ~HAMMER2_AES_KEY_MASK; if (p_len > nmax) p_len = nmax; EVP_EncryptUpdate(&ioq->ctx, @@ -517,6 +553,7 @@ hammer2_crypto_encrypt(hammer2_iocom_t *iocom, hammer2_ioq_t *ioq, } iov[0].iov_base = ioq->buf + ioq->fifo_beg; iov[0].iov_len = ioq->fifo_cdx - ioq->fifo_beg; + *nmaxp = (size_t)(ioq->fifo_cdx - ioq->fifo_beg); return (1); } diff --git a/sbin/hammer2/hammer2.h b/sbin/hammer2/hammer2.h index bdf72a4..0445365 100644 --- a/sbin/hammer2/hammer2.h +++ b/sbin/hammer2/hammer2.h @@ -112,6 +112,7 @@ int cmd_service(void); int cmd_stat(int ac, const char **av); int cmd_leaf(const char *sel_path); int cmd_shell(const char *hostname); +int cmd_debugspan(const char *hostname); int cmd_show(const char *devpath); int cmd_rsainit(const char *dir_path); int cmd_rsaenc(const char **keys, int nkeys); @@ -164,12 +165,13 @@ void hammer2_msg_dbg(hammer2_iocom_t *iocom, hammer2_msg_t *msg); /* * Crypto functions */ +void hammer2_crypto_setup(void); void hammer2_crypto_negotiate(hammer2_iocom_t *iocom); void hammer2_crypto_decrypt(hammer2_iocom_t *iocom, hammer2_ioq_t *ioq); void hammer2_crypto_decrypt_aux(hammer2_iocom_t *iocom, hammer2_ioq_t *ioq, hammer2_msg_t *msg, int already); int hammer2_crypto_encrypt(hammer2_iocom_t *iocom, hammer2_ioq_t *ioq, - struct iovec *iov, int n); + struct iovec *iov, int n, size_t *nmaxp); void hammer2_crypto_encrypt_wrote(hammer2_iocom_t *iocom, hammer2_ioq_t *ioq, int nact); @@ -181,6 +183,9 @@ const char *hammer2_uuid_to_str(uuid_t *uuid, char **strp); const char *hammer2_iptype_to_str(uint8_t type); const char *hammer2_pfstype_to_str(uint8_t type); const char *sizetostr(hammer2_off_t size); +int hammer2_connect(const char *hostname); + +void *master_service(void *data); void hammer2_msg_debug(hammer2_iocom_t *iocom, hammer2_msg_t *msg); void iocom_printf(hammer2_iocom_t *iocom, uint32_t cmd, const char *ctl, ...); diff --git a/sbin/hammer2/icrc.c b/sbin/hammer2/icrc.c index 82cadcd..eea4ea6 100644 --- a/sbin/hammer2/icrc.c +++ b/sbin/hammer2/icrc.c @@ -54,7 +54,7 @@ /* */ /*****************************************************************/ -static uint32_t crc32Table[256] = { +static const uint32_t crc32Table[256] = { 0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L, 0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL, 0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL, diff --git a/sbin/hammer2/main.c b/sbin/hammer2/main.c index b0dd2fb..1172c8d 100644 --- a/sbin/hammer2/main.c +++ b/sbin/hammer2/main.c @@ -55,6 +55,7 @@ main(int ac, char **av) srandomdev(); signal(SIGPIPE, SIG_IGN); + hammer2_crypto_setup(); /* * Core options @@ -140,6 +141,16 @@ main(int ac, char **av) usage(1); } ecode = cmd_remote_connect(sel_path, av[1]); + } else if (strcmp(av[0], "debugspan") == 0) { + /* + * Debug connection to the target hammer2 service and run + * the CONN/SPAN protocol. + */ + if (ac < 2) { + fprintf(stderr, "debugspan: requires hostname\n"); + usage(1); + } + ecode = cmd_debugspan(av[1]); } else if (strcmp(av[0], "disconnect") == 0) { /* * Remove cluster connection @@ -337,6 +348,7 @@ usage(int code) " stat [] Return inode quota & config\n" " leaf Start pfs leaf daemon\n" " shell [] Connect to debug shell\n" + " debugspan Connect to target, run CONN/SPAN\n" " rsainit Initialize rsa fields\n" " show devpath Raw hammer2 media dump\n" ); diff --git a/sbin/hammer2/msg.c b/sbin/hammer2/msg.c index 393933f..29a13e0 100644 --- a/sbin/hammer2/msg.c +++ b/sbin/hammer2/msg.c @@ -392,8 +392,10 @@ hammer2_iocom_core(hammer2_iocom_t *iocom) } } - if (iocom->flags & HAMMER2_IOCOMF_ARWORK) + if (iocom->flags & HAMMER2_IOCOMF_ARWORK) { + iocom->flags &= ~HAMMER2_IOCOMF_ARWORK; iocom->altmsg_callback(iocom); + } } } @@ -526,25 +528,12 @@ again: } /* - * Finally allocate the message and copy the core header - * to the embedded extended header. - * - * Initialize msg->aux_size to 0 and use it to track - * the amount of data copied from the stream. + * Allocate the message, the next state will fill it in. */ msg = hammer2_msg_alloc(iocom, ioq->abytes, 0); ioq->msg = msg; /* - * We are either done or we fall-through - */ - if (ioq->hbytes == sizeof(msg->any.head) && ioq->abytes == 0) { - bcopy(head, &msg->any.head, sizeof(msg->any.head)); - ioq->fifo_beg += ioq->hbytes; - break; - } - - /* * Fall through to the next state. Make sure that the * extended header does not straddle the end of the buffer. * We still want to issue larger reads into our buffer, @@ -566,7 +555,7 @@ again: assert(msg != NULL); if (bytes < ioq->hbytes) { n = read(iocom->sock_fd, - msg->any.buf + ioq->fifo_end, + ioq->buf + ioq->fifo_end, nmax); if (n <= 0) { if (n == 0) { @@ -614,6 +603,9 @@ again: head->hdr_crc = 0; if (hammer2_icrc32(head, ioq->hbytes) != xcrc32) { ioq->error = HAMMER2_IOQ_ERROR_XCRC; + fprintf(stderr, "XCRC FAILED %08x %08x\n", + xcrc32, hammer2_icrc32(head, ioq->hbytes)); + assert(0); break; } head->hdr_crc = xcrc32; @@ -992,12 +984,13 @@ hammer2_iocom_flush2(hammer2_iocom_t *iocom) hammer2_ioq_t *ioq = &iocom->ioq_tx; hammer2_msg_t *msg; ssize_t nmax; + ssize_t omax; ssize_t nact; struct iovec iov[HAMMER2_IOQ_MAXIOVEC]; size_t hbytes; size_t abytes; - int hoff; - int aoff; + size_t hoff; + size_t aoff; int n; if (ioq->error) { @@ -1007,21 +1000,23 @@ hammer2_iocom_flush2(hammer2_iocom_t *iocom) /* * Pump messages out the connection by building an iovec. + * + * ioq->hbytes/ioq->abytes tracks how much of the first message + * in the queue has been successfully written out, so we can + * resume writing. */ n = 0; nmax = 0; + hoff = ioq->hbytes; + aoff = ioq->abytes; TAILQ_FOREACH(msg, &ioq->msgq, qentry) { - hoff = 0; hbytes = (msg->any.head.cmd & HAMMER2_MSGF_SIZE) * HAMMER2_MSG_ALIGN; - aoff = 0; abytes = msg->aux_size; - if (n == 0) { - hoff += ioq->hbytes; - aoff += ioq->abytes; - } - if (hbytes - hoff > 0) { + assert(hoff <= hbytes && aoff <= abytes); + + if (hoff < hbytes) { iov[n].iov_base = (char *)&msg->any.head + hoff; iov[n].iov_len = hbytes - hoff; nmax += hbytes - hoff; @@ -1029,15 +1024,17 @@ hammer2_iocom_flush2(hammer2_iocom_t *iocom) if (n == HAMMER2_IOQ_MAXIOVEC) break; } - if (abytes - aoff > 0) { + if (aoff < abytes) { assert(msg->aux_data != NULL); - iov[n].iov_base = msg->aux_data + aoff; + iov[n].iov_base = (char *)msg->aux_data + aoff; iov[n].iov_len = abytes - aoff; nmax += abytes - aoff; ++n; if (n == HAMMER2_IOQ_MAXIOVEC) break; } + hoff = 0; + aoff = 0; } if (n == 0) return; @@ -1047,9 +1044,11 @@ hammer2_iocom_flush2(hammer2_iocom_t *iocom) * data into the fifo and adjust the iov as necessary. If * encryption is disabled the iov is left alone. * - * hammer2_crypto_encrypt_wrote() + * May return a smaller iov (thus a smaller n), with aggregated + * chunks. May reduce nmax to what fits in the FIFO. */ - n = hammer2_crypto_encrypt(iocom, ioq, iov, n); + omax = nmax; + n = hammer2_crypto_encrypt(iocom, ioq, iov, n, &nmax); /* * Execute the writev() then figure out what happened. @@ -1074,17 +1073,24 @@ hammer2_iocom_flush2(hammer2_iocom_t *iocom) } /* - * Indicate bytes written successfully. If we were unable to - * write the entire iov array then set WREQ to wait for more - * socket buffer space. + * Indicate bytes written successfully. + * + * If we were unable to write the entire iov array then set WREQ + * to wait for more socket buffer space. + * + * If the FIFO space was insufficient to fully drain all messages + * set WWORK to cause the core to call us again for the next batch. */ hammer2_crypto_encrypt_wrote(iocom, ioq, nact); if (nact != nmax) iocom->flags |= HAMMER2_IOCOMF_WREQ; + else if (nmax != omax) + iocom->flags |= HAMMER2_IOCOMF_WWORK; /* * Clean out the transmit queue based on what we successfully - * sent. + * sent. ioq->hbytes/abytes represents the portion of the first + * message previously sent. */ while ((msg = TAILQ_FIRST(&ioq->msgq)) != NULL) { hbytes = (msg->any.head.cmd & HAMMER2_MSGF_SIZE) * @@ -1093,12 +1099,14 @@ hammer2_iocom_flush2(hammer2_iocom_t *iocom) if ((size_t)nact < hbytes - ioq->hbytes) { ioq->hbytes += nact; + /* nact = 0; */ break; } nact -= hbytes - ioq->hbytes; ioq->hbytes = hbytes; if ((size_t)nact < abytes - ioq->abytes) { ioq->abytes += nact; + /* nact = 0; */ break; } nact -= abytes - ioq->abytes; @@ -1110,6 +1118,7 @@ hammer2_iocom_flush2(hammer2_iocom_t *iocom) hammer2_state_cleanuptx(iocom, msg); } + assert(nact == 0); if (ioq->error) { hammer2_iocom_drain(iocom); } @@ -1130,6 +1139,8 @@ hammer2_iocom_drain(hammer2_iocom_t *iocom) hammer2_msg_t *msg; iocom->flags &= ~(HAMMER2_IOCOMF_WREQ | HAMMER2_IOCOMF_WWORK); + ioq->hbytes = 0; + ioq->abytes = 0; while ((msg = TAILQ_FIRST(&ioq->msgq)) != NULL) { TAILQ_REMOVE(&ioq->msgq, msg, qentry); diff --git a/sbin/hammer2/msg_lnk.c b/sbin/hammer2/msg_lnk.c index 5b06ce6..80d578a 100644 --- a/sbin/hammer2/msg_lnk.c +++ b/sbin/hammer2/msg_lnk.c @@ -324,7 +324,7 @@ static struct h2span_connect_queue connq = TAILQ_HEAD_INITIALIZER(connq); static void hammer2_lnk_span(hammer2_state_t *state, hammer2_msg_t *msg); static void hammer2_lnk_conn(hammer2_state_t *state, hammer2_msg_t *msg); static void hammer2_lnk_relay(hammer2_state_t *state, hammer2_msg_t *msg); -static void hammer2_relay_scan(h2span_node_t *node); +static void hammer2_relay_scan(h2span_connect_t *conn, h2span_node_t *node); static void hammer2_relay_delete(h2span_relay_t *relay); /* @@ -383,6 +383,11 @@ hammer2_lnk_conn(hammer2_state_t *state, hammer2_msg_t *msg) TAILQ_INSERT_TAIL(&connq, conn, entry); hammer2_msg_result(state->iocom, msg, 0); + + /* + * Span-synchronize all nodes with the new connection + */ + hammer2_relay_scan(conn, NULL); } /* @@ -478,7 +483,7 @@ hammer2_lnk_span(hammer2_state_t *state, hammer2_msg_t *msg) state->any.link = slink; RB_INSERT(h2span_link_tree, &node->tree, slink); - hammer2_relay_scan(node); + hammer2_relay_scan(NULL, node); } /* @@ -530,7 +535,7 @@ hammer2_lnk_span(hammer2_state_t *state, hammer2_msg_t *msg) * removed and there's nothing left to do. */ if (node) - hammer2_relay_scan(node); + hammer2_relay_scan(NULL, node); } pthread_mutex_unlock(&cluster_mtx); @@ -563,28 +568,27 @@ hammer2_lnk_relay(hammer2_state_t *state, hammer2_msg_t *msg) * * Called with cluster_mtx held. */ -static void hammer2_relay_scan_conn(h2span_node_t *node, - h2span_connect_t *conn); +static void hammer2_relay_scan_specific(h2span_node_t *node, + h2span_connect_t *conn); static void -hammer2_relay_scan(h2span_node_t *node) +hammer2_relay_scan(h2span_connect_t *conn, h2span_node_t *node) { h2span_cluster_t *cls; - h2span_connect_t *conn; if (node) { /* * Iterate specific node */ TAILQ_FOREACH(conn, &connq, entry) - hammer2_relay_scan_conn(node, conn); + hammer2_relay_scan_specific(node, conn); } else { /* - * Full iteration (not currently implemented) + * Full iteration. * - * Iterate cluster ids + * Iterate cluster ids, nodes, and either a specific connection + * or all connections. */ - assert(0); RB_FOREACH(cls, h2span_cluster_tree, &cluster_tree) { /* * Iterate node ids @@ -594,8 +598,15 @@ hammer2_relay_scan(h2span_node_t *node) * Synchronize the node's link (received SPANs) * with each connection's relays. */ - TAILQ_FOREACH(conn, &connq, entry) - hammer2_relay_scan_conn(node, conn); + if (conn) { + hammer2_relay_scan_specific(node, conn); + } else { + TAILQ_FOREACH(conn, &connq, entry) { + hammer2_relay_scan_specific(node, + conn); + } + assert(conn == NULL); + } } } } @@ -637,7 +648,7 @@ hammer2_relay_scan_callback(h2span_relay_t *relay, void *arg) } static void -hammer2_relay_scan_conn(h2span_node_t *node, h2span_connect_t *conn) +hammer2_relay_scan_specific(h2span_node_t *node, h2span_connect_t *conn) { struct relay_scan_info info; h2span_relay_t *relay; @@ -680,7 +691,7 @@ hammer2_relay_scan_conn(h2span_node_t *node, h2span_connect_t *conn) hammer2_msg_t *msg; assert(relay == NULL || - slink->dist <= relay->link->dist); + relay->link->dist <= slink->dist); relay = hammer2_alloc(sizeof(*relay)); relay->conn = conn; relay->link = slink; diff --git a/sbin/hammer2/network.h b/sbin/hammer2/network.h index 6147f6f..e82d9fd 100644 --- a/sbin/hammer2/network.h +++ b/sbin/hammer2/network.h @@ -84,6 +84,9 @@ struct hammer2_handshake { typedef struct hammer2_handshake hammer2_handshake_t; +/* + * NOTE: HAMMER2_MSG_ALIGN (64) must be a multiple of HAMMER2_AES_KEY_SIZE. + */ #define HAMMER2_AES_KEY_SIZE 32 #define HAMMER2_AES_KEY_MASK (HAMMER2_AES_KEY_SIZE - 1) #define HAMMER2_AES_TYPE aes_256_cbc diff --git a/sbin/hammer2/subs.c b/sbin/hammer2/subs.c index 5ead4f8..fcf0394 100644 --- a/sbin/hammer2/subs.c +++ b/sbin/hammer2/subs.c @@ -288,3 +288,48 @@ hammer2_free(void *ptr) { free(ptr); } + +int +hammer2_connect(const char *hostname) +{ + struct sockaddr_in lsin; + struct hostent *hen; + int fd; + + /* + * Acquire socket and set options + */ + if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + fprintf(stderr, "cmd_debug: socket(): %s\n", + strerror(errno)); + return -1; + } + + /* + * Connect to the target + */ + bzero(&lsin, sizeof(lsin)); + lsin.sin_family = AF_INET; + lsin.sin_addr.s_addr = 0; + lsin.sin_port = htons(HAMMER2_LISTEN_PORT); + + if (hostname) { + hen = gethostbyname2(hostname, AF_INET); + if (hen == NULL) { + if (inet_pton(AF_INET, hostname, &lsin.sin_addr) != 1) { + fprintf(stderr, + "Cannot resolve %s\n", hostname); + return -1; + } + } else { + bcopy(hen->h_addr, &lsin.sin_addr, hen->h_length); + } + } + if (connect(fd, (struct sockaddr *)&lsin, sizeof(lsin)) < 0) { + close(fd); + fprintf(stderr, "debug: connect failed: %s\n", + strerror(errno)); + return -1; + } + return (fd); +} -- 1.7.7.2