ambrop7 15 лет назад
Родитель
Сommit
ff876da29e
1 измененных файлов с 92 добавлено и 57 удалено
  1. 92 57
      server/server.c

+ 92 - 57
server/server.c

@@ -453,6 +453,8 @@ int main (int argc, char *argv[])
             BLog(BLOG_ERROR, "NSS_SetDomesticPolicy failed (%d)", (int)PR_GetError());
             goto fail4;
         }
+        
+        // initialize server cache
         if (SSL_ConfigServerSessionIDCache(0, 0, 0, NULL) != SECSuccess) {
             BLog(BLOG_ERROR, "SSL_ConfigServerSessionIDCache failed (%d)", (int)PR_GetError());
             goto fail4;
@@ -461,7 +463,7 @@ int main (int argc, char *argv[])
         // open server certificate and private key
         if (!open_nss_cert_and_key(options.server_cert_name, &server_cert, &server_key)) {
             BLog(BLOG_ERROR, "Cannot open certificate and key");
-            goto fail4;
+            goto fail4a;
         }
         
         // initialize model SSL fd
@@ -526,6 +528,8 @@ fail6:
 fail5:
         CERT_DestroyCertificate(server_cert);
         SECKEY_DestroyPrivateKey(server_key);
+fail4a:
+        SSL_ShutdownServerSessionIDCache();
 fail4:
         ASSERT_FORCE(NSS_Shutdown() == SECSuccess)
 fail3:
@@ -896,7 +900,7 @@ void listener_handler (Listener *listener)
     }
     
     // allocate the client structure
-    struct client_data *client = malloc(sizeof(struct client_data));
+    struct client_data *client = malloc(sizeof(*client));
     if (!client) {
         BLog(BLOG_ERROR, "failed to allocate client");
         goto fail0;
@@ -922,6 +926,8 @@ void client_add (struct client_data *client)
     ASSERT(clients_num < MAX_CLIENTS)
     
     if (options.ssl) {
+        // initialize SSL
+        
         // create BSocket NSPR file descriptor
         BSocketPRFileDesc_Create(&client->bottom_prfd, &client->sock);
         
@@ -949,17 +955,11 @@ void client_add (struct client_data *client)
         
         // initialize BPRFileDesc on SSL file descriptor
         BPRFileDesc_Init(&client->ssl_bprfd, client->ssl_prfd);
-        
-        // set client state
-        client->initstatus = INITSTATUS_HANDSHAKE;
     } else {
-        // initialize i/o chains
+        // initialize I/O
         if (!client_init_io(client)) {
             goto fail0;
         }
-        
-        // set client state
-        client->initstatus = INITSTATUS_WAITHELLO;
     }
     
     // start disconnect timer
@@ -995,6 +995,9 @@ void client_add (struct client_data *client)
     
     // start I/O
     if (options.ssl) {
+        // set client state
+        client->initstatus = INITSTATUS_HANDSHAKE;
+        
         // set read handler for driving handshake
         BPRFileDesc_AddEventHandler(&client->ssl_bprfd, PR_POLL_READ, (BPRFileDesc_handler)client_handshake_read_handler, client);
         
@@ -1002,6 +1005,9 @@ void client_add (struct client_data *client)
         client_try_handshake(client);
         return;
     } else {
+        // set client state
+        client->initstatus = INITSTATUS_WAITHELLO;
+        
         return;
     }
     
@@ -1062,7 +1068,7 @@ static void client_dying_job (struct client_data *client)
     
     LinkedList2Node *node = LinkedList2_GetFirst(&client->know_in_list);
     if (!node) {
-        // deallocate client
+        // notified all clients, deallocate client
         client_dealloc(client);
         return;
     }
@@ -1087,6 +1093,16 @@ void client_dealloc (struct client_data *client)
     ASSERT(LinkedList2_IsEmpty(&client->know_in_list))
     ASSERT(LinkedList2_IsEmpty(&client->peer_out_flows_list))
     
+    // free I/O
+    if (client->initstatus >= INITSTATUS_WAITHELLO && !client->dying) {
+        client_dealloc_io(client);
+    }
+    
+    // free common name
+    if (client->initstatus >= INITSTATUS_WAITHELLO && options.ssl) {
+        PORT_Free(client->common_name);
+    }
+    
     // free publishing
     LinkedList2Iterator_Free(&client->publish_it);
     BPending_Free(&client->publish_job);
@@ -1102,18 +1118,6 @@ void client_dealloc (struct client_data *client)
     // stop disconnect timer
     BReactor_RemoveTimer(&ss, &client->disconnect_timer);
     
-    if (client->initstatus >= INITSTATUS_WAITHELLO) {
-        // free I/O
-        if (!client->dying) {
-            client_dealloc_io(client);
-        }
-        
-        // free common name
-        if (options.ssl) {
-            PORT_Free(client->common_name);
-        }
-    }
-    
     // free SSL
     if (options.ssl) {
         // free BPRFileDesc
@@ -1143,14 +1147,18 @@ void client_log (struct client_data *client, int level, const char *fmt, ...)
 
 void client_disconnect_timer_handler (struct client_data *client)
 {
+    ASSERT(!client->dying)
+    
     client_log(client, BLOG_NOTICE, "timed out");
     
     client_remove(client);
+    return;
 }
 
 void client_try_handshake (struct client_data *client)
 {
     ASSERT(client->initstatus == INITSTATUS_HANDSHAKE)
+    ASSERT(!client->dying)
     
     // attempt handshake
     if (SSL_ForceHandshake(client->ssl_prfd) != SECSuccess) {
@@ -1192,7 +1200,7 @@ void client_try_handshake (struct client_data *client)
     }
     
     // store certificate
-    if (der.len > (unsigned int)sizeof(client->cert)) {
+    if (der.len > sizeof(client->cert)) {
         client_log(client, BLOG_NOTICE, "client certificate too big");
         goto fail2;
     }
@@ -1231,6 +1239,8 @@ fail0:
 
 void client_handshake_read_handler (struct client_data *client, PRInt16 event)
 {
+    ASSERT(client->initstatus == INITSTATUS_HANDSHAKE)
+    ASSERT(!client->dying)
     ASSERT(event == PR_POLL_READ)
     
     // restart no data timer
@@ -1263,11 +1273,8 @@ int client_init_io (struct client_data *client)
     
     // init decoder
     if (!PacketProtoDecoder_Init(
-        &client->input_decoder,
-        FlowErrorReporter_Create(&client->domain, COMPONENT_DECODER),
-        source_interface,
-        &client->input_interface,
-        BReactor_PendingGroup(&ss)
+        &client->input_decoder, FlowErrorReporter_Create(&client->domain, COMPONENT_DECODER),
+        source_interface, &client->input_interface, BReactor_PendingGroup(&ss)
     )) {
         client_log(client, BLOG_ERROR, "PacketProtoDecoder_Init failed");
         goto fail1;
@@ -1276,17 +1283,17 @@ int client_init_io (struct client_data *client)
     // init output common
     
     // init sink
-    StreamPassInterface *sink_input;
+    StreamPassInterface *sink_interface;
     if (options.ssl) {
         PRStreamSink_Init(&client->output_sink.ssl, FlowErrorReporter_Create(&client->domain, COMPONENT_SINK), &client->ssl_bprfd, BReactor_PendingGroup(&ss));
-        sink_input = PRStreamSink_GetInput(&client->output_sink.ssl);
+        sink_interface = PRStreamSink_GetInput(&client->output_sink.ssl);
     } else {
         StreamSocketSink_Init(&client->output_sink.plain, FlowErrorReporter_Create(&client->domain, COMPONENT_SINK), &client->sock, BReactor_PendingGroup(&ss));
-        sink_input = StreamSocketSink_GetInput(&client->output_sink.plain);
+        sink_interface = StreamSocketSink_GetInput(&client->output_sink.plain);
     }
     
     // init sender
-    PacketStreamSender_Init(&client->output_sender, sink_input, PACKETPROTO_ENCLEN(SC_MAX_ENC), BReactor_PendingGroup(&ss));
+    PacketStreamSender_Init(&client->output_sender, sink_interface, PACKETPROTO_ENCLEN(SC_MAX_ENC), BReactor_PendingGroup(&ss));
     
     // init queue
     PacketPassPriorityQueue_Init(&client->output_priorityqueue, PacketStreamSender_GetInput(&client->output_sender), BReactor_PendingGroup(&ss));
@@ -1298,11 +1305,8 @@ int client_init_io (struct client_data *client)
     
     // init PacketProtoFlow
     if (!PacketProtoFlow_Init(
-        &client->output_control_oflow,
-        SC_MAX_ENC,
-        CLIENT_CONTROL_BUFFER_MIN_PACKETS,
-        PacketPassPriorityQueueFlow_GetInput(&client->output_control_qflow),
-        BReactor_PendingGroup(&ss)
+        &client->output_control_oflow, SC_MAX_ENC, CLIENT_CONTROL_BUFFER_MIN_PACKETS,
+        PacketPassPriorityQueueFlow_GetInput(&client->output_control_qflow), BReactor_PendingGroup(&ss)
     )) {
         client_log(client, BLOG_ERROR, "PacketProtoFlow_Init failed");
         goto fail2;
@@ -1444,10 +1448,11 @@ void client_end_control_packet (struct client_data *client, uint8_t type)
     ASSERT(INITSTATUS_HASLINK(client->initstatus))
     ASSERT(!client->dying)
     ASSERT(client->output_control_packet_len >= 0)
+    ASSERT(client->output_control_packet_len <= SC_MAX_PAYLOAD)
     
     // write header
     struct sc_header *header = (struct sc_header *)client->output_control_packet;
-    header->type = type;
+    header->type = htol8(type);
     
     // finish writing packet
     BufferWriter_EndPacket(client->output_control_input, sizeof(struct sc_header) + client->output_control_packet_len);
@@ -1457,6 +1462,11 @@ void client_end_control_packet (struct client_data *client, uint8_t type)
 
 int client_send_newclient (struct client_data *client, struct client_data *nc, int relay_server, int relay_client)
 {
+    ASSERT(client->initstatus == INITSTATUS_COMPLETE)
+    ASSERT(!client->dying)
+    ASSERT(nc->initstatus == INITSTATUS_COMPLETE)
+    ASSERT(!nc->dying)
+    
     int flags = 0;
     if (relay_server) {
         flags |= SCID_NEWCLIENT_FLAG_RELAY_SERVER;
@@ -1481,6 +1491,9 @@ int client_send_newclient (struct client_data *client, struct client_data *nc, i
 
 int client_send_endclient (struct client_data *client, peerid_t end_id)
 {
+    ASSERT(client->initstatus == INITSTATUS_COMPLETE)
+    ASSERT(!client->dying)
+    
     struct sc_server_endclient *pack;
     if (client_start_control_packet(client, (void **)&pack, sizeof(struct sc_server_endclient)) < 0) {
         return -1;
@@ -1493,6 +1506,8 @@ int client_send_endclient (struct client_data *client, peerid_t end_id)
 
 void client_input_handler_send (struct client_data *client, uint8_t *data, int data_len)
 {
+    ASSERT(data_len >= 0)
+    ASSERT(data_len <= SC_MAX_ENC)
     ASSERT(INITSTATUS_HASLINK(client->initstatus))
     ASSERT(!client->dying)
     
@@ -1503,10 +1518,14 @@ void client_input_handler_send (struct client_data *client, uint8_t *data, int d
     }
     
     struct sc_header *header = (struct sc_header *)data;
+    uint8_t type = ltoh8(header->type);
     
     uint8_t *sc_data = data + sizeof(struct sc_header);
     int sc_data_len = data_len - sizeof(struct sc_header);
     
+    ASSERT(sc_data_len >= 0)
+    ASSERT(sc_data_len <= SC_MAX_PAYLOAD)
+    
     // restart no data timer
     BReactor_SetTimer(&ss, &client->disconnect_timer);
     
@@ -1514,7 +1533,7 @@ void client_input_handler_send (struct client_data *client, uint8_t *data, int d
     PacketPassInterface_Done(&client->input_interface);
     
     // perform action based on packet type
-    switch (header->type) {
+    switch (type) {
         case SCID_KEEPALIVE:
             client_log(client, BLOG_DEBUG, "received keep-alive");
             return;
@@ -1571,7 +1590,7 @@ void process_packet_hello (struct client_data *client, uint8_t *data, int data_l
     }
     pack->flags = htol16(0);
     pack->id = htol16(client->id);
-    pack->clientAddr = (client->addr.type == BADDR_TYPE_IPV4 ? client->addr.ipv4.ip : 0);
+    pack->clientAddr = (client->addr.type == BADDR_TYPE_IPV4 ? client->addr.ipv4.ip : htol32(0));
     client_end_control_packet(client, SCID_SERVERHELLO);
 }
 
@@ -1609,7 +1628,7 @@ void client_publish_job (struct client_data *client)
     struct peer_know *k_to = malloc(sizeof(*k_to));
     if (!k_to) {
         client_log(client, BLOG_ERROR, "failed to allocate know to %d", (int)client2->id);
-        goto fail;
+        goto stop_publishing;
     }
     
     if (client_send_newclient(client, client2, relay_to, relay_from) < 0) {
@@ -1624,7 +1643,7 @@ void client_publish_job (struct client_data *client)
     struct peer_know *k_from = malloc(sizeof(*k_from));
     if (!k_from) {
         client_log(client, BLOG_ERROR, "failed to allocate know from %d", (int)client2->id);
-        goto fail;
+        goto stop_publishing;
     }
     
     if (client_send_newclient(client2, client, relay_from, relay_to) < 0) {
@@ -1637,18 +1656,18 @@ void client_publish_job (struct client_data *client)
     // create flow from client to client2
     if (!peer_flow_create(client, client2)) {
         client_log(client, BLOG_ERROR, "failed to allocate flow to %d", (int)client2->id);
-        goto fail;
+        goto stop_publishing;
     }
     
     // create flow from client2 to client
     if (!peer_flow_create(client2, client)) {
         client_log(client, BLOG_ERROR, "failed to allocate flow from %d", (int)client2->id);
-        goto fail;
+        goto stop_publishing;
     }
     
     return;
     
-fail:
+stop_publishing:
     // on out of memory, stop publishing client
     BPending_Unset(&client->publish_job);
 }
@@ -1682,7 +1701,7 @@ void process_packet_outmsg (struct client_data *client, uint8_t *data, int data_
     // lookup flow to destination client
     BAVLNode *node = BAVL_LookupExact(&client->peer_out_flows_tree, &id);
     if (!node) {
-        client_log(client, BLOG_NOTICE, "no flow for message to %d", (int)id);
+        client_log(client, BLOG_INFO, "no flow for message to %d", (int)id);
         return;
     }
     struct peer_flow *flow = UPPER_OBJECT(node, struct peer_flow, src_tree_node);
@@ -1693,7 +1712,7 @@ void process_packet_outmsg (struct client_data *client, uint8_t *data, int data_
         return;
     }
     pack->clientid = htol16(client->id);
-    memcpy((uint8_t *)pack + sizeof(struct sc_server_inmsg), payload, payload_size);
+    memcpy((uint8_t *)(pack + 1), payload, payload_size);
     peer_flow_end_packet(flow, SCID_INMSG);
 }
 
@@ -1716,7 +1735,7 @@ struct peer_flow * peer_flow_create (struct client_data *src_client, struct clie
     flow->dest_client = dest_client;
     flow->dest_client_id = dest_client->id;
     
-    // add to source list and hash table
+    // add to source list and tree
     LinkedList2_Append(&flow->src_client->peer_out_flows_list, &flow->src_list_node);
     ASSERT_EXECUTE(BAVL_Insert(&flow->src_client->peer_out_flows_tree, &flow->src_tree_node, NULL))
     
@@ -1808,9 +1827,8 @@ int peer_flow_start_packet (struct peer_flow *flow, void **data, int len)
 
 void peer_flow_end_packet (struct peer_flow *flow, uint8_t type)
 {
-    ASSERT(flow->dest_client->initstatus == INITSTATUS_COMPLETE)
-    ASSERT(!flow->dest_client->dying)
     ASSERT(flow->packet_len >= 0)
+    ASSERT(flow->packet_len <= SC_MAX_PAYLOAD)
     
     // write header
     struct sc_header *header = (struct sc_header *)flow->packet;
@@ -1868,11 +1886,16 @@ int clients_by_id_key_comparator (peerid_t *id1, peerid_t *id2)
 
 int clients_by_id_hash_function (peerid_t *id, int modulo)
 {
-    return (jenkins_lookup2_hash((uint8_t *)id, sizeof(peerid_t), clients_by_id_initval) % modulo);
+    return (jenkins_lookup2_hash((uint8_t *)id, sizeof(*id), clients_by_id_initval) % modulo);
 }
 
 int clients_allowed (struct client_data *client1, struct client_data *client2)
 {
+    ASSERT(client1->initstatus == INITSTATUS_COMPLETE)
+    ASSERT(!client1->dying)
+    ASSERT(client2->initstatus == INITSTATUS_COMPLETE)
+    ASSERT(!client2->dying)
+    
     if (!options.comm_predicate) {
         return 1;
     }
@@ -1888,7 +1911,13 @@ int clients_allowed (struct client_data *client1, struct client_data *client2)
     BAddr_GetIPAddr(&client1->addr, &comm_predicate_p1addr);
     BAddr_GetIPAddr(&client2->addr, &comm_predicate_p2addr);
     
-    return BPredicate_Eval(&comm_predicate);
+    // evaluate predicate
+    int res = BPredicate_Eval(&comm_predicate);
+    if (res < 0) {
+        return 0;
+    }
+    
+    return res;
 }
 
 int comm_predicate_func_p1name_cb (void *user, void **args)
@@ -1912,7 +1941,7 @@ int comm_predicate_func_p1addr_cb (void *user, void **args)
     BIPAddr addr;
     if (!BIPAddr_Resolve(&addr, arg, 1)) {
         BLog(BLOG_WARNING, "failed to parse address");
-        return 0;
+        return -1;
     }
     
     return BIPAddr_Compare(&addr, &comm_predicate_p1addr);
@@ -1925,7 +1954,7 @@ int comm_predicate_func_p2addr_cb (void *user, void **args)
     BIPAddr addr;
     if (!BIPAddr_Resolve(&addr, arg, 1)) {
         BLog(BLOG_WARNING, "failed to parse address");
-        return 0;
+        return -1;
     }
     
     return BIPAddr_Compare(&addr, &comm_predicate_p2addr);
@@ -1948,7 +1977,13 @@ int relay_allowed (struct client_data *client, struct client_data *relay)
     BAddr_GetIPAddr(&client->addr, &relay_predicate_paddr);
     BAddr_GetIPAddr(&relay->addr, &relay_predicate_raddr);
     
-    return BPredicate_Eval(&relay_predicate);
+    // evaluate predicate
+    int res = BPredicate_Eval(&relay_predicate);
+    if (res < 0) {
+        return 0;
+    }
+    
+    return res;
 }
 
 int relay_predicate_func_pname_cb (void *user, void **args)
@@ -1972,7 +2007,7 @@ int relay_predicate_func_paddr_cb (void *user, void **args)
     BIPAddr addr;
     if (!BIPAddr_Resolve(&addr, arg, 1)) {
         BLog(BLOG_ERROR, "paddr: failed to parse address");
-        return 0;
+        return -1;
     }
     
     return BIPAddr_Compare(&addr, &relay_predicate_paddr);
@@ -1985,7 +2020,7 @@ int relay_predicate_func_raddr_cb (void *user, void **args)
     BIPAddr addr;
     if (!BIPAddr_Resolve(&addr, arg, 1)) {
         BLog(BLOG_ERROR, "raddr: failed to parse address");
-        return 0;
+        return -1;
     }
     
     return BIPAddr_Compare(&addr, &relay_predicate_raddr);