void drive_machine(conn *c) { int exit = 0; int sfd, flags = 1; socklen_t addrlen; struct sockaddr addr; conn *newc; int res; while (!exit) { /*printf("state %d\n", c->state); */ switch(c->state) { case conn_listening: addrlen = sizeof(addr); if ((sfd = accept(c->sfd, &addr, &addrlen)) == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { perror("accept() shouldn't block"); } else { perror("accept()"); } return; } if ((flags = fcntl(sfd, F_GETFL, 0)) < 0 || fcntl(sfd, F_SETFL, flags | O_NONBLOCK) < 0) { perror("setting O_NONBLOCK"); close(sfd); return; } newc = conn_new(sfd, conn_read, EV_READ | EV_PERSIST); if (!newc) { fprintf(stderr, "couldn't create new connection\n"); close(sfd); return; } exit = 1; break; case conn_read: if (try_read_command(c)) { continue; } if (try_read_network(c)) { continue; } /* we have no command line and no data to read from network */ if (!update_event(c, EV_READ | EV_PERSIST)) { fprintf(stderr, "Couldn't update event\n"); c->state = conn_closing; break; } exit = 1; break; case conn_nread: /* we are reading rlbytes into rcurr; */ if (c->rlbytes == 0) { complete_nread(c); break; } /* first check if we have leftovers in the conn_read buffer */ if (c->rbytes > 0) { int tocopy = c->rbytes > c->rlbytes ? c->rlbytes : c->rbytes; memcpy(c->rcurr, c->rbuf, tocopy); c->rcurr += tocopy; c->rlbytes -= tocopy; if (c->rbytes > tocopy) { memmove(c->rbuf, c->rbuf+tocopy, c->rbytes - tocopy); } c->rbytes -= tocopy; break; } /* now try reading from the socket */ res = read(c->sfd, c->rcurr, c->rlbytes); if (res > 0) { stats.bytes_read += res; c->rcurr += res; c->rlbytes -= res; break; } if (res == 0) { /* end of stream */ c->state = conn_closing; break; } if (res == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) { if (!update_event(c, EV_READ | EV_PERSIST)) { fprintf(stderr, "Couldn't update event\n"); c->state = conn_closing; break; } exit = 1; break; } /* otherwise we have a real error, on which we close the connection */ fprintf(stderr, "Failed to read, and not due to blocking\n"); c->state = conn_closing; break; case conn_write: /* we are writing wbytes bytes starting from wcurr */ if (c->wbytes == 0) { if (c->write_and_free) { free(c->write_and_free); c->write_and_free = 0; } if (c->write_and_close) c->state = conn_closing; else c->state = conn_read; break; } res = write(c->sfd, c->wcurr, c->wbytes); if (res > 0) { stats.bytes_written += res; c->wcurr += res; c->wbytes -= res; break; } if (res == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) { if (!update_event(c, EV_WRITE | EV_PERSIST)) { fprintf(stderr, "Couldn't update event\n"); c->state = conn_closing; break; } exit = 1; break; } /* if res==0 or res==-1 and error is not EAGAIN or EWOULDBLOCK, we have a real error, on which we close the connection */ fprintf(stderr, "Failed to write, and not due to blocking\n"); c->state = conn_closing; break; case conn_mwrite: /* * we're writing ibytes bytes from iptr. iptr alternates between * ibuf, where we build a string "VALUE...", and it->data for the * current item. When we finish a chunk, we choose the next one using * ipart, which has the following semantics: 0 - start the loop, 1 - * we finished ibuf, go to current it->data; 2 - we finished it->data, * move to the next item and build its ibuf; 3 - we finished all items, * write "END". */ if (c->ibytes > 0) { res = write(c->sfd, c->iptr, c->ibytes); if (res > 0) { stats.bytes_written += res; c->iptr += res; c->ibytes -= res; break; } if (res == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) { if (!update_event(c, EV_WRITE | EV_PERSIST)) { fprintf(stderr, "Couldn't update event\n"); c->state = conn_closing; break; } exit = 1; break; } /* if res==0 or res==-1 and error is not EAGAIN or EWOULDBLOCK, we have a real error, on which we close the connection */ fprintf(stderr, "Failed to write, and not due to blocking\n"); c->state = conn_closing; break; } else { item *it; /* we finished a chunk, decide what to do next */ switch (c->ipart) { case 1: it = *(c->icurr); c->iptr = it->data; c->ibytes = it->nbytes; c->ipart = 2; break; case 2: it = *(c->icurr); item_remove(it); if (c->ileft <= 1) { c->ipart = 3; break; } else { c->ileft--; c->icurr++; } /* FALL THROUGH */ case 0: it = *(c->icurr); sprintf(c->ibuf, "VALUE %s %u %u\r\n", it->key, it->flags, it->nbytes - 2); c->iptr = c->ibuf; c->ibytes = strlen(c->iptr); c->ipart = 1; break; case 3: out_string(c, "END"); break; } } break; case conn_closing: conn_close(c); exit = 1; break; } } return; }
int read_cb(struct wx_conn_s* wx_conn, struct wx_buf_s* buf, ssize_t n) { struct conn_s* conn = container_of(wx_conn, struct conn_s, wx_conn); if (n == 0 && buf->size!=0) { conn_close(conn); return 0; } wx_timer_stop(&conn->closetimer); char* rnrnpos = strstr(buf->data, "\r\n\r\n"); if (rnrnpos) { char resbody[128]={0}; uint16_t sid; if (1 == sscanf(buf->data, "GET /get/%hu HTTP/", &sid)) { uint32_t ip; uint16_t port; if (0 == l5_sid_route_ipport(sid, &ip, &port)) { char sip[16]={0}; int2ip(ip, sip); sprintf(resbody, "%s:%d", sip, port); } else { sprintf(resbody, "0.0.0.0:0"); } } else { sprintf(resbody, "bad request"); } if (strstr(buf->data, "HTTP/1.1\r\n")) { conn->keepalivems = 15000; } conn->buf = NULL; struct wx_buf_chain_s* bc = (struct wx_buf_chain_s*)conn->data; bc->base = bc->data; bc->size = sizeof(conn->data) - sizeof(bc); bc->cleanup = cleanup_cb; bc->arg = conn; bc->next = NULL; int vertail = 1; char connection[]="keep-alive"; if (conn->keepalivems == 0) { vertail = 0; sprintf(connection, "close"); } bc->size = (size_t)sprintf(bc->base, "HTTP/1.%d 200 OK\r\nConnection: %s\r\nContent-Length: %d\r\n\r\n%s", vertail, connection, strlen(resbody), resbody); wx_conn_write_start(wx_conn, wx_conn->rwatcher.fd, bc); } if (buf->size == 0) { conn->buf = NULL; wx_err("header buffer overflow"); conn_close(conn); return EXIT_FAILURE; } return 0; }
void closetimer_cb(struct wx_timer_s* closetimer) { struct conn_s* conn = container_of(closetimer, struct conn_s, closetimer); conn_close(conn); }
void* handle_req(void* p) { conn_t * pConn = (conn_t*)p; // Network state // FIXME cuda_bridge_request_t == cuda_packet_t == rpkt_t, this is rediculous strm_hdr_t *hdr = NULL; rpkt_t *rpkts = NULL; // array of cuda packets // CLOSE the listen connection // conn_close(pConnListen); // Connection-related structures hdr = &pConn->strm.hdr; rpkts = pConn->strm.rpkts; // an array of packets (MAX_REMOTE_BATCH_SIZE) // these are buffers for extra data transferred as pConn->pReqBuffer = NULL; pConn->pRspBuffer = NULL; while(1) { p_debug("------------------New RPC--------------------\n"); memset(hdr, 0, sizeof(strm_hdr_t)); memset(rpkts, 0, MAX_REMOTE_BATCH_SIZE * sizeof(rpkt_t)); pConn->request_data_size = 0; pConn->response_data_size = 0; pConn->pReqBuffer = freeBuffer(pConn->pReqBuffer); pConn->pRspBuffer = freeBuffer(pConn->pRspBuffer); //recv the header describing the batch of remote requests if (1 != get(pConn, hdr, sizeof(strm_hdr_t))) { break; } p_debug(" received request header. Expecting %d packets. And extra request buffer of data size %d\n", hdr->num_cuda_pkts, hdr->data_size); if (hdr->num_cuda_pkts <= 0) { p_warn("Received header specifying zero packets, ignoring\n"); continue; } // Receive the entire batch. // first the packets, then the extra data (reqbuf) // // let's assume that we have enough space. otherwise we have a problem // pConn allocates the buffers for incoming cuda packets // so we should be fine if(1 != get(pConn, rpkts, hdr->num_cuda_pkts * sizeof(rpkt_t))) { break; } p_info("Received %d packets, each of size of (%lu) bytes\n", hdr->num_cuda_pkts, sizeof(rpkt_t)); p_info( "Received method %s (method_id %d) from Thr_id: %lu.\n", methodIdToString(rpkts[0].method_id), rpkts[0].method_id, rpkts[0].thr_id); // receiving the request buffer if any if(hdr->data_size > 0){ p_info("Expecting data size/Buffer: %u, %d.\n", hdr->data_size, pConn->request_data_size); // let's assume that the expected amount of data will fit into // the buffer we have (size of pConn->request_data_buffer // allocate the right amount of memory for the request buffer pConn->pReqBuffer = malloc(hdr->data_size); if( mallocCheck(pConn->pReqBuffer, __FUNCTION__, NULL) == ERROR ){ break; } //assert(hdr->data_size <= TOTAL_XFER_MAX); if(1 != get(pConn, pConn->pReqBuffer, hdr->data_size)){ pConn->pReqBuffer = freeBuffer(pConn->pReqBuffer); break; } pConn->request_data_size = hdr->data_size; p_info( "Received request buffer (%d bytes)\n", pConn->request_data_size); } // execute the request pkt_execute(&rpkts[0], pConn); // we need to send the one response packet + response_buffer if any // @todo you need to check if he method needs to send // and extended response - you need to provide the right // data_size if( strm_expects_response(&pConn->strm) ){ // send the header about response p_debug( "pConn->response_data_size %d\n", pConn->response_data_size); if (conn_sendCudaPktHdr(&*pConn, 1, pConn->response_data_size) == ERROR) { p_info( "__ERROR__ after : Sending the CUDA packet response header: Quitting ... \n"); break; } // send the standard response (with cuda_error_t, and simple arguments etc) if (1 != put(pConn, rpkts, sizeof(rpkt_t))) { p_info("__ERROR__ after : Sending CUDA response packet: Quitting ... \n"); break; } p_info("Response packet sent.\n"); // send the extra data if you have anything to send if( pConn->response_data_size > 0 ){ if (1 != put(pConn, pConn->pRspBuffer, pConn->response_data_size)) { p_info("__ERROR__ after: Sending accompanying response buffer: Quitting ... \n" ); break; } p_info( "Response buffer sent (%d) bytes.\n", pConn->response_data_size); } } }//while(1) freeBuffer(pConn->pReqBuffer); freeBuffer(pConn->pRspBuffer); //conn_close(pConnListen); conn_close(pConn); //free(pConnListen); free(pConn); return NULL; }
static void tcp_recv_handler(struct mbuf *mb, void *arg) { struct sip_conn *conn = arg; size_t pos; int err = 0; if (conn->mb) { pos = conn->mb->pos; conn->mb->pos = conn->mb->end; err = mbuf_write_mem(conn->mb, mbuf_buf(mb),mbuf_get_left(mb)); if (err) goto out; conn->mb->pos = pos; if (mbuf_get_left(conn->mb) > TCP_BUFSIZE_MAX) { err = EOVERFLOW; goto out; } } else { conn->mb = mem_ref(mb); } for (;;) { struct sip_msg *msg; uint32_t clen; size_t end; if (mbuf_get_left(conn->mb) < 2) break; if (!memcmp(mbuf_buf(conn->mb), "\r\n", 2)) { tmr_start(&conn->tmr, TCP_IDLE_TIMEOUT * 1000, conn_tmr_handler, conn); conn->mb->pos += 2; if (mbuf_get_left(conn->mb) >= 2 && !memcmp(mbuf_buf(conn->mb), "\r\n", 2)) { struct mbuf mbr; conn->mb->pos += 2; mbr.buf = crlfcrlf; mbr.size = sizeof(crlfcrlf); mbr.pos = 0; mbr.end = 2; err = tcp_send(conn->tc, &mbr); if (err) break; } if (mbuf_get_left(conn->mb)) continue; conn->mb = mem_deref(conn->mb); break; } pos = conn->mb->pos; err = sip_msg_decode(&msg, conn->mb); if (err) { if (err == ENODATA) err = 0; break; } if (!msg->clen.p) { mem_deref(msg); err = EBADMSG; break; } clen = pl_u32(&msg->clen); if (mbuf_get_left(conn->mb) < clen) { conn->mb->pos = pos; mem_deref(msg); break; } tmr_start(&conn->tmr, TCP_IDLE_TIMEOUT * 1000, conn_tmr_handler, conn); end = conn->mb->end; msg->mb->end = msg->mb->pos + clen; msg->sock = mem_ref(conn); msg->src = conn->paddr; msg->dst = conn->laddr; msg->tp = conn->sc ? SIP_TRANSP_TLS : SIP_TRANSP_TCP; sip_recv(conn->sip, msg); mem_deref(msg); if (end <= conn->mb->end) { conn->mb = mem_deref(conn->mb); break; } mb = mbuf_alloc(end - conn->mb->end); if (!mb) { err = ENOMEM; goto out; } (void)mbuf_write_mem(mb, &conn->mb->buf[conn->mb->end], end - conn->mb->end); mb->pos = 0; mem_deref(conn->mb); conn->mb = mb; } out: if (err) { conn_close(conn, err); mem_deref(conn); } }
static int net_http_rsp_handler(struct net_handle_cxt* cxt, struct conn* server) { struct conn* client = cxt->client; client->tx = 0; struct net_data* data = mem_alloc(sizeof(struct net_data)); net_data_init(data); int ret = net_fetch_http(server, data); if (ret) { // Failed to fetch response from server conn_close(server); net_bad_gateway(client); net_data_done(data); mem_free(data); return ret; } struct net_rsp rsp; memset(&rsp, 0, sizeof(rsp)); rsp.data = data; ret = net_parse_rsp(&rsp); if (ret) { conn_close(server); net_bad_gateway(client); net_rsp_done(&rsp); return ret; } // TODO check headers and http version ret = net_forward_rsp_header(&rsp, client); if (ret) { net_rsp_done(&rsp); return ret; } if (rsp.ver_major*100 + rsp.ver_minor > 100) { // Higher than http 1.0 ret = net_transfer_body_HTTP_1_1(client, server, rsp.data); } else { PLOGD("Forwarding http 1.0 response"); while (1) { ret = conn_copy(client, server, 64*1024); if (ret < 0) { ret = 0; break; } } conn_close(client); conn_close(server); } struct net_req* req = cxt->head->req; if (ret == 0) ret = rsp.code; // WTF... log_http_req(&client->ep, req->data->buf.p + req->host, req->data->buf.p + req->path, client->tx); PLOGI("%s %s %s:%d%s %d", ep_tostring(&client->ep), req->data->buf.p, req->data->buf.p + req->host, req->port, req->data->buf.p + req->path, client->tx); net_rsp_done(&rsp); return ret; }