/*! Duplicates an FD from another team to this/the kernel team. \param fromTeam The team which owns the FD. \param fd The FD to duplicate. \param kernel If \c true, the new FD will be created in the kernel team, the current userland team otherwise. \return The newly created FD or an error code, if something went wrong. */ int dup_foreign_fd(team_id fromTeam, int fd, bool kernel) { // get the I/O context for the team in question Team* team = Team::Get(fromTeam); if (team == NULL) return B_BAD_TEAM_ID; BReference<Team> teamReference(team, true); io_context* fromContext = team->io_context; // get the file descriptor file_descriptor* descriptor = get_fd(fromContext, fd); if (descriptor == NULL) return B_FILE_ERROR; CObjectDeleter<file_descriptor> descriptorPutter(descriptor, put_fd); // create a new FD in the target I/O context int result = new_fd(get_current_io_context(kernel), descriptor); if (result >= 0) { // the descriptor reference belongs to the slot, now descriptorPutter.Detach(); } return result; }
static int create_socket_fd(net_socket* socket, bool kernel) { // Get the socket's non-blocking flag, so we can set the respective // open mode flag. int32 nonBlock; socklen_t nonBlockLen = sizeof(int32); status_t error = sStackInterface->getsockopt(socket, SOL_SOCKET, SO_NONBLOCK, &nonBlock, &nonBlockLen); if (error != B_OK) return error; // allocate a file descriptor file_descriptor* descriptor = alloc_fd(); if (descriptor == NULL) return B_NO_MEMORY; // init it descriptor->type = FDTYPE_SOCKET; descriptor->ops = &sSocketFDOps; descriptor->u.socket = socket; descriptor->open_mode = O_RDWR | (nonBlock ? O_NONBLOCK : 0); // publish it int fd = new_fd(get_current_io_context(kernel), descriptor); if (fd < 0) free(descriptor); return fd; }
static int dup_fd(int fd, bool kernel) { struct io_context* context = get_current_io_context(kernel); struct file_descriptor* descriptor; int status; TRACE(("dup_fd: fd = %d\n", fd)); // Try to get the fd structure descriptor = get_fd(context, fd); if (descriptor == NULL) return B_FILE_ERROR; // now put the fd in place status = new_fd(context, descriptor); if (status < 0) put_fd(descriptor); else { mutex_lock(&context->io_mutex); fd_set_close_on_exec(context, status, false); mutex_unlock(&context->io_mutex); } return status; }
/*! Duplicates an FD from another team to this/the kernel team. \param fromTeam The team which owns the FD. \param fd The FD to duplicate. \param kernel If \c true, the new FD will be created in the kernel team, the current userland team otherwise. \return The newly created FD or an error code, if something went wrong. */ int dup_foreign_fd(team_id fromTeam, int fd, bool kernel) { // get the I/O context for the team in question InterruptsSpinLocker teamsLocker(gTeamSpinlock); struct team* team = team_get_team_struct_locked(fromTeam); if (team == NULL) return B_BAD_TEAM_ID; io_context* fromContext = team->io_context; vfs_get_io_context(fromContext); teamsLocker.Unlock(); CObjectDeleter<io_context> _(fromContext, vfs_put_io_context); // get the file descriptor file_descriptor* descriptor = get_fd(fromContext, fd); if (descriptor == NULL) return B_FILE_ERROR; CObjectDeleter<file_descriptor> descriptorPutter(descriptor, put_fd); // create a new FD in the target I/O context int result = new_fd(get_current_io_context(kernel), descriptor); if (result >= 0) { // the descriptor reference belongs to the slot, now descriptorPutter.Detach(); } return result; }
// return 0 when failed static int report_accept(struct socket_server *ss, struct socket *s, struct socket_message *result) { union sockaddr_all u; socklen_t len = sizeof(u); int client_fd = accept(s->fd, &u.s, &len); if (client_fd < 0) { return 0; } int id = reserve_id(ss); if (id < 0) { close(client_fd); return 0; } sp_nonblocking(client_fd); struct socket *ns = new_fd(ss, id, client_fd, s->opaque, false); if (ns == NULL) { close(client_fd); return 0; } ns->type = SOCKET_TYPE_PACCEPT; result->opaque = s->opaque; result->id = s->id; result->ud = id; result->data = NULL; void * sin_addr = (u.s.sa_family == AF_INET) ? (void*)&u.v4.sin_addr : (void *)&u.v6.sin6_addr; if (inet_ntop(u.s.sa_family, sin_addr, ss->buffer, sizeof(ss->buffer))) { result->data = ss->buffer; } return 1; }
// return 0 when failed static int report_accept(struct socket_server *ss, struct socket *s, union socket_message *result) { union sockaddr_all u; socklen_t len = sizeof(u); int client_fd = accept(s->fd, &u.s, &len); if (client_fd < 0) { return 0; } sp_nonblocking(client_fd); struct socket *ns = new_fd(ss, client_fd); if (ns == NULL) { close(client_fd); return 0; } ns->type = SOCKET_TYPE_CONNECTED; result->open.id = ns->id; result->open.session = s->session; result->open.fd = s->fd; result->open.addr = NULL; void * sin_addr = (u.s.sa_family == AF_INET) ? (void*)&u.v4.sin_addr : (void *)&u.v6.sin6_addr; if (inet_ntop(u.s.sa_family, sin_addr, ss->buffer, sizeof(ss->buffer))) { result->open.addr = ss->buffer; } return 1; }
void do_dup2(PCB *pcb){ int fd_old = pcb->registers[5], fd_new = pcb->registers[6]; struct File_Descriptor *new_fd_obj, *old_fd_obj, *curr_fd_obj; if(fd_old == fd_new){ syscall_return(pcb, fd_new); } if(fd_new >= 0 && fd_new < MaxFds && valid_fd(pcb, fd_old, -1)){ old_fd_obj = pcb->fd_table[fd_old]; int close = 0; curr_fd_obj = pcb->fd_table[fd_new]; new_fd_obj = new_fd(fd_new, old_fd_obj->permission); dup_fd(old_fd_obj,new_fd_obj); if(curr_fd_obj != senitel_fd){ close_fd(pcb, fd_new); } pcb->fd_table[new_fd_obj->id] = new_fd_obj; syscall_return(pcb, fd_new); }else{ syscall_return(pcb,-1*EBADF); } }
void do_dup(PCB *pcb) { int fd_old = pcb->registers[5], fd_new; struct File_Descriptor *new_fd_obj, *old_fd_obj; if(valid_fd(pcb, fd_old, -1)) { old_fd_obj = pcb->fd_table[fd_old]; fd_new = next_fd(pcb); if(fd_new > -1) { new_fd_obj = new_fd(fd_new, old_fd_obj->permission); dup_fd(old_fd_obj,new_fd_obj); pcb->fd_table[new_fd_obj->id] = new_fd_obj; } else { syscall_return(pcb, -1*EMFILE); } //printf("process %d duping to new fd %d!\n",pcb->pid, fd_new); syscall_return(pcb, fd_new); } else { syscall_return(pcb,-1*EBADF); } }
// return 0 when failed, or -1 when file limit // static int report_accept(struct socket_server *ss, struct socket *s, struct socket_message *result) { union sockaddr_all u; socklen_t len = sizeof(u); // 生成被动套接字 int client_fd = accept(s->fd, &u.s, &len); if (client_fd < 0) { if (errno == EMFILE || errno == ENFILE) { result->opaque = s->opaque; result->id = s->id; result->ud = 0; result->data = strerror(errno); return -1; } else { return 0; } } // 分配id int id = reserve_id(ss); if (id < 0) { close(client_fd); return 0; } // 设置keepalive和非阻塞 socket_keepalive(client_fd); sp_nonblocking(client_fd); // 创建socket实例 struct socket *ns = new_fd(ss, id, client_fd, PROTOCOL_TCP, s->opaque, false); if (ns == NULL) { close(client_fd); return 0; } // 设置socket类型为PACCEPT ns->type = SOCKET_TYPE_PACCEPT; result->opaque = s->opaque; result->id = s->id; // 服务器套接字id result->ud = id; // 被动套接字id result->data = NULL; // 连接客户端ip地址:port端口 void * sin_addr = (u.s.sa_family == AF_INET) ? (void*)&u.v4.sin_addr : (void *)&u.v6.sin6_addr; int sin_port = ntohs((u.s.sa_family == AF_INET) ? u.v4.sin_port : u.v6.sin6_port); char tmp[INET6_ADDRSTRLEN]; if (inet_ntop(u.s.sa_family, sin_addr, tmp, sizeof(tmp))) { snprintf(ss->buffer, sizeof(ss->buffer), "%s:%d", tmp, sin_port); result->data = ss->buffer; } return 1; }
static int bind_socket(struct socket_server *ss, struct request_bind *request, union socket_message *result) { struct socket *s = new_fd(ss, request->fd); if (s == NULL) { result->error.session = request->session; result->error.id = 0; return SOCKET_ERROR; } sp_nonblocking(request->fd); s->type = SOCKET_TYPE_BIND; result->open.id = s->id; result->open.session = request->session; result->open.fd = request->fd; return SOCKET_OPEN; }
static int bind_socket(struct socket_server *ss, struct request_bind *request, struct socket_message *result) { int id = request->id; result->id = id; result->opaque = request->opaque; result->ud = 0; struct socket *s = new_fd(ss, id, request->fd, request->opaque, true); if (s == NULL) { result->data = NULL; return SOCKET_ERROR; } sp_nonblocking(request->fd); s->type = SOCKET_TYPE_BIND; result->data = "binding"; return SOCKET_OPEN; }
// 绑定其他类型的文件描述符,比如stdin和stdout // 创建socket实例并加入事件循环 static int bind_socket(struct socket_server *ss, struct request_bind *request, struct socket_message *result) { int id = request->id; result->id = id; result->opaque = request->opaque; result->ud = 0; struct socket *s = new_fd(ss, id, request->fd, PROTOCOL_TCP, request->opaque, true); if (s == NULL) { result->data = "reach skynet socket number limit"; return SOCKET_ERROR; } // 套接字设置为非阻塞 sp_nonblocking(request->fd); s->type = SOCKET_TYPE_BIND; result->data = "binding"; return SOCKET_OPEN; }
static int listen_socket(struct socket_server *ss, struct request_listen * request, union socket_message *result) { // only support ipv4 // todo: support ipv6 by getaddrinfo uint32_t addr = INADDR_ANY; if (request->host[0]) { addr=inet_addr(request->host); } int listen_fd = socket(AF_INET, SOCK_STREAM, 0); if (listen_fd < 0) { result->error.id = 0; result->error.session = request->session; return SOCKET_ERROR; } int reuse = 1; if (setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, (void *)&reuse, sizeof(int))==-1) { goto _failed; } struct sockaddr_in my_addr; memset(&my_addr, 0, sizeof(struct sockaddr_in)); my_addr.sin_family = AF_INET; my_addr.sin_port = htons(request->port); my_addr.sin_addr.s_addr = addr; if (bind(listen_fd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) { goto _failed; } if (listen(listen_fd, request->backlog) == -1) { goto _failed; } struct socket *s = new_fd(ss, listen_fd); if (s == NULL) { goto _failed; } s->type = SOCKET_TYPE_LISTEN; s->session = request->session; return -1; _failed: close(listen_fd); result->error.id = 0; result->error.session = request->session; return SOCKET_ERROR; }
static void add_udp_socket(struct socket_server *ss, struct request_udp *udp) { int id = udp->id; int protocol; if (udp->family == AF_INET6) { protocol = PROTOCOL_UDPv6; } else { protocol = PROTOCOL_UDP; } struct socket *ns = new_fd(ss, id, udp->fd, protocol, udp->opaque, true); if (ns == NULL) { close(udp->fd); ss->slot[HASH_ID(id)].type = SOCKET_TYPE_INVALID; return; } ns->type = SOCKET_TYPE_CONNECTED; memset(ns->p.udp_address, 0, sizeof(ns->p.udp_address)); }
static int listen_socket(struct socket_server *ss, struct request_listen * request, struct socket_message *result) { int id = request->id; int listen_fd = request->fd; struct socket *s = new_fd(ss, id, listen_fd, request->opaque, false); if (s == NULL) { goto _failed; } s->type = SOCKET_TYPE_PLISTEN; return -1; _failed: close(listen_fd); result->opaque = request->opaque; result->id = id; result->ud = 0; result->data = NULL; ss->slot[HASH_ID(id)].type = SOCKET_TYPE_INVALID; return SOCKET_ERROR; }
// 监听套接字 static int listen_socket(struct socket_server *ss, struct request_listen * request, struct socket_message *result) { int id = request->id; int listen_fd = request->fd; // 创建socket实例,并修改为PListen类型 struct socket *s = new_fd(ss, id, listen_fd, PROTOCOL_TCP, request->opaque, false); if (s == NULL) { goto _failed; } s->type = SOCKET_TYPE_PLISTEN; return -1; _failed: close(listen_fd); result->opaque = request->opaque; result->id = id; result->ud = 0; result->data = "reach skynet socket number limit"; ss->slot[HASH_ID(id)].type = SOCKET_TYPE_INVALID; return SOCKET_ERROR; }
// return 0 when failed static int report_accept(struct socket_server *ss, struct socket *s, struct socket_message *result) { union sockaddr_all u; socklen_t len = sizeof(u); int client_fd = accept(s->fd, &u.s, &len); if (client_fd < 0) { //printf("accept error : %s\n", strerror(errno)); return 0; } int id = reserve_id(ss); if (id < 0) { close(client_fd); return 0; } socket_keepalive(client_fd); sp_nonblocking(client_fd); struct socket *ns = new_fd(ss, id, client_fd, s->opaque, false); if (ns == NULL) { close(client_fd); return 0; } ns->type = SOCKET_TYPE_PACCEPT; result->opaque = s->opaque; result->id = s->id; result->ud = id; result->data = NULL; void * sin_addr = (u.s.sa_family == AF_INET) ? (void*)&u.v4.sin_addr : (void *)&u.v6.sin6_addr; int sin_port = ntohs((u.s.sa_family == AF_INET) ? u.v4.sin_port : u.v6.sin6_port); char tmp[INET6_ADDRSTRLEN]; if (inet_ntop(u.s.sa_family, sin_addr, tmp, sizeof(tmp))) { snprintf(ss->buffer, sizeof(ss->buffer), "%s:%d", tmp, sin_port); result->data = ss->buffer; } return 1; }
// return -1 when connecting // 打开套接字 // 正常返回 SOCKET_OPEN // 其他返回 -1,包括 连接中 的情况 static int open_socket(struct socket_server *ss, struct request_open * request, struct socket_message *result) { int id = request->id; result->opaque = request->opaque; result->id = id; result->ud = 0; result->data = NULL; struct socket *ns; int status; struct addrinfo ai_hints; struct addrinfo *ai_list = NULL; struct addrinfo *ai_ptr = NULL; char port[16]; sprintf(port, "%d", request->port); memset(&ai_hints, 0, sizeof( ai_hints ) ); // 地址族暂不指定 ai_hints.ai_family = AF_UNSPEC; ai_hints.ai_socktype = SOCK_STREAM; ai_hints.ai_protocol = IPPROTO_TCP; // host和port获取地址,支持ipv4和ipv6 status = getaddrinfo( request->host, port, &ai_hints, &ai_list ); if ( status != 0 ) { result->data = (void *)gai_strerror(status); goto _failed; } int sock= -1; for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next ) { // 创建socket套接字 sock = socket( ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol ); if ( sock < 0 ) { continue; } // 设置keepalive和非阻塞 socket_keepalive(sock); sp_nonblocking(sock); // 连接套接字 status = connect( sock, ai_ptr->ai_addr, ai_ptr->ai_addrlen); if ( status != 0 && errno != EINPROGRESS) { // O_NONBLOCK is set for the file descriptor for the socket and the connection cannot be immediately established; the connection shall be established asynchronously. // 当套接字被设置为非阻塞后,连接不会被立即建立,所以errno会返回EINPROGRESS close(sock); sock = -1; continue; } break; } if (sock < 0) { result->data = strerror(errno); goto _failed; } // 创建socket实例 ns = new_fd(ss, id, sock, PROTOCOL_TCP, request->opaque, true); if (ns == NULL) { close(sock); result->data = "reach skynet socket number limit"; goto _failed; } if(status == 0) { // socket修改为已连接类型 ns->type = SOCKET_TYPE_CONNECTED; struct sockaddr * addr = ai_ptr->ai_addr; // 区分ipv4和ipv6,ip地址放入result->data void * sin_addr = (ai_ptr->ai_family == AF_INET) ? (void*)&((struct sockaddr_in *)addr)->sin_addr : (void*)&((struct sockaddr_in6 *)addr)->sin6_addr; if (inet_ntop(ai_ptr->ai_family, sin_addr, ss->buffer, sizeof(ss->buffer))) { result->data = ss->buffer; } freeaddrinfo( ai_list ); return SOCKET_OPEN; } else { // socket修改为连接中类型,在socket_server_poll方法中调用report_connect方法修改为SOCKET_TYPE_CONNECTED,并返回SOCKET_OPEN ns->type = SOCKET_TYPE_CONNECTING; // 打开事件循环中fd的可写权限 sp_write(ss->event_fd, ns->fd, ns, true); } freeaddrinfo( ai_list ); return -1; _failed: freeaddrinfo( ai_list ); ss->slot[HASH_ID(id)].type = SOCKET_TYPE_INVALID; return SOCKET_ERROR; }
// return -1 when connecting static int open_socket(struct socket_server *ss, struct request_open * request, struct socket_message *result) { int id = request->id; result->opaque = request->opaque; result->id = id; result->ud = 0; result->data = NULL; struct socket *ns; int status; struct addrinfo ai_hints; struct addrinfo *ai_list = NULL; struct addrinfo *ai_ptr = NULL; char port[16]; sprintf(port, "%d", request->port); memset( &ai_hints, 0, sizeof( ai_hints ) ); ai_hints.ai_family = AF_UNSPEC; ai_hints.ai_socktype = SOCK_STREAM; ai_hints.ai_protocol = IPPROTO_TCP; status = getaddrinfo( request->host, port, &ai_hints, &ai_list ); if ( status != 0 ) { goto _failed; } int sock= -1; for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next ) { sock = socket( ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol ); if ( sock < 0 ) { continue; } socket_keepalive(sock); sp_nonblocking(sock); status = connect( sock, ai_ptr->ai_addr, ai_ptr->ai_addrlen); if ( status != 0 && errno != EINPROGRESS) { close(sock); sock = -1; continue; } break; } if (sock < 0) { goto _failed; } ns = new_fd(ss, id, sock, request->opaque, true); if (ns == NULL) { close(sock); goto _failed; } if(status == 0) { ns->type = SOCKET_TYPE_CONNECTED; struct sockaddr * addr = ai_ptr->ai_addr; void * sin_addr = (ai_ptr->ai_family == AF_INET) ? (void*)&((struct sockaddr_in *)addr)->sin_addr : (void*)&((struct sockaddr_in6 *)addr)->sin6_addr; if (inet_ntop(ai_ptr->ai_family, sin_addr, ss->buffer, sizeof(ss->buffer))) { result->data = ss->buffer; } freeaddrinfo( ai_list ); return SOCKET_OPEN; } else { ns->type = SOCKET_TYPE_CONNECTING; sp_write(ss->event_fd, ns->fd, ns, true); } freeaddrinfo( ai_list ); return -1; _failed: freeaddrinfo( ai_list ); ss->slot[HASH_ID(id)].type = SOCKET_TYPE_INVALID; return SOCKET_ERROR; }