]> andersk Git - libfaim.git/blob - aim_rxqueue.c
- Thu Aug 17 23:19:40 UTC 2000
[libfaim.git] / aim_rxqueue.c
1 /*
2  *  aim_rxqueue.c
3  *
4  * This file contains the management routines for the receive
5  * (incoming packet) queue.  The actual packet handlers are in
6  * aim_rxhandlers.c.
7  */
8
9 #include <faim/aim.h> 
10
11 /*
12  * Grab a single command sequence off the socket, and enqueue
13  * it in the incoming event queue in a seperate struct.
14  */
15 int aim_get_command(struct aim_session_t *sess, struct aim_conn_t *conn)
16 {
17   unsigned char generic[6]; 
18   struct command_rx_struct *newrx = NULL;
19
20   if (!sess || !conn)
21     return 0;
22
23   if (conn->fd < 3)  /* can happen when people abuse the interface */
24     return 0;
25
26   /*
27    * Rendezvous (client-client) connections do not speak
28    * FLAP, so this function will break on them.
29    */
30   if (conn->type == AIM_CONN_TYPE_RENDEZVOUS) 
31     return aim_get_command_rendezvous(sess, conn);
32   if (conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) 
33     return 0; 
34
35   /*
36    * Read FLAP header.  Six bytes:
37    *    
38    *   0 char  -- Always 0x2a
39    *   1 char  -- Channel ID.  Usually 2 -- 1 and 4 are used during login.
40    *   2 short -- Sequence number 
41    *   4 short -- Number of data bytes that follow.
42    */
43   faim_mutex_lock(&conn->active);
44   if (read(conn->fd, generic, 6) < 6){
45     aim_conn_close(conn);
46     faim_mutex_unlock(&conn->active);
47     return -1;
48   }
49
50   /*
51    * This shouldn't happen unless the socket breaks, the server breaks,
52    * or we break.  We must handle it just in case.
53    */
54   if (generic[0] != 0x2a) {
55     faimdprintf(1, "Bad incoming data!");
56     aim_conn_close(conn);
57     faim_mutex_unlock(&conn->active);
58     return -1;
59   }     
60
61   /* allocate a new struct */
62   if (!(newrx = (struct command_rx_struct *)malloc(sizeof(struct command_rx_struct)))) {
63     faim_mutex_unlock(&conn->active);
64     return -1;
65   }
66   memset(newrx, 0x00, sizeof(struct command_rx_struct));
67
68   newrx->lock = 1;  /* lock the struct */
69
70   /* we're doing OSCAR if we're here */
71   newrx->hdrtype = AIM_FRAMETYPE_OSCAR;
72
73   /* store channel -- byte 2 */
74   newrx->hdr.oscar.type = (char) generic[1];
75
76   /* store seqnum -- bytes 3 and 4 */
77   newrx->hdr.oscar.seqnum = aimutil_get16(generic+2);
78
79   /* store commandlen -- bytes 5 and 6 */
80   newrx->commandlen = aimutil_get16(generic+4);
81
82   newrx->nofree = 0; /* free by default */
83
84   /* malloc for data portion */
85   if (!(newrx->data = (u_char *) malloc(newrx->commandlen))) {
86     free(newrx);
87     faim_mutex_unlock(&conn->active);
88     return -1;
89   }
90
91   /* read the data portion of the packet */
92   if (read(conn->fd, newrx->data, newrx->commandlen) < newrx->commandlen){
93     free(newrx->data);
94     free(newrx);
95     aim_conn_close(conn);
96     faim_mutex_unlock(&conn->active);
97     return -1;
98   }
99   faim_mutex_unlock(&conn->active);
100
101   newrx->conn = conn;
102
103   newrx->next = NULL;  /* this will always be at the bottom */
104   newrx->lock = 0; /* unlock */
105
106   /* enqueue this packet */
107   if (sess->queue_incoming == NULL) {
108     sess->queue_incoming = newrx;
109   } else {
110     struct command_rx_struct *cur;
111
112     /*
113      * This append operation takes a while.  It might be faster
114      * if we maintain a pointer to the last entry in the queue
115      * and just update that.  Need to determine if the overhead
116      * to maintain that is lower than the overhead for this loop.
117      */
118     for (cur = sess->queue_incoming; cur->next; cur = cur->next)
119       ;
120     cur->next = newrx;
121   }
122   
123   newrx->conn->lastactivity = time(NULL);
124
125   return 0;  
126 }
127
128 /*
129  * Purge recieve queue of all handled commands (->handled==1).  Also
130  * allows for selective freeing using ->nofree so that the client can
131  * keep the data for various purposes.  
132  *
133  * If ->nofree is nonzero, the frame will be delinked from the global list, 
134  * but will not be free'ed.  The client _must_ keep a pointer to the
135  * data -- libfaim will not!  If the client marks ->nofree but
136  * does not keep a pointer, it's lost forever.
137  *
138  */
139 void aim_purge_rxqueue(struct aim_session_t *sess)
140 {
141   struct command_rx_struct *cur = NULL;
142   struct command_rx_struct *tmp;
143
144   if (sess->queue_incoming == NULL)
145     return;
146   
147   if (sess->queue_incoming->next == NULL) {
148     if (sess->queue_incoming->handled) {
149       tmp = sess->queue_incoming;
150       sess->queue_incoming = NULL;
151
152       if (!tmp->nofree) {
153         if (tmp->hdrtype == AIM_FRAMETYPE_OFT)
154           free(tmp->hdr.oft.hdr2);
155         free(tmp->data);
156         free(tmp);
157       } else
158         tmp->next = NULL;
159     }
160     return;
161   }
162
163   for(cur = sess->queue_incoming; cur->next != NULL; ) {
164     if (cur->next->handled) {
165       tmp = cur->next;
166       cur->next = tmp->next;
167       if (!tmp->nofree) {
168         if (tmp->hdrtype == AIM_FRAMETYPE_OFT)
169           free(tmp->hdr.oft.hdr2);
170         free(tmp->data);
171         free(tmp);
172       } else
173         tmp->next = NULL;
174     }   
175     cur = cur->next;
176
177     /* 
178      * Be careful here.  Because of the way we just
179      * manipulated the pointer, cur may be NULL and 
180      * the for() will segfault doing the check unless
181      * we find this case first.
182      */
183     if (cur == NULL)    
184       break;
185   }
186
187   return;
188 }
189
190 /*
191  * Since aim_get_command will aim_conn_kill dead connections, we need
192  * to clean up the rxqueue of unprocessed connections on that socket.
193  *
194  * XXX: this is something that was handled better in the old connection
195  * handling method, but eh.
196  */
197 void aim_rxqueue_cleanbyconn(struct aim_session_t *sess, struct aim_conn_t *conn)
198 {
199   struct command_rx_struct *currx;
200
201   for (currx = sess->queue_incoming; currx; currx = currx->next) {
202     if ((!currx->handled) && (currx->conn == conn))
203       currx->handled = 1;
204   }     
205   return;
206 }
This page took 0.048173 seconds and 5 git commands to generate.