00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "asterisk.h"
00027
00028 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 182945 $")
00029
00030 #include <termios.h>
00031 #include <sys/ioctl.h>
00032
00033 #include "asterisk/io.h"
00034 #include "asterisk/utils.h"
00035
00036 #ifdef DEBUG_IO
00037 #define DEBUG DEBUG_M
00038 #else
00039 #define DEBUG(a)
00040 #endif
00041
00042
00043
00044
00045 struct io_rec {
00046 ast_io_cb callback;
00047 void *data;
00048 int *id;
00049 };
00050
00051
00052
00053
00054
00055
00056
00057
00058 #define GROW_SHRINK_SIZE 512
00059
00060
00061
00062 struct io_context {
00063 struct pollfd *fds;
00064 struct io_rec *ior;
00065 unsigned int fdcnt;
00066 unsigned int maxfdcnt;
00067 int current_ioc;
00068 int needshrink;
00069 };
00070
00071
00072 struct io_context *io_context_create(void)
00073 {
00074 struct io_context *tmp = NULL;
00075
00076 if (!(tmp = ast_malloc(sizeof(*tmp))))
00077 return NULL;
00078
00079 tmp->needshrink = 0;
00080 tmp->fdcnt = 0;
00081 tmp->maxfdcnt = GROW_SHRINK_SIZE/2;
00082 tmp->current_ioc = -1;
00083
00084 if (!(tmp->fds = ast_calloc(1, (GROW_SHRINK_SIZE / 2) * sizeof(*tmp->fds)))) {
00085 ast_free(tmp);
00086 tmp = NULL;
00087 } else {
00088 if (!(tmp->ior = ast_calloc(1, (GROW_SHRINK_SIZE / 2) * sizeof(*tmp->ior)))) {
00089 ast_free(tmp->fds);
00090 ast_free(tmp);
00091 tmp = NULL;
00092 }
00093 }
00094
00095 return tmp;
00096 }
00097
00098 void io_context_destroy(struct io_context *ioc)
00099 {
00100
00101 if (ioc->fds)
00102 ast_free(ioc->fds);
00103 if (ioc->ior)
00104 ast_free(ioc->ior);
00105
00106 ast_free(ioc);
00107 }
00108
00109
00110
00111
00112
00113 static int io_grow(struct io_context *ioc)
00114 {
00115 void *tmp;
00116
00117 DEBUG(ast_debug(1, "io_grow()\n"));
00118
00119 ioc->maxfdcnt += GROW_SHRINK_SIZE;
00120
00121 if ((tmp = ast_realloc(ioc->ior, (ioc->maxfdcnt + 1) * sizeof(*ioc->ior)))) {
00122 ioc->ior = tmp;
00123 if ((tmp = ast_realloc(ioc->fds, (ioc->maxfdcnt + 1) * sizeof(*ioc->fds)))) {
00124 ioc->fds = tmp;
00125 } else {
00126
00127
00128
00129
00130
00131
00132 ioc->maxfdcnt -= GROW_SHRINK_SIZE;
00133 return -1;
00134 }
00135 } else {
00136
00137
00138
00139
00140 ioc->maxfdcnt -= GROW_SHRINK_SIZE;
00141 return -1;
00142 }
00143
00144 return 0;
00145 }
00146
00147
00148
00149
00150
00151
00152
00153 int *ast_io_add(struct io_context *ioc, int fd, ast_io_cb callback, short events, void *data)
00154 {
00155 int *ret;
00156
00157 DEBUG(ast_debug(1, "ast_io_add()\n"));
00158
00159 if (ioc->fdcnt >= ioc->maxfdcnt) {
00160
00161
00162
00163
00164 if (io_grow(ioc))
00165 return NULL;
00166 }
00167
00168
00169
00170
00171
00172
00173 ioc->fds[ioc->fdcnt].fd = fd;
00174 ioc->fds[ioc->fdcnt].events = events;
00175 ioc->fds[ioc->fdcnt].revents = 0;
00176 ioc->ior[ioc->fdcnt].callback = callback;
00177 ioc->ior[ioc->fdcnt].data = data;
00178
00179 if (!(ioc->ior[ioc->fdcnt].id = ast_malloc(sizeof(*ioc->ior[ioc->fdcnt].id)))) {
00180
00181 return NULL;
00182 }
00183
00184 *(ioc->ior[ioc->fdcnt].id) = ioc->fdcnt;
00185 ret = ioc->ior[ioc->fdcnt].id;
00186 ioc->fdcnt++;
00187
00188 return ret;
00189 }
00190
00191 int *ast_io_change(struct io_context *ioc, int *id, int fd, ast_io_cb callback, short events, void *data)
00192 {
00193
00194 if (*id > ioc->fdcnt)
00195 return NULL;
00196
00197 if (fd > -1)
00198 ioc->fds[*id].fd = fd;
00199 if (callback)
00200 ioc->ior[*id].callback = callback;
00201 if (events)
00202 ioc->fds[*id].events = events;
00203 if (data)
00204 ioc->ior[*id].data = data;
00205
00206 return id;
00207 }
00208
00209 static int io_shrink(struct io_context *ioc)
00210 {
00211 int getfrom, putto = 0;
00212
00213
00214
00215
00216
00217
00218 for (getfrom = 0; getfrom < ioc->fdcnt; getfrom++) {
00219 if (ioc->ior[getfrom].id) {
00220
00221 if (getfrom != putto) {
00222 ioc->fds[putto] = ioc->fds[getfrom];
00223 ioc->ior[putto] = ioc->ior[getfrom];
00224 *(ioc->ior[putto].id) = putto;
00225 }
00226 putto++;
00227 }
00228 }
00229 ioc->fdcnt = putto;
00230 ioc->needshrink = 0;
00231
00232
00233 return 0;
00234 }
00235
00236 int ast_io_remove(struct io_context *ioc, int *_id)
00237 {
00238 int x;
00239
00240 if (!_id) {
00241 ast_log(LOG_WARNING, "Asked to remove NULL?\n");
00242 return -1;
00243 }
00244
00245 for (x = 0; x < ioc->fdcnt; x++) {
00246 if (ioc->ior[x].id == _id) {
00247
00248 ast_free(ioc->ior[x].id);
00249 ioc->ior[x].id = NULL;
00250 ioc->fds[x].events = 0;
00251 ioc->fds[x].revents = 0;
00252 ioc->needshrink = 1;
00253 if (ioc->current_ioc == -1)
00254 io_shrink(ioc);
00255 return 0;
00256 }
00257 }
00258
00259 ast_log(LOG_NOTICE, "Unable to remove unknown id %p\n", _id);
00260
00261 return -1;
00262 }
00263
00264
00265
00266
00267
00268
00269 int ast_io_wait(struct io_context *ioc, int howlong)
00270 {
00271 int res, x, origcnt;
00272
00273 DEBUG(ast_debug(1, "ast_io_wait()\n"));
00274
00275 if ((res = ast_poll(ioc->fds, ioc->fdcnt, howlong)) <= 0) {
00276 return res;
00277 }
00278
00279
00280 origcnt = ioc->fdcnt;
00281 for (x = 0; x < origcnt; x++) {
00282
00283
00284 if (ioc->fds[x].revents && ioc->ior[x].id) {
00285
00286 ioc->current_ioc = *ioc->ior[x].id;
00287 if (ioc->ior[x].callback) {
00288 if (!ioc->ior[x].callback(ioc->ior[x].id, ioc->fds[x].fd, ioc->fds[x].revents, ioc->ior[x].data)) {
00289
00290 ast_io_remove(ioc, ioc->ior[x].id);
00291 }
00292 }
00293 ioc->current_ioc = -1;
00294 }
00295 }
00296
00297 if (ioc->needshrink)
00298 io_shrink(ioc);
00299
00300 return res;
00301 }
00302
00303 void ast_io_dump(struct io_context *ioc)
00304 {
00305
00306
00307
00308
00309 int x;
00310
00311 ast_debug(1, "Asterisk IO Dump: %d entries, %d max entries\n", ioc->fdcnt, ioc->maxfdcnt);
00312 ast_debug(1, "================================================\n");
00313 ast_debug(1, "| ID FD Callback Data Events |\n");
00314 ast_debug(1, "+------+------+-----------+-----------+--------+\n");
00315 for (x = 0; x < ioc->fdcnt; x++) {
00316 ast_debug(1, "| %.4d | %.4d | %p | %p | %.6x |\n",
00317 *ioc->ior[x].id,
00318 ioc->fds[x].fd,
00319 ioc->ior[x].callback,
00320 ioc->ior[x].data,
00321 ioc->fds[x].events);
00322 }
00323 ast_debug(1, "================================================\n");
00324 }
00325
00326
00327
00328 int ast_hide_password(int fd)
00329 {
00330 struct termios tios;
00331 int res;
00332 int old;
00333 if (!isatty(fd))
00334 return -1;
00335 res = tcgetattr(fd, &tios);
00336 if (res < 0)
00337 return -1;
00338 old = tios.c_lflag & (ECHO | ECHONL);
00339 tios.c_lflag &= ~ECHO;
00340 tios.c_lflag |= ECHONL;
00341 res = tcsetattr(fd, TCSAFLUSH, &tios);
00342 if (res < 0)
00343 return -1;
00344 return old;
00345 }
00346
00347 int ast_restore_tty(int fd, int oldstate)
00348 {
00349 int res;
00350 struct termios tios;
00351 if (oldstate < 0)
00352 return 0;
00353 res = tcgetattr(fd, &tios);
00354 if (res < 0)
00355 return -1;
00356 tios.c_lflag &= ~(ECHO | ECHONL);
00357 tios.c_lflag |= oldstate;
00358 res = tcsetattr(fd, TCSAFLUSH, &tios);
00359 if (res < 0)
00360 return -1;
00361 return 0;
00362 }
00363
00364 int ast_get_termcols(int fd)
00365 {
00366 struct winsize win;
00367 int cols = 0;
00368
00369 if (!isatty(fd))
00370 return -1;
00371
00372 if ( ioctl(fd, TIOCGWINSZ, &win) != -1 ) {
00373 if ( !cols && win.ws_col > 0 )
00374 cols = (int) win.ws_col;
00375 } else {
00376
00377 cols = 80;
00378 }
00379
00380 return cols;
00381 }
00382