1/* 2 * Copyright 2016, Data61 3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4 * ABN 41 687 119 230. 5 * 6 * This software may be distributed and modified according to the terms of 7 * the BSD 2-Clause license. Note that NO WARRANTY is provided. 8 * See "LICENSE_BSD2.txt" for details. 9 * 10 * @TAG(D61_BSD) 11 */ 12 13#include <refos-util/nameserv.h> 14#include <data_struct/cvector.h> 15 16/*! @file 17 @brief Name server implementation library. */ 18 19static nameserv_entry_t* 20nameserv_create_entry(const char* name, seL4_CPtr anonEP) 21{ 22 if (!name || !anonEP) { 23 return NULL; 24 } 25 uint32_t nameLen = strlen(name); 26 if (nameLen == 0) { 27 return NULL; 28 } 29 30 /* Allocate the nameserv entry. */ 31 nameserv_entry_t* entry = malloc(sizeof(nameserv_entry_t)); 32 if (!entry) { 33 printf("WARNING: nameserv_create_entry failed to malloc entry. Out of memory.\n"); 34 return NULL; 35 } 36 37 /* Allocate name for the string. */ 38 entry->name = malloc(sizeof(char) * (nameLen + 2)); 39 if (!entry->name) { 40 printf("WARNING: nameserv_create_entry failed to malloc name str. Out of memory.\n"); 41 free(entry); 42 return NULL; 43 } 44 45 /* Fill in the data. */ 46 strcpy(entry->name, name); 47 entry->magic = REFOS_NAMESERV_ENTRY_MAGIC; 48 entry->anonEP = anonEP; 49 50 return entry; 51} 52 53static void 54nameserv_release_entry(nameserv_state_t *n, nameserv_entry_t* entry) 55{ 56 assert(n && n->magic == REFOS_NAMESERV_MAGIC); 57 assert(entry && entry->magic == REFOS_NAMESERV_ENTRY_MAGIC); 58 assert(n->free_capability); 59 60 entry->magic = 0; 61 free(entry->name); 62 n->free_capability(entry->anonEP); 63 free(entry); 64} 65 66void 67nameserv_init(nameserv_state_t *n, void (*free_cap) (seL4_CPtr cap)) 68{ 69 assert(n && free_cap); 70 n->magic = REFOS_NAMESERV_MAGIC; 71 n->free_capability = free_cap; 72 cvector_init(&n->entries); 73} 74 75void 76nameserv_release(nameserv_state_t *n) 77{ 78 assert(n && n->magic == REFOS_NAMESERV_MAGIC); 79 int nEntries = cvector_count(&n->entries); 80 for (int i = 0; i < nEntries; i++) { 81 nameserv_entry_t *nameEntry = (nameserv_entry_t *) cvector_get(&n->entries, i); 82 nameserv_release_entry(n, nameEntry); 83 } 84 cvector_free(&n->entries); 85 n->magic = 0; 86} 87 88int 89nameserv_add(nameserv_state_t *n, const char* name, seL4_CPtr anonEP) 90{ 91 assert(n && n->magic == REFOS_NAMESERV_MAGIC); 92 if (!name || !anonEP) { 93 return EINVALIDPARAM; 94 } 95 nameserv_delete(n, name); 96 nameserv_entry_t *nameEntry = nameserv_create_entry(name, anonEP); 97 if (!nameEntry) { 98 return ENOMEM; 99 } 100 cvector_add(&n->entries, (cvector_item_t) nameEntry); 101 return ESUCCESS; 102} 103 104static int 105nameserv_find_entry_index(nameserv_state_t *n, const char* name) 106{ 107 assert(n && n->magic == REFOS_NAMESERV_MAGIC); 108 if (!name) { 109 return -1; 110 } 111 int nEntries = cvector_count(&n->entries); 112 /* Loop through the list and find a matching name. */ 113 for (int i = 0; i < nEntries; i++) { 114 nameserv_entry_t *nameEntry = (nameserv_entry_t *) cvector_get(&n->entries, i); 115 assert(nameEntry && nameEntry->name && nameEntry->magic == REFOS_NAMESERV_ENTRY_MAGIC); 116 if (!strcmp(nameEntry->name, name)) { 117 return i; 118 } 119 } 120 return -1; 121} 122 123void 124nameserv_delete(nameserv_state_t *n, const char* name) 125{ 126 assert(n && n->magic == REFOS_NAMESERV_MAGIC); 127 int idx = nameserv_find_entry_index(n, name); 128 if (idx == -1) { 129 return; 130 } 131 nameserv_entry_t *nameEntry = (nameserv_entry_t *) cvector_get(&n->entries, idx); 132 nameserv_release_entry(n, nameEntry); 133 cvector_delete(&n->entries, idx); 134} 135 136int 137nameserv_resolve(nameserv_state_t *n, const char* path, seL4_CPtr *outAnonCap) 138{ 139 assert(n && n->magic == REFOS_NAMESERV_MAGIC); 140 141 /* Return no resolve on empty paths. */ 142 if (!path) { 143 return 0; 144 } 145 int pathLen = strlen(path); 146 if (pathLen <= 0) { 147 return 0; 148 } 149 150 /* Ignore any leading slashes. */ 151 const char* path_ = path; 152 if (path_[0] == '/') { 153 path_++; 154 } 155 156 /* Allocate temporary buffer to store path segment. */ 157 char *pathSegment = malloc(sizeof(char) * (pathLen + 2)); 158 if (!pathSegment) { 159 printf("ERROR: nameserv_resolve could not allocate path segment. OOM.\n"); 160 return 0; 161 } 162 int pathSegmentIndex = 0; 163 164 /* Find the next slash-separated path segment. */ 165 bool segmentFound = false; 166 const char* ci; 167 for (ci = path_; *ci != '\0'; ci++) { 168 if (*ci == '/') { 169 segmentFound = true; 170 break; 171 } 172 pathSegment[pathSegmentIndex++] = *ci; 173 } 174 pathSegment[pathSegmentIndex++] = '\0'; 175 176 /* If are at end of path resolvation, return our own anonymous endpoint. */ 177 if (!segmentFound) { 178 return REFOS_NAMESERV_RESOLVED; 179 } 180 181 /* Otherwise, find the external anon endpoint. */ 182 int idx = nameserv_find_entry_index(n, pathSegment); 183 if (idx == -1) { 184 /* Name not found. */ 185 return 0; 186 } 187 188 /* External EP name resolvation succeeded. */ 189 nameserv_entry_t *nameEntry = (nameserv_entry_t *) cvector_get(&n->entries, idx); 190 assert(nameEntry && nameEntry->name && nameEntry->magic == REFOS_NAMESERV_ENTRY_MAGIC); 191 if (outAnonCap) { 192 (*outAnonCap) = nameEntry->anonEP; 193 } 194 int offset = ci - path; 195 assert(offset >= 0 && offset < pathLen); 196 return offset; 197}