/* * Push a new line on to the end of the buffer. */ int add_to_buffer(struct buffer_s *buffptr, unsigned char *data, size_t length) { struct bufline_s *newline; assert(buffptr != NULL); assert(data != NULL); assert(length > 0); /* * Sanity check here. A buffer with a non-NULL head pointer must * have a size greater than zero, and vice-versa. */ if (BUFFER_HEAD(buffptr) == NULL) assert(buffptr->size == 0); else assert(buffptr->size > 0); /* * Make a new line so we can add it to the buffer. */ if (!(newline = makenewline(data, length))) return -1; if (buffptr->size == 0) BUFFER_HEAD(buffptr) = BUFFER_TAIL(buffptr) = newline; else { BUFFER_TAIL(buffptr)->next = newline; BUFFER_TAIL(buffptr) = newline; } buffptr->size += length; return 0; }
/* * Write the bytes in the buffer to the socket. * Takes a connection and returns the number of bytes written. */ ssize_t write_buffer(int fd, struct buffer_s * buffptr) { ssize_t bytessent; struct bufline_s *line; assert(fd >= 0); assert(buffptr != NULL); if (buffptr->size == 0) return 0; /* Sanity check. It would be bad to be using a NULL pointer! */ assert(BUFFER_HEAD(buffptr) != NULL); line = BUFFER_HEAD(buffptr); bytessent = send(fd, line->string + line->pos, line->length - line->pos, MSG_NOSIGNAL); if (bytessent >= 0) { /* bytes sent, adjust buffer */ line->pos += bytessent; if (line->pos == line->length) free_line(remove_from_buffer(buffptr)); return bytessent; } else { switch (errno) { #ifdef EWOULDBLOCK case EWOULDBLOCK: #else # ifdef EAGAIN case EAGAIN: # endif #endif case EINTR: return 0; case ENOBUFS: case ENOMEM: log_message(LOG_ERR, "writebuff: write() error [NOBUFS/NOMEM] \"%s\" on file descriptor %d", strerror(errno), fd); return 0; default: log_message(LOG_ERR, "writebuff: write() error \"%s\" on file descriptor %d", strerror(errno), fd); return -1; } } }
/* * Remove the first line from the top of the buffer */ static struct bufline_s * remove_from_buffer(struct buffer_s *buffptr) { struct bufline_s *line; assert(buffptr != NULL); assert(BUFFER_HEAD(buffptr) != NULL); line = BUFFER_HEAD(buffptr); BUFFER_HEAD(buffptr) = line->next; buffptr->size -= line->length; return line; }
/* * Delete all the lines in the buffer and the buffer itself */ void delete_buffer(struct buffer_s *buffptr) { struct bufline_s *next; assert(buffptr != NULL); while (BUFFER_HEAD(buffptr)) { next = BUFFER_HEAD(buffptr)->next; free_line(BUFFER_HEAD(buffptr)); BUFFER_HEAD(buffptr) = next; } safefree(buffptr); }
/* * Create a new buffer */ struct buffer_s * new_buffer(void) { struct buffer_s *buffptr; if (!(buffptr = safemalloc(sizeof(struct buffer_s)))) return NULL; /* * Since the buffer is initially empty, set the HEAD and TAIL * pointers to NULL since they can't possibly point anywhere at the * moment. */ BUFFER_HEAD(buffptr) = BUFFER_TAIL(buffptr) = NULL; buffptr->size = 0; return buffptr; }
/** * 从url中抽取ip和端口,有各种情况需要分析 * 0表示抽取成功, * -1表示不包含请求行 * -2表示出错(含有HTTP) */ int extract_ip_buffer( buffer_t *pbuf, char *ip, size_t size, uint16_t *port ) { block_t *pb; int bytes; char *pE; block_t *pnb; pb = BUFFER_HEAD(pbuf); //第一个块含有请求行 if ( NULL != strnstr( BLOCK_SENDADDR(pb), BLOCK_SENDATA(pb), "HTTP", 4 ) ) { return __extract_ip( pbuf, pb, ip, size, port ); } else { pnb = pb->next; if ( NULL == pnb ) return -1; if ( NULL != (pE=strnstr( BLOCK_SENDADDR(pnb), BLOCK_SENDATA(pnb), "HTTP", 4))){ char *p1, *p2; p1 = memchr( BLOCK_SENDADDR(pnb), '/', pE - BLOCK_SENDADDR(pnb) ); //如果vm:port有可能横跨两个block if ( NULL == p1 ) { goto MERGEBLOCK; } p2 = memchr( p1, ':', pE-p1 ); if ( NULL == p2 ) { goto MERGEBLOCK; } //现在可以确定,vm:port在pnb块里面 return __extract_ip( pbuf, pnb, ip, size, port ); } int last = pb->end; //请求行只可能在第一快或是第二个快间.(1024的大小) if ( ( 'H' == pb->data[last-1] && 0 == strncmp( BLOCK_SENDADDR(pnb), "TTP", 3 ) ) || ( 'H' == pb->data[last-2] && 'T' == pb->data[last-1] && 0 == strncmp( BLOCK_SENDADDR(pnb), "TP", 2) ) || ( 0 == strncmp( pb->data+last-3, "HTT", 3 ) && 'P' == pnb->data[pnb->pos] ) ) { return __extract_ip( pbuf, pb, ip, size, port ); } return -1; } MERGEBLOCK: log_message( LOG_DEBUG, "in mergeblock" ); bytes = BLOCK_SENDATA(pb)+ pE - BLOCK_SENDADDR(pnb); if ( bytes <= BLOCK_MAXDATA ) { block_t *newb = (block_t*)safemalloc( sizeof(block_t) ); newb->pos = 0; memcpy( newb->data, BLOCK_SENDADDR(pb), BLOCK_SENDATA(pb) ); newb->end = BLOCK_SENDATA(pb); memcpy( BLOCK_READADDR(newb), BLOCK_SENDADDR(pnb), pE-BLOCK_SENDADDR(pnb) ); newb->end += pE-BLOCK_SENDADDR(pnb); pnb->pos += pE-BLOCK_SENDADDR(pnb); pbuf->head = newb; newb->next = pnb; safefree( pb ); return __extract_ip( pbuf, newb, ip, size, port ); } else { log_message( LOG_ERROR, "vm:port between two block!" ); return -1; } }
/** * 非阻塞写,从第一个block到pos位置 * return 发送的总数据量 */ ssize_t write_buffer( int fd, buffer_t *pbuf ) { assert(fd >= 0); assert( pbuf != NULL); block_t *pb = NULL; int n, total, size; total = 0; g_errno = 1; NONWRITE: if ( 0 == pbuf->size ) //结束发送 return total; pb = BUFFER_HEAD(pbuf); if ( NULL == pb ) { log_message( LOG_ERROR, "head = NULL, but remain size:%d", pbuf->size ); return total; } if ( 0 == BLOCK_SENDATA(pb) ) { //块没有数据发了 delete_head( pbuf ); goto NONWRITE; } size = BLOCK_SENDATA(pb); n = send( fd, BLOCK_SENDADDR(pb), size, 0 ); log_message( LOG_DEBUG, "send %d bytes to fd[%d]", n, fd ); if ( n >= 0 ) { g_errno = 1; pbuf->size -= n; pb->pos += n; total += n; if ( n == size ) { //块数据发送完,其实不应该删除,判断有没有满 delete_head( pbuf ); goto NONWRITE; //et mode } } else { switch (errno) { #ifdef EWOULDBLOCK case EWOULDBLOCK: #else # ifdef EAGAIN case EAGAIN: # endif #endif case EINTR: g_errno = 1; //没有错误,等待下一次事件 break; case ENOBUFS: case ENOMEM: log_message(LOG_ERROR, "writebuff: write() error [NOBUFS/NOMEM] \"%s\" on file descriptor %d", strerror(errno), fd); default: log_message(LOG_ERROR, "writebuff: write() error \"%s\" on file descriptor %d", strerror(errno), fd); g_errno = -1; } } return total; }