SWINLINE swBuffer_trunk* swConnection_get_out_buffer(swConnection *conn, uint32_t type) { swBuffer_trunk *trunk; if (conn->out_buffer == NULL) { conn->out_buffer = swBuffer_new(SW_BUFFER_SIZE); if (conn->out_buffer == NULL) { return NULL; } } if (type == SW_TRUNK_SENDFILE) { trunk = swBuffer_new_trunk(conn->out_buffer, SW_TRUNK_SENDFILE, 0); } else { trunk = swBuffer_get_trunk(conn->out_buffer); if (trunk == NULL) { trunk = swBuffer_new_trunk(conn->out_buffer, SW_TRUNK_DATA, conn->out_buffer->trunk_size); } } return trunk; }
SWINLINE swBuffer_trunk* swConnection_get_in_buffer(swConnection *conn) { swBuffer_trunk *trunk = NULL; swBuffer *buffer; if (conn->in_buffer == NULL) { buffer = swBuffer_new(SW_BUFFER_SIZE); //buffer create failed if (buffer == NULL) { return NULL; } //new trunk trunk = swBuffer_new_trunk(buffer, SW_TRUNK_DATA, buffer->trunk_size); if (trunk == NULL) { sw_free(buffer); return NULL; } conn->in_buffer = buffer; } else { buffer = conn->in_buffer; trunk = buffer->tail; if (trunk == NULL || trunk->length == buffer->trunk_size) { trunk = swBuffer_new_trunk(buffer, SW_TRUNK_DATA, buffer->trunk_size); } } return trunk; }
int swFactory_end(swFactory *factory, int fd) { swServer *serv = factory->ptr; swSendData _send; swDataHead info; bzero(&_send, sizeof(_send)); _send.info.fd = fd; _send.info.len = 0; _send.info.type = SW_EVENT_CLOSE; swConnection *conn = swWorker_get_connection(serv, fd); if (conn == NULL || conn->active == 0) { //swWarn("can not close. Connection[%d] not found.", _send.info.fd); return SW_ERR; } else if (conn->close_force) { goto do_close; } else if (conn->closing) { swWarn("The connection[%d] is closing.", fd); return SW_ERR; } else if (conn->closed) { return SW_ERR; } else { do_close: conn->closing = 1; if (serv->onClose != NULL) { info.fd = fd; info.from_id = conn->from_id; info.from_fd = conn->from_fd; serv->onClose(serv, &info); } conn->closing = 0; conn->closed = 1; conn->close_errno = 0; if (swBuffer_empty(conn->out_buffer)) { swReactor *reactor = &serv->reactor_threads[SwooleTG.id].reactor; return swReactorThread_close(reactor, conn->fd); } else { swBuffer_trunk *trunk = swBuffer_new_trunk(conn->out_buffer, SW_CHUNK_CLOSE, 0); trunk->store.data.val1 = _send.info.type; return SW_OK; } } }
/** * append to buffer queue */ int swBuffer_in(swBuffer *buffer, swSendData *send_data) { swBuffer_trunk *trunk = swBuffer_new_trunk(buffer, SW_TRUNK_DATA, send_data->info.len); if (trunk == NULL) { return SW_ERR; } trunk->length = send_data->info.len; memcpy(trunk->data, send_data->data, trunk->length); swTraceLog(SW_TRACE_BUFFER, "trunk_n=%d|data_len=%d|trunk_len=%d|trunk=%p", buffer->trunk_num, send_data->info.len, trunk->length, trunk); return SW_OK; }
/** * append to buffer queue */ int swBuffer_append(swBuffer *buffer, void *data, uint32_t size) { swBuffer_trunk *chunk = swBuffer_new_trunk(buffer, SW_CHUNK_DATA, size); if (chunk == NULL) { return SW_ERR; } buffer->length += size; chunk->length = size; memcpy(chunk->store.ptr, data, size); swTraceLog(SW_TRACE_BUFFER, "trunk_n=%d|size=%d|trunk_len=%d|trunk=%p", buffer->trunk_num, size, chunk->length, chunk); return SW_OK; }
/** * send to client or append to out_buffer */ int swReactorThread_send(swEventData *resp) { int buf_size, copy_n; swServer *serv = SwooleG.serv; swSendData send_data; swEvent closeFd; swBuffer_trunk *trunk; swTask_sendfile *task; swConnection *conn = swServer_get_connection(serv, resp->info.fd); swReactor *reactor = &(serv->reactor_threads[conn->from_id].reactor); //recv length=0, will close connection if (resp->info.len == 0) { #ifdef SW_REACTOR_DIRECT_SEND close_fd: #endif { closeFd.fd = resp->info.fd; closeFd.from_id = resp->info.from_id; closeFd.type = SW_EVENT_CLOSE; //printf("closeFd.fd=%d|from_id=%d\n", closeFd.fd, closeFd.from_id); swReactorThread_onClose(reactor, &closeFd); } return SW_OK; } //sendfile to client else if(resp->info.type == SW_EVENT_SENDFILE) { trunk = swConnection_get_out_buffer(conn, SW_TRUNK_SENDFILE); if (trunk == NULL) { swWarn("get out_buffer trunk failed."); return SW_ERR; } task = sw_malloc(sizeof(swTask_sendfile)); if (task == NULL) { swWarn("malloc for swTask_sendfile failed."); //TODO: 回收这里的内存 return SW_ERR; } bzero(task, sizeof(swTask_sendfile)); int file_fd = open(resp->data, O_RDONLY); if (file_fd < 0) { swWarn("open file[%s] failed. Error: %s[%d]", task->filename, strerror(errno), errno); return SW_ERR; } struct stat file_stat; if (fstat(file_fd, &file_stat) < 0) { swWarn("swoole_async_readfile: fstat failed. Error: %s[%d]", strerror(errno), errno); return SW_ERR; } task->filesize = file_stat.st_size; task->fd = file_fd; trunk->data = (void *)task; reactor->set(reactor, resp->info.fd, SW_EVENT_TCP | SW_EVENT_WRITE | SW_EVENT_READ); } //send data else { send_data.data = resp->data; send_data.info.len = resp->info.len; send_data.info.from_id = resp->info.from_id; send_data.info.fd = resp->info.fd; #ifdef SW_REACTOR_DIRECT_SEND if(!swBuffer_empty(conn->out_buffer)) { trunk = swBuffer_get_trunk(conn->out_buffer); #else { trunk = swConnection_get_out_buffer(conn, SW_TRUNK_DATA); #endif buf_size = conn->out_buffer->trunk_size - trunk->length; #ifdef SW_REACTOR_DIRECT_SEND append_out_buffer: #else //listen EPOLLOUT event reactor->set(reactor, resp->info.fd, SW_EVENT_TCP | SW_EVENT_WRITE | SW_EVENT_READ); #endif do { copy_n = (buf_size >= send_data.info.len) ? send_data.info.len : buf_size; memcpy(trunk->data, send_data.data, copy_n); send_data.data += copy_n; send_data.info.len -= copy_n; trunk->length += copy_n; buf_size += copy_n; //trunk is full, create new trunk if (trunk->length == conn->out_buffer->trunk_size) { //trunk no enough space, creating a new trunk trunk = swBuffer_new_trunk(conn->out_buffer, SW_TRUNK_DATA); if (trunk == NULL) { swWarn("append to out_buffer failed."); return SW_ERR; } buf_size = conn->out_buffer->trunk_size; } } while(send_data.info.len > 0); } #ifdef SW_REACTOR_DIRECT_SEND else { //try send int ret = swWrite(send_data.info.fd, send_data.data, send_data.info.len); if (ret < 0) { //连接已被关闭 if (errno == ECONNRESET || errno == EBADF) { goto close_fd; } swWarn("factory->onFinish failed.fd=%d|from_id=%d. Error: %s[%d]", resp->info.fd, resp->info.from_id, strerror(errno), errno); } //Did not finish, add to writable event callback else if(ret < resp->info.len) { trunk = swConnection_get_out_buffer(conn, SW_TRUNK_DATA); send_data.data += ret; send_data.info.len -= ret; buf_size = conn->out_buffer->trunk_size; goto append_out_buffer; } //printf("[writer]pop.fd=%d|from_id=%d|data=%s\n", resp->info.fd, resp->info.from_id, resp->data); } #endif }