/** * Only for synchronous client */ static int swClient_tcp_recv_no_buffer(swClient *cli, char *data, int len, int flag) { int ret; while (1) { ret = swConnection_recv(cli->socket, data, len, flag); if (ret >= 0) { break; } if (errno == EINTR) { continue; } #ifdef SW_USE_OPENSSL if (errno == EAGAIN && cli->socket->ssl) { int timeout_ms = (int) (cli->timeout * 1000); if (cli->socket->ssl_want_read && swSocket_wait(cli->socket->fd, timeout_ms, SW_EVENT_READ) == SW_OK) { continue; } else if (cli->socket->ssl_want_write && swSocket_wait(cli->socket->fd, timeout_ms, SW_EVENT_WRITE) == SW_OK) { continue; } } #endif break; } return ret; }
int swSocket_sendto_blocking(int fd, void *__buf, size_t __n, int flag, struct sockaddr *__addr, socklen_t __addr_len) { int n = 0; while (1) { n = sendto(fd, __buf, __n, flag, __addr, __addr_len); if (n >= 0) { break; } else { if (errno == EINTR) { continue; } else if (errno == EAGAIN) { swSocket_wait(fd, 1000, SW_EVENT_WRITE); continue; } else { break; } } } return n; }
static int swClient_tcp_recv_no_buffer(swClient *cli, char *data, int len, int waitall) { int flag = 0, ret; if (waitall == 1) { flag = MSG_WAITALL; } #ifdef SW_CLIENT_SOCKET_WAIT if (cli->socket->socket_wait) { swSocket_wait(cli->socket->fd, cli->timeout_ms, SW_EVENT_READ); } #endif ret = recv(cli->socket->fd, data, len, flag); if (ret < 0) { if (errno == EINTR) { ret = recv(cli->socket->fd, data, len, flag); } else { return SW_ERR; } } return ret; }
int swConnection_send_blocking(int fd, void *data, int length, int timeout) { int n, writen = length; while (writen > 0) { if (swSocket_wait(fd, timeout, SW_EVENT_WRITE) < 0) { return SW_ERR; } else { n = send(fd, data, writen, MSG_NOSIGNAL | MSG_DONTWAIT); if (n < 0) { swWarn("send() failed. Error: %s[%d]", strerror(errno), errno); return SW_ERR; } else { writen -= n; continue; } } } return 0; }
static int swClient_tcp_send_sync(swClient *cli, char *data, int length, int flags) { int written = 0; int n; assert(length > 0); assert(data != NULL); while (written < length) { n = swConnection_send(cli->socket, data, length - written, flags); if (n < 0) { if (errno == EINTR) { continue; } else if (errno == EAGAIN) { swSocket_wait(cli->socket->fd, 1000, SW_EVENT_WRITE); continue; } else { return SW_ERR; } } written += n; data += n; } return written; }
static int swPipeEventfd_read(swPipe *p, void *data, int length) { int ret = -1; swPipeEventfd *object = p->object; //eventfd not support socket timeout if (p->blocking == 1 && p->timeout > 0) { if (swSocket_wait(object->event_fd, p->timeout * 1000, SW_EVENT_READ) < 0) { return SW_ERR; } } while (1) { ret = read(object->event_fd, data, sizeof(uint64_t)); if (ret < 0 && errno == EINTR) { continue; } break; } return ret; }
int swSocket_write_blocking(int __fd, void *__data, int __len) { int n = 0; int written = 0; while (written < __len) { n = write(__fd, (char *) __data + written, __len - written); if (n < 0) { if (errno == EINTR) { continue; } else if (swConnection_error(errno) == SW_WAIT) { swSocket_wait(__fd, SW_WORKER_WAIT_TIMEOUT, SW_EVENT_WRITE); continue; } else { swSysError("write %d bytes failed.", __len); return SW_ERR; } } written += n; } return written; }
int swSocket_write_blocking(int __fd, void *__data, int __len) { int n = 0; int written = 0; while (written < __len) { n = write(__fd, __data + written, __len - written); if (n < 0) { if (errno == EINTR) { continue; } #ifdef HAVE_KQUEUE else if (errno == EAGAIN || errno == ENOBUFS) #else else if (errno == EAGAIN) #endif { swSocket_wait(__fd, SW_WORKER_WAIT_TIMEOUT, SW_EVENT_WRITE); continue; } else { swSysError("write %d bytes failed.", __len); return SW_ERR; } } written += n; } return written; }
/** * dispatch data to worker */ int swProcessPool_dispatch(swProcessPool *pool, swEventData *data, int worker_id) { int ret; //no worker_id, will round if (worker_id < 0) { worker_id = (pool->round_id++)%pool->worker_num; } struct { long mtype; swEventData buf; } in; if (pool->use_msgqueue) { in.mtype = worker_id + 1; memcpy(&in.buf, data, sizeof(data->info) + data->info.len); ret = pool->queue.in(&pool->queue, (swQueue_data *) &in, sizeof(data->info) + data->info.len); if (ret < 0) { swWarn("msgsnd failed. Error: %s[%d]", strerror(errno), errno); } } else { swWorker *worker = &swProcessPool_worker(pool, worker_id); while(1) { ret = write(worker->pipe_master, data, sizeof(data->info) + data->info.len); if (ret < 0) { /** * Wait pipe can be written. */ if (errno == EAGAIN && swSocket_wait(worker->pipe_master, SW_WORKER_WAIT_TIMEOUT, SW_EVENT_WRITE) == SW_OK) { continue; } else if (errno == EINTR) { continue; } else { break; } } break; } if (ret < 0) { swWarn("sendto unix socket failed. Error: %s[%d]", strerror(errno), errno); } } return ret; }
int swSocket_sendfile_sync(int sock, char *filename, off_t offset, size_t length, double timeout) { int timeout_ms = timeout < 0 ? -1 : timeout * 1000; int file_fd = open(filename, O_RDONLY); if (file_fd < 0) { swWarn("open(%s) failed. Error: %s[%d]", filename, strerror(errno), errno); return SW_ERR; } if (length == 0) { struct stat file_stat; if (fstat(file_fd, &file_stat) < 0) { swWarn("fstat() failed. Error: %s[%d]", strerror(errno), errno); close(file_fd); return SW_ERR; } length = file_stat.st_size; } else { length = offset + length; } int n, sendn; while (offset < length) { if (swSocket_wait(sock, timeout_ms, SW_EVENT_WRITE) < 0) { close(file_fd); return SW_ERR; } else { sendn = (length - offset > SW_SENDFILE_CHUNK_SIZE) ? SW_SENDFILE_CHUNK_SIZE : length - offset; n = swoole_sendfile(sock, file_fd, &offset, sendn); if (n <= 0) { close(file_fd); swSysError("sendfile(%d, %s) failed.", sock, filename); return SW_ERR; } else { continue; } } } close(file_fd); return SW_OK; }
int swSocket_sendfile_sync(int sock, char *filename, double timeout) { int timeout_ms = timeout < 0 ? -1 : timeout * 1000; int file_fd = open(filename, O_RDONLY); if (file_fd < 0) { swWarn("open(%s) failed. Error: %s[%d]", filename, strerror(errno), errno); return SW_ERR; } struct stat file_stat; if (fstat(file_fd, &file_stat) < 0) { swWarn("fstat() failed. Error: %s[%d]", strerror(errno), errno); return SW_ERR; } int n, sendn; off_t offset = 0; size_t file_size = file_stat.st_size; while (offset < file_size) { if (swSocket_wait(sock, timeout_ms, SW_EVENT_WRITE) < 0) { return SW_ERR; } else { sendn = (file_size - offset > SW_SENDFILE_TRUNK) ? SW_SENDFILE_TRUNK : file_size - offset; n = swoole_sendfile(sock, file_fd, &offset, sendn); if (n <= 0) { swWarn("sendfile() failed. Error: %s[%d]", strerror(errno), errno); return SW_ERR; } else { continue; } } } return SW_OK; }
int swConnection_sendfile_blocking(int fd, char *filename, int timeout) { int file_fd = open(filename, O_RDONLY); if (file_fd < 0) { swWarn("open file[%s] failed. Error: %s[%d]", filename, strerror(errno), errno); return SW_ERR; } struct stat file_stat; if (fstat(file_fd, &file_stat) < 0) { swWarn("fstat() failed. Error: %s[%d]", strerror(errno), errno); return SW_ERR; } int n, sendn; off_t offset = 0; size_t file_size = file_stat.st_size; while (offset < file_size) { if (swSocket_wait(fd, timeout, SW_EVENT_WRITE) < 0) { return SW_ERR; } else { sendn = (file_size - offset > SW_SENDFILE_TRUNK) ? SW_SENDFILE_TRUNK : file_size - offset; n = swoole_sendfile(fd, file_fd, &offset, sendn); if (n <= 0) { return SW_ERR; } else { continue; } } } return 0; }
static int swClient_tcp_recv_no_buffer(swClient *cli, char *data, int len, int flag) { #ifdef SW_CLIENT_SOCKET_WAIT if (cli->socket->socket_wait) { swSocket_wait(cli->socket->fd, cli->timeout_ms, SW_EVENT_READ); } #endif int ret = swConnection_recv(cli->socket, data, len, flag); if (ret < 0) { if (errno == EINTR) { ret = swConnection_recv(cli->socket, data, len, flag); } else { return SW_ERR; } } return ret; }
/** * Send the task result to worker */ int swTaskWorker_finish(swServer *serv, char *data, int data_len) { swEventData buf; if (SwooleG.task_worker_num < 1) { swWarn("cannot use task/finish, because no set serv->task_worker_num."); return SW_ERR; } int ret; //for swoole_server_task if (current_task->info.type == SW_TASK_NONBLOCK) { buf.info.type = SW_EVENT_FINISH; buf.info.fd = current_task->info.fd; //write to file if (data_len >= sizeof(buf.data)) { if (swTaskWorker_large_pack(&buf, data, data_len) < 0 ) { swWarn("large task pack failed()"); return SW_ERR; } } else { memcpy(buf.data, data, data_len); buf.info.len = data_len; buf.info.from_fd = 0; } //tasking /** * TODO: 这里需要重构,改成统一的模式 */ if (serv->factory_mode == SW_MODE_PROCESS) { ret = swServer_send2worker_blocking(serv, &buf, sizeof(buf.info) + buf.info.len, current_task->info.from_id); } else { ret = swWrite(SwooleG.event_workers->workers[current_task->info.from_id].pipe_worker, &buf, sizeof(buf.info) + data_len); } } else { uint64_t flag = 1; uint16_t worker_id = current_task->info.from_id; /** * Use worker shm store the result */ swEventData *result = &(SwooleG.task_result[worker_id]); swPipe *task_notify_pipe = &(SwooleG.task_notify[worker_id]); result->info.type = SW_EVENT_FINISH; result->info.fd = current_task->info.fd; if (data_len >= sizeof(buf.data)) { if (swTaskWorker_large_pack(result, data, data_len) < 0) { swWarn("large task pack failed()"); return SW_ERR; } } else { memcpy(result->data, data, data_len); result->info.len = data_len; result->info.from_fd = 0; } while (1) { ret = task_notify_pipe->write(task_notify_pipe, &flag, sizeof(flag)); if (ret < 0 && errno == EAGAIN) { if (swSocket_wait(task_notify_pipe->getFd(task_notify_pipe, 1), -1, SW_EVENT_WRITE) == 0) { continue; } } break; } } if (ret < 0) { swWarn("TaskWorker: send result to worker failed. Error: %s[%d]", strerror(errno), errno); } return ret; }
/** * worker: send to client */ int swFactoryProcess_finish(swFactory *factory, swSendData *resp) { int ret, sendn, count; swServer *serv = factory->ptr; int fd = resp->info.fd; //unix dgram if (resp->info.type == SW_EVENT_UNIX_DGRAM) { socklen_t len; struct sockaddr_un addr_un; int from_sock = resp->info.from_fd; addr_un.sun_family = AF_UNIX; memcpy(addr_un.sun_path, resp->sun_path, resp->sun_path_len); len = sizeof(addr_un); ret = swSendto(from_sock, resp->data, resp->info.len, 0, (struct sockaddr *) &addr_un, len); goto finish; } //UDP pacakge else if (resp->info.type == SW_EVENT_UDP || resp->info.type == SW_EVENT_UDP6) { ret = swServer_udp_send(serv, resp); goto finish; } //swQueue_data for msg queue struct { long pti; swEventData _send; } sdata; //for message queue sdata.pti = (SwooleWG.id % serv->writer_num) + 1; swConnection *conn = swServer_connection_get(serv, fd); if (conn == NULL || conn->active == 0) { swWarn("connection[%d] not found.", fd); return SW_ERR; } sdata._send.info.fd = fd; sdata._send.info.type = resp->info.type; swWorker *worker = swServer_get_worker(serv, SwooleWG.id); /** * Big response, use shared memory */ if (resp->length > 0) { int64_t wait_reactor; /** * Storage is in use right now, wait notify. */ if (worker->store.lock == 1) { worker->notify->read(worker->notify, &wait_reactor, sizeof(wait_reactor)); } swPackage_response response; response.length = resp->length; response.worker_id = SwooleWG.id; //swWarn("BigPackage, length=%d|worker_id=%d", response.length, response.worker_id); sdata._send.info.from_fd = SW_RESPONSE_BIG; sdata._send.info.len = sizeof(response); memcpy(sdata._send.data, &response, sizeof(response)); /** * Lock the worker storage */ worker->store.lock = 1; memcpy(worker->store.ptr, resp->data, resp->length); } else { //copy data memcpy(sdata._send.data, resp->data, resp->info.len); sdata._send.info.len = resp->info.len; sdata._send.info.from_fd = SW_RESPONSE_SMALL; } #if SW_REACTOR_SCHEDULE == 2 sdata._send.info.from_id = fd % serv->reactor_num; #else sdata._send.info.from_id = conn->from_id; #endif sendn = sdata._send.info.len + sizeof(resp->info); //swWarn("send: sendn=%d|type=%d|content=%s", sendn, resp->info.type, resp->data); swTrace("[Worker]input_queue[%ld]->in| fd=%d", sdata.pti, fd); for (count = 0; count < SW_WORKER_SENDTO_COUNT; count++) { if (serv->ipc_mode == SW_IPC_MSGQUEUE) { ret = serv->write_queue.in(&serv->write_queue, (swQueue_data *) &sdata, sendn); } else { int master_pipe = swWorker_get_write_pipe(serv, fd); //swWarn("send to reactor. fd=%d|pipe=%d|reactor_id=%d|reactor_pipe_num=%d", fd, master_pipe, conn->from_id, serv->reactor_pipe_num); ret = write(master_pipe, &sdata._send, sendn); #ifdef SW_WORKER_WAIT_PIPE if (ret < 0 && errno == EAGAIN) { /** * Wait pipe can be written. */ if (swSocket_wait(master_pipe, SW_WORKER_WAIT_TIMEOUT, SW_EVENT_WRITE) == SW_OK) { continue; } else { goto finish; } } #endif } //swTraceLog("wt_queue->in: fd=%d|from_id=%d|data=%s|ret=%d|errno=%d", sdata._send.info.fd, sdata._send.info.from_id, sdata._send.data, ret, errno); if (ret >= 0) { break; } else if (errno == EINTR) { continue; } else if (errno == EAGAIN) { swYield(); } else { break; } } finish: if (ret < 0) { swWarn("sendto to reactor failed. Error: %s [%d]", strerror(errno), errno); } return ret; }
/** * Send the task result to worker */ int swTaskWorker_finish(swServer *serv, char *data, int data_len, int flags) { swEventData buf; if (!current_task) { swWarn("cannot use finish in worker"); return SW_ERR; } if (serv->task_worker_num < 1) { swWarn("cannot use task/finish, because no set serv->task_worker_num."); return SW_ERR; } if (current_task->info.type == SW_EVENT_PIPE_MESSAGE) { swWarn("task/finish is not supported in onPipeMessage callback."); return SW_ERR; } uint16_t source_worker_id = current_task->info.from_id; swWorker *worker = swServer_get_worker(serv, source_worker_id); if (worker == NULL) { swWarn("invalid worker_id[%d].", source_worker_id); return SW_ERR; } int ret; //for swoole_server_task if (swTask_type(current_task) & SW_TASK_NONBLOCK) { buf.info.type = SW_EVENT_FINISH; buf.info.fd = current_task->info.fd; //callback function if (swTask_type(current_task) & SW_TASK_CALLBACK) { flags |= SW_TASK_CALLBACK; } else if (swTask_type(current_task) & SW_TASK_COROUTINE) { flags |= SW_TASK_COROUTINE; } swTask_type(&buf) = flags; //write to file if (data_len >= SW_IPC_MAX_SIZE - sizeof(buf.info)) { if (swTaskWorker_large_pack(&buf, data, data_len) < 0 ) { swWarn("large task pack failed()"); return SW_ERR; } } else { memcpy(buf.data, data, data_len); buf.info.len = data_len; } if (worker->pool->use_socket && worker->pool->stream->last_connection > 0) { int32_t _len = htonl(data_len); ret = swSocket_write_blocking(worker->pool->stream->last_connection, (void *) &_len, sizeof(_len)); if (ret > 0) { ret = swSocket_write_blocking(worker->pool->stream->last_connection, data, data_len); } } else { ret = swWorker_send2worker(worker, &buf, sizeof(buf.info) + buf.info.len, SW_PIPE_MASTER); } } else { uint64_t flag = 1; /** * Use worker shm store the result */ swEventData *result = &(serv->task_result[source_worker_id]); swPipe *task_notify_pipe = &(serv->task_notify[source_worker_id]); //lock worker worker->lock.lock(&worker->lock); if (swTask_type(current_task) & SW_TASK_WAITALL) { sw_atomic_t *finish_count = (sw_atomic_t*) result->data; char *_tmpfile = result->data + 4; int fd = open(_tmpfile, O_APPEND | O_WRONLY); if (fd >= 0) { buf.info.type = SW_EVENT_FINISH; buf.info.fd = current_task->info.fd; swTask_type(&buf) = flags; //result pack if (data_len >= SW_IPC_MAX_SIZE - sizeof(buf.info)) { if (swTaskWorker_large_pack(&buf, data, data_len) < 0) { swWarn("large task pack failed()"); buf.info.len = 0; } } else { buf.info.len = data_len; memcpy(buf.data, data, data_len); } //write to tmpfile if (swoole_sync_writefile(fd, &buf, sizeof(buf.info) + buf.info.len) < 0) { swSysError("write(%s, %ld) failed.", _tmpfile, sizeof(buf.info) + buf.info.len); } sw_atomic_fetch_add(finish_count, 1); close(fd); } } else { result->info.type = SW_EVENT_FINISH; result->info.fd = current_task->info.fd; swTask_type(result) = flags; if (data_len >= SW_IPC_MAX_SIZE - sizeof(buf.info)) { if (swTaskWorker_large_pack(result, data, data_len) < 0) { //unlock worker worker->lock.unlock(&worker->lock); swWarn("large task pack failed()"); return SW_ERR; } } else { memcpy(result->data, data, data_len); result->info.len = data_len; } } //unlock worker worker->lock.unlock(&worker->lock); while (1) { ret = task_notify_pipe->write(task_notify_pipe, &flag, sizeof(flag)); #ifdef HAVE_KQUEUE if (ret < 0 && (errno == EAGAIN || errno == ENOBUFS)) #else if (ret < 0 && errno == EAGAIN) #endif { if (swSocket_wait(task_notify_pipe->getFd(task_notify_pipe, 1), -1, SW_EVENT_WRITE) == 0) { continue; } } break; } } if (ret < 0) { swWarn("TaskWorker: send result to worker failed. Error: %s[%d]", strerror(errno), errno); } return ret; }
/** * Send the task result to worker */ int swTaskWorker_finish(swServer *serv, char *data, int data_len, int flags) { swEventData buf; if (SwooleG.task_worker_num < 1) { swWarn("cannot use task/finish, because no set serv->task_worker_num."); return SW_ERR; } int ret; //for swoole_server_task if (swTask_type(current_task) & SW_TASK_NONBLOCK) { buf.info.type = SW_EVENT_FINISH; buf.info.fd = current_task->info.fd; swTask_type(&buf) = flags; //write to file if (data_len >= SW_IPC_MAX_SIZE - sizeof(buf.info)) { if (swTaskWorker_large_pack(&buf, data, data_len) < 0 ) { swWarn("large task pack failed()"); return SW_ERR; } } else { memcpy(buf.data, data, data_len); buf.info.len = data_len; } uint16_t target_worker_id = current_task->info.from_id; swWorker *worker = swServer_get_worker(serv, target_worker_id); ret = swWorker_send2worker(worker, &buf, sizeof(buf.info) + buf.info.len, SW_PIPE_MASTER); } else { uint64_t flag = 1; uint16_t worker_id = current_task->info.from_id; /** * Use worker shm store the result */ swEventData *result = &(SwooleG.task_result[worker_id]); swPipe *task_notify_pipe = &(SwooleG.task_notify[worker_id]); result->info.type = SW_EVENT_FINISH; result->info.fd = current_task->info.fd; swTask_type(result) = flags; if (data_len >= SW_IPC_MAX_SIZE - sizeof(buf.info)) { if (swTaskWorker_large_pack(result, data, data_len) < 0) { swWarn("large task pack failed()"); return SW_ERR; } } else { memcpy(result->data, data, data_len); result->info.len = data_len; } while (1) { ret = task_notify_pipe->write(task_notify_pipe, &flag, sizeof(flag)); #ifdef HAVE_KQUEUE if (errno == EAGAIN || errno == ENOBUFS) #else if (errno == EAGAIN) #endif { if (swSocket_wait(task_notify_pipe->getFd(task_notify_pipe, 1), -1, SW_EVENT_WRITE) == 0) { continue; } } break; } } if (ret < 0) { swWarn("TaskWorker: send result to worker failed. Error: %s[%d]", strerror(errno), errno); } return ret; }