int check_msg(client_t* client, msg_t* msg) { size_t msg_data_len; if (msg->zone.clip) { if (msg->zone.last) msg_data_len = msg_data_length(msg) % client->max_length; else msg_data_len = client->max_length; } else msg_data_len = msg_data_length(msg); if (checksum(msg, sizeof(msg_t) + msg_data_len)) { SYSLOG(LOG_ERR, "Invalid msg"); return 0; } return 1; }
int process_clip_msg(local_fd_type fd, client_t* client, msg_t* msg, size_t* room_id) { size_t i; unsigned int ident = ntohl(msg->ident); size_t all_len = msg_data_length(msg); msg_group_t* group = msg_group_lookup(&client->recv_table, ident); if (!msg->zone.clip) return 0; if (group == NULL) { group = group_pool_room_alloc(&qtun->group_pool, sizeof(msg_group_t)); if (group == NULL) { SYSLOG(LOG_ERR, "Not enough memory"); return 0; } group->count = (unsigned short)ceil((double)all_len / client->max_length); group->elements = group_pool_room_alloc(&qtun->group_pool, sizeof(msg_t*) * group->count); memset(group->elements, 0, sizeof(msg_t*) * group->count); group->ident = ident; group->ttl_start = qtun->msg_ttl; if (!hash_set(&client->recv_table, (void*)(unsigned long)ident, sizeof(ident), group, sizeof(msg_group_t))) return 0; } if (qtun->msg_ttl - group->ttl_start > MSG_MAX_TTL) return 0; // expired for (i = 0; i < group->count; ++i) { if (group->elements[i] == NULL) // 收包顺序可能与发包顺序不同 { size_t this_len = sizeof(msg_t) + (msg->zone.last ? all_len % client->max_length : client->max_length); msg_t* dup = group_pool_room_alloc(&qtun->group_pool, this_len); if (dup == NULL) break; memcpy(dup, msg, this_len); group->elements[i] = dup; if (i == group->count - 1) { void* buffer = NULL; unsigned short len = 0; if (parse_msg_group(client->max_length, group, &buffer, &len, room_id)) { ssize_t written; #ifdef WIN32 WriteFile(fd, buffer, len, &written, NULL); #else written = write(fd, buffer, len); #endif SYSLOG(LOG_INFO, "write local length: %ld", written); pool_room_free(&qtun->pool, *room_id); } else SYSLOG(LOG_WARNING, "Parse message error"); hash_del(&client->recv_table, (void*)(unsigned long)ident, sizeof(ident)); } break; } } return 1; }
static void tcp_process(fd_set* set, vector_t* for_del) { active_vector_iterator_t iter = active_vector_begin(&this.clients); while (!active_vector_is_end(iter)) { client_t* client = iter.data; if (FD_ISSET(client->fd, set)) { ssize_t rc = read_pre(client->fd, client->read, client->want); if (rc <= 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) goto end; perror("read"); vector_push_back(for_del, (void*)(long)active_vector_iterator_idx(iter), sizeof(active_vector_iterator_idx(iter))); goto end; } client->read += rc; client->want -= rc; if (client->want == 0) { if (IS_CLIENT_STATUS_WAITING_HEADER(client->status)) { size_t len = msg_data_length((msg_t*)client->buffer); if (len) { msg_t* msg = (msg_t*)client->buffer; client->status = (client->status & ~CLIENT_STATUS_WAITING_HEADER) | CLIENT_STATUS_WAITING_BODY; if (msg->zone.clip) { if (msg->zone.last) client->want = len % client->max_length; else client->want = client->max_length; } else client->want = len; client->buffer_len = sizeof(msg_t) + client->want; client->buffer = group_pool_room_realloc(&this.group_pool, client->buffer, sizeof(msg_t) + client->want); if (client->buffer == NULL) { SYSLOG(LOG_ERR, "Not enough memory"); vector_push_back(for_del, (void*)(long)active_vector_iterator_idx(iter), sizeof(active_vector_iterator_idx(iter))); exit(1); } client->read = ((msg_t*)client->buffer)->data; } else process_msg(client, (msg_t*)client->buffer, for_del, active_vector_iterator_idx(iter)); } else process_msg(client, (msg_t*)client->buffer, for_del, active_vector_iterator_idx(iter)); } } checkout_ttl(&client->recv_table); end: iter = active_vector_next(iter); } }
ssize_t read_msg_t(client_t* client, msg_t** msg, double timeout) { if (qtun->use_udp) { *msg = pool_room_realloc(&qtun->pool, RECV_ROOM_IDX, qtun->recv_buffer_len); return read_t(client, *msg, qtun->recv_buffer_len, timeout); } else { ssize_t rc; size_t len; *msg = pool_room_realloc(&qtun->pool, RECV_ROOM_IDX, sizeof(msg_t)); if (*msg == NULL) return -2; rc = read_t(client, *msg, sizeof(**msg), timeout); if (rc <= 0) { pool_room_free(&qtun->pool, RECV_ROOM_IDX); *msg = NULL; return rc; } len = msg_data_length(*msg); *msg = pool_room_realloc(&qtun->pool, RECV_ROOM_IDX, sizeof(msg_t) + len); if (*msg == NULL) return -2; rc = read_t(client, (*msg)->data, len, timeout); if (rc <= 0 && len) { pool_room_free(&qtun->pool, RECV_ROOM_IDX); *msg = NULL; return rc; } if (checksum(*msg, sizeof(msg_t) + len)) { SYSLOG(LOG_ERR, "Invalid msg"); pool_room_free(&qtun->pool, RECV_ROOM_IDX); *msg = NULL; return -2; } SYSLOG(LOG_INFO, "read msg length: %lu", (unsigned long)len); return rc + sizeof(msg_t); } }
ssize_t send_msg_group(client_t* client, msg_group_t* g) { size_t i; ssize_t written, ret = 0; size_t left, fixed; if (g->count == 0) return -1; left = msg_data_length(g->elements[0]); fixed = qtun->max_length; for (i = 0; i < g->count - 1UL; ++i) { written = write_c(client, g->elements[i], sizeof(msg_t) + fixed); if (written <= 0) return written; ret += written; left -= fixed; } written = write_c(client, g->elements[g->count - 1], sizeof(msg_t) + left); if (written <= 0) return written; return ret + written; }
int connect_server(char* ip, unsigned short port) { int fd, rc; struct sockaddr_in addr = {0}; msg_t* msg; int flag = 1; fd = socket(AF_INET, SOCK_STREAM, 0); if (fd == -1) { perror("socket"); return -1; } addr.sin_family = AF_INET; addr.sin_port = htons(port); if (inet_aton(ip, &addr.sin_addr) == 0) { fprintf(stderr, "Convert ip address error!\n"); close(fd); return -1; } rc = connect(fd, (struct sockaddr*)&addr, sizeof(addr)); if (rc == -1) { perror("connect"); close(fd); return -1; } if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag)) == -1) { perror("setsockopt"); } msg = new_login_msg(this.localip, 0, 1); if (msg) { write_n(fd, msg, sizeof(msg_t) + msg_data_length(msg)); pool_room_free(&this.pool, MSG_ROOM_IDX); if (read_msg_t(fd, &msg, 5) > 0) { unsigned int ip; unsigned char mask; if (msg->compress != this.compress || msg->encrypt != this.encrypt) { fprintf(stderr, "compress algorithm or encrypt algorithm is not same\n"); pool_room_free(&this.pool, RECV_ROOM_IDX); goto end; } if (!parse_login_reply_msg(msg, &ip, &mask)) goto end; pool_room_free(&this.pool, RECV_ROOM_IDX); if (ip == 0) { fprintf(stderr, "Not enough ip address\n"); goto end; } if (ip != this.localip) { struct in_addr a; char saddr[16], daddr[16]; a.s_addr = this.localip; strcpy(saddr, inet_ntoa(a)); a.s_addr = ip; strcpy(daddr, inet_ntoa(a)); fprintf(stderr, "%s is inuse, but %s is not inuse\n", saddr, daddr); goto end; } this.netmask = mask; this.keepalive = time(NULL); return fd; } fprintf(stderr, "read sys_login_reply message timeouted\n"); goto end; } fprintf(stderr, "Not enough memory\n"); end: close(fd); return -1; }
static int client_process(int max, fd_set* set, int remotefd, int localfd) { msg_t* msg; if (FD_ISSET(localfd, set)) { unsigned char buffer[2048]; ssize_t readen; readen = read(localfd, buffer, sizeof(buffer)); if (readen > 0) { msg = new_msg(buffer, readen); if (msg) { write_n(remotefd, msg, sizeof(msg_t) + msg_data_length(msg)); pool_room_free(&this.pool, MSG_ROOM_IDX); printf("send msg length: %lu\n", msg_data_length(msg)); } } } if (FD_ISSET(remotefd, set)) { ssize_t rc = read_pre(remotefd, this.client.read, this.client.want); if (rc == 0) { fprintf(stderr, "connection closed\n"); return RETURN_CONNECTION_CLOSED; } else if (rc < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) return RETURN_OK; fprintf(stderr, "read error\n"); perror("read"); return RETURN_READ_ERROR; } else { this.client.read += rc; this.client.want -= rc; if (this.client.want == 0) { if (IS_CLIENT_STATUS_WAITING_HEADER(this.client.status)) { size_t len = msg_data_length((msg_t*)this.client.buffer); if (len) { this.client.status = (this.client.status & ~CLIENT_STATUS_WAITING_HEADER) | CLIENT_STATUS_WAITING_BODY; this.client.want = len; this.client.buffer = pool_room_realloc(&this.pool, RECV_ROOM_IDX, sizeof(msg_t) + this.client.want); if (this.client.buffer == NULL) { fprintf(stderr, "Not enough memory\n"); exit(1); } this.client.read = ((msg_t*)this.client.buffer)->data; } else process_msg((msg_t*)this.client.buffer, localfd); } else process_msg((msg_t*)this.client.buffer, localfd); } } } return RETURN_OK; }
static void server_process_login(client_t* client, msg_t* msg, size_t idx, vector_t* for_del) { sys_login_msg_t* login; msg_t* new_msg; int sys; void* data = NULL; unsigned short len; size_t room_id; if (!IS_CLIENT_STATUS_CHECKLOGIN(client->status)) { SYSLOG(LOG_ERR, "Invalid status, want(%d) current(%d)", CLIENT_STATUS_CHECKLOGIN, client->status); close_client(for_del, idx); goto end; } if (msg->compress != this.compress || msg->encrypt != this.encrypt) // 算法不同直接将本地的加密压缩算法返回 { msg->compress = this.compress; msg->encrypt = this.encrypt; msg->checksum = 0; msg->checksum = checksum(msg, sizeof(msg_t) + msg_data_length(msg)); write_c(client, msg, sizeof(msg_t) + msg_data_length(msg)); goto end; } if (!parse_msg(msg, &sys, &data, &len, &room_id)) { SYSLOG(LOG_ERR, "parse sys_login_request failed"); close_client(for_del, idx); goto end; } login = (sys_login_msg_t*)data; if (memcmp(login->check, SYS_MSG_CHECK, sizeof(login->check)) || !check_ip_by_mask(login->ip, this.localip, this.netmask)) // 非法数据包 { SYSLOG(LOG_ERR, "unknown sys_login_request message"); close_client(for_del, idx); goto end; } if (login->ip == this.localip || active_vector_exists(&this.clients, compare_clients_by_local_ip, (void*)(long)login->ip, sizeof(login->ip)) >= 0) // IP已被占用 { unsigned short i; unsigned int localip = login->ip & LEN2MASK(this.netmask); for (i = 1; i < LEN2MASK(32 - this.netmask); ++i) { unsigned int newip = (i << this.netmask) | localip; if (active_vector_exists(&this.clients, compare_clients_by_local_ip, (void*)(long)newip, sizeof(newip)) == -1 && newip != this.localip) { pool_room_free(&this.pool, room_id); data = NULL; new_msg = new_login_msg(newip, 0, this.netmask, 0); if (new_msg) { write_c(client, new_msg, sizeof(msg_t) + msg_data_length(new_msg)); pool_room_free(&this.pool, MSG_ROOM_IDX); } else { SYSLOG(LOG_ERR, "Can not create login message"); close_client(for_del, idx); } goto end; } } pool_room_free(&this.pool, room_id); data = NULL; new_msg = new_login_msg(0, 0, 0, 0); if (new_msg) { write_c(client, new_msg, sizeof(msg_t) + msg_data_length(new_msg)); pool_room_free(&this.pool, MSG_ROOM_IDX); } else { SYSLOG(LOG_ERR, "Can not create login message"); close_client(for_del, idx); } } else { unsigned int remote_ip = login->ip; unsigned short internal_mtu = ntohs(login->internal_mtu); pool_room_free(&this.pool, room_id); data = NULL; new_msg = new_login_msg(remote_ip, this.localip, this.netmask, 0); if (new_msg == NULL) { SYSLOG(LOG_ERR, "Can not create login message"); close_client(for_del, idx); goto end; } client->local_ip = remote_ip; client->keepalive = (unsigned int)time(NULL); client->internal_mtu = internal_mtu; client->max_length = ROUND_UP(client->internal_mtu - sizeof(msg_t) - sizeof(struct iphdr) - (this.use_udp ? sizeof(struct udphdr) : sizeof(struct tcphdr)), 8); client->status = CLIENT_STATUS_NORMAL; if (this.use_udp && client->max_length + sizeof(msg_t) > this.recv_buffer_len) { this.recv_buffer_len = client->max_length + sizeof(msg_t); this.recv_buffer = pool_room_realloc(&this.pool, RECV_ROOM_IDX, this.recv_buffer_len); if (this.recv_buffer == NULL) { SYSLOG(LOG_INFO, "Not enough memory"); close_client(for_del, idx); goto end; } } #ifdef WIN32 // 将对端内网IP添加到ARP表 { char cmd[1024]; char str[16]; struct in_addr a; a.s_addr = remote_ip; strcpy(str, inet_ntoa(a)); sprintf(cmd, "arp -s %s ff-ff-ff-ff-ff-ff", str); // TODO: get mac from remote SYSTEM_NORMAL(cmd); } #endif write_c(client, new_msg, sizeof(msg_t) + msg_data_length(new_msg)); pool_room_free(&this.pool, MSG_ROOM_IDX); } end: if (data) pool_room_free(&this.pool, room_id); }