static int do_l2t_write_rpl2(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m) { struct adapter *sc = iq->adapter; const struct cpl_l2t_write_rpl *rpl = (const void *)(rss + 1); unsigned int tid = GET_TID(rpl); unsigned int idx = tid % L2T_SIZE; int rc; rc = do_l2t_write_rpl(iq, rss, m); if (rc != 0) return (rc); if (tid & F_SYNC_WR) { struct l2t_entry *e = &sc->l2t->l2tab[idx - sc->vres.l2t.start]; mtx_lock(&e->lock); if (e->state != L2T_STATE_SWITCHING) { send_pending(sc, e); e->state = L2T_STATE_VALID; } mtx_unlock(&e->lock); } return (0); }
int do_l2t_write_rpl2(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m) { struct adapter *sc = iq->adapter; const struct cpl_l2t_write_rpl *rpl = (const void *)(rss + 1); unsigned int tid = GET_TID(rpl); unsigned int idx = tid % L2T_SIZE; if (__predict_false(rpl->status != CPL_ERR_NONE)) { log(LOG_ERR, "Unexpected L2T_WRITE_RPL (%u) for entry at hw_idx %u\n", rpl->status, idx); return (EINVAL); } if (tid & F_SYNC_WR) { struct l2t_entry *e = &sc->l2t->l2tab[idx - sc->vres.l2t.start]; mtx_lock(&e->lock); if (e->state != L2T_STATE_SWITCHING) { send_pending(sc, e); e->state = L2T_STATE_VALID; } mtx_unlock(&e->lock); } return (0); }
/** * Sends all pending aggregate message for a given group */ void send_all_pending(int listidx) { int i; for (i = 0; i < MAX_PEND; i++) { if (group_list[listidx].pending[i].msg != 0) { send_pending(listidx, i); } } }
/** * Sends all pending aggregate message for a given group */ void send_all_pending(struct pr_group_list_t *group) { int i; for (i = 0; i < MAX_PEND; i++) { if (group->pending[i].msg != 0) { send_pending(group, i); } } }
int t4_l2t_send_slow(struct adapter *sc, struct wrqe *wr, struct l2t_entry *e) { again: switch (e->state) { case L2T_STATE_STALE: /* entry is stale, kick off revalidation */ if (resolve_entry(sc, e) != EWOULDBLOCK) goto again; /* entry updated, re-examine state */ /* Fall through */ case L2T_STATE_VALID: /* fast-path, send the packet on */ t4_wrq_tx(sc, wr); return (0); case L2T_STATE_RESOLVING: case L2T_STATE_SYNC_WRITE: mtx_lock(&e->lock); if (e->state != L2T_STATE_SYNC_WRITE && e->state != L2T_STATE_RESOLVING) { /* state changed by the time we got here */ mtx_unlock(&e->lock); goto again; } arpq_enqueue(e, wr); mtx_unlock(&e->lock); if (resolve_entry(sc, e) == EWOULDBLOCK) break; mtx_lock(&e->lock); if (e->state == L2T_STATE_VALID && !STAILQ_EMPTY(&e->wr_list)) send_pending(sc, e); if (e->state == L2T_STATE_FAILED) resolution_failed(e); mtx_unlock(&e->lock); break; case L2T_STATE_FAILED: resolution_failed_for_wr(wr); return (EHOSTUNREACH); } return (0); }
/** * Puts the given message on the pending message list. If it doesn't match * any pending message and there are no open slots, first send what's pending. * If the pending list is full after adding the given message, then send. */ void check_pending(int listidx, int hostidx, const unsigned char *message) { struct infoack_h *infoack; struct status_h *status; struct complete_h *complete; const uint8_t *func; struct pr_pending_info_t *pending; int match, pendidx; func = message; infoack = (struct infoack_h *)message; status = (struct status_h *)message; complete = (struct complete_h *)message; for (pendidx = 0; pendidx < MAX_PEND; pendidx++) { pending = &group_list[listidx].pending[pendidx]; if (group_list[listidx].pending[pendidx].msg == 0) { match = 1; break; } match = (*func == pending->msg); switch (*func) { case REGISTER: // REGISTER always matches itself break; case INFO_ACK: // Only in response to FILEINFO. // Responses to KEYINFO are not forwarded. match = match && (ntohs(infoack->file_id) == pending->file_id); break; case STATUS: match = match && ((ntohs(status->file_id) == pending->file_id) && (status->pass == pending->pass) && (ntohs(status->section) == pending->section)); break; case COMPLETE: match = match && ((ntohs(complete->file_id) == pending->file_id) && (complete->status == pending->comp_status)); break; default: log(group_list[listidx].group_id, 0, "Tried to check pending " "on invalid type %s", func_name(*func)); return; } if (match) { break; } } if (!match) { send_all_pending(listidx); pendidx = 0; pending = &group_list[listidx].pending[pendidx]; } pending->msg = *func; if (group_list[listidx].destinfo[hostidx].pending != pendidx) { group_list[listidx].destinfo[hostidx].pending = pendidx; pending->count++; } switch (*func) { case INFO_ACK: if (pending->count == 1) { pending->partial = 1; } pending->file_id = ntohs(infoack->file_id); pending->partial = pending->partial && ((infoack->flags & FLAG_PARTIAL) != 0); break; case STATUS: pending->file_id = ntohs(status->file_id); pending->pass = status->pass; pending->section = ntohs(status->section); pending->seq = group_list[listidx].last_seq; if (!pending->naklist) { pending->naklist = calloc(group_list[listidx].blocksize, 1); if (pending->naklist == NULL) { syserror(0, 0, "calloc failed!"); exit(1); } } if (ntohl(status->nak_count) != 0) { add_naks_to_pending(listidx, pendidx, message); } break; case COMPLETE: pending->file_id = ntohs(complete->file_id); pending->comp_status = complete->status; break; } if (pending->count == max_msg_dest(listidx, *func)) { send_pending(listidx, pendidx); } else { int total_pending, i; for (total_pending = 0, i = 0; i < MAX_PEND; i++) { total_pending += group_list[listidx].pending[i].count; } if (total_pending == 1) { set_timeout(listidx, 1); } } }
/** * Puts the given message on the pending message list. If it doesn't match * any pending message and there are no open slots, first send what's pending. * If the pending list is full after adding the given message, then send. */ void check_pending(struct pr_group_list_t *group, int hostidx, const unsigned char *message) { const struct fileinfoack_h *fileinfoack; const struct status_h *status; const struct complete_h *complete; const uint8_t *func; struct pr_pending_info_t *pending; int match, pendidx, hlen; func = message; fileinfoack = (const struct fileinfoack_h *)message; status = (const struct status_h *)message; complete = (const struct complete_h *)message; glog3(group, "check_timeout: looking for pending %s", func_name(*func)); for (pendidx = 0; pendidx < MAX_PEND; pendidx++) { pending = &group->pending[pendidx]; if (group->pending[pendidx].msg == 0) { glog3(group, "check_timeout: found empty slot %d", pendidx); match = 1; break; } match = (*func == pending->msg); switch (*func) { case REGISTER: // REGISTER always matches itself break; case FILEINFO_ACK: match = match && (ntohs(fileinfoack->file_id) == pending->file_id); break; case STATUS: match = match && ((ntohs(status->file_id) == pending->file_id) && (ntohs(status->section) == pending->section)); break; case COMPLETE: match = match && ((ntohs(complete->file_id) == pending->file_id) && (complete->status == pending->comp_status)); break; default: glog1(group, "Tried to check pending on invalid type %s", func_name(*func)); return; } if (match) { break; } } if (!match) { send_all_pending(group); pendidx = 0; pending = &group->pending[pendidx]; } glog3(group, "check_timeout: found match at slot %d", pendidx); pending->msg = *func; if (group->destinfo[hostidx].pending != pendidx) { group->destinfo[hostidx].pending = pendidx; pending->count++; } switch (*func) { case REGISTER: hlen = sizeof(struct register_h); if (pending->count == 1) { gettimeofday(&pending->rx_tstamp, NULL); pending->tstamp = group->destinfo[hostidx].regtime; glog3(group, "send time = %d.%06d", pending->tstamp.tv_sec, pending->tstamp.tv_usec); glog3(group, "rx time = %d.%06d", pending->rx_tstamp.tv_sec, pending->rx_tstamp.tv_usec); } break; case FILEINFO_ACK: hlen = sizeof(struct fileinfoack_h); if (pending->count == 1) { pending->partial = 1; gettimeofday(&pending->rx_tstamp, NULL); pending->tstamp.tv_sec = ntohl(fileinfoack->tstamp_sec); pending->tstamp.tv_usec = ntohl(fileinfoack->tstamp_usec); glog3(group, "send time = %d.%06d", pending->tstamp.tv_sec, pending->tstamp.tv_usec); glog3(group, "rx time = %d.%06d", pending->rx_tstamp.tv_sec, pending->rx_tstamp.tv_usec); } pending->file_id = ntohs(fileinfoack->file_id); pending->partial = pending->partial && ((fileinfoack->flags & FLAG_PARTIAL) != 0); break; case STATUS: hlen = sizeof(struct status_h); pending->file_id = ntohs(status->file_id); pending->section = ntohs(status->section); if (!pending->naklist) { pending->naklist = safe_calloc(group->blocksize, 1); } add_naks_to_pending(group, pendidx, message); break; case COMPLETE: hlen = sizeof(struct complete_h); pending->file_id = ntohs(complete->file_id); pending->comp_status = complete->status; break; } if ((*func != STATUS) && (pending->count == max_msg_dest(group, *func, hlen))) { send_pending(group, pendidx); } else { int total_pending, i; glog3(group, "check_timeout: getting pending count for %s", func_name(*func)); for (total_pending = 0, i = 0; i < MAX_PEND; i++) { glog3(group, "check_timeout: adding %d pending for %d", group->pending[i].count, i); total_pending += group->pending[i].count; } if (total_pending == 1) { set_timeout(group, 1, 0); } } }
int main(int argc , char *argv[]) { int socket_desc , client_sock , read_size; socklen_t c; struct sockaddr_in server , client; char client_message[0xFFFF]; #ifdef _WIN32 WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); #else signal(SIGPIPE, SIG_IGN); #endif socket_desc = socket(AF_INET , SOCK_STREAM , 0); if (socket_desc == -1) { printf("Could not create socket"); return 0; } int port = 2000; if (argc > 1) { port = atoi(argv[1]); if (port <= 0) port = 2000; } server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY; server.sin_port = htons(port); if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0) { perror("bind failed. Error"); return 1; } int enable = 1; setsockopt(socket_desc, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)); listen(socket_desc , 3); c = sizeof(struct sockaddr_in); unsigned int size; struct TLSContext *server_context = tls_create_context(1, TLS_V12); // load keys load_keys(server_context, "testcert/fullchain.pem", "testcert/privkey.pem"); char source_buf[0xFFFF]; int source_size = read_from_file("tlshelloworld.c", source_buf, 0xFFFF); while (1) { identity_str[0] = 0; client_sock = accept(socket_desc, (struct sockaddr *)&client, &c); if (client_sock < 0) { perror("accept failed"); return 1; } struct TLSContext *context = tls_accept(server_context); // uncomment next line to request client certificate tls_request_client_certificate(context); // make the TLS context serializable (this must be called before negotiation) tls_make_exportable(context, 1); fprintf(stderr, "Client connected\n"); while ((read_size = recv(client_sock, client_message, sizeof(client_message), 0)) > 0) { if (tls_consume_stream(context, client_message, read_size, verify_signature) > 0) break; } send_pending(client_sock, context); if (read_size > 0) { fprintf(stderr, "USED CIPHER: %s\n", tls_cipher_name(context)); int ref_packet_count = 0; int res; while ((read_size = recv(client_sock, client_message, sizeof(client_message) , 0)) > 0) { if (tls_consume_stream(context, client_message, read_size, verify_signature) < 0) { fprintf(stderr, "Error in stream consume\n"); break; } send_pending(client_sock, context); if (tls_established(context) == 1) { unsigned char read_buffer[0xFFFF]; int read_size = tls_read(context, read_buffer, sizeof(read_buffer) - 1); if (read_size > 0) { read_buffer[read_size] = 0; unsigned char export_buffer[0xFFF]; // simulate serialization / deserialization to another process char sni[0xFF]; sni[0] = 0; if (context->sni) snprintf(sni, 0xFF, "%s", context->sni); /* COOL STUFF => */ int size = tls_export_context(context, export_buffer, sizeof(export_buffer), 1); if (size > 0) { /* COOLER STUFF => */ struct TLSContext *imported_context = tls_import_context(export_buffer, size); // This is cool because a context can be sent to an existing process. // It will work both with fork and with already existing worker process. fprintf(stderr, "Imported context (size: %i): %x\n", size, imported_context); if (imported_context) { // destroy old context tls_destroy_context(context); // simulate serialization/deserialization of context context = imported_context; } } // ugly inefficient code ... don't write like me char send_buffer[0xF000]; char send_buffer_with_header[0xF000]; char out_buffer[0xFFF]; int tls_version = 2; switch (context->version) { case TLS_V10: tls_version = 0; break; case TLS_V11: tls_version = 1; break; } snprintf(send_buffer, sizeof(send_buffer), "Hello world from TLS 1.%i (used chipher is: %s), SNI: %s\r\nYour identity is: %s\r\n\r\nCertificate: %s\r\n\r\nBelow is the received header:\r\n%s\r\nAnd the source code for this example: \r\n\r\n%s", tls_version, tls_cipher_name(context), sni, identity_str, tls_certificate_to_string(server_context->certificates[0], out_buffer, sizeof(out_buffer)), read_buffer, source_buf); int content_length = strlen(send_buffer); snprintf(send_buffer_with_header, sizeof(send_buffer), "HTTP/1.1 200 OK\r\nConnection: close\r\nContent-type: text/plain\r\nContent-length: %i\r\n\r\n%s", content_length, send_buffer); tls_write(context, send_buffer_with_header, strlen(send_buffer_with_header)); tls_close_notify(context); send_pending(client_sock, context); break; } } } } #ifdef __WIN32 shutdown(client_sock, SD_BOTH); closesocket(client_sock); #else shutdown(client_sock, SHUT_RDWR); close(client_sock); #endif tls_destroy_context(context); } tls_destroy_context(server_context); return 0; }
static int run_server(struct sockaddr *sa, socklen_t salen) { static quicly_conn_t **conns; size_t num_conns = 0; int fd, ret; if ((fd = socket(sa->sa_family, SOCK_DGRAM, IPPROTO_UDP)) == -1) { perror("socket(2) failed"); return 1; } int on = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) != 0) { perror("setsockopt(SO_REUSEADDR) failed"); return 1; } if (bind(fd, sa, salen) != 0) { perror("bind(2) failed"); return 1; } while (1) { fd_set readfds; struct timeval *tv, tvbuf; do { int64_t timeout_at = INT64_MAX; size_t i; for (i = 0; i != num_conns; ++i) { int64_t conn_to = quicly_get_first_timeout(conns[i]); if (conn_to < timeout_at) timeout_at = conn_to; } if (timeout_at != INT64_MAX) { int64_t delta = timeout_at - ctx.now(&ctx); if (delta > 0) { tvbuf.tv_sec = delta / 1000; tvbuf.tv_usec = (delta % 1000) * 1000; } else { tvbuf.tv_sec = 0; tvbuf.tv_usec = 0; } tv = &tvbuf; } else { tv = NULL; } FD_ZERO(&readfds); FD_SET(fd, &readfds); } while (select(fd + 1, &readfds, NULL, NULL, tv) == -1 && errno == EINTR); if (FD_ISSET(fd, &readfds)) { uint8_t buf[4096]; struct msghdr mess; struct sockaddr sa; struct iovec vec; memset(&mess, 0, sizeof(mess)); mess.msg_name = &sa; mess.msg_namelen = sizeof(sa); vec.iov_base = buf; vec.iov_len = sizeof(buf); mess.msg_iov = &vec; mess.msg_iovlen = 1; ssize_t rret; while ((rret = recvmsg(fd, &mess, 0)) <= 0) ; if (verbosity >= 2) hexdump("recvmsg", buf, rret); quicly_decoded_packet_t packet; if (quicly_decode_packet(&packet, buf, rret) == 0) { if (packet.has_connection_id) { quicly_conn_t *conn = NULL; size_t i; for (i = 0; i != num_conns; ++i) { if (quicly_get_connection_id(conns[i]) == packet.connection_id) { conn = conns[i]; break; } } if (conn != NULL) { /* existing connection */ quicly_receive(conn, &packet); if (quicly_get_state(conn) == QUICLY_STATE_1RTT_ENCRYPTED && quicly_get_next_stream_id(conn) == 1) { quicly_stream_t *stream; ret = quicly_open_stream(conn, &stream); assert(ret == 0); stream->on_update = on_resp_receive; send_data(stream, "GET / HTTP/1.0\r\n\r\n"); } } else { /* new connection */ if (quicly_accept(&conn, &ctx, &sa, mess.msg_namelen, NULL, &packet) == 0) { assert(conn != NULL); conns = realloc(conns, sizeof(*conns) * (num_conns + 1)); assert(conns != NULL); conns[num_conns++] = conn; } else { assert(conn == NULL); } } if (conn != NULL && send_pending(fd, conn) != 0) { for (i = 0; i != num_conns; ++i) { if (conns[i] == conn) { memcpy(conns + i, conns + i + 1, (num_conns - i - 1) * sizeof(*conns)); --num_conns; break; } } quicly_free(conn); } } else { fprintf(stderr, "ignoring packet without connection-id\n"); } } } } }
static int run_client(struct sockaddr *sa, socklen_t salen, const char *host) { int fd, ret; struct sockaddr_in local; quicly_conn_t *conn = NULL; if ((fd = socket(sa->sa_family, SOCK_DGRAM, IPPROTO_UDP)) == -1) { perror("socket(2) failed"); return 1; } memset(&local, 0, sizeof(local)); local.sin_family = AF_INET; if (bind(fd, (void *)&local, sizeof(local)) != 0) { perror("bind(2) failed"); return 1; } ret = quicly_connect(&conn, &ctx, host, sa, salen, NULL); assert(ret == 0); send_pending(fd, conn); while (1) { fd_set readfds; struct timeval *tv, tvbuf; do { int64_t timeout_at = conn != NULL ? quicly_get_first_timeout(conn) : INT64_MAX; if (timeout_at != INT64_MAX) { int64_t delta = timeout_at - quicly_get_context(conn)->now(quicly_get_context(conn)); if (delta > 0) { tvbuf.tv_sec = delta / 1000; tvbuf.tv_usec = (delta % 1000) * 1000; } else { tvbuf.tv_sec = 0; tvbuf.tv_usec = 0; } tv = &tvbuf; } else { tv = NULL; } FD_ZERO(&readfds); FD_SET(fd, &readfds); } while (select(fd + 1, &readfds, NULL, NULL, tv) == -1 && errno == EINTR); if (FD_ISSET(fd, &readfds)) { uint8_t buf[4096]; struct msghdr mess; struct sockaddr sa; struct iovec vec; memset(&mess, 0, sizeof(mess)); mess.msg_name = &sa; mess.msg_namelen = sizeof(sa); vec.iov_base = buf; vec.iov_len = sizeof(buf); mess.msg_iov = &vec; mess.msg_iovlen = 1; ssize_t rret; while ((rret = recvmsg(fd, &mess, 0)) <= 0) ; if (verbosity >= 2) hexdump("recvmsg", buf, rret); quicly_decoded_packet_t packet; if (quicly_decode_packet(&packet, buf, rret) == 0) { quicly_receive(conn, &packet); if (quicly_get_state(conn) == QUICLY_STATE_1RTT_ENCRYPTED && quicly_get_next_stream_id(conn) == 1) { quicly_stream_t *stream; ret = quicly_open_stream(conn, &stream); assert(ret == 0); stream->on_update = on_resp_receive; send_data(stream, "GET /\r\n"); } } } if (conn != NULL && send_pending(fd, conn) != 0) { quicly_free(conn); conn = NULL; } } }