source: mainline/uspace/lib/nettl/src/portrng.c@ d776329b

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since d776329b was 8a637a4, checked in by Martin Decky <martin@…>, 10 years ago

remove EEXISTS in favor of EEXIST

  • Property mode set to 100644
File size: 5.5 KB
Line 
1/*
2 * Copyright (c) 2015 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libnettl
30 * @{
31 */
32
33/**
34 * @file Port range allocator
35 *
36 * Allocates port numbers from IETF port number ranges.
37 */
38
39#include <adt/list.h>
40#include <errno.h>
41#include <inet/endpoint.h>
42#include <nettl/portrng.h>
43#include <stdint.h>
44#include <stdlib.h>
45
46#include <io/log.h>
47
48/** Create port range.
49 *
50 * @param rpr Place to store pointer to new port range
51 * @return EOK on success, ENOMEM if out of memory
52 */
53int portrng_create(portrng_t **rpr)
54{
55 portrng_t *pr;
56
57 log_msg(LOG_DEFAULT, LVL_DEBUG2, "portrng_create() - begin");
58
59 pr = calloc(1, sizeof(portrng_t));
60 if (pr == NULL)
61 return ENOMEM;
62
63 list_initialize(&pr->used);
64 *rpr = pr;
65 log_msg(LOG_DEFAULT, LVL_DEBUG2, "portrng_create() - end");
66 return EOK;
67}
68
69/** Destroy port range.
70 *
71 * @param pr Port range
72 */
73void portrng_destroy(portrng_t *pr)
74{
75 log_msg(LOG_DEFAULT, LVL_DEBUG2, "portrng_destroy()");
76 assert(list_empty(&pr->used));
77 free(pr);
78}
79
80/** Allocate port number from port range.
81 *
82 * @param pr Port range
83 * @param pnum Port number to allocate specific port, or zero to allocate
84 * any valid port from range
85 * @param arg User argument to set for port
86 * @param flags Flags, @c pf_allow_system to allow ports from system range
87 * to be specified by @a pnum.
88 * @param apnum Place to store allocated port number
89 *
90 * @return EOK on success, ENOENT if no free port number found, EEXIST
91 * if @a pnum is specified but it is already allocated,
92 * EINVAL if @a pnum is specified from the system range, but
93 * @c pf_allow_system was not set.
94 */
95int portrng_alloc(portrng_t *pr, uint16_t pnum, void *arg,
96 portrng_flags_t flags, uint16_t *apnum)
97{
98 portrng_port_t *p;
99 uint32_t i;
100 bool found;
101
102 log_msg(LOG_DEFAULT, LVL_DEBUG2, "portrng_alloc() - begin");
103
104 if (pnum == inet_port_any) {
105
106 for (i = inet_port_dyn_lo; i <= inet_port_dyn_hi; i++) {
107 log_msg(LOG_DEFAULT, LVL_DEBUG2, "trying %" PRIu32, i);
108 found = false;
109 list_foreach(pr->used, lprng, portrng_port_t, port) {
110 if (port->pn == pnum) {
111 found = true;
112 break;
113 }
114 }
115
116 if (!found) {
117 pnum = i;
118 break;
119 }
120 }
121
122 if (pnum == inet_port_any) {
123 /* No free port found */
124 return ENOENT;
125 }
126 log_msg(LOG_DEFAULT, LVL_DEBUG2, "selected %" PRIu16, pnum);
127 } else {
128 log_msg(LOG_DEFAULT, LVL_DEBUG2, "user asked for %" PRIu16, pnum);
129
130 if ((flags & pf_allow_system) == 0 &&
131 pnum < inet_port_user_lo) {
132 log_msg(LOG_DEFAULT, LVL_DEBUG2, "system port not allowed");
133 return EINVAL;
134 }
135
136 list_foreach(pr->used, lprng, portrng_port_t, port) {
137 if (port->pn == pnum) {
138 log_msg(LOG_DEFAULT, LVL_DEBUG2, "port already used");
139 return EEXIST;
140 }
141 }
142 }
143
144 p = calloc(1, sizeof(portrng_port_t));
145 if (p == NULL)
146 return ENOMEM;
147
148 p->pn = pnum;
149 p->arg = arg;
150 list_append(&p->lprng, &pr->used);
151 *apnum = pnum;
152 log_msg(LOG_DEFAULT, LVL_DEBUG2, "portrng_alloc() - end OK pn=%" PRIu16,
153 pnum);
154 return EOK;
155}
156
157/** Find allocated port number and return its argument.
158 *
159 * @param pr Port range
160 * @param pnum Port number
161 * @param rarg Place to store user argument
162 *
163 * @return EOK on success, ENOENT if specified port number is not allocated
164 */
165int portrng_find_port(portrng_t *pr, uint16_t pnum, void **rarg)
166{
167 list_foreach(pr->used, lprng, portrng_port_t, port) {
168 if (port->pn == pnum) {
169 *rarg = port->arg;
170 return EOK;
171 }
172 }
173
174 return ENOENT;
175}
176
177/** Free port in port range.
178 *
179 * @param pr Port range
180 * @param pnum Port number
181 */
182void portrng_free_port(portrng_t *pr, uint16_t pnum)
183{
184 log_msg(LOG_DEFAULT, LVL_DEBUG2, "portrng_free_port() - begin");
185 list_foreach(pr->used, lprng, portrng_port_t, port) {
186 if (port->pn == pnum) {
187 list_remove(&port->lprng);
188 free(port);
189 return;
190 }
191 }
192
193 assert(false);
194 log_msg(LOG_DEFAULT, LVL_DEBUG2, "portrng_free_port() - end");
195}
196
197/** Determine if port range is empty.
198 *
199 * @param pr Port range
200 * @return @c true if no ports are allocated from @a pr, @c false otherwise
201 */
202bool portrng_empty(portrng_t *pr)
203{
204 log_msg(LOG_DEFAULT, LVL_DEBUG2, "portrng_empty()");
205 return list_empty(&pr->used);
206}
207
208/**
209 * @}
210 */
211
Note: See TracBrowser for help on using the repository browser.