psd_server.c

Go to the documentation of this file.
00001 /*
00002  * $Id: psd_server.c 366303 2010-03-05 13:14:01Z taoliu $
00003  *
00004  * This code is provided as is by Juniper Networks SDK Developer Support.
00005  * It is provided with no warranties or guarantees, and Juniper Networks
00006  * will not provide support or maintenance of this code in any fashion.
00007  * The code is provided only to help a developer better understand how
00008  * the SDK can be used.
00009  *
00010  * Copyright (c) 2007-2008, Juniper Networks, Inc.
00011  * All rights reserved.
00012  */
00013 
00014 
00021 #include <sync/common.h>
00022 #include <sync/psd_ipc.h>
00023 #include <fnmatch.h>
00024 #include "psd_config.h"
00025 #include "psd_server.h"
00026 #include "psd_logging.h"
00027 
00028 #include PS_OUT_H
00029 
00030 /*** Constants ***/
00031 
00032 
00033 #define MAX_IPC_CONN        64        
00034 #define MAX_IPC_WAIT_CONN   3         
00035 
00036 
00039 #define BUFFER_SIZE         1024
00040 
00041 
00042 /*** Define'd helpers ***/
00043 
00047 #ifndef evInitID
00048 #define evInitID(id) ((id)->opaque = NULL)
00049 #endif
00050 
00054 #ifndef evTestID
00055 #define evTestID(id) ((id).opaque != NULL)
00056 #endif
00057 
00058 
00059 /*** Data Structures ***/
00060 
00064 typedef struct psd_ipc_conn_s {
00065     ipc_pipe_t * pipe;       
00066     int          socket;     
00067     evFileID     id;         
00068 } psd_ipc_conn_t;
00069 
00070 
00071 static psd_ipc_conn_t * connect_table[MAX_IPC_CONN]; 
00072 
00076 static evConnID server_conn_id;
00077 
00081 static evContext psd_ctx;
00082 
00083 
00084 /*** STATIC/INTERNAL Functions ***/
00085 
00086 
00090 static void
00091 connect_table_init(void)
00092 {
00093     int i;
00094 
00095     for(i = 0; i < MAX_IPC_CONN; i++) {
00096         connect_table[i] = NULL;
00097     }
00098 }
00099 
00100 
00110 static boolean
00111 connect_table_add(psd_ipc_conn_t *conn)
00112 {
00113     int i;
00114 
00115     for(i = 0; i < MAX_IPC_CONN; ++i) {
00116         if(connect_table[i] == NULL) {
00117             connect_table[i] = conn;
00118             return TRUE;
00119         }
00120     }
00121     return FALSE;
00122 }
00123 
00124 
00135 static boolean
00136 connect_table_del(psd_ipc_conn_t *conn)
00137 {
00138     int i;
00139 
00140     for(i = 0; i < MAX_IPC_CONN; ++i) {
00141         if(connect_table[i] == conn) {
00142             connect_table[i] = NULL;
00143             return TRUE;
00144         }
00145     }
00146     return FALSE;
00147 }
00148 
00149 
00156 static void
00157 psd_ipc_shutdown_conn(psd_ipc_conn_t *conn)
00158 {
00159     junos_trace(PSD_TRACEFLAG_NORMAL, "%s", __func__);
00160 
00161     if(evTestID(conn->id)) { // if select failed then don't deselect
00162         if(evDeselectFD(psd_ctx, conn->id) < 0) {  // Detach event.
00163             ERRMSG(PSD, TRACE_LOG_ERR,
00164                 "%s: evDeselect FAILED!", __func__);
00165         }
00166         evInitID(&conn->id);
00167     }
00168     
00169     ipc_pipe_detach_socket(conn->pipe, conn->socket);  // Detach pipe.
00170     
00171     if (conn->pipe != NULL)
00172         ipc_pipe_destroy(conn->pipe);  // Close pipe.
00173     
00174     close(conn->socket);  // Close socket to this client
00175     
00176     connect_table_del(conn);  // Remove connection from the table.
00177     
00178     free(conn);
00179 }
00180 
00181 
00192 static psd_policy_t *
00193 lookup_policy(policy_req_msg_t *req)
00194 {
00195     psd_policy_t *policy;
00196 
00197     junos_trace(PSD_TRACEFLAG_NORMAL, "%s", __func__);
00198 
00199     policy = first_policy();
00200     while(policy != NULL) {
00201         if((fnmatch(policy->ifname, req->ifname, 0) == 0) &&
00202                 (policy->af == req->af)) {
00203             break;
00204         }
00205         policy = next_policy(policy);
00206     }
00207     return policy;
00208 }
00209 
00210 
00226 static void 
00227 send_msg(ipc_pipe_t *ipc_pipe, msg_type_e msg_type, void *data, int len)
00228 {
00229     ipc_msg_t reply;
00230 
00231     reply.type = IPC_MSG_TYPE_PSD;
00232     reply.subtype = msg_type;
00233     reply.opcode = 0;
00234     reply.error = 0;
00235     reply.length = len;
00236 
00237     if(ipc_msg_write(ipc_pipe, &reply, data)) {
00238         ERRMSG(PSD, TRACE_LOG_ERR,
00239                   "%s: Write message FAILED!", __func__);
00240         
00241     } else if(ipc_pipe_write(ipc_pipe, NULL)) {
00242         ERRMSG(PSD, TRACE_LOG_ERR,
00243                   "%s: Write pipe FAILED!", __func__);
00244     }
00245     
00246     ipc_pipe_write_clean(ipc_pipe);
00247 }
00248 
00249 
00270 static void
00271 psd_ipc_dispatch (evContext ctx __unused,
00272                       void * uap,
00273                       int sockfd __unused,
00274                       int eventmask)
00275 {
00276     psd_ipc_conn_t *conn = (psd_ipc_conn_t *)uap;
00277     ipc_msg_t *msg;
00278     psd_policy_t *policy;
00279     psd_policy_route_t *route;
00280     policy_filter_msg_t fmsg;
00281     policy_route_msg_t rmsg;
00282 
00283     INSIST(conn != NULL);
00284 
00285     if(eventmask & EV_EXCEPT) { // check if it's an exception
00286         // We received out-of-band data
00287         ERRMSG(PSD, TRACE_LOG_ERR,
00288                 "%s: closing connection due to client exception", __func__);
00289         psd_ipc_shutdown_conn(conn);
00290         return;
00291     }
00292 
00293     // Otherwise it's a read
00294     if(ipc_pipe_read(conn->pipe) < 0) {
00295         /*
00296          * When errno is EAGAIN don't shutdown the connection.
00297          * EAGAIN is received when only partial msg is read.
00298          * So bail out and try later.
00299          */
00300         if(errno == EAGAIN || errno == EINTR) //ignore
00301             return;
00302 
00303         if(errno != 0) { // problem
00304             ERRMSG(PSD, TRACE_LOG_ERR,
00305                 "%s: Null ipc read causing connection shutdown due to: %m",
00306                 __func__);
00307 
00308             // if cannot read anything, shutdown the connection
00309             psd_ipc_shutdown_conn(conn);
00310             
00311         } else {
00312             junos_trace(PSD_TRACEFLAG_NORMAL,
00313                 "%s: Remote side of the pipe closed", __func__);
00314 
00315             // if cannot read anything, shutdown the connection
00316             psd_ipc_shutdown_conn(conn);
00317         }
00318         return;
00319     }
00320 
00321     while((msg = ipc_msg_read(conn->pipe)) != NULL) {
00322 
00323         /* if we got a null message, complain and break out */
00324         if (msg && msg->type == 0 && msg->subtype == 0 &&
00325             msg->length == 0 && msg->opcode == 0 && msg->error == 0) {
00326 
00327             ERRMSG(PSD, TRACE_LOG_ERR,
00328                       "%s: Received null msg", __func__);
00329             break;
00330         }
00331 
00332         //sanity checks; we just complain but still proceed.
00333         if(msg->type != IPC_MSG_TYPE_PSD) {
00334             ERRMSG(PSD, TRACE_LOG_ERR,
00335                 "%s: Unexpected message type %d", __func__, msg->type);
00336             continue;
00337         }
00338 
00339         switch(msg->subtype) {
00340             case MSG_POLICY_REQ:
00341                 junos_trace(PSD_TRACEFLAG_NORMAL,
00342                     "%s: Got policy request.", __func__);
00343                 policy = lookup_policy((policy_req_msg_t *)msg->data);
00344                 if(policy) {
00345                     if(policy->filter) {
00346                         junos_trace(PSD_TRACEFLAG_NORMAL,
00347                             "%s: Send filter.", __func__);
00348                         
00349                         // copy the template msg from the policy 
00350                         // into the local msg here (except ifname)
00351                         memcpy(((char *)&fmsg) + sizeof(fmsg.ifname),
00352                             ((char *)&policy->filter->filter_data) +
00353                                  sizeof(fmsg.ifname),
00354                             sizeof(policy_filter_msg_t) - sizeof(fmsg.ifname));
00355 
00356                         // copy the interface name we received in the reqest
00357                         // into the reply message                            
00358                         bzero(fmsg.ifname, sizeof(fmsg.ifname));
00359                         strcpy(fmsg.ifname,
00360                             ((policy_req_msg_t *)msg->data)->ifname);
00361                         
00362                         //send
00363                         send_msg(conn->pipe, MSG_FILTER, &fmsg,
00364                             sizeof(policy_filter_msg_t));
00365                     }
00366                     if(policy->route) {
00367                         route = policy->route;
00368                         while(route) {
00369                             junos_trace(PSD_TRACEFLAG_NORMAL,
00370                                 "%s: Send route.", __func__);
00371                         
00372                             // copy the template msg from the policy 
00373                             // into the local msg here (except ifname)        
00374                             memcpy(((char *)&rmsg) + sizeof(rmsg.ifname),
00375                                 ((char *)&route->route_data) +
00376                                     sizeof(rmsg.ifname),
00377                                 sizeof(policy_route_msg_t) -
00378                                     sizeof(rmsg.ifname));
00379 
00380                             // copy the interface name we received in the reqest
00381                             // into the reply message
00382                             bzero(rmsg.ifname, sizeof(rmsg.ifname));
00383                             strcpy(rmsg.ifname,
00384                                 ((policy_req_msg_t *)msg->data)->ifname);
00385                             
00386                             //send
00387                             send_msg(conn->pipe, MSG_ROUTE, &rmsg,
00388                                     sizeof(policy_route_msg_t));
00389                             route = route->next;
00390                         }
00391                     }
00392                 } else {
00393                     junos_trace(PSD_TRACEFLAG_NORMAL,
00394                             "%s: Send no policy.", __func__);
00395                     // No policy, echo policy request message.
00396                     send_msg(conn->pipe, MSG_POLICY_NA, msg->data,
00397                             sizeof(policy_req_msg_t));
00398                 }
00399                 break;
00400             case MSG_HB:
00401                 junos_trace(PSD_TRACEFLAG_HB,
00402                         "%s: Got heartbeat and reply.", __func__);
00403                 // Echo heart-beat message, no message data.
00404                 send_msg(conn->pipe, MSG_HB, NULL, 0);
00405                 break;
00406             case MSG_UPDATE_DONE:
00407                 junos_trace(PSD_TRACEFLAG_NORMAL,
00408                         "%s: Got update done and reply.", __func__);
00409                 // Echo update-done message, no message data.
00410                 send_msg(conn->pipe, MSG_UPDATE_DONE, NULL, 0);
00411                 break;
00412             default:
00413                 ERRMSG(PSD, TRACE_LOG_ERR,
00414                         "%s: Unexpected message subtype %d",
00415                          __func__, msg->subtype);
00416         }
00417     }
00418     ipc_pipe_read_clean(conn->pipe);
00419 }
00420 
00449 static void
00450 psd_ipc_connect (evContext ctx __unused, void * uap __unused, int sockfd,
00451                      const void * la, int lalen, // local addr from getsockname
00452                      const void * ra, int ralen) // remote addr from getpeername
00453 {
00454     psd_ipc_conn_t * conn;
00455     const struct sockaddr_in * laddr, * raddr;
00456 
00457     junos_trace(PSD_TRACEFLAG_NORMAL, "%s", __func__);
00458 
00459     laddr = (const struct sockaddr_in *)la;
00460     raddr = (const struct sockaddr_in *)ra;
00461 
00462     // check they are inet addresses of course
00463     INSIST(laddr != NULL && sizeof(struct sockaddr_in) == lalen);
00464     INSIST(raddr != NULL && sizeof(struct sockaddr_in) == ralen);
00465 
00466     junos_trace(PSD_TRACEFLAG_NORMAL,
00467             "%s: Received connection from %s:%d", 
00468              __func__, inet_ntoa(raddr->sin_addr), ntohs(raddr->sin_port));
00469 
00470     // create the connection structure
00471     conn = malloc(sizeof(*conn));
00472     INSIST(conn != NULL);
00473     bzero(conn, sizeof(*conn));
00474 
00475     // fill out the connection args
00476     conn->socket = sockfd;
00477     conn->pipe = ipc_pipe_create(BUFFER_SIZE);
00478     evInitID(&conn->id);
00479 
00480     // attach socket with pipe
00481     ipc_pipe_attach_socket(conn->pipe, conn->socket);
00482     connect_table_add(conn);
00483     
00484     if(evSelectFD(psd_ctx, sockfd, EV_READ | EV_EXCEPT,
00485                     psd_ipc_dispatch, conn, &conn->id) < 0) {
00486         ERRMSG(PSD, TRACE_LOG_ERR,
00487                 "%s: evSelectFD: %m", __func__);
00488 
00489         psd_ipc_shutdown_conn(conn);
00490     }
00491     // How do we shutdown in the normal disconnect case: We get a EV_READ
00492 }
00493 
00494 
00495 /*** GLOBAL/EXTERNAL Functions ***/
00496 
00497 
00510 int
00511 server_init (evContext ctx)
00512 {
00513     struct sockaddr_in addr;
00514     int sock = -1;
00515     const int sndbuf = BUFFER_SIZE;
00516     const int on = 1; // turn option on
00517     const int port = PSD_PORT_NUM;
00518 
00519     junos_trace(PSD_TRACEFLAG_NORMAL, "%s", __func__);
00520 
00521     psd_ctx = ctx; // save context
00522     connect_table_init();
00523 
00524     // Create socket and set options
00525     if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
00526         ERRMSG(PSD, TRACE_LOG_ERR,
00527                 "%s: Create socket FAILED!", __func__);
00528         return EFAIL;
00529     }
00530 
00531     // Set some socket options
00532     if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on))) {
00533         close(sock);
00534         ERRMSG(PSD, TRACE_LOG_ERR,
00535                 "%s: Set socket option SO_REUSEADDR FAILED!", __func__);
00536         return EFAIL;
00537     }
00538     if(setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf))) {
00539         close(sock);
00540         ERRMSG(PSD, TRACE_LOG_ERR,
00541                 "%s: Set socket option SO_SNDBUF FAILED!", __func__);
00542         return EFAIL;
00543     }
00544 
00545     if(vrf_setsocketbyvrfname(sock, "__juniper_private2__", NULL)) {
00546         close(sock);
00547         ERRMSG(PSD, TRACE_LOG_ERR,
00548                 "%s: Set socket to VRF FAILED!", __func__);
00549         return EFAIL;
00550     }
00551 
00552     // bind socket to address:
00553     bzero(&addr, sizeof(addr));
00554     addr.sin_len = sizeof (addr);
00555     addr.sin_family = AF_INET;
00556     addr.sin_port = htons(port);
00557     addr.sin_addr.s_addr = INADDR_ANY;
00558 
00559     if(bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
00560         close(sock);
00561         ERRMSG(PSD, TRACE_LOG_ERR,
00562                 "%s: Bind socket FAILED!", __func__);
00563         return EFAIL;
00564     }
00565 
00566     // listen for connection events.
00567     junos_trace(PSD_TRACEFLAG_NORMAL,
00568             "%s: policy server bound and listening on 0.0.0.0:%d",
00569              __func__, port);
00570              
00571     evInitID(&server_conn_id);
00572     if(evListen(psd_ctx, sock, MAX_IPC_WAIT_CONN, psd_ipc_connect,
00573                 NULL, &server_conn_id) < 0) { // no user data
00574         // NOTE: should unlink socket
00575         close(sock);
00576         ERRMSG(PSD, TRACE_LOG_ERR,
00577                 "%s: evListen FAILED!", __func__);
00578         return EFAIL;
00579     }
00580     
00581     return SUCCESS;   
00582 }
00583 
00584 
00589 void
00590 notify_all_clients(void)
00591 {
00592     int i;
00593 
00594     for(i = 0; i < MAX_IPC_CONN; i++) {
00595         if(connect_table[i]) {
00596             junos_trace(PSD_TRACEFLAG_NORMAL, "%s: %d", __func__, i);
00597             send_msg(connect_table[i]->pipe, MSG_POLICY_UPDATE, NULL, 0);
00598         }
00599     }
00600 }
00601 
00602 
00614 int
00615 server_shutdown(void)
00616 {
00617     int i;
00618     
00619     junos_trace(PSD_TRACEFLAG_NORMAL, "%s", __func__);
00620     
00621     // Stop listening for connections
00622 
00623     // if listen failed then don't cancel
00624     if(evTestID(server_conn_id)) {
00625         
00626         // This should stop accepting and close the server socket
00627         
00628         if(evCancelConn(psd_ctx, server_conn_id) < 0) {
00629             ERRMSG(PSD, TRACE_LOG_ERR,
00630                 "%s: Unable to stop listening for connections: %s",
00631                     __func__, strerror(errno));
00632             return EFAIL;
00633         }
00634 
00635         // need to call this after closing the connection
00636         evInitID(&server_conn_id);
00637     }
00638 
00639     // Get rid of any remaining connections to clients
00640     
00641     for(i = 0; i < MAX_IPC_CONN; ++i) {
00642         if(connect_table[i] != NULL) {
00643             psd_ipc_shutdown_conn(connect_table[i]);
00644         }
00645     }
00646 
00647     return SUCCESS;   
00648 }

2007-2009 Juniper Networks, Inc. All rights reserved. The information contained herein is confidential information of Juniper Networks, Inc., and may not be used, disclosed, distributed, modified, or copied without the prior written consent of Juniper Networks, Inc. in an express license. This information is subject to change by Juniper Networks, Inc. Juniper Networks, the Juniper Networks logo, and JUNOS are registered trademarks of Juniper Networks, Inc. in the United States and other countries. All other trademarks, service marks, registered trademarks, or registered service marks are the property of their respective owners.
Generated on Sun May 30 20:27:07 2010 for SDK Your Net Corporation Policy Manager Example: Policy Server Daemon 1.0 by Doxygen 1.5.1