Sun, 30 Apr 2000 21:47:04 +0000
[gaim-migrate @ 210]
Made the receive non-blocking, added a cancel button, and a few other updates.
No, sending a file to someone does not work yet. Be patient.
| 2 | 1 | |
| 2 | /* | |
| 3 | * aim_conn.c | |
| 4 | * | |
| 5 | * Does all this gloriously nifty connection handling stuff... | |
| 6 | * | |
| 7 | */ | |
| 8 | ||
| 9 | #include "aim.h" | |
| 10 | ||
| 11 | void aim_connrst(void) | |
| 12 | { | |
| 13 | int i; | |
| 14 | for (i = 0; i < AIM_CONN_MAX; i++) | |
| 15 | { | |
| 16 | aim_conns[i].fd = -1; | |
| 17 | aim_conns[i].type = -1; | |
| 18 | aim_conns[i].status = 0; | |
| 19 | } | |
| 20 | ||
| 21 | } | |
| 22 | ||
| 23 | struct aim_conn_t *aim_conn_getnext(void) | |
| 24 | { | |
| 25 | int i; | |
| 26 | for (i=0;i<AIM_CONN_MAX;i++) | |
| 27 | if (aim_conns[i].fd == -1) | |
| 28 | return &(aim_conns[i]); | |
| 29 | return NULL; | |
| 30 | } | |
| 31 | ||
| 32 | void aim_conn_close(struct aim_conn_t *deadconn) | |
| 33 | { | |
| 34 | if (deadconn->fd >= 3) | |
| 35 | close(deadconn->fd); | |
| 36 | deadconn->fd = -1; | |
| 37 | deadconn->type = -1; | |
| 38 | } | |
| 39 | ||
| 40 | struct aim_conn_t *aim_getconn_type(int type) | |
| 41 | { | |
| 42 | int i; | |
| 43 | for (i=0; i<AIM_CONN_MAX; i++) | |
| 44 | if (aim_conns[i].type == type) | |
| 45 | return &(aim_conns[i]); | |
| 46 | return NULL; | |
| 47 | } | |
| 48 | ||
| 49 | /* | |
| 50 | * aim_newconn(type, dest) | |
| 51 | * | |
| 52 | * Opens a new connection to the specified dest host of type type. | |
| 53 | * | |
| 54 | * TODO: fix for proxies | |
| 55 | * FIXME: Return errors in a more sane way. | |
| 56 | * | |
| 57 | */ | |
| 58 | struct aim_conn_t *aim_newconn(int type, char *dest) | |
| 59 | { | |
| 60 | struct aim_conn_t *connstruct; | |
| 61 | int ret; | |
| 62 | struct sockaddr_in sa; | |
| 63 | struct hostent *hp; | |
| 64 | int port = FAIM_LOGIN_PORT; | |
| 65 | int i=0; | |
| 66 | ||
| 67 | if (!dest || ((connstruct=aim_conn_getnext())==NULL)) | |
| 68 | return NULL; | |
| 69 | ||
| 70 | connstruct->type = type; | |
| 71 | ||
| 72 | /* | |
| 73 | * As of 23 Jul 1999, AOL now sends the port number, preceded by a | |
| 74 | * colon, in the BOS redirect. This fatally breaks all previous | |
| 75 | * libfaims. Bad, bad AOL. | |
| 76 | * | |
| 77 | * We put this here to catch every case. | |
| 78 | * | |
| 79 | */ | |
| 80 | for(i=0;(i<strlen(dest));i++) | |
| 81 | if (dest[i] == ':') break; | |
| 82 | if (i<strlen(dest)) | |
| 83 | { | |
| 84 | port = atoi(dest+i); | |
| 85 | dest[i] = '\0'; | |
| 86 | } | |
| 87 | ||
| 88 | hp = gethostbyname2(dest, AF_INET); | |
| 89 | if (hp == NULL) | |
| 90 | { | |
| 91 | connstruct->status = (h_errno | AIM_CONN_STATUS_RESOLVERR); | |
| 92 | return connstruct; | |
| 93 | } | |
| 94 | ||
| 95 | memset(&sa.sin_zero, 0, 8); | |
| 96 | sa.sin_port = htons(port); | |
| 97 | memcpy(&sa.sin_addr, hp->h_addr, hp->h_length); | |
| 98 | sa.sin_family = hp->h_addrtype; | |
| 99 | ||
| 100 | connstruct->fd = socket(hp->h_addrtype, SOCK_STREAM, 0); | |
| 101 | ret = connect(connstruct->fd, (struct sockaddr *)&sa, sizeof(struct sockaddr_in)); | |
| 102 | if( ret < 0) | |
| 103 | { | |
| 104 | connstruct->fd = -1; | |
| 105 | connstruct->status = (errno | AIM_CONN_STATUS_CONNERR); | |
| 106 | return connstruct; | |
| 107 | } | |
| 108 | ||
| 109 | return connstruct; | |
| 110 | } | |
| 111 | ||
| 112 | int aim_conngetmaxfd(void) | |
| 113 | { | |
| 114 | int i,j; | |
| 115 | j=0; | |
| 116 | for (i=0;i<AIM_CONN_MAX;i++) | |
| 117 | if(aim_conns[i].fd > j) | |
| 118 | j = aim_conns[i].fd; | |
| 119 | return j; | |
| 120 | } | |
| 121 | ||
| 122 | int aim_countconn(void) | |
| 123 | { | |
| 124 | int i,cnt; | |
| 125 | cnt = 0; | |
| 126 | for (i=0;i<AIM_CONN_MAX;i++) | |
| 127 | if (aim_conns[i].fd > -1) | |
| 128 | cnt++; | |
| 129 | return cnt; | |
| 130 | } | |
| 131 | ||
| 132 | /* | |
| 133 | * aim_select(timeout) | |
| 134 | * | |
| 135 | * Waits for a socket with data or for timeout, whichever comes first. | |
| 136 | * See select(2). | |
| 137 | * | |
| 138 | */ | |
| 139 | struct aim_conn_t *aim_select(struct timeval *timeout) | |
| 140 | { | |
| 141 | fd_set fds; | |
| 142 | fd_set errfds; | |
| 143 | int i; | |
| 144 | ||
| 145 | if (aim_countconn() <= 0) | |
| 146 | return 0; | |
| 147 | ||
| 148 | FD_ZERO(&fds); | |
| 149 | FD_ZERO(&errfds); | |
| 150 | ||
| 151 | for(i=0;i<AIM_CONN_MAX;i++) | |
| 152 | if (aim_conns[i].fd>-1) | |
| 153 | { | |
| 154 | FD_SET(aim_conns[i].fd, &fds); | |
| 155 | FD_SET(aim_conns[i].fd, &errfds); | |
| 156 | } | |
| 157 | ||
| 158 | i = select(aim_conngetmaxfd()+1, &fds, NULL, &errfds, timeout); | |
| 159 | if (i>=1) | |
| 160 | { | |
| 161 | int j; | |
| 162 | for (j=0;j<AIM_CONN_MAX;j++) | |
| 163 | { | |
| 164 | if ((FD_ISSET(aim_conns[j].fd, &errfds))) | |
| 165 | { | |
| 166 | /* got an exception; close whats left of it up */ | |
| 167 | aim_conn_close(&(aim_conns[j])); | |
| 168 | return (struct aim_conn_t *)-1; | |
| 169 | } | |
| 170 | else if ((FD_ISSET(aim_conns[j].fd, &fds))) | |
| 171 | return &(aim_conns[j]); /* return the first waiting struct */ | |
| 172 | } | |
| 173 | /* should never get here */ | |
| 174 | } | |
| 175 | else | |
| 176 | return (struct aim_conn_t *)i; /* no waiting or error, return -- FIXME: return type funnies */ | |
| 177 | return NULL; /* NO REACH */ | |
| 178 | } | |
| 179 | ||
| 180 | int aim_conn_isready(struct aim_conn_t *conn) | |
| 181 | { | |
| 182 | if (conn) | |
| 183 | return (conn->status & 0x0001); | |
| 184 | else | |
| 185 | return -1; | |
| 186 | } | |
| 187 | ||
| 188 | int aim_conn_setstatus(struct aim_conn_t *conn, int status) | |
| 189 | { | |
| 190 | if (conn) | |
| 191 | return (conn->status ^= status); | |
| 192 | else | |
| 193 | return -1; | |
| 194 | } | |
| 195 |