Пример #1
0
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;
}
Пример #2
0
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;
}
Пример #3
0
void closetimer_cb(struct wx_timer_s* closetimer) {
    struct conn_s* conn = container_of(closetimer, struct conn_s, closetimer);
    conn_close(conn);
}
Пример #4
0
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;
        
    
}
Пример #5
0
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);
	}
}
Пример #6
0
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;
}